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:
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;