Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1487 lines
33KB

  1. /*
  2. * DISTHRO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the license see the GPL.txt file
  16. */
  17. #include "DistrhoDefines.h"
  18. #ifdef DISTRHO_UI_OPENGL
  19. # include "DistrhoUIOpenGLExt.h"
  20. #include <cassert>
  21. #include <cmath>
  22. #include <vector>
  23. #if DISTRHO_OS_LINUX
  24. # include <X11/Xlib.h>
  25. #endif
  26. START_NAMESPACE_DISTRHO
  27. // -------------------------------------------------
  28. // Point
  29. Point::Point(int x, int y)
  30. : _x(x),
  31. _y(y)
  32. {
  33. }
  34. Point::Point(const Point& pos)
  35. : _x(pos._x),
  36. _y(pos._y)
  37. {
  38. }
  39. int Point::getX() const
  40. {
  41. return _x;
  42. }
  43. int Point::getY() const
  44. {
  45. return _y;
  46. }
  47. void Point::setX(int x)
  48. {
  49. _x = x;
  50. }
  51. void Point::setY(int y)
  52. {
  53. _y = y;
  54. }
  55. Point& Point::operator=(const Point& pos)
  56. {
  57. _x = pos._x;
  58. _y = pos._y;
  59. return *this;
  60. }
  61. Point& Point::operator+=(const Point& pos)
  62. {
  63. _x += pos._x;
  64. _y += pos._y;
  65. return *this;
  66. }
  67. Point& Point::operator-=(const Point& pos)
  68. {
  69. _x -= pos._x;
  70. _y -= pos._y;
  71. return *this;
  72. }
  73. bool Point::operator==(const Point& pos) const
  74. {
  75. return (_x == pos._x && _y == pos._y);
  76. }
  77. bool Point::operator!=(const Point& pos) const
  78. {
  79. return !operator==(pos);
  80. }
  81. // -------------------------------------------------
  82. // Point
  83. Size::Size(int width, int height)
  84. : _width(width),
  85. _height(height)
  86. {
  87. }
  88. Size::Size(const Size& size)
  89. : _width(size._width),
  90. _height(size._height)
  91. {
  92. }
  93. int Size::getWidth() const
  94. {
  95. return _width;
  96. }
  97. int Size::getHeight() const
  98. {
  99. return _height;
  100. }
  101. void Size::setWidth(int width)
  102. {
  103. _width = width;
  104. }
  105. void Size::setHeight(int height)
  106. {
  107. _height = height;
  108. }
  109. Size& Size::operator=(const Size& size)
  110. {
  111. _width = size._width;
  112. _height = size._height;
  113. return *this;
  114. }
  115. Size& Size::operator+=(const Size& size)
  116. {
  117. _width += size._width;
  118. _height += size._height;
  119. return *this;
  120. }
  121. Size& Size::operator-=(const Size& size)
  122. {
  123. _width -= size._width;
  124. _height -= size._height;
  125. return *this;
  126. }
  127. Size& Size::operator*=(int m)
  128. {
  129. _width *= m;
  130. _height *= m;
  131. return *this;
  132. }
  133. Size& Size::operator/=(int d)
  134. {
  135. _width /= d;
  136. _height /= d;
  137. return *this;
  138. }
  139. Size& Size::operator*=(float m)
  140. {
  141. _width *= m;
  142. _height *= m;
  143. return *this;
  144. }
  145. Size& Size::operator/=(float d)
  146. {
  147. _width /= d;
  148. _height /= d;
  149. return *this;
  150. }
  151. // -------------------------------------------------
  152. // Rectangle
  153. Rectangle::Rectangle(int x, int y, int width, int height)
  154. : _pos(x, y),
  155. _size(width, height)
  156. {
  157. }
  158. Rectangle::Rectangle(int x, int y, const Size& size)
  159. : _pos(x, y),
  160. _size(size)
  161. {
  162. }
  163. Rectangle::Rectangle(const Point& pos, int width, int height)
  164. : _pos(pos),
  165. _size(width, height)
  166. {
  167. }
  168. Rectangle::Rectangle(const Point& pos, const Size& size)
  169. : _pos(pos),
  170. _size(size)
  171. {
  172. }
  173. Rectangle::Rectangle(const Rectangle& rect)
  174. : _pos(rect._pos),
  175. _size(rect._size)
  176. {
  177. }
  178. int Rectangle::getX() const
  179. {
  180. return _pos._x;
  181. }
  182. int Rectangle::getY() const
  183. {
  184. return _pos._y;
  185. }
  186. int Rectangle::getWidth() const
  187. {
  188. return _size._width;
  189. }
  190. int Rectangle::getHeight() const
  191. {
  192. return _size._height;
  193. }
  194. const Point& Rectangle::getPos() const
  195. {
  196. return _pos;
  197. }
  198. const Size& Rectangle::getSize() const
  199. {
  200. return _size;
  201. }
  202. bool Rectangle::contains(int x, int y) const
  203. {
  204. return (x >= _pos._x && y >= _pos._y && x <= _pos._x+_size._width && y <= _pos._y+_size._height);
  205. }
  206. bool Rectangle::contains(const Point& pos) const
  207. {
  208. return contains(pos._x, pos._y);
  209. }
  210. bool Rectangle::containsX(int x) const
  211. {
  212. return (x >= _pos._x && x <= _pos._x+_size._width);
  213. }
  214. bool Rectangle::containsY(int y) const
  215. {
  216. return (y >= _pos._y && y <= _pos._y+_size._height);
  217. }
  218. void Rectangle::setX(int x)
  219. {
  220. _pos._x = x;
  221. }
  222. void Rectangle::setY(int y)
  223. {
  224. _pos._y = y;
  225. }
  226. void Rectangle::setPos(int x, int y)
  227. {
  228. _pos._x = x;
  229. _pos._y = y;
  230. }
  231. void Rectangle::setPos(const Point& pos)
  232. {
  233. _pos = pos;
  234. }
  235. void Rectangle::move(int x, int y)
  236. {
  237. _pos._x += x;
  238. _pos._y += y;
  239. }
  240. void Rectangle::move(const Point& pos)
  241. {
  242. _pos += pos;
  243. }
  244. void Rectangle::setWidth(int width)
  245. {
  246. _size._width = width;
  247. }
  248. void Rectangle::setHeight(int height)
  249. {
  250. _size._height = height;
  251. }
  252. void Rectangle::setSize(int width, int height)
  253. {
  254. _size._width = width;
  255. _size._height = height;
  256. }
  257. void Rectangle::setSize(const Size& size)
  258. {
  259. _size = size;
  260. }
  261. void Rectangle::grow(int m)
  262. {
  263. _size *= m;
  264. }
  265. void Rectangle::grow(float m)
  266. {
  267. _size *= m;
  268. }
  269. void Rectangle::grow(int width, int height)
  270. {
  271. _size._width += width;
  272. _size._height += height;
  273. }
  274. void Rectangle::grow(const Size& size)
  275. {
  276. _size += size;
  277. }
  278. void Rectangle::shrink(int m)
  279. {
  280. _size /= m;
  281. }
  282. void Rectangle::shrink(float m)
  283. {
  284. _size /= m;
  285. }
  286. void Rectangle::shrink(int width, int height)
  287. {
  288. _size._width -= width;
  289. _size._height -= height;
  290. }
  291. void Rectangle::shrink(const Size& size)
  292. {
  293. _size -= size;
  294. }
  295. Rectangle& Rectangle::operator=(const Rectangle& rect)
  296. {
  297. _pos = rect._pos;
  298. _size = rect._size;
  299. return *this;
  300. }
  301. Rectangle& Rectangle::operator+=(const Point& pos)
  302. {
  303. _pos += pos;
  304. return *this;
  305. }
  306. Rectangle& Rectangle::operator-=(const Point& pos)
  307. {
  308. _pos -= pos;
  309. return *this;
  310. }
  311. Rectangle& Rectangle::operator+=(const Size& size)
  312. {
  313. _size += size;
  314. return *this;
  315. }
  316. Rectangle& Rectangle::operator-=(const Size& size)
  317. {
  318. _size -= size;
  319. return *this;
  320. }
  321. // -------------------------------------------------
  322. // Image
  323. Image::Image(const char* data, int width, int height, GLenum format, GLenum type)
  324. : _data(data),
  325. _size(width, height),
  326. _format(format),
  327. _type(type)
  328. {
  329. }
  330. Image::Image(const char* data, const Size& size, GLenum format, GLenum type)
  331. : _data(data),
  332. _size(size),
  333. _format(format),
  334. _type(type)
  335. {
  336. }
  337. Image::Image(const Image& image)
  338. : _data(image._data),
  339. _size(image._size),
  340. _format(image._format),
  341. _type(image._type)
  342. {
  343. }
  344. bool Image::isValid() const
  345. {
  346. return (_data && getWidth() > 0 && getHeight() > 0);
  347. }
  348. int Image::getWidth() const
  349. {
  350. return _size.getWidth();
  351. }
  352. int Image::getHeight() const
  353. {
  354. return _size.getHeight();
  355. }
  356. const Size& Image::getSize() const
  357. {
  358. return _size;
  359. }
  360. const char* Image::getData() const
  361. {
  362. return _data;
  363. }
  364. GLenum Image::getFormat() const
  365. {
  366. return _format;
  367. }
  368. GLenum Image::getType() const
  369. {
  370. return _type;
  371. }
  372. Image& Image::operator=(const Image& image)
  373. {
  374. _data = image._data;
  375. _size = image._size;
  376. _format = image._format;
  377. _type = image._type;
  378. return *this;
  379. }
  380. // -------------------------------------------------
  381. // ImageButton
  382. ImageButton::ImageButton(const Image& imageNormal, const Image& imageHover, const Image& imageDown, const Point& pos)
  383. : _imageNormal(imageNormal),
  384. _imageHover(imageHover),
  385. _imageDown(imageDown),
  386. _curImage(&_imageNormal),
  387. _pos(pos),
  388. _area(pos, imageNormal.getSize())
  389. {
  390. }
  391. ImageButton::ImageButton(const ImageButton& imageButton)
  392. : _imageNormal(imageButton._imageNormal),
  393. _imageHover(imageButton._imageHover),
  394. _imageDown(imageButton._imageDown),
  395. _curImage(&_imageNormal),
  396. _pos(imageButton._pos),
  397. _area(imageButton._area)
  398. {
  399. }
  400. int ImageButton::getWidth() const
  401. {
  402. return _area.getWidth();
  403. }
  404. int ImageButton::getHeight() const
  405. {
  406. return _area.getHeight();
  407. }
  408. const Size& ImageButton::getSize() const
  409. {
  410. return _area.getSize();
  411. }
  412. ImageButton& ImageButton::operator=(const ImageButton& imageButton)
  413. {
  414. _imageNormal = imageButton._imageNormal;
  415. _imageHover = imageButton._imageHover;
  416. _imageDown = imageButton._imageDown;
  417. _curImage = &_imageNormal;
  418. _pos = imageButton._pos;
  419. _area = imageButton._area;
  420. return *this;
  421. }
  422. // -------------------------------------------------
  423. // ImageKnob
  424. ImageKnob::ImageKnob(const Image& image, const Point& pos, Orientation orientation)
  425. : _image(image),
  426. _pos(pos),
  427. _orientation(orientation),
  428. _isVertical(image.getHeight() > image.getWidth()),
  429. _layerSize(_isVertical ? image.getWidth() : image.getHeight()),
  430. _layerCount(_isVertical ? image.getHeight()/_layerSize : image.getWidth()/_layerSize),
  431. _area(_pos, _layerSize, _layerSize)
  432. {
  433. _min = 0.0f;
  434. _max = 1.0f;
  435. _value = _min;
  436. }
  437. ImageKnob::ImageKnob(const ImageKnob& imageKnob)
  438. : _image(imageKnob._image),
  439. _pos(imageKnob._pos),
  440. _orientation(imageKnob._orientation),
  441. _isVertical(imageKnob._isVertical),
  442. _layerSize(imageKnob._layerSize),
  443. _layerCount(imageKnob._layerCount),
  444. _area(imageKnob._area)
  445. {
  446. _min = imageKnob._min;
  447. _max = imageKnob._max;
  448. _value = imageKnob._value;
  449. }
  450. void ImageKnob::setOrientation(Orientation orientation)
  451. {
  452. _orientation = orientation;
  453. }
  454. void ImageKnob::setRange(float min, float max)
  455. {
  456. _min = min;
  457. _max = max;
  458. if (_value < _min)
  459. _value = _min;
  460. else if (_value > _max)
  461. _value = _max;
  462. }
  463. void ImageKnob::setValue(float value)
  464. {
  465. if (value < _min)
  466. value = _min;
  467. else if (value > _max)
  468. value = _max;
  469. _value = value;
  470. }
  471. ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob)
  472. {
  473. _image = imageKnob._image;
  474. _pos = imageKnob._pos;
  475. _orientation = imageKnob._orientation;
  476. _isVertical = imageKnob._isVertical;
  477. _layerSize = imageKnob._layerSize;
  478. _layerCount = imageKnob._layerCount;
  479. _area = imageKnob._area;
  480. _min = imageKnob._min;
  481. _max = imageKnob._max;
  482. _value = imageKnob._value;
  483. return *this;
  484. }
  485. // -------------------------------------------------
  486. // ImageSlider
  487. ImageSlider::ImageSlider(const Image& image, const Point& startPos, const Point& endPos)
  488. : _image(image),
  489. _startPos(startPos),
  490. _endPos(endPos),
  491. _area(startPos.getX(), startPos.getY(),
  492. endPos.getX() > startPos.getX() ? endPos.getX() + image.getWidth() - startPos.getX() : image.getWidth(),
  493. endPos.getY() > startPos.getY() ? endPos.getY() + image.getHeight() - startPos.getY() : image.getHeight())
  494. {
  495. _min = 0.0f;
  496. _max = 1.0f;
  497. _value = _min;
  498. }
  499. ImageSlider::ImageSlider(const ImageSlider& imageSlider)
  500. : _image(imageSlider._image),
  501. _startPos(imageSlider._startPos),
  502. _endPos(imageSlider._endPos),
  503. _area(imageSlider._area)
  504. {
  505. _min = imageSlider._min;
  506. _max = imageSlider._max;
  507. _value = imageSlider._value;
  508. }
  509. int ImageSlider::getWidth() const
  510. {
  511. return _image.getWidth();
  512. }
  513. int ImageSlider::getHeight() const
  514. {
  515. return _image.getHeight();
  516. }
  517. void ImageSlider::setRange(float min, float max)
  518. {
  519. _min = min;
  520. _max = max;
  521. if (_value < _min)
  522. _value = _min;
  523. else if (_value > _max)
  524. _value = _max;
  525. }
  526. void ImageSlider::setValue(float value)
  527. {
  528. if (value < _min)
  529. value = _min;
  530. else if (value > _max)
  531. value = _max;
  532. _value = value;
  533. }
  534. ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider)
  535. {
  536. _image = imageSlider._image;
  537. _startPos = imageSlider._startPos;
  538. _endPos = imageSlider._endPos;
  539. _area = imageSlider._area;
  540. _min = imageSlider._min;
  541. _max = imageSlider._max;
  542. _value = imageSlider._value;
  543. return *this;
  544. }
  545. // -------------------------------------------------
  546. class OpenGLDialog
  547. {
  548. public:
  549. OpenGLDialog(PuglView* parentView, const Size& parentSize, const Image& image_, const char* title)
  550. : image(image_)
  551. {
  552. #if DISTRHO_OS_LINUX
  553. bool addToDesktop = false;
  554. #else
  555. bool addToDesktop = true;
  556. #endif
  557. view = puglCreate(0, title, image.getWidth(), image.getHeight(), false, addToDesktop);
  558. closed = bool(!view);
  559. if (closed)
  560. return;
  561. puglSetHandle(view, this);
  562. puglSetDisplayFunc(view, onDisplayCallback);
  563. puglSetKeyboardFunc(view, onKeyboardCallback);
  564. puglSetMotionFunc(view, onMotionCallback);
  565. puglSetMouseFunc(view, onMouseCallback);
  566. puglSetScrollFunc(view, onScrollCallback);
  567. puglSetSpecialFunc(view, onSpecialCallback);
  568. puglSetReshapeFunc(view, onReshapeCallback);
  569. puglSetCloseFunc(view, onCloseCallback);
  570. #if DISTRHO_OS_LINUX
  571. Display* display = view->impl->display;
  572. Window thisWindow = view->impl->win;
  573. Window parentWindow = parentView->impl->win;
  574. int x = (parentSize.getWidth()-image.getWidth())/2;
  575. int y = (parentSize.getHeight()-image.getHeight())/2;
  576. Window childRet;
  577. if (XTranslateCoordinates(display, parentWindow, thisWindow, x, y, &x, &y, &childRet))
  578. XMoveWindow(display, thisWindow, x, y);
  579. XSetTransientForHint(display, thisWindow, parentWindow);
  580. XMapRaised(display, thisWindow);
  581. #endif
  582. }
  583. ~OpenGLDialog()
  584. {
  585. if (view)
  586. puglDestroy(view);
  587. }
  588. bool idle()
  589. {
  590. if (view)
  591. puglProcessEvents(view);
  592. return !closed;
  593. }
  594. void close()
  595. {
  596. closed = true;
  597. }
  598. void raise()
  599. {
  600. if (view)
  601. {
  602. #if DISTRHO_OS_LINUX
  603. Display* display = view->impl->display;
  604. Window window = view->impl->win;
  605. XRaiseWindow(display, window);
  606. XSetInputFocus(display, window, RevertToPointerRoot, CurrentTime);
  607. #endif
  608. }
  609. }
  610. protected:
  611. void onDisplay()
  612. {
  613. glClear(GL_COLOR_BUFFER_BIT);
  614. glRasterPos2i(0, image.getHeight());
  615. glDrawPixels(image.getWidth(), image.getHeight(), image.getFormat(), image.getType(), image.getData());
  616. }
  617. void onKeyboard(bool press, uint32_t key)
  618. {
  619. if (press && key == CHAR_ESCAPE)
  620. closed = true;
  621. }
  622. void onMotion(int, int)
  623. {
  624. }
  625. void onMouse(int, bool, int, int)
  626. {
  627. }
  628. void onReshape(int width, int height)
  629. {
  630. glMatrixMode(GL_PROJECTION);
  631. glLoadIdentity();
  632. glOrtho(0, width, height, 0, 0, 1);
  633. glViewport(0, 0, width, height);
  634. glMatrixMode(GL_MODELVIEW);
  635. glLoadIdentity();
  636. }
  637. void onScroll(float, float)
  638. {
  639. }
  640. void onSpecial(bool, Key)
  641. {
  642. }
  643. void onClose()
  644. {
  645. closed = true;
  646. }
  647. private:
  648. PuglView* view;
  649. bool closed;
  650. const Image image;
  651. // Callbacks
  652. static void onDisplayCallback(PuglView* view)
  653. {
  654. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  655. _this_->onDisplay();
  656. }
  657. static void onKeyboardCallback(PuglView* view, bool press, uint32_t key)
  658. {
  659. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  660. _this_->onKeyboard(press, key);
  661. }
  662. static void onMotionCallback(PuglView* view, int x, int y)
  663. {
  664. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  665. _this_->onMotion(x, y);
  666. }
  667. static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
  668. {
  669. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  670. _this_->onMouse(button, press, x, y);
  671. }
  672. static void onReshapeCallback(PuglView* view, int width, int height)
  673. {
  674. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  675. _this_->onReshape(width, height);
  676. }
  677. static void onScrollCallback(PuglView* view, float dx, float dy)
  678. {
  679. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  680. _this_->onScroll(dx, dy);
  681. }
  682. static void onSpecialCallback(PuglView* view, bool press, PuglKey key)
  683. {
  684. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  685. _this_->onSpecial(press, (Key)key);
  686. }
  687. static void onCloseCallback(PuglView* view)
  688. {
  689. OpenGLDialog* _this_ = (OpenGLDialog*)puglGetHandle(view);
  690. _this_->onClose();
  691. }
  692. };
  693. enum ObjectType {
  694. OBJECT_NULL = 0,
  695. OBJECT_BUTTON = 1,
  696. OBJECT_KNOB = 2,
  697. OBJECT_SLIDER = 3
  698. };
  699. #if DISTRHO_OS_LINUX
  700. struct LinuxData {
  701. Display* display;
  702. Window window;
  703. char colorData[8];
  704. XColor colorBlack;
  705. Pixmap pixmapBlack;
  706. Cursor cursorBlack;
  707. LinuxData()
  708. : display(nullptr),
  709. window(0),
  710. colorData{0},
  711. colorBlack{0, 0, 0, 0, 0, 0}
  712. {
  713. }
  714. ~LinuxData()
  715. {
  716. XFreeCursor(display, cursorBlack);
  717. }
  718. };
  719. #endif
  720. struct OpenGLExtUIPrivateData {
  721. int initialPosX;
  722. int initialPosY;
  723. void* lastObj;
  724. Point lastCursorPos;
  725. ObjectType lastObjType;
  726. Image background;
  727. std::vector<ImageButton*> buttons;
  728. std::vector<ImageKnob*> knobs;
  729. std::vector<ImageSlider*> sliders;
  730. OpenGLDialog* dialog;
  731. #if DISTRHO_OS_LINUX
  732. LinuxData linuxData;
  733. #endif
  734. OpenGLExtUIPrivateData()
  735. : initialPosX(0),
  736. initialPosY(0),
  737. lastObj(nullptr),
  738. lastCursorPos(0, 0),
  739. lastObjType(OBJECT_NULL),
  740. background(nullptr, 0, 0),
  741. dialog(nullptr)
  742. {
  743. }
  744. void showCursor()
  745. {
  746. #if DISTRHO_OS_LINUX
  747. if (lastCursorPos != Point(-1, -2))
  748. XWarpPointer(linuxData.display, None, DefaultRootWindow(linuxData.display), 0, 0, 0, 0, lastCursorPos.getX(), lastCursorPos.getY());
  749. XUndefineCursor(linuxData.display, linuxData.window);
  750. #endif
  751. }
  752. void hideCursor()
  753. {
  754. #if DISTRHO_OS_LINUX
  755. Window root, child;
  756. int rootX, rootY, winX, winY;
  757. unsigned int mask;
  758. if (XQueryPointer(linuxData.display, DefaultRootWindow(linuxData.display), &root, &child, &rootX, &rootY, &winX, &winY, &mask))
  759. lastCursorPos = Point(rootX, rootY);
  760. else
  761. lastCursorPos = Point(-1, -2);
  762. XDefineCursor(linuxData.display, linuxData.window, linuxData.cursorBlack);
  763. #endif
  764. }
  765. };
  766. // -------------------------------------------------
  767. OpenGLExtUI::OpenGLExtUI()
  768. : OpenGLUI()
  769. {
  770. data = new OpenGLExtUIPrivateData;
  771. }
  772. OpenGLExtUI::~OpenGLExtUI()
  773. {
  774. assert(! data->dialog);
  775. delete data;
  776. }
  777. // -------------------------------------------------
  778. // UI Callbacks
  779. void OpenGLExtUI::d_uiIdle()
  780. {
  781. if (data->dialog && ! data->dialog->idle())
  782. {
  783. delete data->dialog;
  784. data->dialog = nullptr;
  785. }
  786. OpenGLUI::d_uiIdle();
  787. }
  788. // -------------------------------------------------
  789. // Extended Calls
  790. void OpenGLExtUI::setBackgroundImage(const Image& image)
  791. {
  792. data->background = image;
  793. d_uiRepaint();
  794. }
  795. void OpenGLExtUI::addImageButton(ImageButton* button)
  796. {
  797. data->buttons.push_back(button);
  798. }
  799. void OpenGLExtUI::addImageKnob(ImageKnob* knob)
  800. {
  801. data->knobs.push_back(knob);
  802. }
  803. void OpenGLExtUI::addImageSlider(ImageSlider* slider)
  804. {
  805. data->sliders.push_back(slider);
  806. }
  807. void OpenGLExtUI::showImageModalDialog(const Image& image, const char* title)
  808. {
  809. data->dialog = new OpenGLDialog(OpenGLUI::data->widget, Size(d_width(), d_height()), image, title);
  810. }
  811. // -------------------------------------------------
  812. // Extended Callbacks
  813. void OpenGLExtUI::imageButtonClicked(ImageButton*)
  814. {
  815. }
  816. void OpenGLExtUI::imageKnobDragStarted(ImageKnob*)
  817. {
  818. }
  819. void OpenGLExtUI::imageKnobDragFinished(ImageKnob*)
  820. {
  821. }
  822. void OpenGLExtUI::imageKnobValueChanged(ImageKnob*, float)
  823. {
  824. }
  825. void OpenGLExtUI::imageSliderValueChanged(ImageSlider*, float)
  826. {
  827. }
  828. void OpenGLExtUI::imageSliderDragStarted(ImageSlider*)
  829. {
  830. }
  831. void OpenGLExtUI::imageSliderDragFinished(ImageSlider*)
  832. {
  833. }
  834. void OpenGLExtUI::d_onInit()
  835. {
  836. glEnable(GL_BLEND);
  837. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  838. glMatrixMode(GL_PROJECTION);
  839. glLoadIdentity();
  840. glOrtho(0, d_width(), d_height(), 0, 0, 1);
  841. glViewport(0, 0, d_width(), d_height());
  842. glMatrixMode(GL_MODELVIEW);
  843. glLoadIdentity();
  844. #if DISTRHO_OS_LINUX
  845. data->linuxData.display = OpenGLUI::data->widget->impl->display;
  846. data->linuxData.window = OpenGLUI::data->widget->impl->win;
  847. data->linuxData.pixmapBlack = XCreateBitmapFromData(data->linuxData.display, data->linuxData.window, data->linuxData.colorData, 8, 8);
  848. data->linuxData.cursorBlack = XCreatePixmapCursor(data->linuxData.display, data->linuxData.pixmapBlack, data->linuxData.pixmapBlack,
  849. &data->linuxData.colorBlack, &data->linuxData.colorBlack, 0, 0);
  850. #endif
  851. }
  852. void OpenGLExtUI::d_onDisplay()
  853. {
  854. glClear(GL_COLOR_BUFFER_BIT);
  855. // Background
  856. if (data->background.isValid())
  857. {
  858. glRasterPos2i(0, d_height());
  859. glDrawPixels(d_width(), d_height(), data->background._format, data->background._type, data->background._data);
  860. }
  861. // Buttons
  862. if (data->buttons.size() > 0)
  863. {
  864. for (auto it = data->buttons.begin(); it != data->buttons.end(); it++)
  865. {
  866. ImageButton* button(*it);
  867. glRasterPos2i(button->_pos.getX(), button->_pos.getY() + button->_area.getHeight());
  868. glDrawPixels(button->getWidth(), button->getHeight(), button->_curImage->getFormat(), button->_curImage->getType(), button->_curImage->getData());
  869. }
  870. }
  871. // Knobs
  872. if (data->knobs.size() > 0)
  873. {
  874. for (auto it = data->knobs.begin(); it != data->knobs.end(); it++)
  875. {
  876. ImageKnob* knob(*it);
  877. float vper = (knob->_value - knob->_min) / (knob->_max - knob->_min);
  878. int layerDataSize = knob->_layerSize * knob->_layerSize * 4;
  879. int imageDataSize = layerDataSize * knob->_layerCount;
  880. int imageDataOffset = imageDataSize - layerDataSize - layerDataSize * rint(vper*(knob->_layerCount-1));
  881. glRasterPos2i(knob->_pos.getX(), knob->_pos.getY()+knob->_area.getHeight());
  882. glDrawPixels(knob->_layerSize, knob->_layerSize, knob->_image.getFormat(), knob->_image.getType(), knob->_image.getData() + imageDataOffset);
  883. }
  884. }
  885. // Sliders
  886. if (data->sliders.size() > 0)
  887. {
  888. for (auto it = data->sliders.begin(); it != data->sliders.end(); it++)
  889. {
  890. ImageSlider* slider(*it);
  891. float vper = (slider->_value - slider->_min) / (slider->_max - slider->_min);
  892. int x = slider->_area.getX();
  893. int y = slider->_area.getY();
  894. if (slider->_endPos.getX() > slider->_startPos.getX())
  895. // horizontal
  896. x += rint(vper * (slider->_area.getWidth()-slider->getWidth()));
  897. else
  898. // vertical
  899. y += slider->_area.getHeight() - rint(vper * (slider->_area.getHeight()-slider->getHeight()));
  900. #if 0 // DEBUG
  901. glColor3i(160, 90, 161);
  902. glBegin(GL_QUADS);
  903. glTexCoord2f(0.0f, 0.0f); glVertex3f(slider->_area.getX(), slider->_area.getY(), 0);
  904. glTexCoord2f(1.0f, 0.0f); glVertex3f(slider->_area.getX()+slider->_area.getWidth(), slider->_area.getY(), 0);
  905. glTexCoord2f(1.0f, 1.0f); glVertex3f(slider->_area.getX()+slider->_area.getWidth(), slider->_area.getY()+slider->_area.getHeight(), 0);
  906. glTexCoord2f(0.0f, 1.0f); glVertex3f(slider->_area.getX(), slider->_area.getY()+slider->_area.getHeight(), 0);
  907. glEnd();
  908. glColor3i(160, 90, 161);
  909. #endif
  910. glRasterPos2i(x, y);
  911. glDrawPixels(slider->getWidth(), slider->getHeight(), slider->_image._format, slider->_image._type, slider->_image._data);
  912. }
  913. }
  914. }
  915. void OpenGLExtUI::d_onKeyboard(bool press, uint32_t key)
  916. {
  917. if (data->dialog)
  918. return;
  919. (void)press;
  920. (void)key;
  921. }
  922. void OpenGLExtUI::d_onMotion(int x, int y)
  923. {
  924. if (data->dialog)
  925. return;
  926. // Buttons
  927. if (data->buttons.size() > 0)
  928. {
  929. for (auto it = data->buttons.begin(); it != data->buttons.end(); it++)
  930. {
  931. ImageButton* button(*it);
  932. if (button == data->lastObj)
  933. continue;
  934. if (button->_area.contains(x, y))
  935. {
  936. if (button->_curImage != &button->_imageHover)
  937. d_uiRepaint();
  938. button->_curImage = &button->_imageHover;
  939. }
  940. else
  941. {
  942. if (button->_curImage != &button->_imageNormal)
  943. d_uiRepaint();
  944. button->_curImage = &button->_imageNormal;
  945. }
  946. }
  947. }
  948. if (data->lastObjType == OBJECT_NULL || ! data->lastObj)
  949. return;
  950. // Knobs
  951. if (data->lastObjType == OBJECT_KNOB && data->knobs.size() > 0)
  952. {
  953. for (auto it = data->knobs.begin(); it != data->knobs.end(); it++)
  954. {
  955. ImageKnob* knob(*it);
  956. if (knob != data->lastObj)
  957. continue;
  958. if (knob->_orientation == ImageKnob::Horizontal)
  959. {
  960. int movX = x - data->initialPosX;
  961. if (movX != 0)
  962. {
  963. int d = (d_uiGetModifiers() & MOD_SHIFT) ? 2000 : 200;
  964. float value = knob->_value + (knob->_max - knob->_min) / d * movX;
  965. if (value < knob->_min)
  966. value = knob->_min;
  967. else if (value > knob->_max)
  968. value = knob->_max;
  969. if (knob->_value != value)
  970. {
  971. knob->_value = value;
  972. imageKnobValueChanged(knob, value);
  973. d_uiRepaint();
  974. }
  975. }
  976. }
  977. else if (knob->_orientation == ImageKnob::Vertical)
  978. {
  979. int movY = data->initialPosY - y;
  980. if (movY != 0)
  981. {
  982. int d = (d_uiGetModifiers() & MOD_SHIFT) ? 2000 : 200;
  983. float value = knob->_value + (knob->_max - knob->_min) / d * movY;
  984. if (value < knob->_min)
  985. value = knob->_min;
  986. else if (value > knob->_max)
  987. value = knob->_max;
  988. if (knob->_value != value)
  989. {
  990. knob->_value = value;
  991. imageKnobValueChanged(knob, value);
  992. d_uiRepaint();
  993. }
  994. }
  995. }
  996. data->initialPosX = x;
  997. data->initialPosY = y;
  998. return;
  999. }
  1000. }
  1001. // Sliders
  1002. if (data->lastObjType == OBJECT_SLIDER && data->sliders.size() > 0)
  1003. {
  1004. for (auto it = data->sliders.begin(); it != data->sliders.end(); it++)
  1005. {
  1006. ImageSlider* slider(*it);
  1007. if (slider != data->lastObj)
  1008. continue;
  1009. bool horizontal = slider->_endPos.getX() > slider->_startPos.getX();
  1010. if ((horizontal && slider->_area.containsX(x)) || (slider->_area.containsY(y) && ! horizontal))
  1011. {
  1012. float vper;
  1013. if (horizontal)
  1014. // horizontal
  1015. vper = float(x - slider->_area.getX()) / slider->_area.getWidth();
  1016. else
  1017. // vertical
  1018. vper = float(y - slider->_area.getY()) / slider->_area.getHeight();
  1019. float value = slider->_max - vper * (slider->_max - slider->_min);
  1020. if (value < slider->_min)
  1021. value = slider->_min;
  1022. else if (value > slider->_max)
  1023. value = slider->_max;
  1024. if (slider->_value != value)
  1025. {
  1026. slider->_value = value;
  1027. imageSliderValueChanged(slider, value);
  1028. d_uiRepaint();
  1029. }
  1030. }
  1031. else if (y < slider->_area.getY())
  1032. {
  1033. if (slider->_value != slider->_max)
  1034. {
  1035. slider->_value = slider->_max;
  1036. imageSliderValueChanged(slider, slider->_max);
  1037. d_uiRepaint();
  1038. }
  1039. }
  1040. else
  1041. {
  1042. if (slider->_value != slider->_min)
  1043. {
  1044. slider->_value = slider->_min;
  1045. imageSliderValueChanged(slider, slider->_min);
  1046. d_uiRepaint();
  1047. }
  1048. }
  1049. return;
  1050. }
  1051. }
  1052. }
  1053. void OpenGLExtUI::d_onMouse(int button, bool press, int x, int y)
  1054. {
  1055. if (data->dialog)
  1056. {
  1057. data->dialog->raise();
  1058. return;
  1059. }
  1060. if ((!press) && data->lastObjType == OBJECT_BUTTON && data->lastObj && data->buttons.size() > 0)
  1061. {
  1062. for (auto it = data->buttons.begin(); it != data->buttons.end(); it++)
  1063. {
  1064. ImageButton* button(*it);
  1065. if (button == data->lastObj)
  1066. {
  1067. if (button->_area.contains(x, y))
  1068. imageButtonClicked(button);
  1069. button->_curImage = &button->_imageNormal;
  1070. d_uiRepaint();
  1071. break;
  1072. }
  1073. }
  1074. }
  1075. if (button != 1)
  1076. return;
  1077. if (data->lastObjType != OBJECT_NULL && data->lastObj)
  1078. {
  1079. if (data->lastObjType == OBJECT_KNOB)
  1080. {
  1081. data->showCursor();
  1082. imageKnobDragFinished((ImageKnob*)data->lastObj);
  1083. }
  1084. else if (data->lastObjType == OBJECT_SLIDER)
  1085. imageSliderDragFinished((ImageSlider*)data->lastObj);
  1086. }
  1087. data->initialPosX = 0;
  1088. data->initialPosY = 0;
  1089. data->lastObj = nullptr;
  1090. data->lastObjType = OBJECT_NULL;
  1091. if (! press)
  1092. return;
  1093. // Buttons
  1094. if (data->buttons.size() > 0)
  1095. {
  1096. for (auto it = data->buttons.begin(); it != data->buttons.end(); it++)
  1097. {
  1098. ImageButton* button(*it);
  1099. if (button->_area.contains(x, y))
  1100. {
  1101. data->initialPosX = x;
  1102. data->initialPosY = y;
  1103. data->lastObj = button;
  1104. data->lastObjType = OBJECT_BUTTON;
  1105. button->_curImage = &button->_imageDown;
  1106. d_uiRepaint();
  1107. return;
  1108. }
  1109. }
  1110. }
  1111. // Knobs
  1112. if (data->knobs.size() > 0)
  1113. {
  1114. for (auto it = data->knobs.begin(); it != data->knobs.end(); it++)
  1115. {
  1116. ImageKnob* knob(*it);
  1117. if (knob->_area.contains(x, y))
  1118. {
  1119. data->initialPosX = x;
  1120. data->initialPosY = y;
  1121. data->lastObj = knob;
  1122. data->lastObjType = OBJECT_KNOB;
  1123. data->hideCursor();
  1124. imageKnobDragStarted(knob);
  1125. return;
  1126. }
  1127. }
  1128. }
  1129. // Sliders
  1130. if (data->sliders.size() > 0)
  1131. {
  1132. for (auto it = data->sliders.begin(); it != data->sliders.end(); it++)
  1133. {
  1134. ImageSlider* slider(*it);
  1135. if (slider->_area.contains(x, y))
  1136. {
  1137. data->initialPosX = x;
  1138. data->initialPosY = y;
  1139. data->lastObj = slider;
  1140. data->lastObjType = OBJECT_SLIDER;
  1141. imageSliderDragStarted(slider);
  1142. float vper;
  1143. if (slider->_endPos.getX() > slider->_startPos.getX())
  1144. // horizontal
  1145. vper = float(x - slider->_area.getX()) / slider->_area.getWidth();
  1146. else
  1147. // vertical
  1148. vper = float(y - slider->_area.getY()) / slider->_area.getHeight();
  1149. float value = slider->_max - vper * (slider->_max - slider->_min);
  1150. if (value < slider->_min)
  1151. value = slider->_min;
  1152. else if (value > slider->_max)
  1153. value = slider->_max;
  1154. if (slider->_value != value)
  1155. {
  1156. slider->_value = value;
  1157. imageSliderValueChanged(slider, value);
  1158. d_uiRepaint();
  1159. }
  1160. return;
  1161. }
  1162. }
  1163. }
  1164. }
  1165. void OpenGLExtUI::d_onReshape(int width, int height)
  1166. {
  1167. glEnable(GL_BLEND);
  1168. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1169. glMatrixMode(GL_PROJECTION);
  1170. glLoadIdentity();
  1171. glOrtho(0, width, height, 0, 0, 1);
  1172. glViewport(0, 0, width, height);
  1173. glMatrixMode(GL_MODELVIEW);
  1174. glLoadIdentity();
  1175. }
  1176. void OpenGLExtUI::d_onScroll(float dx, float dy)
  1177. {
  1178. if (data->dialog)
  1179. return;
  1180. // unused
  1181. (void)dx;
  1182. (void)dy;
  1183. }
  1184. void OpenGLExtUI::d_onSpecial(bool press, Key key)
  1185. {
  1186. if (data->dialog)
  1187. return;
  1188. // unused
  1189. (void)press;
  1190. (void)key;
  1191. }
  1192. void OpenGLExtUI::d_onClose()
  1193. {
  1194. if (data->dialog)
  1195. {
  1196. data->dialog->close();
  1197. delete data->dialog;
  1198. data->dialog = nullptr;
  1199. }
  1200. if (data->lastObjType != OBJECT_NULL && data->lastObj)
  1201. {
  1202. if (data->lastObjType == OBJECT_KNOB)
  1203. {
  1204. data->showCursor();
  1205. imageKnobDragFinished((ImageKnob*)data->lastObj);
  1206. }
  1207. else if (data->lastObjType == OBJECT_SLIDER)
  1208. imageSliderDragFinished((ImageSlider*)data->lastObj);
  1209. }
  1210. data->initialPosX = 0;
  1211. data->initialPosY = 0;
  1212. data->lastObj = nullptr;
  1213. data->lastObjType = OBJECT_NULL;
  1214. data->buttons.clear();
  1215. data->knobs.clear();
  1216. data->sliders.clear();
  1217. }
  1218. // -------------------------------------------------
  1219. END_NAMESPACE_DISTRHO
  1220. #endif // DISTRHO_UI_OPENGL