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.

169 lines
5.6KB

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