@@ -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; | ||||