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.

210 lines
6.0KB

  1. #pragma once
  2. #include <list>
  3. #include <common.hpp>
  4. #include <math.hpp>
  5. #include <window.hpp>
  6. #include <color.hpp>
  7. #include <event.hpp>
  8. namespace rack {
  9. /** General UI widgets
  10. */
  11. namespace widget {
  12. /** A node in the 2D [scene graph](https://en.wikipedia.org/wiki/Scene_graph).
  13. The bounding box of a Widget is a rectangle specified by `box` relative to their parent.
  14. The appearance is defined by overriding `draw()`, and the behavior is defined by overriding `step()` and `on*()` event handlers.
  15. */
  16. struct Widget {
  17. /** Stores position and size */
  18. math::Rect box = math::Rect(math::Vec(), math::Vec(INFINITY, INFINITY));
  19. /** Automatically set when Widget is added as a child to another Widget */
  20. Widget* parent = NULL;
  21. std::list<Widget*> children;
  22. /** Disables rendering but allow stepping */
  23. bool visible = true;
  24. /** If set to true, parent will delete Widget in the next step() */
  25. bool requestedDelete = false;
  26. virtual ~Widget();
  27. void setPosition(math::Vec pos);
  28. math::Vec getPosition() {
  29. return box.pos;
  30. }
  31. void setSize(math::Vec size);
  32. math::Vec getSize() {
  33. return box.size;
  34. }
  35. void show();
  36. void hide();
  37. bool isVisible() {
  38. return visible;
  39. }
  40. void requestDelete();
  41. virtual math::Rect getChildrenBoundingBox();
  42. /** Returns `v` transformed into the coordinate system of `relative` */
  43. virtual math::Vec getRelativeOffset(math::Vec v, Widget* relative);
  44. /** Returns `v` transformed into world coordinates */
  45. math::Vec getAbsoluteOffset(math::Vec v) {
  46. return getRelativeOffset(v, NULL);
  47. }
  48. /** Returns a subset of the given math::Rect bounded by the box of this widget and all ancestors */
  49. virtual math::Rect getViewport(math::Rect r);
  50. template <class T>
  51. T* getAncestorOfType() {
  52. if (!parent)
  53. return NULL;
  54. T* p = dynamic_cast<T*>(parent);
  55. if (p)
  56. return p;
  57. return parent->getAncestorOfType<T>();
  58. }
  59. template <class T>
  60. T* getFirstDescendantOfType() {
  61. for (Widget* child : children) {
  62. T* c = dynamic_cast<T*>(child);
  63. if (c)
  64. return c;
  65. c = child->getFirstDescendantOfType<T>();
  66. if (c)
  67. return c;
  68. }
  69. return NULL;
  70. }
  71. /** Adds widget to list of children.
  72. Gives ownership of widget to this widget instance.
  73. */
  74. void addChild(Widget* child);
  75. void addChildBottom(Widget* child);
  76. /** Removes widget from list of children if it exists.
  77. Does not delete widget but transfers ownership to caller
  78. */
  79. void removeChild(Widget* child);
  80. /** Removes and deletes all children */
  81. void clearChildren();
  82. /** Advances the module by one frame */
  83. virtual void step();
  84. struct DrawArgs {
  85. NVGcontext* vg;
  86. math::Rect clipBox;
  87. NVGLUframebuffer* fb = NULL;
  88. };
  89. /** Draws the widget to the NanoVG context */
  90. virtual void draw(const DrawArgs& args);
  91. /** Override draw(const DrawArgs &args) instead */
  92. DEPRECATED virtual void draw(NVGcontext* vg) {}
  93. // Events
  94. /** Recurses an event to all visible Widgets */
  95. template <typename TMethod, class TEvent>
  96. void recurseEvent(TMethod f, const TEvent& e) {
  97. for (auto it = children.rbegin(); it != children.rend(); it++) {
  98. // Stop propagation if requested
  99. if (!e.isPropagating())
  100. break;
  101. Widget* child = *it;
  102. // Filter child by visibility
  103. if (!child->visible)
  104. continue;
  105. // Clone event for (currently) no reason
  106. TEvent e2 = e;
  107. // Call child event handler
  108. (child->*f)(e2);
  109. }
  110. }
  111. /** Recurses an event to all visible Widgets until it is consumed. */
  112. template <typename TMethod, class TEvent>
  113. void recursePositionEvent(TMethod f, const TEvent& e) {
  114. for (auto it = children.rbegin(); it != children.rend(); it++) {
  115. // Stop propagation if requested
  116. if (!e.isPropagating())
  117. break;
  118. Widget* child = *it;
  119. // Filter child by visibility and position
  120. if (!child->visible)
  121. continue;
  122. if (!child->box.isContaining(e.pos))
  123. continue;
  124. // Clone event and adjust its position
  125. TEvent e2 = e;
  126. e2.pos = e.pos.minus(child->box.pos);
  127. // Call child event handler
  128. (child->*f)(e2);
  129. }
  130. }
  131. /** Override these event callbacks to respond to events.
  132. See event.hpp for a description of each event.
  133. */
  134. virtual void onHover(const event::Hover& e) {
  135. recursePositionEvent(&Widget::onHover, e);
  136. }
  137. virtual void onButton(const event::Button& e) {
  138. recursePositionEvent(&Widget::onButton, e);
  139. }
  140. virtual void onDoubleClick(const event::DoubleClick& e) {}
  141. virtual void onHoverKey(const event::HoverKey& e) {
  142. recursePositionEvent(&Widget::onHoverKey, e);
  143. }
  144. virtual void onHoverText(const event::HoverText& e) {
  145. recursePositionEvent(&Widget::onHoverText, e);
  146. }
  147. virtual void onHoverScroll(const event::HoverScroll& e) {
  148. recursePositionEvent(&Widget::onHoverScroll, e);
  149. }
  150. virtual void onEnter(const event::Enter& e) {}
  151. virtual void onLeave(const event::Leave& e) {}
  152. virtual void onSelect(const event::Select& e) {}
  153. virtual void onDeselect(const event::Deselect& e) {}
  154. virtual void onSelectKey(const event::SelectKey& e) {}
  155. virtual void onSelectText(const event::SelectText& e) {}
  156. virtual void onDragStart(const event::DragStart& e) {}
  157. virtual void onDragEnd(const event::DragEnd& e) {}
  158. virtual void onDragMove(const event::DragMove& e) {}
  159. virtual void onDragHover(const event::DragHover& e) {
  160. recursePositionEvent(&Widget::onDragHover, e);
  161. }
  162. virtual void onDragEnter(const event::DragEnter& e) {}
  163. virtual void onDragLeave(const event::DragLeave& e) {}
  164. virtual void onDragDrop(const event::DragDrop& e) {}
  165. virtual void onPathDrop(const event::PathDrop& e) {
  166. recursePositionEvent(&Widget::onPathDrop, e);
  167. }
  168. virtual void onAction(const event::Action& e) {}
  169. virtual void onChange(const event::Change& e) {}
  170. virtual void onDirty(const event::Dirty& e) {
  171. recurseEvent(&Widget::onDirty, e);
  172. }
  173. virtual void onReposition(const event::Reposition& e) {}
  174. virtual void onResize(const event::Resize& e) {}
  175. virtual void onAdd(const event::Add& e) {}
  176. virtual void onRemove(const event::Remove& e) {}
  177. virtual void onShow(const event::Show& e) {
  178. recurseEvent(&Widget::onShow, e);
  179. }
  180. virtual void onHide(const event::Hide& e) {
  181. recurseEvent(&Widget::onHide, e);
  182. }
  183. };
  184. } // namespace widget
  185. } // namespace rack