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
3.3KB

  1. #include "widgets.hpp"
  2. #include "app.hpp"
  3. #include <algorithm>
  4. namespace rack {
  5. Widget::~Widget() {
  6. // You should only delete orphaned widgets
  7. assert(!parent);
  8. // Stop dragging and hovering this widget
  9. if (gHoveredWidget == this) gHoveredWidget = NULL;
  10. if (gDraggedWidget == this) gDraggedWidget = NULL;
  11. if (gDragHoveredWidget == this) gDragHoveredWidget = NULL;
  12. if (gFocusedWidget == this) gFocusedWidget = NULL;
  13. clearChildren();
  14. }
  15. Rect Widget::getChildrenBoundingBox() {
  16. Rect bound;
  17. for (Widget *child : children) {
  18. if (child == children.front()) {
  19. bound = child->box;
  20. }
  21. else {
  22. bound = bound.expand(child->box);
  23. }
  24. }
  25. return bound;
  26. }
  27. Vec Widget::getRelativeOffset(Vec v, Widget *relative) {
  28. if (this == relative) {
  29. return v;
  30. }
  31. v = v.plus(box.pos);
  32. if (parent) {
  33. v = parent->getRelativeOffset(v, relative);
  34. }
  35. return v;
  36. }
  37. Rect Widget::getViewport(Rect r) {
  38. Rect bound;
  39. if (parent) {
  40. bound = parent->getViewport(box);
  41. }
  42. else {
  43. bound = box;
  44. }
  45. bound.pos = bound.pos.minus(box.pos);
  46. return r.clamp(bound);
  47. }
  48. void Widget::addChild(Widget *widget) {
  49. assert(!widget->parent);
  50. widget->parent = this;
  51. children.push_back(widget);
  52. }
  53. void Widget::removeChild(Widget *widget) {
  54. assert(widget->parent == this);
  55. auto it = std::find(children.begin(), children.end(), widget);
  56. if (it != children.end()) {
  57. children.erase(it);
  58. widget->parent = NULL;
  59. }
  60. }
  61. void Widget::clearChildren() {
  62. for (Widget *child : children) {
  63. child->parent = NULL;
  64. delete child;
  65. }
  66. children.clear();
  67. }
  68. void Widget::finalizeEvents() {
  69. // Stop dragging and hovering this widget
  70. if (gHoveredWidget == this) {
  71. EventMouseLeave e;
  72. gHoveredWidget->onMouseLeave(e);
  73. gHoveredWidget = NULL;
  74. }
  75. if (gDraggedWidget == this) {
  76. EventDragEnd e;
  77. gDraggedWidget->onDragEnd(e);
  78. gDraggedWidget = NULL;
  79. }
  80. if (gDragHoveredWidget == this) {
  81. gDragHoveredWidget = NULL;
  82. }
  83. if (gFocusedWidget == this) {
  84. EventDefocus e;
  85. gFocusedWidget->onDefocus(e);
  86. gFocusedWidget = NULL;
  87. }
  88. for (Widget *child : children) {
  89. child->finalizeEvents();
  90. }
  91. }
  92. void Widget::step() {
  93. for (Widget *child : children) {
  94. child->step();
  95. }
  96. }
  97. void Widget::draw(NVGcontext *vg) {
  98. for (Widget *child : children) {
  99. if (!child->visible)
  100. continue;
  101. nvgSave(vg);
  102. nvgTranslate(vg, child->box.pos.x, child->box.pos.y);
  103. child->draw(vg);
  104. nvgRestore(vg);
  105. }
  106. }
  107. #define RECURSE_EVENT_POSITION(_method) { \
  108. Vec pos = e.pos; \
  109. for (auto it = children.rbegin(); it != children.rend(); it++) { \
  110. Widget *child = *it; \
  111. if (!child->visible) \
  112. continue; \
  113. if (child->box.contains(pos)) { \
  114. e.pos = pos.minus(child->box.pos); \
  115. child->_method(e); \
  116. if (e.consumed) \
  117. break; \
  118. } \
  119. } \
  120. e.pos = pos; \
  121. }
  122. void Widget::onMouseDown(EventMouseDown &e) {
  123. RECURSE_EVENT_POSITION(onMouseDown);
  124. }
  125. void Widget::onMouseUp(EventMouseUp &e) {
  126. RECURSE_EVENT_POSITION(onMouseUp);
  127. }
  128. void Widget::onMouseMove(EventMouseMove &e) {
  129. RECURSE_EVENT_POSITION(onMouseMove);
  130. }
  131. void Widget::onHoverKey(EventHoverKey &e) {
  132. RECURSE_EVENT_POSITION(onHoverKey);
  133. }
  134. void Widget::onScroll(EventScroll &e) {
  135. RECURSE_EVENT_POSITION(onScroll);
  136. }
  137. void Widget::onPathDrop(EventPathDrop &e) {
  138. RECURSE_EVENT_POSITION(onPathDrop);
  139. }
  140. void Widget::onZoom(EventZoom &e) {
  141. for (auto it = children.rbegin(); it != children.rend(); it++) {
  142. Widget *child = *it;
  143. child->onZoom(e);
  144. }
  145. }
  146. } // namespace rack