commit b6d130b97f9c2f349a56f174197cdb03d67bd5f6
parent 8bd1093698cf4fcd4f2198e1357ff64d38f1f091
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 26 May 2022 13:12:21 +0200
add support for generic condition system to show/hide components based on parameter values
Diffstat:
12 files changed, 172 insertions(+), 77 deletions(-)
diff --git a/source/jucePlugin/ui3/FxPage.cpp b/source/jucePlugin/ui3/FxPage.cpp
@@ -7,48 +7,21 @@
namespace genericVirusUI
{
- FxPage::FxPage(VirusEditor& _editor) : m_editor(_editor)
+ FxPage::FxPage(const VirusEditor& _editor)
{
- m_reverbContainer = _editor.findComponent("ContainerReverb");
- m_delayContainer = _editor.findComponent("ContainerDelay");
+ const auto delayReverbMode = _editor.getController().getParameterIndexByName(Virus::g_paramDelayReverbMode);
+ const auto p = _editor.getController().getParamValueObject(delayReverbMode);
- const auto delayReverbMode = m_editor.getController().getParameterIndexByName(Virus::g_paramDelayReverbMode);
- const auto p = m_editor.getController().getParameter(delayReverbMode, 0);
+ const auto containerReverb = _editor.findComponent("ContainerReverb");
+ const auto containerDelay = _editor.findComponent("ContainerDelay");
- if (p)
- {
- p->getValueObject().addListener(this);
- }
-
- updateReverbDelay();
+ m_conditionReverb.reset(new genericUI::Condition(*containerReverb, *p, {2,3,4}));
+ m_conditionDelay.reset(new genericUI::Condition(*containerDelay, *p, {0,1,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}));
}
FxPage::~FxPage()
{
- const auto delayReverbMode = m_editor.getController().getParameterIndexByName(Virus::g_paramDelayReverbMode);
- const auto p = m_editor.getController().getParameter(delayReverbMode, 0);
- if(p)
- p->getValueObject().removeListener(this);
- }
-
- void FxPage::valueChanged(juce::Value& value)
- {
- updateReverbDelay();
- }
-
- void FxPage::updateReverbDelay() const
- {
- const auto delayReverbMode = m_editor.getController().getParameterIndexByName(Virus::g_paramDelayReverbMode);
- const auto p = m_editor.getController().getParameter(delayReverbMode, 0);
-
- if (!p)
- return;
-
- const auto value = static_cast<int>(p->getValueObject().getValueSource().getValue());
-
- const bool isReverb = (value > 1 && value < 5);
-
- VirusEditor::setEnabled(*m_delayContainer, !isReverb);
- VirusEditor::setEnabled(*m_reverbContainer, isReverb);
+ m_conditionReverb.reset();
+ m_conditionDelay.reset();
}
}
diff --git a/source/jucePlugin/ui3/FxPage.h b/source/jucePlugin/ui3/FxPage.h
@@ -1,28 +1,18 @@
#pragma once
-#include <juce_audio_processors/juce_audio_processors.h>
-
-namespace juce
-{
- class Component;
-}
+#include "../juceUiLib/condition.h"
namespace genericVirusUI
{
class VirusEditor;
- class FxPage : public juce::Value::Listener
+ class FxPage
{
public:
- explicit FxPage(VirusEditor& _editor);
- ~FxPage() override;
-
- void valueChanged(juce::Value& value) override;
+ explicit FxPage(const VirusEditor& _editor);
+ ~FxPage();
private:
- void updateReverbDelay() const;
-
- VirusEditor& m_editor;
- juce::Component* m_reverbContainer = nullptr;
- juce::Component* m_delayContainer = nullptr;
+ std::unique_ptr<genericUI::Condition> m_conditionReverb;
+ std::unique_ptr<genericUI::Condition> m_conditionDelay;
};
}
diff --git a/source/jucePlugin/ui3/VirusEditor.cpp b/source/jucePlugin/ui3/VirusEditor.cpp
@@ -12,11 +12,11 @@
namespace genericVirusUI
{
- VirusEditor::VirusEditor(VirusParameterBinding& _binding, AudioPluginAudioProcessor &_processorRef, const std::string& _jsonFilename, const std::string& _skinFolder, std::function<void()> _openMenuCallback) :
+ VirusEditor::VirusEditor(VirusParameterBinding& _binding, AudioPluginAudioProcessor &_processorRef, const std::string& _jsonFilename, std::string _skinFolder, std::function<void()> _openMenuCallback) :
Editor(static_cast<EditorInterface&>(*this)),
m_processor(_processorRef),
m_parameterBinding(_binding),
- m_skinFolder(_skinFolder),
+ m_skinFolder(std::move(_skinFolder)),
m_openMenuCallback(std::move(_openMenuCallback))
{
create(_jsonFilename);
@@ -28,7 +28,11 @@ namespace genericVirusUI
m_tabs.reset(new Tabs(*this));
m_midiPorts.reset(new MidiPorts(*this));
- m_fxPage.reset(new FxPage(*this));
+
+ // be backwards compatible with old skins
+ if(!getConditionCountRecursive())
+ m_fxPage.reset(new FxPage(*this));
+
m_patchBrowser.reset(new PatchBrowser(*this));
m_presetName = findComponentT<juce::Label>("PatchName");
@@ -128,21 +132,6 @@ namespace genericVirusUI
return m_processor.getController();
}
- void VirusEditor::setEnabled(juce::Component& _component, bool _enable)
- {
- if(_component.getProperties().contains("disabledAlpha"))
- {
- const float a = _component.getProperties()["disabledAlpha"];
-
- _component.setAlpha(_enable ? 1.0f : a);
- _component.setEnabled(_enable);
- }
- else
- {
- _component.setVisible(_enable);
- }
- }
-
const char* VirusEditor::findNamedResourceByFilename(const std::string& _filename, uint32_t& _size)
{
for(size_t i=0; i<BinaryData::namedResourceListSize; ++i)
@@ -236,6 +225,11 @@ namespace genericVirusUI
return true;
}
+ juce::Value* VirusEditor::getParameterValue(int _parameterIndex)
+ {
+ return getController().getParamValueObject(_parameterIndex);
+ }
+
void VirusEditor::onProgramChange()
{
m_parts->onProgramChange();
diff --git a/source/jucePlugin/ui3/VirusEditor.h b/source/jucePlugin/ui3/VirusEditor.h
@@ -16,7 +16,8 @@ namespace genericVirusUI
class VirusEditor : public genericUI::EditorInterface, public genericUI::Editor
{
public:
- VirusEditor(VirusParameterBinding& _binding, AudioPluginAudioProcessor &_processorRef, const std::string& _jsonFilename, const std::string& _skinFolder, std::function<void()> _openMenuCallback);
+ VirusEditor(VirusParameterBinding& _binding, AudioPluginAudioProcessor &_processorRef, const std::string& _jsonFilename,
+ std::string _skinFolder, std::function<void()> _openMenuCallback);
~VirusEditor() override;
void setPart(size_t _part);
@@ -26,8 +27,6 @@ namespace genericVirusUI
Virus::Controller& getController() const;
- static void setEnabled(juce::Component& _component, bool _enable);
-
static const char* findNamedResourceByFilename(const std::string& _filename, uint32_t& _size);
private:
@@ -36,6 +35,7 @@ namespace genericVirusUI
bool bindParameter(juce::Button& _target, int _parameterIndex) override;
bool bindParameter(juce::ComboBox& _target, int _parameterIndex) override;
bool bindParameter(juce::Slider& _target, int _parameterIndex) override;
+ juce::Value* getParameterValue(int _parameterIndex) override;
void onProgramChange();
void onPlayModeChanged();
diff --git a/source/juceUiLib/CMakeLists.txt b/source/juceUiLib/CMakeLists.txt
@@ -4,6 +4,7 @@ project(juceUiLib VERSION ${CMAKE_PROJECT_VERSION})
set(SOURCES
editor.cpp editor.h
editorInterface.h
+ condition.cpp condition.h
image.cpp image.h
rotaryStyle.cpp rotaryStyle.h
comboboxStyle.cpp comboboxStyle.h
diff --git a/source/juceUiLib/condition.cpp b/source/juceUiLib/condition.cpp
@@ -0,0 +1,26 @@
+#include "condition.h"
+
+#include "editor.h"
+
+namespace genericUI
+{
+ Condition::Condition(juce::Component& _target, juce::Value& _value, std::set<uint8_t> _values) : m_target(_target), m_value(_value), m_values(std::move(_values))
+ {
+ m_value.addListener(this);
+ valueChanged(m_value);
+ }
+
+ Condition::~Condition()
+ {
+ m_value.removeListener(this);
+ }
+
+ void Condition::valueChanged(juce::Value& _value)
+ {
+ const auto v = roundToInt(_value.getValueSource().getValue());
+
+ const auto enable = m_values.find(static_cast<uint8_t>(v)) != m_values.end();
+
+ Editor::setEnabled(m_target, enable);
+ }
+}
diff --git a/source/juceUiLib/condition.h b/source/juceUiLib/condition.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <juce_audio_processors/juce_audio_processors.h>
+
+#include <set>
+
+#include "condition.h"
+
+namespace juce
+{
+ class Value;
+ class Component;
+}
+
+namespace genericUI
+{
+ class Condition : juce::Value::Listener
+ {
+ public:
+ Condition(juce::Component& _target, juce::Value& _value, std::set<uint8_t> _values);
+ ~Condition() override;
+ void valueChanged(juce::Value& _value) override;
+ private:
+ juce::Component& m_target;
+ juce::Value& m_value;
+ std::set<uint8_t> m_values;
+ };
+}
diff --git a/source/juceUiLib/editor.cpp b/source/juceUiLib/editor.cpp
@@ -201,4 +201,24 @@ namespace genericUI
throw std::runtime_error("Failed to find component named " + _name);
return comps.empty() ? nullptr : comps.front();
}
+
+ size_t Editor::getConditionCountRecursive() const
+ {
+ return m_rootObject ? m_rootObject->getConditionCountRecursive() : 0;
+ }
+
+ void Editor::setEnabled(juce::Component& _component, const bool _enable)
+ {
+ if(_component.getProperties().contains("disabledAlpha"))
+ {
+ const float a = _component.getProperties()["disabledAlpha"];
+
+ _component.setAlpha(_enable ? 1.0f : a);
+ _component.setEnabled(_enable);
+ }
+ else
+ {
+ _component.setVisible(_enable);
+ }
+ }
}
diff --git a/source/juceUiLib/editor.h b/source/juceUiLib/editor.h
@@ -72,6 +72,10 @@ namespace genericUI
return m_tabGroupsByName.size();
}
+ size_t getConditionCountRecursive() const;
+
+ static void setEnabled(juce::Component& _component, bool _enable);
+
private:
EditorInterface& m_interface;
diff --git a/source/juceUiLib/editorInterface.h b/source/juceUiLib/editorInterface.h
@@ -10,6 +10,7 @@ namespace genericUI
virtual const char* getResourceByFilename(const std::string& _name, uint32_t& _dataSize) = 0;
virtual int getParameterIndexByName(const std::string& _name) = 0;
+ virtual juce::Value* getParameterValue(int _parameterIndex) = 0;
virtual bool bindParameter(juce::Slider& _target, int _parameterIndex) = 0;
virtual bool bindParameter(juce::Button& _target, int _parameterIndex) = 0;
diff --git a/source/juceUiLib/uiObject.cpp b/source/juceUiLib/uiObject.cpp
@@ -28,7 +28,7 @@ namespace genericUI
m_style.reset();
}
- void UiObject::createJuceTree(Editor& _editor) const
+ void UiObject::createJuceTree(Editor& _editor)
{
apply(_editor, _editor);
@@ -64,7 +64,7 @@ namespace genericUI
}
}
- void UiObject::apply(Editor& _editor, juce::Component& _target) const
+ void UiObject::apply(Editor& _editor, juce::Component& _target)
{
const auto x = getPropertyInt("x");
const auto y = getPropertyInt("y");
@@ -80,6 +80,8 @@ namespace genericUI
_target.setTopLeftPosition(x, y);
_target.setSize(w, h);
+
+ createCondition(_editor, _target);
}
void UiObject::apply(Editor& _editor, juce::Slider& _target)
@@ -240,6 +242,56 @@ namespace genericUI
return _default;
}
+ size_t UiObject::getConditionCountRecursive() const
+ {
+ size_t count = m_condition ? 1 : 0;
+
+ for (const auto & c : m_children)
+ count += c->getConditionCountRecursive();
+
+ return count;
+ }
+
+ void UiObject::createCondition(Editor& _editor, juce::Component& _target)
+ {
+ if(!hasComponent("condition"))
+ return;
+
+ const auto paramName = getProperty("enableOnParameter");
+
+ const auto index = _editor.getInterface().getParameterIndexByName(paramName);
+
+ if(index < 0)
+ throw std::runtime_error("Parameter named " + paramName + " not found");
+
+ const auto v = _editor.getInterface().getParameterValue(index);
+
+ if(!v)
+ throw std::runtime_error("Parameter named " + paramName + " not found");
+
+ const auto conditionValues = getProperty("enableOnValues");
+
+ size_t start = 0;
+
+ std::set<uint8_t> values;
+
+ for(size_t i=0; i<=conditionValues.size(); ++i)
+ {
+ const auto isEnd = i == conditionValues.size() || conditionValues[i] == ',' || conditionValues[i] == ';';
+
+ if(!isEnd)
+ continue;
+
+ const auto valueString = conditionValues.substr(start, i - start);
+ const int val = strtol(valueString.c_str(), nullptr, 10);
+ values.insert(static_cast<uint8_t>(val));
+
+ start = i + 1;
+ }
+
+ m_condition.reset(new Condition(_target, *v, values));
+ }
+
bool UiObject::parse(juce::DynamicObject* _obj)
{
if (!_obj)
diff --git a/source/juceUiLib/uiObject.h b/source/juceUiLib/uiObject.h
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
+#include "condition.h"
#include "tabgroup.h"
namespace juce
@@ -34,11 +35,11 @@ namespace genericUI
explicit UiObject(const juce::var& _json);
~UiObject();
- void createJuceTree(Editor& _editor) const;
+ void createJuceTree(Editor& _editor);
void createChildObjects(Editor& _editor, juce::Component& _parent) const;
void createTabGroups(Editor& _editor);
- void apply(Editor& _editor, juce::Component& _target) const;
+ void apply(Editor& _editor, juce::Component& _target);
void apply(Editor& _editor, juce::Slider& _target);
void apply(Editor& _editor, juce::ComboBox& _target);
void apply(Editor& _editor, juce::DrawableButton& _target);
@@ -54,10 +55,13 @@ namespace genericUI
float getPropertyFloat(const std::string& _key, float _default = 0.0f) const;
std::string getProperty(const std::string& _key, const std::string& _default = std::string()) const;
+ size_t getConditionCountRecursive() const;
+
private:
bool hasComponent(const std::string& _component) const;
template<typename T> T* createJuceObject(Editor& _editor);
template<typename T> T* createJuceObject(Editor& _editor, T* _object);
+ void createCondition(Editor& _editor, juce::Component& _target);
bool parse(juce::DynamicObject* _obj);
@@ -75,6 +79,8 @@ namespace genericUI
std::vector<std::unique_ptr<juce::Component>> m_juceObjects;
std::unique_ptr<UiObjectStyle> m_style;
+ std::unique_ptr<Condition> m_condition;
+
TabGroup m_tabGroup;
};