| @@ -24,7 +24,7 @@ struct Knob : ParamWidget { | |||||
| /** Fractional value between the param's value and the dragged knob position. */ | /** Fractional value between the param's value and the dragged knob position. */ | ||||
| float snapDelta = 0.f; | float snapDelta = 0.f; | ||||
| void init() override; | |||||
| void initParamQuantity() override; | |||||
| void onHover(const event::Hover& e) override; | void onHover(const event::Hover& e) override; | ||||
| void onButton(const event::Button& e) override; | void onButton(const event::Button& e) override; | ||||
| void onDragStart(const event::DragStart& e) override; | void onDragStart(const event::DragStart& e) override; | ||||
| @@ -19,7 +19,10 @@ struct ParamWidget : widget::OpaqueWidget { | |||||
| /** For triggering the Change event. `*/ | /** For triggering the Change event. `*/ | ||||
| float lastValue = NAN; | float lastValue = NAN; | ||||
| virtual void init() {} | |||||
| /** Configures ParamQuantity properties based on the type of ParamWidget. | |||||
| This seems a bit hacky, but it's easier than requiring plugin developers to set `ParamQuantity::randomizeEnabled`, etc. | |||||
| */ | |||||
| virtual void initParamQuantity() {} | |||||
| engine::ParamQuantity* getParamQuantity(); | engine::ParamQuantity* getParamQuantity(); | ||||
| void step() override; | void step() override; | ||||
| void draw(const DrawArgs& args) override; | void draw(const DrawArgs& args) override; | ||||
| @@ -19,7 +19,7 @@ struct Switch : ParamWidget { | |||||
| bool momentaryPressed = false; | bool momentaryPressed = false; | ||||
| bool momentaryReleased = false; | bool momentaryReleased = false; | ||||
| void init() override; | |||||
| void initParamQuantity() override; | |||||
| void step() override; | void step() override; | ||||
| void onDoubleClick(const event::DoubleClick& e) override; | void onDoubleClick(const event::DoubleClick& e) override; | ||||
| void onDragStart(const event::DragStart& e) override; | void onDragStart(const event::DragStart& e) override; | ||||
| @@ -110,7 +110,7 @@ struct Module { | |||||
| q->maxValue = maxValue; | q->maxValue = maxValue; | ||||
| q->defaultValue = defaultValue; | q->defaultValue = defaultValue; | ||||
| if (label == "") | if (label == "") | ||||
| q->label = string::f("Parameter %d", paramId + 1); | |||||
| q->label = string::f("#%d", paramId + 1); | |||||
| else | else | ||||
| q->label = label; | q->label = label; | ||||
| q->unit = unit; | q->unit = unit; | ||||
| @@ -127,7 +127,7 @@ struct Module { | |||||
| PortInfo* p = new PortInfo; | PortInfo* p = new PortInfo; | ||||
| if (label == "") | if (label == "") | ||||
| p->label = string::f("Input %d", portId + 1); | |||||
| p->label = string::f("#%d", portId + 1); | |||||
| else | else | ||||
| p->label = label; | p->label = label; | ||||
| inputInfos[portId] = p; | inputInfos[portId] = p; | ||||
| @@ -140,7 +140,7 @@ struct Module { | |||||
| PortInfo* p = new PortInfo; | PortInfo* p = new PortInfo; | ||||
| if (label == "") | if (label == "") | ||||
| p->label = string::f("Output %d", portId + 1); | |||||
| p->label = string::f("#%d", portId + 1); | |||||
| else | else | ||||
| p->label = label; | p->label = label; | ||||
| outputInfos[portId] = p; | outputInfos[portId] = p; | ||||
| @@ -62,7 +62,7 @@ TParamWidget* createParam(math::Vec pos, engine::Module* module, int paramId) { | |||||
| o->box.pos = pos; | o->box.pos = pos; | ||||
| o->app::ParamWidget::module = module; | o->app::ParamWidget::module = module; | ||||
| o->app::ParamWidget::paramId = paramId; | o->app::ParamWidget::paramId = paramId; | ||||
| o->init(); | |||||
| o->initParamQuantity(); | |||||
| return o; | return o; | ||||
| } | } | ||||
| @@ -12,8 +12,8 @@ namespace app { | |||||
| static const float KNOB_SENSITIVITY = 0.0015f; | static const float KNOB_SENSITIVITY = 0.0015f; | ||||
| void Knob::init() { | |||||
| ParamWidget::init(); | |||||
| void Knob::initParamQuantity() { | |||||
| ParamWidget::initParamQuantity(); | |||||
| engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
| if (pq) { | if (pq) { | ||||
| if (snap) | if (snap) | ||||
| @@ -20,16 +20,17 @@ struct PortTooltip : ui::Tooltip { | |||||
| engine::Port* port = portWidget->getPort(); | engine::Port* port = portWidget->getPort(); | ||||
| engine::PortInfo* portInfo = portWidget->getPortInfo(); | engine::PortInfo* portInfo = portWidget->getPortInfo(); | ||||
| // Label | // Label | ||||
| text = portInfo->label; | |||||
| text = (portWidget->type == engine::Port::INPUT) ? "Input" : "Output"; | |||||
| text += ": "; | |||||
| text += portInfo->label; | |||||
| // Voltage, number of channels | // Voltage, number of channels | ||||
| int channels = port->getChannels(); | int channels = port->getChannels(); | ||||
| for (int i = 0; i < channels; i++) { | for (int i = 0; i < channels; i++) { | ||||
| // Add newline or comma | // Add newline or comma | ||||
| if (i % 4 == 0) | |||||
| text += "\n"; | |||||
| else | |||||
| text += " "; | |||||
| text += string::f("%5gV", port->getVoltage(i)); | |||||
| text += "\n"; | |||||
| if (channels > 1) | |||||
| text += string::f("%d: ", i + 1); | |||||
| text += string::f("% .3fV", port->getVoltage(i)); | |||||
| } | } | ||||
| // Description | // Description | ||||
| std::string description = portInfo->description; | std::string description = portInfo->description; | ||||
| @@ -64,6 +65,8 @@ PortWidget::PortWidget() { | |||||
| } | } | ||||
| PortWidget::~PortWidget() { | PortWidget::~PortWidget() { | ||||
| // HACK: In case onDragDrop() is called but not onLeave() afterwards... | |||||
| destroyTooltip(); | |||||
| // plugLight is not a child and is thus owned by the PortWidget, so we need to delete it here | // plugLight is not a child and is thus owned by the PortWidget, so we need to delete it here | ||||
| delete plugLight; | delete plugLight; | ||||
| // HACK | // HACK | ||||
| @@ -236,6 +239,10 @@ void PortWidget::onDragEnd(const event::DragEnd& e) { | |||||
| } | } | ||||
| void PortWidget::onDragDrop(const event::DragDrop& e) { | void PortWidget::onDragDrop(const event::DragDrop& e) { | ||||
| // HACK: Only delete tooltip if we're not (normal) dragging it. | |||||
| if (e.origin == this) | |||||
| createTooltip(); | |||||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | if (e.button != GLFW_MOUSE_BUTTON_LEFT) | ||||
| return; | return; | ||||
| @@ -258,6 +265,7 @@ void PortWidget::onDragDrop(const event::DragDrop& e) { | |||||
| void PortWidget::onDragEnter(const event::DragEnter& e) { | void PortWidget::onDragEnter(const event::DragEnter& e) { | ||||
| createTooltip(); | createTooltip(); | ||||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | if (e.button != GLFW_MOUSE_BUTTON_LEFT) | ||||
| return; | return; | ||||
| @@ -278,6 +286,7 @@ void PortWidget::onDragEnter(const event::DragEnter& e) { | |||||
| void PortWidget::onDragLeave(const event::DragLeave& e) { | void PortWidget::onDragLeave(const event::DragLeave& e) { | ||||
| destroyTooltip(); | destroyTooltip(); | ||||
| if (e.button != GLFW_MOUSE_BUTTON_LEFT) | if (e.button != GLFW_MOUSE_BUTTON_LEFT) | ||||
| return; | return; | ||||
| @@ -35,10 +35,10 @@ void SvgKnob::onChange(const event::Change& e) { | |||||
| // Re-transform the widget::TransformWidget | // Re-transform the widget::TransformWidget | ||||
| engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
| if (pq) { | if (pq) { | ||||
| float value = pq->getScaledValue(); | |||||
| float value = pq->getSmoothValue(); | |||||
| float angle; | float angle; | ||||
| if (pq->isBounded()) { | if (pq->isBounded()) { | ||||
| angle = math::rescale(value, 0.f, 1.f, minAngle, maxAngle); | |||||
| angle = math::rescale(value, pq->getMinValue(), pq->getMaxValue(), minAngle, maxAngle); | |||||
| } | } | ||||
| else { | else { | ||||
| // Center unbounded knobs | // Center unbounded knobs | ||||
| @@ -34,7 +34,7 @@ void SvgSlider::onChange(const event::Change& e) { | |||||
| engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
| if (pq) { | if (pq) { | ||||
| // Interpolate handle position | // Interpolate handle position | ||||
| float v = pq->getScaledValue(); | |||||
| float v = math::rescale(pq->getSmoothValue(), pq->getMinValue(), pq->getMaxValue(), 0.f, 1.f); | |||||
| 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)); | ||||
| @@ -9,8 +9,8 @@ namespace rack { | |||||
| namespace app { | namespace app { | ||||
| void Switch::init() { | |||||
| ParamWidget::init(); | |||||
| void Switch::initParamQuantity() { | |||||
| ParamWidget::initParamQuantity(); | |||||
| engine::ParamQuantity* pq = getParamQuantity(); | engine::ParamQuantity* pq = getParamQuantity(); | ||||
| if (pq) { | if (pq) { | ||||
| pq->snapEnabled = true; | pq->snapEnabled = true; | ||||
| @@ -786,9 +786,10 @@ Cable* Engine::getCable(int cableId) { | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| void Engine::setParam(Module* module, int paramId, float value) { | void Engine::setParam(Module* module, int paramId, float value) { | ||||
| // TODO Does this need to be thread-safe? | |||||
| // If being smoothed, cancel smoothing | |||||
| // Don't lock because this is called too frequently. | |||||
| // If param is being smoothed, cancel smoothing. | |||||
| if (internal->smoothModule == module && internal->smoothParamId == paramId) { | if (internal->smoothModule == module && internal->smoothParamId == paramId) { | ||||
| internal->smoothModule = NULL; | internal->smoothModule = NULL; | ||||
| internal->smoothParamId = 0; | internal->smoothParamId = 0; | ||||