| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "app/common.hpp" | #include "app/common.hpp" | ||||
| #include "widgets/OpaqueWidget.hpp" | #include "widgets/OpaqueWidget.hpp" | ||||
| #include "ui/Tooltip.hpp" | |||||
| #include "ui/Quantity.hpp" | #include "ui/Quantity.hpp" | ||||
| @@ -10,17 +11,15 @@ namespace rack { | |||||
| struct ParamWidget : OpaqueWidget { | struct ParamWidget : OpaqueWidget { | ||||
| Quantity *quantity = NULL; | Quantity *quantity = NULL; | ||||
| float dirtyValue = NAN; | float dirtyValue = NAN; | ||||
| Tooltip *tooltip = NULL; | |||||
| ~ParamWidget() { | |||||
| if (quantity) | |||||
| delete quantity; | |||||
| } | |||||
| ~ParamWidget(); | |||||
| void step() override; | void step() override; | ||||
| /** For legacy patch loading */ | /** For legacy patch loading */ | ||||
| void fromJson(json_t *rootJ); | void fromJson(json_t *rootJ); | ||||
| void onButton(const event::Button &e) override; | void onButton(const event::Button &e) override; | ||||
| void onDragMove(const event::DragMove &e) override; | |||||
| void onEnter(const event::Enter &e) override; | |||||
| void onLeave(const event::Leave &e) override; | |||||
| }; | }; | ||||
| @@ -14,6 +14,7 @@ struct Engine; | |||||
| struct Window; | struct Window; | ||||
| /** Contains the application state */ | |||||
| struct Context { | struct Context { | ||||
| event::State *event = NULL; | event::State *event = NULL; | ||||
| Scene *scene = NULL; | Scene *scene = NULL; | ||||
| @@ -22,6 +23,7 @@ struct Context { | |||||
| }; | }; | ||||
| /** Returns the global context */ | |||||
| Context *context(); | Context *context(); | ||||
| @@ -9,15 +9,8 @@ namespace rack { | |||||
| struct Tooltip : virtual Widget { | struct Tooltip : virtual Widget { | ||||
| std::string text; | std::string text; | ||||
| void draw(NVGcontext *vg) override { | |||||
| // Wrap size to contents | |||||
| box.size.x = bndLabelWidth(vg, -1, text.c_str()) + 10.0; | |||||
| box.size.y = bndLabelHeight(vg, -1, text.c_str(), INFINITY); | |||||
| bndTooltipBackground(vg, 0.0, 0.0, box.size.x, box.size.y); | |||||
| bndMenuLabel(vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||||
| Widget::draw(vg); | |||||
| } | |||||
| void step() override; | |||||
| void draw(NVGcontext *vg) override; | |||||
| }; | }; | ||||
| @@ -59,11 +59,11 @@ struct Widget { | |||||
| /** Adds widget to list of children. | /** Adds widget to list of children. | ||||
| Gives ownership of widget to this widget instance. | Gives ownership of widget to this widget instance. | ||||
| */ | */ | ||||
| void addChild(Widget *widget); | |||||
| void addChild(Widget *child); | |||||
| /** Removes widget from list of children if it exists. | /** Removes widget from list of children if it exists. | ||||
| Does not delete widget but transfers ownership to caller | Does not delete widget but transfers ownership to caller | ||||
| */ | */ | ||||
| void removeChild(Widget *widget); | |||||
| void removeChild(Widget *child); | |||||
| /** Removes and deletes all children */ | /** Removes and deletes all children */ | ||||
| void clearChildren(); | void clearChildren(); | ||||
| @@ -17,8 +17,6 @@ namespace rack { | |||||
| static std::set<Model*> sFavoriteModels; | static std::set<Model*> sFavoriteModels; | ||||
| static std::string sAuthorFilter; | |||||
| static std::string sTagFilter; | |||||
| struct ModuleBox : OpaqueWidget { | struct ModuleBox : OpaqueWidget { | ||||
| @@ -1,10 +1,17 @@ | |||||
| #include "app/ParamWidget.hpp" | #include "app/ParamWidget.hpp" | ||||
| #include "app/Scene.hpp" | |||||
| #include "context.hpp" | |||||
| #include "random.hpp" | #include "random.hpp" | ||||
| namespace rack { | namespace rack { | ||||
| ParamWidget::~ParamWidget() { | |||||
| if (quantity) | |||||
| delete quantity; | |||||
| } | |||||
| void ParamWidget::step() { | void ParamWidget::step() { | ||||
| if (quantity) { | if (quantity) { | ||||
| float value = quantity->getValue(); | float value = quantity->getValue(); | ||||
| @@ -16,6 +23,12 @@ void ParamWidget::step() { | |||||
| } | } | ||||
| } | } | ||||
| if (tooltip) { | |||||
| if (quantity) | |||||
| tooltip->text = quantity->getString(); | |||||
| tooltip->box.pos = getAbsoluteOffset(box.size); | |||||
| } | |||||
| OpaqueWidget::step(); | OpaqueWidget::step(); | ||||
| } | } | ||||
| @@ -39,10 +52,19 @@ void ParamWidget::onButton(const event::Button &e) { | |||||
| OpaqueWidget::onButton(e); | OpaqueWidget::onButton(e); | ||||
| } | } | ||||
| void ParamWidget::onDragMove(const event::DragMove &e) { | |||||
| if (quantity) { | |||||
| DEBUG("%s", quantity->getString().c_str()); | |||||
| } | |||||
| void ParamWidget::onEnter(const event::Enter &e) { | |||||
| if (tooltip) | |||||
| return; | |||||
| tooltip = new Tooltip; | |||||
| context()->scene->addChild(tooltip); | |||||
| } | |||||
| void ParamWidget::onLeave(const event::Leave &e) { | |||||
| if (!tooltip) | |||||
| return; | |||||
| context()->scene->removeChild(tooltip); | |||||
| delete tooltip; | |||||
| tooltip = NULL; | |||||
| } | } | ||||
| @@ -9,7 +9,6 @@ namespace rack { | |||||
| Widget::~Widget() { | Widget::~Widget() { | ||||
| // You should only delete orphaned widgets | // You should only delete orphaned widgets | ||||
| assert(!parent); | assert(!parent); | ||||
| context()->event->finalizeWidget(this); | |||||
| clearChildren(); | clearChildren(); | ||||
| } | } | ||||
| @@ -49,22 +48,28 @@ math::Rect Widget::getViewport(math::Rect r) { | |||||
| return r.clamp(bound); | return r.clamp(bound); | ||||
| } | } | ||||
| void Widget::addChild(Widget *widget) { | |||||
| assert(!widget->parent); | |||||
| widget->parent = this; | |||||
| children.push_back(widget); | |||||
| void Widget::addChild(Widget *child) { | |||||
| assert(!child->parent); | |||||
| child->parent = this; | |||||
| children.push_back(child); | |||||
| } | } | ||||
| void Widget::removeChild(Widget *widget) { | |||||
| assert(widget->parent == this); | |||||
| auto it = std::find(children.begin(), children.end(), widget); | |||||
| void Widget::removeChild(Widget *child) { | |||||
| // Make sure `this` is the child's parent | |||||
| assert(child->parent == this); | |||||
| // Prepare to remove widget from the event state | |||||
| context()->event->finalizeWidget(child); | |||||
| // Delete child from children list | |||||
| auto it = std::find(children.begin(), children.end(), child); | |||||
| assert(it != children.end()); | assert(it != children.end()); | ||||
| children.erase(it); | children.erase(it); | ||||
| widget->parent = NULL; | |||||
| // Revoke child's parent | |||||
| child->parent = NULL; | |||||
| } | } | ||||
| void Widget::clearChildren() { | void Widget::clearChildren() { | ||||
| for (Widget *child : children) { | for (Widget *child : children) { | ||||
| context()->event->finalizeWidget(child); | |||||
| child->parent = NULL; | child->parent = NULL; | ||||
| delete child; | delete child; | ||||
| } | } | ||||
| @@ -76,6 +81,7 @@ void Widget::step() { | |||||
| Widget *child = *it; | Widget *child = *it; | ||||
| // Delete children if a delete is requested | // Delete children if a delete is requested | ||||
| if (child->requestedDelete) { | if (child->requestedDelete) { | ||||
| context()->event->finalizeWidget(child); | |||||
| it = children.erase(it); | it = children.erase(it); | ||||
| child->parent = NULL; | child->parent = NULL; | ||||
| delete child; | delete child; | ||||