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.

189 lines
3.8KB

  1. #include <widget/Widget.hpp>
  2. #include <app.hpp>
  3. #include <algorithm>
  4. namespace rack {
  5. namespace widget {
  6. Widget::~Widget() {
  7. // You should only delete orphaned widgets
  8. assert(!parent);
  9. clearChildren();
  10. }
  11. void Widget::setPosition(math::Vec pos) {
  12. box.pos = pos;
  13. // event::Reposition
  14. event::Reposition eReposition;
  15. onReposition(eReposition);
  16. }
  17. void Widget::setSize(math::Vec size) {
  18. box.size = size;
  19. // event::Resize
  20. event::Resize eResize;
  21. onResize(eResize);
  22. }
  23. void Widget::show() {
  24. if (visible)
  25. return;
  26. visible = true;
  27. // event::Show
  28. event::Show eShow;
  29. onShow(eShow);
  30. }
  31. void Widget::hide() {
  32. if (!visible)
  33. return;
  34. visible = false;
  35. // event::Hide
  36. event::Hide eHide;
  37. onHide(eHide);
  38. }
  39. void Widget::requestDelete() {
  40. requestedDelete = true;
  41. }
  42. math::Rect Widget::getChildrenBoundingBox() {
  43. math::Vec min = math::Vec(INFINITY, INFINITY);
  44. math::Vec max = math::Vec(-INFINITY, -INFINITY);
  45. for (Widget *child : children) {
  46. if (!child->visible)
  47. continue;
  48. min = min.min(child->box.getTopLeft());
  49. max = max.max(child->box.getBottomRight());
  50. }
  51. return math::Rect::fromMinMax(min, max);
  52. }
  53. math::Vec Widget::getRelativeOffset(math::Vec v, Widget *relative) {
  54. if (this == relative) {
  55. return v;
  56. }
  57. v = v.plus(box.pos);
  58. if (parent) {
  59. v = parent->getRelativeOffset(v, relative);
  60. }
  61. return v;
  62. }
  63. math::Rect Widget::getViewport(math::Rect r) {
  64. math::Rect bound;
  65. if (parent) {
  66. bound = parent->getViewport(box);
  67. }
  68. else {
  69. bound = box;
  70. }
  71. bound.pos = bound.pos.minus(box.pos);
  72. return r.clamp(bound);
  73. }
  74. void Widget::addChild(Widget *child) {
  75. assert(child);
  76. assert(!child->parent);
  77. child->parent = this;
  78. children.push_back(child);
  79. // event::Add
  80. event::Add eAdd;
  81. child->onAdd(eAdd);
  82. }
  83. void Widget::addChildBottom(Widget *child) {
  84. assert(child);
  85. assert(!child->parent);
  86. child->parent = this;
  87. children.push_front(child);
  88. // event::Add
  89. event::Add eAdd;
  90. child->onAdd(eAdd);
  91. }
  92. void Widget::removeChild(Widget *child) {
  93. assert(child);
  94. // Make sure `this` is the child's parent
  95. assert(child->parent == this);
  96. // event::Remove
  97. event::Remove eRemove;
  98. child->onRemove(eRemove);
  99. // Prepare to remove widget from the event state
  100. APP->event->finalizeWidget(child);
  101. // Delete child from children list
  102. auto it = std::find(children.begin(), children.end(), child);
  103. assert(it != children.end());
  104. children.erase(it);
  105. // Revoke child's parent
  106. child->parent = NULL;
  107. }
  108. void Widget::clearChildren() {
  109. for (Widget *child : children) {
  110. // event::Remove
  111. event::Remove eRemove;
  112. child->onRemove(eRemove);
  113. APP->event->finalizeWidget(child);
  114. child->parent = NULL;
  115. delete child;
  116. }
  117. children.clear();
  118. }
  119. void Widget::step() {
  120. for (auto it = children.begin(); it != children.end();) {
  121. Widget *child = *it;
  122. // Delete children if a delete is requested
  123. if (child->requestedDelete) {
  124. // event::Remove
  125. event::Remove eRemove;
  126. child->onRemove(eRemove);
  127. APP->event->finalizeWidget(child);
  128. it = children.erase(it);
  129. child->parent = NULL;
  130. delete child;
  131. continue;
  132. }
  133. child->step();
  134. it++;
  135. }
  136. }
  137. void Widget::draw(const DrawArgs &args) {
  138. // Iterate children
  139. for (Widget *child : children) {
  140. // Don't draw if invisible
  141. if (!child->visible)
  142. continue;
  143. // Don't draw if child is outside clip box
  144. if (!args.clipBox.isIntersecting(child->box))
  145. continue;
  146. DrawArgs childCtx = args;
  147. // Intersect child clip box with self
  148. childCtx.clipBox = childCtx.clipBox.intersect(child->box);
  149. childCtx.clipBox.pos = childCtx.clipBox.pos.minus(child->box.pos);
  150. nvgSave(args.vg);
  151. nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y);
  152. child->draw(childCtx);
  153. #pragma GCC diagnostic push
  154. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  155. // Call deprecated draw function, which does nothing by default
  156. child->draw(args.vg);
  157. #pragma GCC diagnostic pop
  158. nvgRestore(args.vg);
  159. }
  160. }
  161. } // namespace widget
  162. } // namespace rack