From 4630c1379a27bf3ad377cf2a030a3fbfce2bfcd3 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 11 Oct 2023 17:50:08 -0400 Subject: [PATCH] Start of a collection of cleanups (#49) * Start of a collection of cleanups 1. component-adapters exist for at least a simple discrete case 2. Make the componet take Continuous or ContinuousModulatable so not every client needs to drag around the modulation api. 3. Fix up the destruct sequence once and for all 4. Includes and stuff --- examples/component-demo/CoupledControls.h | 13 +--- examples/component-demo/CustomStyleDemo.h | 8 +-- examples/component-demo/DraggableTextDemo.h | 8 +-- examples/component-demo/HSliderDemo.h | 8 +-- examples/component-demo/KnobDemo.h | 8 +-- examples/component-demo/MixerPrototype.h | 8 +-- examples/component-demo/VSliderDemo.h | 8 +-- .../component-adapters/DiscreteToReference.h | 67 +++++++++++++++++++ .../sst/jucegui/components/ComponentBase.h | 54 ++++++++++++--- .../jucegui/components/DiscreteParamEditor.h | 5 ++ include/sst/jucegui/data/Continuous.h | 27 +++++++- include/sst/jucegui/data/Discrete.h | 7 +- .../components/ContinuousParamEditor.cpp | 46 +++++++------ .../components/DraggableTextEditableValue.cpp | 19 +++--- src/sst/jucegui/components/HSlider.cpp | 32 ++++----- src/sst/jucegui/components/HSliderFilled.cpp | 28 ++++---- src/sst/jucegui/components/Knob.cpp | 12 +++- src/sst/jucegui/components/KnobPainter.hxx | 20 ++++-- src/sst/jucegui/components/VSlider.cpp | 14 ++-- 19 files changed, 250 insertions(+), 142 deletions(-) create mode 100644 include/sst/jucegui/component-adapters/DiscreteToReference.h diff --git a/examples/component-demo/CoupledControls.h b/examples/component-demo/CoupledControls.h index 2efa215..64a69c5 100644 --- a/examples/component-demo/CoupledControls.h +++ b/examples/component-demo/CoupledControls.h @@ -63,18 +63,7 @@ struct CoupledControlsDemo : public sst::jucegui::components::WindowPanel idleTimer = std::make_unique(this); idleTimer->startTimer(1000.0 / 60.0); } - ~MixedControls() - { - idleTimer->stopTimer(); - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - for (const auto &k : sliders) - { - k->setSource(nullptr); - } - } + ~MixedControls() { idleTimer->stopTimer(); } float ival = 0.f; void idle() diff --git a/examples/component-demo/CustomStyleDemo.h b/examples/component-demo/CustomStyleDemo.h index 6181813..376c4fd 100644 --- a/examples/component-demo/CustomStyleDemo.h +++ b/examples/component-demo/CustomStyleDemo.h @@ -89,13 +89,7 @@ struct CustomStyleDemo : public sst::jucegui::components::WindowPanel sources.push_back(std::move(d)); } } - ~SomeSliders() - { - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - } + ~SomeSliders() {} void resized() override { auto b = getLocalBounds(); diff --git a/examples/component-demo/DraggableTextDemo.h b/examples/component-demo/DraggableTextDemo.h index 70902c1..a4ff573 100644 --- a/examples/component-demo/DraggableTextDemo.h +++ b/examples/component-demo/DraggableTextDemo.h @@ -39,13 +39,7 @@ struct DraggableTextDemo : public sst::jucegui::components::WindowPanel sources.push_back(std::move(d)); } } - ~SomeEditors() - { - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - } + ~SomeEditors() {} void resized() override { auto b = getLocalBounds(); diff --git a/examples/component-demo/HSliderDemo.h b/examples/component-demo/HSliderDemo.h index d601e21..0786ed8 100644 --- a/examples/component-demo/HSliderDemo.h +++ b/examples/component-demo/HSliderDemo.h @@ -71,13 +71,7 @@ struct HSliderDemo : public sst::jucegui::components::WindowPanel sources.push_back(std::move(d)); } } - ~SomeSliders() - { - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - } + ~SomeSliders() {} void resized() override { auto b = getLocalBounds(); diff --git a/examples/component-demo/KnobDemo.h b/examples/component-demo/KnobDemo.h index 4ebf9c6..ed3e9cc 100644 --- a/examples/component-demo/KnobDemo.h +++ b/examples/component-demo/KnobDemo.h @@ -61,13 +61,7 @@ struct KnobDemo : public sst::jucegui::components::WindowPanel sources.push_back(std::move(d)); } } - ~SomeKnobs() - { - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - } + ~SomeKnobs() {} void resized() override { auto b = getLocalBounds(); diff --git a/examples/component-demo/MixerPrototype.h b/examples/component-demo/MixerPrototype.h index 3e766d4..69c0323 100644 --- a/examples/component-demo/MixerPrototype.h +++ b/examples/component-demo/MixerPrototype.h @@ -50,13 +50,7 @@ struct MixerProto : public sst::jucegui::components::WindowPanel addAndMakeVisible(*lab); } - ~Channel() - { - solo->setSource(nullptr); - pan->setSource(nullptr); - mute->setSource(nullptr); - level->setSource(nullptr); - } + ~Channel() {} std::unique_ptr level; std::unique_ptr pan; diff --git a/examples/component-demo/VSliderDemo.h b/examples/component-demo/VSliderDemo.h index 27552bf..dc028a1 100644 --- a/examples/component-demo/VSliderDemo.h +++ b/examples/component-demo/VSliderDemo.h @@ -66,13 +66,7 @@ struct VSliderDemo : public sst::jucegui::components::WindowPanel sources.push_back(std::move(d)); } } - ~SomeSliders() - { - for (const auto &k : knobs) - { - k->setSource(nullptr); - } - } + ~SomeSliders() {} void resized() override { auto b = getLocalBounds(); diff --git a/include/sst/jucegui/component-adapters/DiscreteToReference.h b/include/sst/jucegui/component-adapters/DiscreteToReference.h new file mode 100644 index 0000000..52196cf --- /dev/null +++ b/include/sst/jucegui/component-adapters/DiscreteToReference.h @@ -0,0 +1,67 @@ +/* + * sst-juce-gui - an open source library of juce widgets + * built by Surge Synth Team. + * + * Copyright 2023, various authors, as described in the GitHub + * transaction log. + * + * sst-basic-blocks is released under the MIT license, as described + * by "LICENSE.md" in this repository. This means you may use this + * in commercial software if you are a JUCE Licensee. If you use JUCE + * in the open source / GPL3 context, your combined work must be + * released under GPL3. + * + * All source in sst-juce-gui available at + * https://github.com/surge-synthesizer/sst-juce-gui + */ + +#ifndef INCLUDE_SST_JUCEGUI_COMPONENT_ADAPTERS_DISCRETETOREFERENCE_H +#define INCLUDE_SST_JUCEGUI_COMPONENT_ADAPTERS_DISCRETETOREFERENCE_H + +#include +#include + +#include "sst/jucegui/components/DiscreteParamEditor.h" + +namespace sst::jucegui::component_adapters +{ +template struct DiscreteToValueReference : data::Discrete +{ + static_assert(std::is_integral()); + std::unique_ptr widget; + V &underlyer; + static_assert(std::is_base_of::value); + DiscreteToValueReference(std::unique_ptr &wid, V &und) + : widget(std::move(wid)), underlyer(und) + { + setup(); + } + DiscreteToValueReference(V &und) : widget(std::make_unique()), underlyer(und) { setup(); } + + void setup() { widget->setSource(this); } + + std::string label; + void setLabel(const std::string &s) + { + label = s; + widget->repaint(); + } + std::string getLabel() const override { return label; } + + std::function onValueChanged{nullptr}; + int getValue() const override { return underlyer; } + void setValueFromGUI(const int &f) override + { + underlyer = f; + if (onValueChanged) + onValueChanged(f); + } + void setValueFromModel(const int &f) override + { + underlyer = f; + widget->repaint(); + } +}; +} // namespace sst::jucegui::component_adapters + +#endif // CONDUIT_DISCRETETOREFERENCE_H diff --git a/include/sst/jucegui/components/ComponentBase.h b/include/sst/jucegui/components/ComponentBase.h index bfe1ef8..6e32ba2 100644 --- a/include/sst/jucegui/components/ComponentBase.h +++ b/include/sst/jucegui/components/ComponentBase.h @@ -19,6 +19,7 @@ #define INCLUDE_SST_JUCEGUI_COMPONENTS_COMPONENTBASE_H #include +#include #include #include @@ -95,8 +96,10 @@ template struct Modulatable : public data::Continuous::DataListener virtual ~Modulatable() { - if (source) - source->removeGUIDataListener(this); + if (continuous()) + { + continuous()->removeGUIDataListener(this); + } } T *asT() { return static_cast(this); } @@ -119,21 +122,56 @@ template struct Modulatable : public data::Continuous::DataListener isEditingMod = b; asT()->repaint(); } - void setSource(data::ContinunousModulatable *s) + + data::Continuous *continuous() { - if (source) - source->removeGUIDataListener(this); + switch (source.index()) + { + case 0: + return std::get<0>(source); + case 1: + return std::get<1>(source); + } + assert(false); + return nullptr; + } + data::ContinunousModulatable *continuousModulatable() + { + if (std::holds_alternative(source)) + { + return std::get(source); + } + return nullptr; + } + + template void setSource(S *s) + { + if (continuous()) + continuous()->removeGUIDataListener(this); source = s; - if (source) - source->addGUIDataListener(this); + if (continuous()) + continuous()->addGUIDataListener(this); asT()->repaint(); } + void clearSource() + { + if (continuous()) + continuous()->removeGUIDataListener(this); + source = (data::ContinunousModulatable *)nullptr; + } + void dataChanged() override { asT()->repaint(); } + void sourceVanished(data::Continuous *s) override + { + assert(s == continuous()); + clearSource(); + } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Modulatable) - data::ContinunousModulatable *source{nullptr}; + std::variant source{ + (data::Continuous *)nullptr}; bool isEditingMod{false}; ModulationDisplay modulationDisplay{NONE}; }; diff --git a/include/sst/jucegui/components/DiscreteParamEditor.h b/include/sst/jucegui/components/DiscreteParamEditor.h index 28acd84..ee49e97 100644 --- a/include/sst/jucegui/components/DiscreteParamEditor.h +++ b/include/sst/jucegui/components/DiscreteParamEditor.h @@ -27,6 +27,11 @@ struct DiscreteParamEditor : public juce::Component, public data::Discrete::DataListener { void dataChanged() override { repaint(); } + void sourceVanished(data::Discrete *d) override + { + assert(d == data); + setSource(nullptr); + } void setSource(data::Discrete *d) { if (data) diff --git a/include/sst/jucegui/data/Continuous.h b/include/sst/jucegui/data/Continuous.h index 1c5d43e..56f1e98 100644 --- a/include/sst/jucegui/data/Continuous.h +++ b/include/sst/jucegui/data/Continuous.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "Labeled.h" @@ -28,16 +30,35 @@ namespace sst::jucegui::data { struct Continuous : public Labeled { - virtual ~Continuous() = default; + virtual ~Continuous() + { + supressListenerModification = true; + for (auto *dl : guilisteners) + { + dl->sourceVanished(this); + } + supressListenerModification = false; + }; struct DataListener { virtual ~DataListener() = default; // FIXME - in the future we may want this more fine grained virtual void dataChanged() = 0; + virtual void sourceVanished(Continuous *) = 0; }; - void addGUIDataListener(DataListener *l) { guilisteners.insert(l); } - void removeGUIDataListener(DataListener *l) { guilisteners.erase(l); } + bool supressListenerModification{false}; + void addGUIDataListener(DataListener *l) + { + assert(!supressListenerModification); + if (!supressListenerModification) + guilisteners.insert(l); + } + void removeGUIDataListener(DataListener *l) + { + if (!supressListenerModification) + guilisteners.erase(l); + } void addModelDataListener(DataListener *l) { modellisteners.insert(l); } void removeModelDataListener(DataListener *l) { modellisteners.erase(l); } diff --git a/include/sst/jucegui/data/Discrete.h b/include/sst/jucegui/data/Discrete.h index df7f2cc..2a90980 100644 --- a/include/sst/jucegui/data/Discrete.h +++ b/include/sst/jucegui/data/Discrete.h @@ -25,13 +25,18 @@ namespace sst::jucegui::data { struct Discrete : public Labeled { - virtual ~Discrete() = default; + virtual ~Discrete() + { + for (auto *l : guilisteners) + l->sourceVanished(this); + } struct DataListener { virtual ~DataListener() = default; // FIXME - in the future we may want this more fine grained virtual void dataChanged() = 0; + virtual void sourceVanished(Discrete *) = 0; }; void addGUIDataListener(DataListener *l) { guilisteners.insert(l); } void removeGUIDataListener(DataListener *l) { guilisteners.erase(l); } diff --git a/src/sst/jucegui/components/ContinuousParamEditor.cpp b/src/sst/jucegui/components/ContinuousParamEditor.cpp index 8f74561..188a24c 100644 --- a/src/sst/jucegui/components/ContinuousParamEditor.cpp +++ b/src/sst/jucegui/components/ContinuousParamEditor.cpp @@ -28,7 +28,7 @@ void ContinuousParamEditor::mouseDown(const juce::MouseEvent &e) return; jassert(settings()); - jassert(source); + jassert(continuous()); if (e.mods.isPopupMenu()) { @@ -39,10 +39,10 @@ void ContinuousParamEditor::mouseDown(const juce::MouseEvent &e) mouseMode = DRAG; onBeginEdit(); - if (isEditingMod) - mouseDownV0 = source->getModulationValuePM1(); + if (isEditingMod && continuousModulatable()) + mouseDownV0 = continuousModulatable()->getModulationValuePM1(); else - mouseDownV0 = source->getValue(); + mouseDownV0 = continuous()->getValue(); mouseDownY0 = e.position.y; mouseDownX0 = e.position.x; } @@ -62,7 +62,7 @@ void ContinuousParamEditor::mouseDoubleClick(const juce::MouseEvent &e) return; onBeginEdit(); - source->setValueFromGUI(source->getDefaultValue()); + continuous()->setValueFromGUI(continuous()->getDefaultValue()); onEndEdit(); repaint(); @@ -79,11 +79,11 @@ void ContinuousParamEditor::mouseDrag(const juce::MouseEvent &e) float dy = -(e.position.y - mouseDownY0); float dx = (e.position.x - mouseDownX0); float d = 0; - float minForScaling = source->getMin(); - float maxForScaling = source->getMax(); - if (isEditingMod) + float minForScaling = continuous()->getMin(); + float maxForScaling = continuous()->getMax(); + if (isEditingMod && continuousModulatable()) { - if (source->isModulationBipolar()) + if (continuousModulatable()->isModulationBipolar()) minForScaling = -1.0f; else minForScaling = 0.0f; @@ -100,18 +100,18 @@ void ContinuousParamEditor::mouseDrag(const juce::MouseEvent &e) } if (e.mods.isShiftDown()) d = d * 0.1; - if (isEditingMod) + if (isEditingMod && continuousModulatable()) { - if (source->isModulationBipolar()) + if (continuousModulatable()->isModulationBipolar()) d = d * 0.5; auto vn = std::clamp(mouseDownV0 + d, -1.f, 1.f); - source->setModulationValuePM1(vn); + continuousModulatable()->setModulationValuePM1(vn); mouseDownV0 = vn; } else { - auto vn = std::clamp(mouseDownV0 + d, source->getMin(), source->getMax()); - source->setValueFromGUI(vn); + auto vn = std::clamp(mouseDownV0 + d, continuous()->getMin(), continuous()->getMax()); + continuous()->setValueFromGUI(vn); mouseDownV0 = vn; } mouseDownX0 = e.position.x; @@ -129,25 +129,27 @@ void ContinuousParamEditor::mouseWheelMove(const juce::MouseEvent &e, return; onBeginEdit(); - if (isEditingMod) + if (isEditingMod && continuousModulatable()) { // fixme - callibration and sharing auto d = (wheel.isReversed ? -1 : 1) * wheel.deltaY * (2); if (e.mods.isShiftDown()) d = d * 0.1; - auto vn = std::clamp(source->getModulationValuePM1() + d, -1.f, 1.f); - source->setModulationValuePM1(vn); + auto vn = std::clamp(continuousModulatable()->getModulationValuePM1() + d, -1.f, 1.f); + continuousModulatable()->setModulationValuePM1(vn); } else { // fixme - callibration and sharing - auto d = (wheel.isReversed ? -1 : 1) * wheel.deltaY * (source->getMax() - source->getMin()); + auto d = (wheel.isReversed ? -1 : 1) * wheel.deltaY * + (continuous()->getMax() - continuous()->getMin()); if (e.mods.isShiftDown()) d = d * 0.1; - auto vn = std::clamp(source->getValue() + d, source->getMin(), source->getMax()); - source->setValueFromGUI(vn); + auto vn = std::clamp(continuous()->getValue() + d, continuous()->getMin(), + continuous()->getMax()); + continuous()->setValueFromGUI(vn); } onEndEdit(); repaint(); @@ -155,9 +157,9 @@ void ContinuousParamEditor::mouseWheelMove(const juce::MouseEvent &e, bool ContinuousParamEditor::processMouseActions() { - if (!source) + if (!continuous()) return false; - if (source->isHidden()) + if (continuous()->isHidden()) return false; if (!isEnabled()) return false; diff --git a/src/sst/jucegui/components/DraggableTextEditableValue.cpp b/src/sst/jucegui/components/DraggableTextEditableValue.cpp index a6a9a19..2813f2f 100644 --- a/src/sst/jucegui/components/DraggableTextEditableValue.cpp +++ b/src/sst/jucegui/components/DraggableTextEditableValue.cpp @@ -46,11 +46,11 @@ void DraggableTextEditableValue::setFromEditor() auto t = underlyingEditor->getText(); if (t.isEmpty()) { - source->setValueFromGUI(source->getDefaultValue()); + continuous()->setValueFromGUI(continuous()->getDefaultValue()); } else { - source->setValueAsString(t.toStdString()); + continuous()->setValueAsString(t.toStdString()); } underlyingEditor->setVisible(false); repaint(); @@ -73,7 +73,7 @@ void DraggableTextEditableValue::paint(juce::Graphics &g) g.fillRoundedRectangle(getLocalBounds().toFloat(), 3.f); g.setColour(getColour(Styles::bordercol)); g.drawRoundedRectangle(getLocalBounds().toFloat(), 3.f, 1.f); - if (source && !underlyingEditor->isVisible()) + if (continuous() && !underlyingEditor->isVisible()) { g.setFont(getFont(Styles::labelfont)); if (underlyingEditor->isVisible()) @@ -82,23 +82,24 @@ void DraggableTextEditableValue::paint(juce::Graphics &g) g.setColour(getColour(Styles::textoffcol)); else g.setColour(getColour(Styles::texthoveroffcol)); - g.drawText(source->getValueAsString(), getLocalBounds(), juce::Justification::centred); + g.drawText(continuous()->getValueAsString(), getLocalBounds(), + juce::Justification::centred); } } void DraggableTextEditableValue::mouseDown(const juce::MouseEvent &e) { onBeginEdit(); - valueOnMouseDown = source->getValue(); + valueOnMouseDown = continuous()->getValue(); } void DraggableTextEditableValue::mouseUp(const juce::MouseEvent &e) { onEndEdit(); } void DraggableTextEditableValue::mouseDrag(const juce::MouseEvent &e) { auto d = e.getDistanceFromDragStartY(); auto fac = 0.5f * (e.mods.isShiftDown() ? 0.1f : 1.f); - auto nv = valueOnMouseDown - fac * d * source->getFineQuantizedStepSize(); - nv = std::clamp(nv, source->getMin(), source->getMax()); - source->setValueFromGUI(nv); + auto nv = valueOnMouseDown - fac * d * continuous()->getFineQuantizedStepSize(); + nv = std::clamp(nv, continuous()->getMin(), continuous()->getMax()); + continuous()->setValueFromGUI(nv); repaint(); } void DraggableTextEditableValue::mouseWheelMove(const juce::MouseEvent &event, @@ -109,7 +110,7 @@ void DraggableTextEditableValue::mouseWheelMove(const juce::MouseEvent &event, void DraggableTextEditableValue::mouseDoubleClick(const juce::MouseEvent &e) { - underlyingEditor->setText(source->getValueAsString()); + underlyingEditor->setText(continuous()->getValueAsString()); underlyingEditor->setVisible(true); underlyingEditor->selectAll(); underlyingEditor->grabKeyboardFocus(); diff --git a/src/sst/jucegui/components/HSlider.cpp b/src/sst/jucegui/components/HSlider.cpp index 517cb50..b569c23 100644 --- a/src/sst/jucegui/components/HSlider.cpp +++ b/src/sst/jucegui/components/HSlider.cpp @@ -28,7 +28,7 @@ HSlider::~HSlider() = default; void HSlider::paint(juce::Graphics &g) { - if (!source) + if (!continuous()) { g.fillAll(juce::Colours::red); g.setColour(juce::Colours::white); @@ -36,7 +36,7 @@ void HSlider::paint(juce::Graphics &g) return; } - if (source->isHidden()) + if (continuous()->isHidden()) return; bool vCenter = !showLabel && !showValue; @@ -45,14 +45,14 @@ void HSlider::paint(juce::Graphics &g) { g.setColour(getColour(Styles::labeltextcol)); g.setFont(getFont(Styles::labeltextfont)); - g.drawText(source->getLabel(), getLocalBounds().reduced(2, 1), + g.drawText(continuous()->getLabel(), getLocalBounds().reduced(2, 1), juce::Justification::bottomLeft); } if (showValue) { g.setColour(getColour(Styles::valuetextcol)); g.setFont(getFont(Styles::valuetextfont)); - g.drawText(source->getValueAsString(), getLocalBounds().reduced(2, 1), + g.drawText(continuous()->getValueAsString(), getLocalBounds().reduced(2, 1), juce::Justification::bottomRight); } @@ -93,11 +93,11 @@ void HSlider::paint(juce::Graphics &g) g.fillRoundedRectangle(gutter.reduced(2), gutterheight * 0.25); } - auto v = source->getValue01(); + auto v = continuous()->getValue01(); auto w = (1 - v) * gutter.getWidth(); auto hc = gutter.withTrimmedLeft(gutter.getWidth() - w).withWidth(1).expanded(0, 4).getCentre(); - if (source->isBipolar()) + if (continuous()->isBipolar()) { auto t = hc.getX(); auto b = gutter.getWidth() / 2 + gutter.getX(); @@ -116,15 +116,17 @@ void HSlider::paint(juce::Graphics &g) auto hr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(hc); - auto mvplus = std::clamp(v + source->getModulationValuePM1(), 0.f, 1.f); - auto mvminus = std::clamp(v - source->getModulationValuePM1(), 0.f, 1.f); - auto hm = (1.0 - mvplus) * gutter.getWidth(); - auto mpc = - gutter.withTrimmedLeft(gutter.getWidth() - hm).withWidth(1).expanded(0, 4).getCentre(); - auto mpr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(mpc); - - if (isEditingMod) + juce::Point mpc{}; + juce::Rectangle mpr{}; + if (isEditingMod && continuousModulatable()) { + auto mvplus = std::clamp(v + continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); + auto mvminus = std::clamp(v - continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); + auto hm = (1.0 - mvplus) * gutter.getWidth(); + mpc = + gutter.withTrimmedLeft(gutter.getWidth() - hm).withWidth(1).expanded(0, 4).getCentre(); + mpr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(mpc); + // draw rules { auto t = hc.getX(); @@ -136,7 +138,7 @@ void HSlider::paint(juce::Graphics &g) g.fillRoundedRectangle(val, gutterheight * 0.25); } - if (source->isModulationBipolar()) + if (continuousModulatable()->isModulationBipolar()) { auto t = hc.getX(); auto b = (mvminus)*gutter.getWidth() + gutter.getX(); diff --git a/src/sst/jucegui/components/HSliderFilled.cpp b/src/sst/jucegui/components/HSliderFilled.cpp index e504350..b007b89 100644 --- a/src/sst/jucegui/components/HSliderFilled.cpp +++ b/src/sst/jucegui/components/HSliderFilled.cpp @@ -27,7 +27,7 @@ HSliderFilled::HSliderFilled() void HSliderFilled::paint(juce::Graphics &g) { - if (!source) + if (!continuous()) { g.fillAll(juce::Colours::red); g.setColour(juce::Colours::white); @@ -35,7 +35,7 @@ void HSliderFilled::paint(juce::Graphics &g) return; } - if (source->isHidden()) + if (continuous()->isHidden()) return; // Gutter @@ -66,11 +66,11 @@ void HSliderFilled::paint(juce::Graphics &g) g.fillRoundedRectangle(gutter.reduced(2), rectRad); } - auto v = source->getValue01(); + auto v = continuous()->getValue01(); auto w = (1 - v) * gutter.getWidth(); auto hc = gutter.withTrimmedLeft(gutter.getWidth() - w).withWidth(1).expanded(0, 4).getCentre(); - if (source->isBipolar()) + if (continuous()->isBipolar()) { auto t = hc.getX(); auto b = gutter.getWidth() / 2 + gutter.getX(); @@ -89,15 +89,17 @@ void HSliderFilled::paint(juce::Graphics &g) auto hr = juce::Rectangle(2, gutter.getHeight()).withCentre(hc); - auto mvplus = std::clamp(v + source->getModulationValuePM1(), 0.f, 1.f); - auto mvminus = std::clamp(v - source->getModulationValuePM1(), 0.f, 1.f); - auto hm = (1.0 - mvplus) * gutter.getWidth(); - auto mpc = - gutter.withTrimmedLeft(gutter.getWidth() - hm).withWidth(1).expanded(0, 4).getCentre(); - auto mpr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(mpc); - - if (isEditingMod) + juce::Point mpc; + juce::Rectangle mpr; + if (continuousModulatable() && isEditingMod) { + auto mvplus = std::clamp(v + continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); + auto mvminus = std::clamp(v - continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); + auto hm = (1.0 - mvplus) * gutter.getWidth(); + mpc = + gutter.withTrimmedLeft(gutter.getWidth() - hm).withWidth(1).expanded(0, 4).getCentre(); + mpr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(mpc); + // draw rules { auto t = hc.getX(); @@ -109,7 +111,7 @@ void HSliderFilled::paint(juce::Graphics &g) g.fillRoundedRectangle(val, rectRad); } - if (source->isModulationBipolar()) + if (continuousModulatable()->isModulationBipolar()) { auto t = hc.getX(); auto b = (mvminus)*gutter.getWidth() + gutter.getX(); diff --git a/src/sst/jucegui/components/Knob.cpp b/src/sst/jucegui/components/Knob.cpp index 71093b4..ac55e80 100644 --- a/src/sst/jucegui/components/Knob.cpp +++ b/src/sst/jucegui/components/Knob.cpp @@ -28,14 +28,20 @@ Knob::~Knob() = default; void Knob::paint(juce::Graphics &g) { auto b = getLocalBounds(); - knobPainter(g, this, source); - + if (continuousModulatable()) + { + knobPainter(g, this, continuousModulatable()); + } + else + { + knobPainter(g, this, continuous()); + } if (drawLabel) { auto textarea = b.withTrimmedTop(b.getWidth()); g.setColour(getColour(Styles::labeltextcol)); g.setFont(getFont(Styles::labeltextfont)); - g.drawText(source->getLabel(), textarea, juce::Justification::centred); + g.drawText(continuous()->getLabel(), textarea, juce::Justification::centred); } } diff --git a/src/sst/jucegui/components/KnobPainter.hxx b/src/sst/jucegui/components/KnobPainter.hxx index f3e93f7..813b7f7 100644 --- a/src/sst/jucegui/components/KnobPainter.hxx +++ b/src/sst/jucegui/components/KnobPainter.hxx @@ -6,12 +6,15 @@ #define CONDUIT_KNOBPAINTER_H #include +#include namespace sst::jucegui::components { template void knobPainter(juce::Graphics &g, T* that, S *source) { + constexpr bool supportsMod = std::is_base_of_v; + if (!source) { g.fillAll(juce::Colours::red); @@ -152,16 +155,19 @@ void knobPainter(juce::Graphics &g, T* that, S *source) g.fillPath(pIn); // modulation arcs - if (that->isEditingMod) + if constexpr (supportsMod) { - pIn = modPath(5, source->getValue01(), source->getModulationValuePM1(), 1); - g.setColour(that->getColour(T::Styles::modvalcol)); - g.fillPath(pIn); - if (source->isModulationBipolar()) + if (that->isEditingMod) { - pIn = modPath(5, source->getValue01(), source->getModulationValuePM1(), -1); - g.setColour(that->getColour(T::Styles::modvalnegcol)); + pIn = modPath(5, source->getValue01(), source->getModulationValuePM1(), 1); + g.setColour(that->getColour(T::Styles::modvalcol)); g.fillPath(pIn); + if (source->isModulationBipolar()) + { + pIn = modPath(5, source->getValue01(), source->getModulationValuePM1(), -1); + g.setColour(that->getColour(T::Styles::modvalnegcol)); + g.fillPath(pIn); + } } } diff --git a/src/sst/jucegui/components/VSlider.cpp b/src/sst/jucegui/components/VSlider.cpp index 51faf8b..e1932f3 100644 --- a/src/sst/jucegui/components/VSlider.cpp +++ b/src/sst/jucegui/components/VSlider.cpp @@ -27,13 +27,13 @@ VSlider::~VSlider() = default; void VSlider::paint(juce::Graphics &g) { - if (!source) + if (!continuous()) { g.fillAll(juce::Colours::red); return; } - if (source->isHidden()) + if (continuous()->isHidden()) return; // Gutter @@ -65,11 +65,11 @@ void VSlider::paint(juce::Graphics &g) g.fillRoundedRectangle(gutter.reduced(2), gutterwidth * 0.25); } - auto v = source->getValue01(); + auto v = continuous()->getValue01(); auto h = (1.0 - v) * gutter.getHeight(); auto hc = gutter.withTrimmedTop(h).withHeight(1).expanded(0, 4).getCentre(); - if (source->isBipolar()) + if (continuous()->isBipolar()) { auto t = hc.getY(); auto b = gutter.getHeight() / 2 + gutter.getY(); @@ -88,8 +88,8 @@ void VSlider::paint(juce::Graphics &g) auto hr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(hc); - auto mvplus = std::clamp(v + source->getModulationValuePM1(), 0.f, 1.f); - auto mvminus = std::clamp(v - source->getModulationValuePM1(), 0.f, 1.f); + auto mvplus = std::clamp(v + continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); + auto mvminus = std::clamp(v - continuousModulatable()->getModulationValuePM1(), 0.f, 1.f); auto hm = (1.0 - mvplus) * gutter.getHeight(); auto mpc = gutter.withTrimmedTop(hm).withHeight(1).expanded(0, 4).getCentre(); auto mpr = juce::Rectangle(2 * hanRadius, 2 * hanRadius).withCentre(mpc); @@ -107,7 +107,7 @@ void VSlider::paint(juce::Graphics &g) g.fillRoundedRectangle(val, gutterwidth * 0.25); } - if (source->isModulationBipolar()) + if (continuousModulatable()->isModulationBipolar()) { auto t = hc.getY(); auto b = (1 - mvminus) * gutter.getHeight() + gutter.getY();