gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit a3aadfd8d400357ef3bd4b96442343f4bd93b041
parent db21a3e1608ecd7d886acbbd3e3a000196e65c01
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Mon, 16 Dec 2024 22:15:04 +0100

add support for styles to prevent that too much json code has to be duplicated each time

Diffstat:
Msource/juceUiLib/editor.cpp | 2+-
Msource/juceUiLib/uiObject.cpp | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msource/juceUiLib/uiObject.h | 9++++++++-
3 files changed, 96 insertions(+), 8 deletions(-)

diff --git a/source/juceUiLib/editor.cpp b/source/juceUiLib/editor.cpp @@ -23,7 +23,7 @@ namespace genericUI m_jsonFilename = _jsonFilename; - m_rootObject.reset(new UiObject(json)); + m_rootObject.reset(new UiObject(nullptr, json)); std::set<std::string> textures; m_rootObject->collectVariants(textures, "texture"); diff --git a/source/juceUiLib/uiObject.cpp b/source/juceUiLib/uiObject.cpp @@ -22,7 +22,7 @@ namespace genericUI { - UiObject::UiObject(const juce::var& _json, const bool _isTemplate/* = false*/) : m_isTemplate(_isTemplate) + UiObject::UiObject(UiObject* _parent, const juce::var& _json, const bool _isTemplate/* = false*/) : m_isTemplate(_isTemplate), m_parent(_parent) { auto* obj = _json.getDynamicObject(); @@ -407,17 +407,78 @@ namespace genericUI } } + juce::DynamicObject& UiObject::applyStyle(juce::DynamicObject& _obj, const std::string& _styleName) + { + if (m_parent) + m_parent->applyStyle(_obj, _styleName); + + const auto it = m_styles.find(_styleName); + if (it == m_styles.end()) + return _obj; + + const auto& s = it->second; + const auto sourceObj = s.getDynamicObject(); + + if (sourceObj) + copyPropertiesRecursive(_obj, *sourceObj); + + return _obj; + } + + bool UiObject::copyPropertiesRecursive(juce::DynamicObject& _target, const juce::DynamicObject& _source) + { + bool result = false; + + for (const auto& sourceProp : _source.getProperties()) + { + const auto& key = sourceProp.name; + const auto& val = sourceProp.value; + + if (!_target.hasProperty(key)) + { + _target.setProperty(key, val); + result = true; + } + else + { + auto& targetProperty = _target.getProperty(key); + + if (targetProperty.isObject()) + { + auto targetObj = targetProperty.getDynamicObject(); + if (targetObj) + { + auto sourceObj = val.getDynamicObject(); + if (sourceObj) + copyPropertiesRecursive(*targetObj, *sourceObj); + } + } + } + } + return true; + } + bool UiObject::parse(juce::DynamicObject* _obj) { if (!_obj) return false; - const auto& props = _obj->getProperties(); + auto props = _obj->getProperties(); + + auto styleName = props["style"].toString().toStdString(); + + std::unique_ptr<juce::DynamicObject> newObj; + + if (!styleName.empty()) + { + newObj = _obj->clone(); + props = applyStyle(*newObj, styleName).getProperties(); + } for (int i = 0; i < props.size(); ++i) { const auto key = std::string(props.getName(i).toString().toUTF8()); - const auto value = props.getValueAt(i); + const auto& value = props.getValueAt(i); if (key == "name") { @@ -429,10 +490,10 @@ namespace genericUI if (children) { - for(int c=0; c<children->size(); ++c) + for (auto&& c : *children) { std::unique_ptr<UiObject> child; - child.reset(new UiObject((*children)[c])); + child.reset(new UiObject(this, c)); m_children.emplace_back(std::move(child)); } } @@ -442,7 +503,27 @@ namespace genericUI if (const auto children = value.getArray()) { for (const auto& c : *children) - m_templates.emplace_back(std::make_shared<UiObject>(c, true)); + m_templates.emplace_back(std::make_shared<UiObject>(this, c, true)); + } + } + else if (key == "styles") + { + auto obj = value.getDynamicObject(); + if (!obj) + throw std::runtime_error("styles must be an object"); + + auto p = obj->getProperties(); + + for (const auto& s : p) + { + const auto name = s.name.toString().toStdString(); + + if (name.empty()) + throw std::runtime_error("style needs to have a name"); + if (m_styles.find(name) != m_styles.end()) + throw std::runtime_error("style with name " + name + " already exists"); + + m_styles.insert({name, s.value}); } } else if(key == "tabgroup") diff --git a/source/juceUiLib/uiObject.h b/source/juceUiLib/uiObject.h @@ -33,7 +33,7 @@ namespace genericUI class UiObject { public: - explicit UiObject(const juce::var& _json, bool _isTemplate = false); + explicit UiObject(UiObject* _parent, const juce::var& _json, bool _isTemplate = false); ~UiObject(); void createJuceTree(Editor& _editor); @@ -81,6 +81,10 @@ namespace genericUI template<typename T> T* createJuceObject(Editor& _editor, T* _object); void createCondition(const Editor& _editor, juce::Component& _target); + juce::DynamicObject& applyStyle(juce::DynamicObject& _obj, const std::string& _styleName); + + static bool copyPropertiesRecursive(juce::DynamicObject& _target, const juce::DynamicObject& _source); + bool parse(juce::DynamicObject* _obj); template<typename T> void bindParameter(const Editor& _editor, T& _target) const; @@ -94,12 +98,15 @@ namespace genericUI std::string m_name; std::map<std::string, std::map<std::string, std::string>> m_components; std::vector<std::unique_ptr<UiObject>> m_children; + UiObject* m_parent = nullptr; std::vector<std::shared_ptr<UiObject>> m_templates; std::vector<std::unique_ptr<juce::Component>> m_juceObjects; std::unique_ptr<UiObjectStyle> m_style; + std::map<std::string, juce::var> m_styles; + std::unique_ptr<Condition> m_condition; TabGroup m_tabGroup;