| @@ -15,6 +15,7 @@ struct Knob : ParamWidget { | |||||
| /** Multiplier for mouse movement to adjust knob value */ | /** Multiplier for mouse movement to adjust knob value */ | ||||
| float speed = 1.0; | float speed = 1.0; | ||||
| void onButton(event::Button &e) override; | |||||
| void onDragStart(event::DragStart &e) override; | void onDragStart(event::DragStart &e) override; | ||||
| void onDragEnd(event::DragEnd &e) override; | void onDragEnd(event::DragEnd &e) override; | ||||
| void onDragMove(event::DragMove &e) override; | void onDragMove(event::DragMove &e) override; | ||||
| @@ -9,12 +9,14 @@ namespace rack { | |||||
| struct ParamWidget : OpaqueWidget { | struct ParamWidget : OpaqueWidget { | ||||
| Quantity *quantity = NULL; | Quantity *quantity = NULL; | ||||
| float dirtyValue = NAN; | |||||
| ~ParamWidget() { | ~ParamWidget() { | ||||
| if (quantity) | if (quantity) | ||||
| delete quantity; | delete quantity; | ||||
| } | } | ||||
| void step() override; | |||||
| /** For legacy patch loading */ | /** For legacy patch loading */ | ||||
| void fromJson(json_t *rootJ); | void fromJson(json_t *rootJ); | ||||
| void onButton(event::Button &e) override; | void onButton(event::Button &e) override; | ||||
| @@ -15,6 +15,7 @@ struct SVGSwitch : virtual ParamWidget, FramebufferWidget { | |||||
| SVGWidget *sw; | SVGWidget *sw; | ||||
| SVGSwitch(); | SVGSwitch(); | ||||
| void step() override; | |||||
| /** Adds an SVG file to represent the next switch position */ | /** Adds an SVG file to represent the next switch position */ | ||||
| void addFrame(std::shared_ptr<SVG> svg); | void addFrame(std::shared_ptr<SVG> svg); | ||||
| void onChange(event::Change &e) override; | void onChange(event::Change &e) override; | ||||
| @@ -4,6 +4,15 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void Knob::onButton(event::Button &e) { | |||||
| float r = box.size.x / 2; | |||||
| math::Vec c = box.size.div(2); | |||||
| float dist = e.pos.minus(c).norm(); | |||||
| if (dist <= r) { | |||||
| ParamWidget::onButton(e); | |||||
| } | |||||
| } | |||||
| void Knob::onDragStart(event::DragStart &e) { | void Knob::onDragStart(event::DragStart &e) { | ||||
| context()->window->cursorLock(); | context()->window->cursorLock(); | ||||
| } | } | ||||
| @@ -28,9 +37,6 @@ void Knob::onDragMove(event::DragMove &e) { | |||||
| if (context()->window->isModPressed()) | if (context()->window->isModPressed()) | ||||
| delta /= 16.f; | delta /= 16.f; | ||||
| quantity->moveValue(delta); | quantity->moveValue(delta); | ||||
| event::Change eChange; | |||||
| onChange(eChange); | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,6 +5,20 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void ParamWidget::step() { | |||||
| if (quantity) { | |||||
| float value = quantity->getValue(); | |||||
| // Trigger change event when quantity value changes | |||||
| if (value != dirtyValue) { | |||||
| dirtyValue = value; | |||||
| event::Change eChange; | |||||
| onChange(eChange); | |||||
| } | |||||
| } | |||||
| OpaqueWidget::step(); | |||||
| } | |||||
| void ParamWidget::fromJson(json_t *rootJ) { | void ParamWidget::fromJson(json_t *rootJ) { | ||||
| json_t *valueJ = json_object_get(rootJ, "value"); | json_t *valueJ = json_object_get(rootJ, "value"); | ||||
| if (valueJ) { | if (valueJ) { | ||||
| @@ -20,7 +34,6 @@ void ParamWidget::onButton(event::Button &e) { | |||||
| quantity->reset(); | quantity->reset(); | ||||
| // Here's another way of doing it, but either works. | // Here's another way of doing it, but either works. | ||||
| // dynamic_cast<ParamQuantity*>(quantity)->getParam()->reset(); | // dynamic_cast<ParamQuantity*>(quantity)->getParam()->reset(); | ||||
| return; | |||||
| } | } | ||||
| OpaqueWidget::onButton(e); | OpaqueWidget::onButton(e); | ||||
| @@ -26,8 +26,13 @@ void SVGKnob::setSVG(std::shared_ptr<SVG> svg) { | |||||
| } | } | ||||
| void SVGKnob::step() { | void SVGKnob::step() { | ||||
| // Re-transform TransformWidget if dirty | |||||
| if (dirty && quantity) { | |||||
| Knob::step(); | |||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void SVGKnob::onChange(event::Change &e) { | |||||
| // Re-transform the TransformWidget | |||||
| if (quantity) { | |||||
| float angle; | float angle; | ||||
| if (quantity->isBounded()) { | if (quantity->isBounded()) { | ||||
| angle = math::rescale(quantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle); | angle = math::rescale(quantity->getScaledValue(), 0.f, 1.f, minAngle, maxAngle); | ||||
| @@ -42,12 +47,8 @@ void SVGKnob::step() { | |||||
| tw->translate(center); | tw->translate(center); | ||||
| tw->rotate(angle); | tw->rotate(angle); | ||||
| tw->translate(center.neg()); | tw->translate(center.neg()); | ||||
| dirty = true; | |||||
| } | } | ||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void SVGKnob::onChange(event::Change &e) { | |||||
| dirty = true; | |||||
| Knob::onChange(e); | Knob::onChange(e); | ||||
| } | } | ||||
| @@ -23,18 +23,19 @@ void SVGSlider::setSVGs(std::shared_ptr<SVG> backgroundSVG, std::shared_ptr<SVG> | |||||
| } | } | ||||
| void SVGSlider::step() { | void SVGSlider::step() { | ||||
| if (dirty && quantity) { | |||||
| Knob::step(); | |||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void SVGSlider::onChange(event::Change &e) { | |||||
| if (quantity) { | |||||
| // Interpolate handle position | // Interpolate handle position | ||||
| float v = quantity->getScaledValue(); | float v = quantity->getScaledValue(); | ||||
| handle->box.pos = math::Vec( | handle->box.pos = math::Vec( | ||||
| math::rescale(v, 0.f, 1.f, minHandlePos.x, maxHandlePos.x), | math::rescale(v, 0.f, 1.f, minHandlePos.x, maxHandlePos.x), | ||||
| math::rescale(v, 0.f, 1.f, minHandlePos.y, maxHandlePos.y)); | math::rescale(v, 0.f, 1.f, minHandlePos.y, maxHandlePos.y)); | ||||
| dirty = true; | |||||
| } | } | ||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void SVGSlider::onChange(event::Change &e) { | |||||
| dirty = true; | |||||
| ParamWidget::onChange(e); | ParamWidget::onChange(e); | ||||
| } | } | ||||
| @@ -9,6 +9,11 @@ SVGSwitch::SVGSwitch() { | |||||
| addChild(sw); | addChild(sw); | ||||
| } | } | ||||
| void SVGSwitch::step() { | |||||
| ParamWidget::step(); | |||||
| FramebufferWidget::step(); | |||||
| } | |||||
| void SVGSwitch::addFrame(std::shared_ptr<SVG> svg) { | void SVGSwitch::addFrame(std::shared_ptr<SVG> svg) { | ||||
| frames.push_back(svg); | frames.push_back(svg); | ||||
| // If this is our first frame, automatically set SVG and size | // If this is our first frame, automatically set SVG and size | ||||
| @@ -31,7 +31,7 @@ static void drawPlug(NVGcontext *vg, math::Vec pos, NVGcolor color) { | |||||
| nvgFill(vg); | nvgFill(vg); | ||||
| } | } | ||||
| static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float width, float tension, float opacity) { | |||||
| static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||||
| NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | ||||
| NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | ||||
| @@ -54,7 +54,7 @@ static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor co | |||||
| nvgMoveTo(vg, pos1.x, pos1.y); | nvgMoveTo(vg, pos1.x, pos1.y); | ||||
| nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | ||||
| nvgStrokeColor(vg, colorShadow); | nvgStrokeColor(vg, colorShadow); | ||||
| nvgStrokeWidth(vg, width); | |||||
| nvgStrokeWidth(vg, thickness); | |||||
| nvgStroke(vg); | nvgStroke(vg); | ||||
| // Wire outline | // Wire outline | ||||
| @@ -62,12 +62,12 @@ static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor co | |||||
| nvgMoveTo(vg, pos1.x, pos1.y); | nvgMoveTo(vg, pos1.x, pos1.y); | ||||
| nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | ||||
| nvgStrokeColor(vg, colorOutline); | nvgStrokeColor(vg, colorOutline); | ||||
| nvgStrokeWidth(vg, width); | |||||
| nvgStrokeWidth(vg, thickness); | |||||
| nvgStroke(vg); | nvgStroke(vg); | ||||
| // Wire solid | // Wire solid | ||||
| nvgStrokeColor(vg, color); | nvgStrokeColor(vg, color); | ||||
| nvgStrokeWidth(vg, width - 2); | |||||
| nvgStrokeWidth(vg, thickness - 2); | |||||
| nvgStroke(vg); | nvgStroke(vg); | ||||
| nvgRestore(vg); | nvgRestore(vg); | ||||
| @@ -179,17 +179,17 @@ void WireWidget::draw(NVGcontext *vg) { | |||||
| opacity = 1.0; | opacity = 1.0; | ||||
| } | } | ||||
| float width = 5; | |||||
| float thickness = 5; | |||||
| if (wire && wire->outputModule) { | if (wire && wire->outputModule) { | ||||
| Output *output = &wire->outputModule->outputs[wire->outputId]; | Output *output = &wire->outputModule->outputs[wire->outputId]; | ||||
| if (output->numChannels != 1) { | if (output->numChannels != 1) { | ||||
| width = 8; | |||||
| thickness = 8; | |||||
| } | } | ||||
| } | } | ||||
| math::Vec outputPos = getOutputPos(); | math::Vec outputPos = getOutputPos(); | ||||
| math::Vec inputPos = getInputPos(); | math::Vec inputPos = getInputPos(); | ||||
| drawWire(vg, outputPos, inputPos, color, width, tension, opacity); | |||||
| drawWire(vg, outputPos, inputPos, color, thickness, tension, opacity); | |||||
| } | } | ||||
| void WireWidget::drawPlugs(NVGcontext *vg) { | void WireWidget::drawPlugs(NVGcontext *vg) { | ||||
| @@ -21,9 +21,6 @@ void Module::setup(int numParams, int numInputs, int numOutputs, int numLights) | |||||
| json_t *Module::toJson() { | json_t *Module::toJson() { | ||||
| json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
| // id | |||||
| json_object_set_new(rootJ, "id", json_integer(id)); | |||||
| // params | // params | ||||
| json_t *paramsJ = json_array(); | json_t *paramsJ = json_array(); | ||||
| for (Param ¶m : params) { | for (Param ¶m : params) { | ||||
| @@ -42,11 +39,6 @@ json_t *Module::toJson() { | |||||
| } | } | ||||
| void Module::fromJson(json_t *rootJ) { | void Module::fromJson(json_t *rootJ) { | ||||
| // id | |||||
| json_t *idJ = json_object_get(rootJ, "id"); | |||||
| if (idJ) | |||||
| id = json_integer_value(idJ); | |||||
| // params | // params | ||||
| json_t *paramsJ = json_object_get(rootJ, "params"); | json_t *paramsJ = json_object_get(rootJ, "params"); | ||||
| size_t i; | size_t i; | ||||