commit 49c40c14640130bce5a00d7b7ba31e43f0ed2984
parent 729dbcfa6a3683aeb317d1329219393009d2d4bd
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 30 May 2024 22:34:33 +0200
implement parameter overlays and use them to indicate if a parameter is locked
Diffstat:
12 files changed, 311 insertions(+), 3 deletions(-)
diff --git a/source/jucePluginData/lock.png b/source/jucePluginData/lock.png
Binary files differ.
diff --git a/source/jucePluginData/lock.psd b/source/jucePluginData/lock.psd
Binary files differ.
diff --git a/source/jucePluginEditorLib/CMakeLists.txt b/source/jucePluginEditorLib/CMakeLists.txt
@@ -8,6 +8,8 @@ set(SOURCES
lcd.cpp lcd.h
led.cpp led.h
midiPorts.cpp midiPorts.h
+ parameterOverlay.cpp parameterOverlay.h
+ parameterOverlays.cpp parameterOverlays.h
partbutton.cpp partbutton.h
pluginEditor.cpp pluginEditor.h
pluginEditorWindow.cpp pluginEditorWindow.h
diff --git a/source/jucePluginEditorLib/parameterOverlay.cpp b/source/jucePluginEditorLib/parameterOverlay.cpp
@@ -0,0 +1,127 @@
+#include "parameterOverlay.h"
+#include "parameterOverlays.h"
+#include "pluginEditor.h"
+#include "imagePool.h"
+
+#include "../jucePluginLib/parameter.h"
+#include "../juceUiLib/uiObjectStyle.h"
+
+namespace jucePluginEditorLib
+{
+ ParameterOverlay::ParameterOverlay(ParameterOverlays& _overlays, juce::Component* _component) : m_overlays(_overlays), m_component(_component)
+ {
+ }
+
+ ParameterOverlay::~ParameterOverlay()
+ {
+ delete m_imageLock;
+ setParameter(nullptr);
+ }
+
+ void ParameterOverlay::onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter)
+ {
+ setParameter(_parameter.parameter);
+ }
+
+ void ParameterOverlay::onUnbind(const pluginLib::ParameterBinding::BoundParameter&)
+ {
+ setParameter(nullptr);
+ }
+
+ ParameterOverlay::OverlayProperties ParameterOverlay::getOverlayProperties() const
+ {
+ OverlayProperties result;
+
+ const auto& editor = m_overlays.getEditor();
+
+ auto& root = editor.getRootObject();
+ const auto& props = m_component->getProperties();
+
+ result.scale = root.getPropertyFloat("overlayScale", 0.2f);
+ result.scale = props.getWithDefault("overlayScale", result.scale);
+
+ std::string color = root.getProperty("overlayColor", "ffffffff");
+ color = props.getWithDefault("overlayColor", juce::String(color)).toString().toStdString();
+ genericUI::UiObjectStyle::parseColor(result.color, color);
+
+ result.position.x = root.getPropertyFloat("overlayPosX", 0.0f);
+ result.position.y = root.getPropertyFloat("overlayPosY", 0.0f);
+
+ result.position.x = props.getWithDefault("overlayPosX", result.position.x);
+ result.position.y = props.getWithDefault("overlayPosY", result.position.y);
+
+ return result;
+ }
+
+ void ParameterOverlay::toggleOverlay(juce::DrawableImage*& _image, ImagePool::Type _type, bool _enable) const
+ {
+ if(_enable)
+ {
+ const auto props = getOverlayProperties();
+
+ auto updatePosition = [&]()
+ {
+ _image->setCentrePosition(static_cast<int>(props.position.x) + m_component->getPosition().x, static_cast<int>(props.position.y) + m_component->getPosition().y);
+ };
+
+ if(!_image)
+ {
+ auto& editor = m_overlays.getEditor();
+
+ auto* image = editor.getImagePool().getImage(_type, props.scale);
+
+ if(image)
+ {
+ _image = new juce::DrawableImage(*image);
+
+// _image->setOverlayColour(props.color); // juce cannot do it, it does not multiply but replaced the color entirely
+ _image->setInterceptsMouseClicks(false, false);
+ _image->setAlwaysOnTop(true);
+
+ m_component->getParentComponent()->addAndMakeVisible(_image);
+ }
+ }
+ else
+ {
+ _image->setVisible(true);
+ }
+
+ updatePosition();
+ }
+ else if(_image)
+ {
+ _image->setVisible(false);
+ }
+ }
+
+ void ParameterOverlay::updateOverlays()
+ {
+ const auto isLocked = m_parameter != nullptr && m_parameter->isLocked();
+
+ toggleOverlay(m_imageLock, ImagePool::Type::Lock, isLocked);
+ }
+
+ void ParameterOverlay::setParameter(pluginLib::Parameter* _parameter)
+ {
+ if(m_parameter == _parameter)
+ return;
+
+ if(m_parameter)
+ {
+ m_parameter->onLockedChanged.removeListener(m_parameterLockChangedListener);
+ m_parameterLockChangedListener = InvalidListenerId;
+ }
+
+ m_parameter = _parameter;
+
+ if(m_parameter)
+ {
+ m_parameterLockChangedListener = m_parameter->onLockedChanged.addListener([this](pluginLib::Parameter*, const bool&)
+ {
+ updateOverlays();
+ });
+ }
+
+ updateOverlays();
+ }
+}
diff --git a/source/jucePluginEditorLib/parameterOverlay.h b/source/jucePluginEditorLib/parameterOverlay.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "imagePool.h"
+#include "../jucePluginLib/parameterbinding.h"
+
+namespace juce
+{
+ class Component;
+}
+
+namespace jucePluginEditorLib
+{
+ class ParameterOverlays;
+
+ class ParameterOverlay
+ {
+ public:
+ static constexpr size_t InvalidListenerId = pluginLib::Event<int>::InvalidListenerId;
+
+ explicit ParameterOverlay(ParameterOverlays& _overlays, juce::Component* _component);
+ ~ParameterOverlay();
+
+ void onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter);
+ void onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter);
+
+ private:
+ struct OverlayProperties
+ {
+ juce::Colour color = juce::Colour(0xffffffff);
+ float scale = 0.2f;
+ juce::Point<float> position = juce::Point<float>(0,0);;
+ };
+
+ OverlayProperties getOverlayProperties() const;
+
+ void toggleOverlay(juce::DrawableImage*& _image, ImagePool::Type _type, bool _enable) const;
+
+ void updateOverlays();
+ void setParameter(pluginLib::Parameter* _parameter);
+
+ ParameterOverlays& m_overlays;
+ juce::Component* const m_component;
+ pluginLib::Parameter* m_parameter = nullptr;
+
+ size_t m_parameterLockChangedListener = InvalidListenerId;
+
+ juce::DrawableImage* m_imageLock = nullptr;
+ };
+}
diff --git a/source/jucePluginEditorLib/parameterOverlays.cpp b/source/jucePluginEditorLib/parameterOverlays.cpp
@@ -0,0 +1,69 @@
+#include "parameterOverlays.h"
+
+#include "../jucePluginLib/parameterbinding.h"
+
+namespace jucePluginEditorLib
+{
+ ParameterOverlays::ParameterOverlays(Editor& _editor, pluginLib::ParameterBinding& _binding) : m_editor(_editor), m_binding(_binding)
+ {
+ m_onBindListenerId = m_binding.onBind.addListener([this](const pluginLib::ParameterBinding::BoundParameter& _param)
+ {
+ onBind(_param);
+ });
+
+ m_onUnbindListenerId = m_binding.onUnbind.addListener([this](const pluginLib::ParameterBinding::BoundParameter& _param)
+ {
+ onUnbind(_param);
+ });
+ }
+
+ ParameterOverlays::~ParameterOverlays()
+ {
+ m_binding.onBind.removeListener(m_onBindListenerId);
+ m_binding.onUnbind.removeListener(m_onUnbindListenerId);
+ }
+
+ bool ParameterOverlays::registerComponent(juce::Component* _component)
+ {
+ if(m_overlays.find(_component) != m_overlays.end())
+ return false;
+
+ m_overlays.insert({_component, std::make_unique<ParameterOverlay>(*this, _component)});
+
+ return true;
+ }
+
+ void ParameterOverlays::onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter)
+ {
+ registerComponent(_parameter.component);
+
+ auto* o = getOverlay(_parameter);
+ if(!o)
+ return;
+
+ o->onBind(_parameter);
+ }
+
+ void ParameterOverlays::onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter)
+ {
+ auto* o = getOverlay(_parameter);
+
+ if(!o)
+ return;
+
+ o->onUnbind(_parameter);
+ }
+
+ ParameterOverlay* ParameterOverlays::getOverlay(const juce::Component* _comp)
+ {
+ const auto it = m_overlays.find(_comp);
+ if(it == m_overlays.end())
+ return nullptr;
+ return it->second.get();
+ }
+
+ ParameterOverlay* ParameterOverlays::getOverlay(const pluginLib::ParameterBinding::BoundParameter& _parameter)
+ {
+ return getOverlay(_parameter.component);
+ }
+}
diff --git a/source/jucePluginEditorLib/parameterOverlays.h b/source/jucePluginEditorLib/parameterOverlays.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <map>
+#include <memory>
+
+#include "parameterOverlay.h"
+
+#include "../jucePluginLib/parameterbinding.h"
+
+namespace pluginLib
+{
+ class ParameterBinding;
+}
+
+namespace juce
+{
+ class Component;
+}
+
+namespace jucePluginEditorLib
+{
+ class Editor;
+
+ class ParameterOverlays
+ {
+ public:
+ explicit ParameterOverlays(Editor& _editor, pluginLib::ParameterBinding& _binding);
+ ~ParameterOverlays();
+
+ bool registerComponent(juce::Component* _component);
+
+ Editor& getEditor() const { return m_editor; }
+
+ private:
+ void onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter);
+ void onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter);
+
+ ParameterOverlay* getOverlay(const juce::Component* _comp);
+ ParameterOverlay* getOverlay(const pluginLib::ParameterBinding::BoundParameter& _parameter);
+
+ Editor& m_editor;
+ pluginLib::ParameterBinding& m_binding;
+
+ std::map<const juce::Component*, std::unique_ptr<ParameterOverlay>> m_overlays;
+ size_t m_onBindListenerId;
+ size_t m_onUnbindListenerId;
+ };
+}
diff --git a/source/jucePluginEditorLib/pluginEditor.cpp b/source/jucePluginEditorLib/pluginEditor.cpp
@@ -18,6 +18,7 @@ namespace jucePluginEditorLib
, m_processor(_processor)
, m_binding(_binding)
, m_skinFolder(std::move(_skinFolder))
+ , m_overlays(*this, _binding)
{
showDisclaimer();
}
@@ -261,7 +262,7 @@ namespace jucePluginEditorLib
if(!param)
return false;
- const auto& controller = m_processor.getController();
+ auto& controller = m_processor.getController();
const auto& regions = controller.getParameterDescriptions().getRegions();
const auto paramRegionIds = controller.getRegionIdsForParameter(param);
diff --git a/source/jucePluginEditorLib/pluginEditor.h b/source/jucePluginEditorLib/pluginEditor.h
@@ -1,6 +1,8 @@
#pragma once
#include "imagePool.h"
+#include "parameterOverlays.h"
+#include "types.h"
#include "../juceUiLib/editor.h"
@@ -8,8 +10,6 @@
#include "../jucePluginLib/event.h"
-#include "types.h"
-
namespace pluginLib
{
class ParameterBinding;
@@ -105,5 +105,6 @@ namespace jucePluginEditorLib
std::vector<std::shared_ptr<juce::TemporaryFile>> m_dragAndDropTempFiles;
std::vector<juce::File> m_dragAndDropFiles;
ImagePool m_imagePool;
+ ParameterOverlays m_overlays;
};
}
diff --git a/source/jucePluginLib/parameterbinding.cpp b/source/jucePluginLib/parameterbinding.cpp
@@ -264,10 +264,14 @@ namespace pluginLib
m_boundParameters.insert(std::make_pair(_boundParameter.parameter, _boundParameter.component));
m_boundComponents.insert(std::make_pair(_boundParameter.component, _boundParameter.parameter));
+
+ onBind(_boundParameter);
}
void ParameterBinding::disableBinding(const BoundParameter& _b)
{
+ onUnbind(_b);
+
m_boundParameters.erase(_b.parameter);
m_boundComponents.erase(_b.component);
diff --git a/source/jucePluginLib/parameterbinding.h b/source/jucePluginLib/parameterbinding.h
@@ -2,6 +2,8 @@
#include "juce_gui_basics/juce_gui_basics.h"
+#include "event.h"
+
namespace juce
{
class Button;
@@ -44,6 +46,9 @@ namespace pluginLib
uint32_t onChangeListenerId = 0;
};
+ Event<const BoundParameter&> onBind;
+ Event<const BoundParameter&> onUnbind;
+
ParameterBinding(Controller& _controller) : m_controller(_controller)
{
}
diff --git a/source/juceUiLib/editor.h b/source/juceUiLib/editor.h
@@ -97,6 +97,8 @@ namespace genericUI
virtual Button<juce::DrawableButton>* createJuceComponent(Button<juce::DrawableButton>*, UiObject& _object, const std::string& _name, juce::DrawableButton::ButtonStyle) { return nullptr; }
virtual Button<juce::TextButton>* createJuceComponent(Button<juce::TextButton>*, UiObject& _object) { return nullptr; }
+ const UiObject& getRootObject() const { return *(m_rootObject.get()); }
+
private:
EditorInterface& m_interface;