diff --git a/include/app/Knob.hpp b/include/app/Knob.hpp index 3c6c23a2..a56e4122 100644 --- a/include/app/Knob.hpp +++ b/include/app/Knob.hpp @@ -15,32 +15,9 @@ struct Knob : ParamWidget { /** Multiplier for mouse movement to adjust knob value */ float speed = 1.0; - void onDragStart(event::DragStart &e) override { - context()->window->cursorLock(); - } - - void onDragEnd(event::DragEnd &e) override { - context()->window->cursorUnlock(); - } - - void onDragMove(event::DragMove &e) override { - if (quantity) { - float range; - if (quantity->isBounded()) { - range = quantity->getRange(); - } - else { - // Continuous encoders scale as if their limits are +/-1 - range = 2.f; - } - float delta = KNOB_SENSITIVITY * -e.mouseDelta.y * speed * range; - - // Drag slower if Mod is held - if (context()->window->isModPressed()) - delta /= 16.f; - quantity->moveValue(delta); - } - } + void onDragStart(event::DragStart &e) override; + void onDragEnd(event::DragEnd &e) override; + void onDragMove(event::DragMove &e) override; }; diff --git a/include/app/LedDisplay.hpp b/include/app/LedDisplay.hpp index 606db92c..b97da325 100644 --- a/include/app/LedDisplay.hpp +++ b/include/app/LedDisplay.hpp @@ -8,7 +8,7 @@ namespace rack { -struct LedDisplay : VirtualWidget { +struct LedDisplay : virtual Widget { void draw(NVGcontext *vg) override; }; diff --git a/include/app/ParamQuantity.hpp b/include/app/ParamQuantity.hpp index d4844249..2d4fafec 100644 --- a/include/app/ParamQuantity.hpp +++ b/include/app/ParamQuantity.hpp @@ -1,6 +1,7 @@ #pragma once #include "ui/Quantity.hpp" #include "engine/Module.hpp" +#include "engine/Param.hpp" namespace rack { @@ -16,70 +17,19 @@ struct ParamQuantity : Quantity { bool snap = false; float snapValue = 0.f; - Param *getParam() { - assert(module); - return &module->params[paramId]; - } - - void commitSnap() { - // TODO - } - - void setValue(float value) override { - // TODO Smooth - // TODO Snap - getParam()->value = value; - } - - float getValue() override { - return getParam()->value; - } - - float getMinValue() override { - return getParam()->minValue; - } - - float getMaxValue() override { - return getParam()->maxValue; - } - - float getDefaultValue() override { - return getParam()->defaultValue; - } - - float getDisplayValue() override { - if (getParam()->displayBase == 0.f) { - // Linear - return getParam()->value * getParam()->displayMultiplier; - } - else { - // Exponential - return std::pow(getParam()->displayBase, getParam()->value) * getParam()->displayMultiplier; - } - } - - void setDisplayValue(float displayValue) override { - if (getParam()->displayBase == 0.f) { - // Linear - getParam()->value = displayValue / getParam()->displayMultiplier; - } - else { - // Exponential - getParam()->value = std::log(displayValue / getParam()->displayMultiplier) / std::log(getParam()->displayBase); - } - } - - int getDisplayPrecision() override { - return getParam()->displayPrecision; - } - - std::string getLabel() override { - return getParam()->label; - } - - std::string getUnit() override { - return getParam()->unit; - } + Param *getParam(); + void commitSnap(); + + void setValue(float value) override; + float getValue() override; + float getMinValue() override; + float getMaxValue() override; + float getDefaultValue() override; + float getDisplayValue() override; + void setDisplayValue(float displayValue) override ; + int getDisplayPrecision() override; + std::string getLabel() override; + std::string getUnit() override; }; diff --git a/include/app/ParamWidget.hpp b/include/app/ParamWidget.hpp index 08451666..658571d6 100644 --- a/include/app/ParamWidget.hpp +++ b/include/app/ParamWidget.hpp @@ -1,22 +1,18 @@ #pragma once #include "app/common.hpp" #include "widgets/OpaqueWidget.hpp" -#include "app/ParamQuantity.hpp" +#include "ui/Quantity.hpp" namespace rack { -/** Controls a ParamQuantity */ struct ParamWidget : OpaqueWidget { - ParamQuantity *quantity; - - ParamWidget() { - quantity = new ParamQuantity; - } + Quantity *quantity = NULL; ~ParamWidget() { - delete quantity; + if (quantity) + delete quantity; } /** For legacy patch loading */ diff --git a/include/app/PluginManagerWidget.hpp b/include/app/PluginManagerWidget.hpp index 70b51f7c..64b0308b 100644 --- a/include/app/PluginManagerWidget.hpp +++ b/include/app/PluginManagerWidget.hpp @@ -6,7 +6,7 @@ namespace rack { -struct PluginManagerWidget : VirtualWidget { +struct PluginManagerWidget : virtual Widget { Widget *loginWidget; Widget *manageWidget; Widget *downloadWidget; diff --git a/include/helpers.hpp b/include/helpers.hpp index aea4aea7..8973ef21 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -1,11 +1,13 @@ #include "plugin/Model.hpp" -#include "event.hpp" #include "ui/MenuLabel.hpp" #include "ui/MenuItem.hpp" #include "ui/Menu.hpp" #include "app/Port.hpp" +#include "app/ParamQuantity.hpp" +#include "app/ParamWidget.hpp" #include "engine/Module.hpp" #include "context.hpp" +#include "window.hpp" namespace rack { @@ -54,8 +56,10 @@ template TParamWidget *createParam(math::Vec pos, Module *module, int paramId) { TParamWidget *o = new TParamWidget; o->box.pos = pos; - o->quantity->module = module; - o->quantity->paramId = paramId; + ParamQuantity *q = new ParamQuantity; + q->module = module; + q->paramId = paramId; + o->quantity = q; return o; } @@ -63,8 +67,10 @@ template TParamWidget *createParamCentered(math::Vec pos, Module *module, int paramId) { TParamWidget *o = new TParamWidget; o->box.pos = pos.minus(o->box.size.div(2)); - o->quantity->module = module; - o->quantity->paramId = paramId; + ParamQuantity *q = new ParamQuantity; + q->module = module; + q->paramId = paramId; + o->quantity = q; return o; } diff --git a/include/ui/Label.hpp b/include/ui/Label.hpp index 4c23ef6f..ef34bd25 100644 --- a/include/ui/Label.hpp +++ b/include/ui/Label.hpp @@ -6,7 +6,7 @@ namespace rack { -struct Label : VirtualWidget { +struct Label : virtual Widget { std::string text; float fontSize; NVGcolor color; diff --git a/include/ui/ProgressBar.hpp b/include/ui/ProgressBar.hpp index bf68a8b4..84ecb68c 100644 --- a/include/ui/ProgressBar.hpp +++ b/include/ui/ProgressBar.hpp @@ -5,7 +5,7 @@ namespace rack { -struct ProgressBar : VirtualWidget { +struct ProgressBar : virtual Widget { Quantity *quantity = NULL; ProgressBar() { diff --git a/include/ui/Quantity.hpp b/include/ui/Quantity.hpp index 4f1be7cd..c228d959 100644 --- a/include/ui/Quantity.hpp +++ b/include/ui/Quantity.hpp @@ -1,4 +1,6 @@ #pragma once +#include "ui/common.hpp" +#include "math.hpp" #include "string.hpp" diff --git a/include/ui/SequentialLayout.hpp b/include/ui/SequentialLayout.hpp index 0322f0bf..3afee106 100644 --- a/include/ui/SequentialLayout.hpp +++ b/include/ui/SequentialLayout.hpp @@ -7,7 +7,7 @@ namespace rack { /** Positions children in a row/column based on their widths/heights */ -struct SequentialLayout : VirtualWidget { +struct SequentialLayout : virtual Widget { enum Orientation { HORIZONTAL_ORIENTATION, VERTICAL_ORIENTATION, diff --git a/include/ui/Tooltip.hpp b/include/ui/Tooltip.hpp index 4584d57d..e7cdb51b 100644 --- a/include/ui/Tooltip.hpp +++ b/include/ui/Tooltip.hpp @@ -6,7 +6,7 @@ namespace rack { -struct Tooltip : VirtualWidget { +struct Tooltip : virtual Widget { std::string text; void draw(NVGcontext *vg) override { diff --git a/include/widgets/FramebufferWidget.hpp b/include/widgets/FramebufferWidget.hpp index e83875e1..4e32c0ed 100644 --- a/include/widgets/FramebufferWidget.hpp +++ b/include/widgets/FramebufferWidget.hpp @@ -9,7 +9,7 @@ namespace rack { When `dirty` is true, its children will be re-rendered on the next call to step() override. Events are not passed to the underlying scene. */ -struct FramebufferWidget : VirtualWidget { +struct FramebufferWidget : virtual Widget { /** Set this to true to re-render the children to the framebuffer the next time it is drawn */ bool dirty = true; /** A margin in pixels around the children in the framebuffer diff --git a/include/widgets/OpaqueWidget.hpp b/include/widgets/OpaqueWidget.hpp index 49415eec..c5e2783d 100644 --- a/include/widgets/OpaqueWidget.hpp +++ b/include/widgets/OpaqueWidget.hpp @@ -9,7 +9,7 @@ namespace rack { You can of course override the events. You may also call OpaqueWidget::on*() from the overridden method to continue recursing/consuming the event. */ -struct OpaqueWidget : VirtualWidget { +struct OpaqueWidget : virtual Widget { void onHover(event::Hover &e) override { Widget::onHover(e); if (!e.target) diff --git a/include/widgets/SVGWidget.hpp b/include/widgets/SVGWidget.hpp index 8d9e8dad..da8a65bb 100644 --- a/include/widgets/SVGWidget.hpp +++ b/include/widgets/SVGWidget.hpp @@ -7,7 +7,7 @@ namespace rack { /** Draws an SVG */ -struct SVGWidget : VirtualWidget { +struct SVGWidget : virtual Widget { std::shared_ptr svg; /** Sets the box size to the svg image size */ diff --git a/include/widgets/TransformWidget.hpp b/include/widgets/TransformWidget.hpp index 9575d0f1..9c784935 100644 --- a/include/widgets/TransformWidget.hpp +++ b/include/widgets/TransformWidget.hpp @@ -6,7 +6,7 @@ namespace rack { /** Transforms appearance only, not positions of events */ -struct TransformWidget : VirtualWidget { +struct TransformWidget : virtual Widget { /** The transformation matrix */ float transform[6]; diff --git a/include/widgets/TransparentWidget.hpp b/include/widgets/TransparentWidget.hpp index 2476268b..f53910a5 100644 --- a/include/widgets/TransparentWidget.hpp +++ b/include/widgets/TransparentWidget.hpp @@ -6,7 +6,7 @@ namespace rack { /** Widget that does not respond to events and does not pass events to children */ -struct TransparentWidget : VirtualWidget { +struct TransparentWidget : virtual Widget { /** Override behavior to do nothing instead. */ void onHover(event::Hover &e) override {} void onButton(event::Button &e) override {} diff --git a/include/widgets/Widget.hpp b/include/widgets/Widget.hpp index f2bf33c6..937cf5e4 100644 --- a/include/widgets/Widget.hpp +++ b/include/widgets/Widget.hpp @@ -12,7 +12,7 @@ namespace rack { /** A node in the 2D scene graph It is recommended to inherit virtually from Widget instead of directly. -e.g. `struct MyWidget : VirtualWidget {}` +e.g. `struct MyWidget : virtual Widget {}` */ struct Widget { /** Stores position and size */ @@ -125,10 +125,4 @@ struct Widget { }; -/** Inherit from this class instead of inheriting from Widget directly. -Allows multiple inheritance in the class hierarchy. -*/ -struct VirtualWidget : virtual Widget {}; - - } // namespace rack diff --git a/include/widgets/ZoomWidget.hpp b/include/widgets/ZoomWidget.hpp index bf33c404..8149023e 100644 --- a/include/widgets/ZoomWidget.hpp +++ b/include/widgets/ZoomWidget.hpp @@ -5,7 +5,7 @@ namespace rack { -struct ZoomWidget : VirtualWidget { +struct ZoomWidget : virtual Widget { float zoom = 1.f; math::Vec getRelativeOffset(math::Vec v, Widget *relative) override { @@ -36,39 +36,32 @@ struct ZoomWidget : VirtualWidget { } void onHover(event::Hover &e) override { - event::Hover e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onHover(e2); + e.pos = e.pos.div(zoom); + Widget::onHover(e); } void onButton(event::Button &e) override { - event::Button e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onButton(e2); + e.pos = e.pos.div(zoom); + Widget::onButton(e); } void onHoverKey(event::HoverKey &e) override { - event::HoverKey e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onHoverKey(e2); + e.pos = e.pos.div(zoom); + Widget::onHoverKey(e); } void onHoverText(event::HoverText &e) override { - event::HoverText e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onHoverText(e2); + e.pos = e.pos.div(zoom); + Widget::onHoverText(e); } void onHoverScroll(event::HoverScroll &e) override { - event::HoverScroll e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onHoverScroll(e2); + e.pos = e.pos.div(zoom); + Widget::onHoverScroll(e); } void onDragHover(event::DragHover &e) override { - event::DragHover e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onDragHover(e2); + e.pos = e.pos.div(zoom); + Widget::onDragHover(e); } void onPathDrop(event::PathDrop &e) override { - event::PathDrop e2 = e; - e2.pos = e.pos.div(zoom); - Widget::onPathDrop(e2); + e.pos = e.pos.div(zoom); + Widget::onPathDrop(e); } }; diff --git a/src/app/Knob.cpp b/src/app/Knob.cpp new file mode 100644 index 00000000..ecdc0f48 --- /dev/null +++ b/src/app/Knob.cpp @@ -0,0 +1,39 @@ +#include "app/Knob.hpp" + + +namespace rack { + + +void Knob::onDragStart(event::DragStart &e) { + context()->window->cursorLock(); + e.target = this; +} + +void Knob::onDragEnd(event::DragEnd &e) { + context()->window->cursorUnlock(); +} + +void Knob::onDragMove(event::DragMove &e) { + if (quantity) { + float range; + if (quantity->isBounded()) { + range = quantity->getRange(); + } + else { + // Continuous encoders scale as if their limits are +/-1 + range = 2.f; + } + float delta = KNOB_SENSITIVITY * -e.mouseDelta.y * speed * range; + + // Drag slower if Mod is held + if (context()->window->isModPressed()) + delta /= 16.f; + quantity->moveValue(delta); + + event::Change eChange; + onChange(eChange); + } +} + + +} // namespace rack diff --git a/src/app/ModuleBrowser.cpp b/src/app/ModuleBrowser.cpp index caf14fd8..d8d35931 100644 --- a/src/app/ModuleBrowser.cpp +++ b/src/app/ModuleBrowser.cpp @@ -12,6 +12,7 @@ #include "ui/TextField.hpp" #include "plugin.hpp" #include "context.hpp" +#include "logger.hpp" static const float itemMargin = 2.0; diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index d227ce9a..933d1bba 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -365,6 +365,7 @@ void ModuleWidget::onHoverKey(event::HoverKey &e) { void ModuleWidget::onDragStart(event::DragStart &e) { dragPos = context()->scene->rackWidget->lastMousePos.minus(box.pos); + e.target = this; } void ModuleWidget::onDragEnd(event::DragEnd &e) { diff --git a/src/app/ParamQuantity.cpp b/src/app/ParamQuantity.cpp new file mode 100644 index 00000000..49485f3d --- /dev/null +++ b/src/app/ParamQuantity.cpp @@ -0,0 +1,74 @@ +#include "app/ParamQuantity.hpp" + + +namespace rack { + + +Param *ParamQuantity::getParam() { + assert(module); + return &module->params[paramId]; +} + +void ParamQuantity::commitSnap() { + // TODO +} + +void ParamQuantity::setValue(float value) { + value = math::clamp(value, getMinValue(), getMaxValue()); + // TODO Smooth + // TODO Snap + getParam()->value = value; +} + +float ParamQuantity::getValue() { + return getParam()->value; +} + +float ParamQuantity::getMinValue() { + return getParam()->minValue; +} + +float ParamQuantity::getMaxValue() { + return getParam()->maxValue; +} + +float ParamQuantity::getDefaultValue() { + return getParam()->defaultValue; +} + +float ParamQuantity::getDisplayValue() { + if (getParam()->displayBase == 0.f) { + // Linear + return getParam()->value * getParam()->displayMultiplier; + } + else { + // Exponential + return std::pow(getParam()->displayBase, getParam()->value) * getParam()->displayMultiplier; + } +} + +void ParamQuantity::setDisplayValue(float displayValue) { + if (getParam()->displayBase == 0.f) { + // Linear + getParam()->value = displayValue / getParam()->displayMultiplier; + } + else { + // Exponential + getParam()->value = std::log(displayValue / getParam()->displayMultiplier) / std::log(getParam()->displayBase); + } +} + +int ParamQuantity::getDisplayPrecision() { + return getParam()->displayPrecision; +} + +std::string ParamQuantity::getLabel() { + return getParam()->label; +} + +std::string ParamQuantity::getUnit() { + return getParam()->unit; +} + + +} // namespace rack diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 42e77e6f..1a0b0072 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -511,6 +511,7 @@ void RackWidget::onHover(event::Hover &e) { } void RackWidget::onButton(event::Button &e) { + DEBUG("what"); OpaqueWidget::onButton(e); if (e.target == this) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { diff --git a/src/app/SVGKnob.cpp b/src/app/SVGKnob.cpp index c362696c..04655a41 100644 --- a/src/app/SVGKnob.cpp +++ b/src/app/SVGKnob.cpp @@ -30,11 +30,11 @@ void SVGKnob::step() { if (dirty && quantity) { float angle; if (quantity->isBounded()) { - angle = math::rescale(quantity->getValue(), -1.f, 1.f, minAngle, maxAngle); + angle = math::rescale(quantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle); angle = std::fmod(angle, 2*M_PI); } else { - angle = math::rescale(quantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle); + angle = math::rescale(quantity->getValue(), 0.f, 1.f, minAngle, maxAngle); } tw->identity(); // Rotate SVG @@ -48,7 +48,7 @@ void SVGKnob::step() { void SVGKnob::onChange(event::Change &e) { dirty = true; - ParamWidget::onChange(e); + Knob::onChange(e); } diff --git a/src/event.cpp b/src/event.cpp index c298a308..c56ec9dc 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -22,7 +22,7 @@ void Context::handleButton(math::Vec pos, int button, int action, int mods) { // event::DragStart event::DragStart eDragStart; clickedWidget->onDragStart(eDragStart); - draggedWidget = clickedWidget; + draggedWidget = eDragStart.target; } if (action == GLFW_RELEASE && draggedWidget) { @@ -63,14 +63,14 @@ void Context::handleButton(math::Vec pos, int button, int action, int mods) { } } - if (button == GLFW_MOUSE_BUTTON_MIDDLE) { - if (action == GLFW_PRESS) { - scrollWidget = clickedWidget; - } - if (action == GLFW_RELEASE) { - scrollWidget = NULL; - } - } + // if (button == GLFW_MOUSE_BUTTON_MIDDLE) { + // if (action == GLFW_PRESS) { + // scrollWidget = clickedWidget; + // } + // if (action == GLFW_RELEASE) { + // scrollWidget = NULL; + // } + // } } diff --git a/src/widgets/Widget.cpp b/src/widgets/Widget.cpp index 35f8fe3f..97672f7f 100644 --- a/src/widgets/Widget.cpp +++ b/src/widgets/Widget.cpp @@ -99,6 +99,15 @@ void Widget::draw(NVGcontext *vg) { nvgSave(vg); nvgTranslate(vg, child->box.pos.x, child->box.pos.y); child->draw(vg); + + // Draw red hitboxes + // if (context()->event->hoveredWidget == child) { + // nvgBeginPath(vg); + // nvgRect(vg, 0, 0, child->box.size.x, child->box.size.y); + // nvgFillColor(vg, nvgRGBAf(1, 0, 0, 0.5)); + // nvgFill(vg); + // } + nvgRestore(vg); } }