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.

228 lines
6.6KB

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