diff --git a/extra/testTheme.txt b/extra/testTheme.txt index 2ea4098..d681e43 100644 --- a/extra/testTheme.txt +++ b/extra/testTheme.txt @@ -30,8 +30,23 @@ window.backgroundColor = Color(rgba(40, 0, 0, 255)) borderColor = Color(rgb(0, 255, 0)) } +(label:pressed) { + textColor = Color(#FF0000FF) +} + (@testLabel label:hover) { borderColor = $color2 } +(@testLabel label:pressed) { + backgroundColor = Color(#0040AAFF) + textColor = Color(#505050FF) +} + +(label:disabled) { + backgroundColor = Color(#EEEEEEFF) + textColor = Color(#505050FF) + borderColor = Color(#000000FF) +} + % =================================================== diff --git a/src/ogfx/gui/Widgets.cpp b/src/ogfx/gui/Widgets.cpp index 0edd3e0..26c470d 100644 --- a/src/ogfx/gui/Widgets.cpp +++ b/src/ogfx/gui/Widgets.cpp @@ -333,6 +333,29 @@ namespace ogfx } } + void Widget::setThemeQualifier(const ostd::String& qualifier, bool value) + { + for (auto& [name, state] : m_qualifierList) + { + if (name == qualifier) + { + state = value; + reloadTheme(); + return; + } + } + } + + bool Widget::getThemeQualifier(const ostd::String& qualifier) + { + for (auto& [name, state] : m_qualifierList) + { + if (name == qualifier) + return state; + } + return false; + } + void Widget::__draw(ogfx::BasicRenderer2D& gfx) { if (isDrawBoxEnabled()) @@ -351,6 +374,7 @@ namespace ogfx void Widget::__onMousePressed(const Event& event) { + setThemeQualifier("pressed"); if (hasChildren()) m_widgets.onMousePressed(event); if (!event.isHandled()) @@ -364,6 +388,7 @@ namespace ogfx void Widget::__onMouseReleased(const Event& event) { + setThemeQualifier("pressed", false); m_pressedButton = ogfx::MouseEventData::eButton::None; if (hasChildren()) m_widgets.onMouseReleased(event); @@ -389,8 +414,7 @@ namespace ogfx void Widget::__onMouseEntered(const Event& event) { - m_qualifier = "hover"; - reloadTheme(); + setThemeQualifier("hover"); if (callback_onMouseEntered) callback_onMouseEntered(event); onMouseEntered(event); @@ -398,8 +422,7 @@ namespace ogfx void Widget::__onMouseExited(const Event& event) { - m_qualifier = ""; - reloadTheme(); + setThemeQualifier("hover", false); if (callback_onMouseExited) callback_onMouseExited(event); onMouseExited(event); @@ -528,7 +551,7 @@ namespace ogfx void RootWidget::applyTheme(const ostd::Stylesheet& theme) { - m_color = theme.get("window.backgroundColor", getWindow().getClearColor(), getThemeID(), getThemeQualifier()); + m_color = theme.get("window.backgroundColor", getWindow().getClearColor(), getThemeID(), getThemeQualifierList()); } void RootWidget::onDraw(ogfx::BasicRenderer2D& gfx) @@ -552,15 +575,15 @@ namespace ogfx void Label::applyTheme(const ostd::Stylesheet& theme) { - setColor(theme.get("label.textColor", ostd::Colors::White, getThemeID(), getThemeQualifier())); - setBackGroundColor(theme.get("label.backgroundColor", ostd::Colors::Transparent, getThemeID(), getThemeQualifier())); - setFontSize(theme.get("label.fontSize", 20, getThemeID(), getThemeQualifier())); - m_borderRadius = theme.get("label.borderRadius", 10, getThemeID(), getThemeQualifier()); - m_borderWidth = theme.get("label.borderWidth", 2, getThemeID(), getThemeQualifier()); - m_showBorder = theme.get("label.showBorder", false, getThemeID(), getThemeQualifier()); - m_borderColor = theme.get("label.borderColor", ostd::Colors::White, getThemeID(), getThemeQualifier()); - enableBackground(theme.get("label.showBackground", false, getThemeID(), getThemeQualifier())); - setPadding(theme.get("label.padding", { 5, 5, 5, 5 }, getThemeID(), getThemeQualifier())); + setColor(theme.get("label.textColor", ostd::Colors::White, getThemeID(), getThemeQualifierList())); + setBackGroundColor(theme.get("label.backgroundColor", ostd::Colors::Transparent, getThemeID(), getThemeQualifierList())); + setFontSize(theme.get("label.fontSize", 20, getThemeID(), getThemeQualifierList())); + m_borderRadius = theme.get("label.borderRadius", 10, getThemeID(), getThemeQualifierList()); + m_borderWidth = theme.get("label.borderWidth", 2, getThemeID(), getThemeQualifierList()); + m_showBorder = theme.get("label.showBorder", false, getThemeID(), getThemeQualifierList()); + m_borderColor = theme.get("label.borderColor", ostd::Colors::White, getThemeID(), getThemeQualifierList()); + enableBackground(theme.get("label.showBackground", false, getThemeID(), getThemeQualifierList())); + setPadding(theme.get("label.padding", { 5, 5, 5, 5 }, getThemeID(), getThemeQualifierList())); } void Label::onDraw(ogfx::BasicRenderer2D& gfx) diff --git a/src/ogfx/gui/Widgets.hpp b/src/ogfx/gui/Widgets.hpp index d997449..d73bb2f 100644 --- a/src/ogfx/gui/Widgets.hpp +++ b/src/ogfx/gui/Widgets.hpp @@ -88,6 +88,9 @@ namespace ogfx virtual void applyTheme(const ostd::Stylesheet& theme) = 0; void addThemeOverride(const ostd::String& key, ostd::Stylesheet::TypeVariant value, const ostd::String& themeID = "", const ostd::String& qualifier = "", bool propagate = true); void reloadTheme(void); + void setThemeQualifier(const ostd::String& qualifier, bool value = true); + bool getThemeQualifier(const ostd::String& qualifier); + inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; } inline virtual void onDraw(ogfx::BasicRenderer2D& gfx) { } inline virtual void onUpdate(void) { } @@ -154,7 +157,6 @@ namespace ogfx inline ogfx::MouseEventData::eButton getPressedMouseButton(void) const { return m_pressedButton; } inline ostd::String getThemeID(void) const { return m_themeID; } inline void setThemeID(const ostd::String& id) { m_themeID = id; } - inline ostd::String getThemeQualifier(void) const { return m_qualifier; } protected: inline void disableChildren(void) { m_allowChildren = false; } @@ -193,7 +195,13 @@ namespace ogfx MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None }; ostd::String m_themeID { "" }; - ostd::String m_qualifier { "" }; + ostd::Stylesheet::QualifierList m_qualifierList { + { "disabled", false }, + { "pressed", false }, + { "hover", false }, + { "focused", false }, + { "active", false } + }; std::vector m_themeOverrides; bool m_drawBox { true }; diff --git a/src/ostd/io/Stylesheet.cpp b/src/ostd/io/Stylesheet.cpp index 2f6b273..b1e53d2 100644 --- a/src/ostd/io/Stylesheet.cpp +++ b/src/ostd/io/Stylesheet.cpp @@ -34,16 +34,17 @@ namespace ostd return *this; } - Stylesheet& Stylesheet::loadFromFile(const ostd::String& filePath) + Stylesheet& Stylesheet::loadFromFile(const ostd::String& filePath, bool clearCurrentRules) { ostd::String outContent = ""; ostd::FileSystem::readTextFileRaw(filePath, outContent); - return loadFromString(outContent, filePath); + return loadFromString(outContent, filePath, clearCurrentRules); } - Stylesheet& Stylesheet::loadFromString(const ostd::String& content, const ostd::String& filePath) + Stylesheet& Stylesheet::loadFromString(const ostd::String& content, const ostd::String& filePath, bool clearCurrentRules) { - + if (clearCurrentRules) + m_values.clear(); std::vector lines = content.tokenize("\n", false, true).getRawData(); uint32_t lineNumber = 0; ostd::String lineCopy = ""; @@ -121,7 +122,6 @@ namespace ostd } ostd::String rawSelector = line.new_substr(1, line.indexOf(")")).trim(); groupSelector = parseGroupSelector(rawSelector); - std::cout << groupSelector << "\n"; if (line.contains("{")) { line.substr(line.indexOf("{")).trim(); @@ -151,31 +151,43 @@ namespace ostd m_values[fullKey] = std::move(value); } - const Stylesheet::TypeVariant* Stylesheet::getVariant(const ostd::String& key, const ostd::String& themeID, const ostd::String& qualifier) const + const Stylesheet::TypeVariant* Stylesheet::getVariant(const ostd::String& key, const ostd::String& themeID, const QualifierList& qualifierList) const { - if (auto v = getFull("@" + themeID + ":" + qualifier + "." + key)) + for (const auto&[qualifier, state] : qualifierList) { - return v; + const TypeVariant* v = (state ? getFull("@" + themeID + ":" + qualifier + "." + key) : nullptr); + // std::cout << "0: " << "@" + themeID + ":" + qualifier + "." + key << "\n"; + if (v) + { + std::cout << "1: " << "@" + themeID + ":" + qualifier + "." + key << "\n"; + return v; + } + v = (state ? getFull("@:" + qualifier + "." + key) : nullptr); + if (v) + { + std::cout << "2: " << "@:" + qualifier + "." + key << "\n"; + return v; + } } - else if (auto v = getFull("@:" + qualifier + "." + key)) - { - return v; - } - else if (auto v = getFull("@" + themeID + "." + key)) + if (auto v = getFull("@" + themeID + "." + key)) { + std::cout << "3: " << "@" + themeID + "." + key << "\n"; return v; } else if (auto v = getFull("@." + key)) { + std::cout << "4: " << "@." + key << "\n"; return v; } + std::cout << "\n\n"; return nullptr; } const Stylesheet::TypeVariant* Stylesheet::getFull(const ostd::String& fullKey) const { - // std::cout << " GET: " << key << "\n"; auto it = m_values.find(fullKey); + // if (it != m_values.end()) + // std::cout << " GET: " << fullKey << "\n"; return it != m_values.end() ? &it->second : nullptr; } @@ -286,4 +298,12 @@ namespace ostd newLines.push_back(selector.new_add(".").new_add(property)); return newLines; } + + void Stylesheet::debugPrint(void) + { + for (const auto&[key, value] : m_values) + { + std::cout << key << "\n"; + } + } } diff --git a/src/ostd/io/Stylesheet.hpp b/src/ostd/io/Stylesheet.hpp index 2e083d1..d6791c7 100644 --- a/src/ostd/io/Stylesheet.hpp +++ b/src/ostd/io/Stylesheet.hpp @@ -29,21 +29,22 @@ namespace ostd { class Stylesheet { + public: using QualifierList = std::vector>; public: using TypeVariant = std::variant; public: Stylesheet(void); Stylesheet& clear(void); - Stylesheet& loadFromFile(const ostd::String& filePath); - Stylesheet& loadFromString(const ostd::String& content, const ostd::String& filePath = "memory://"); + Stylesheet& loadFromFile(const ostd::String& filePath, bool clearCurrentRules = true); + Stylesheet& loadFromString(const ostd::String& content, const ostd::String& filePath = "memory://", bool clearCurrentRules = true); void set(const std::string& key, TypeVariant value, const ostd::String& themeID); void setFull(const ostd::String& fullKey, TypeVariant value); - const TypeVariant* getVariant(const ostd::String& key, const ostd::String& themeID, const ostd::String& qualifier) const; + const TypeVariant* getVariant(const ostd::String& key, const ostd::String& themeID, const QualifierList& qualifierList) const; const TypeVariant* getFull(const ostd::String& fullKey) const; template - inline T get(const ostd::String& key, const T& fallback, const ostd::String& themeID, const ostd::String& qualifier) const + inline T get(const ostd::String& key, const T& fallback, const ostd::String& themeID, const QualifierList& qualifierList) const { - if (auto v = getVariant(key, themeID, qualifier)) + if (auto v = getVariant(key, themeID, qualifierList)) { if (auto p = std::get_if(v)) return *p; @@ -51,6 +52,8 @@ namespace ostd return fallback; } + void debugPrint(void); + private: bool parseThemeFileLine(const ostd::String& line); ostd::String parseGroupSelector(const ostd::String& rawSelector) const; diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index 7849d9b..3aa8871 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -63,6 +63,7 @@ class Window : public ogfx::gui::Window // m_label1.applyThemeValue(m_theme, "label.backgroundColor", ostd::Colors::DarkGreen, false); // }); addWidget(m_label1); + m_label1.setThemeQualifier("disabled"); m_label2.setPosition(100, 400); m_label2.setText("Ciccia Bella!");