From 3fa66680d2b8274c915dfba44a4ab54535229be5 Mon Sep 17 00:00:00 2001 From: Dario Date: Thu, 16 Jan 2025 20:31:47 -0300 Subject: [PATCH] Multi-style state and disabled state propagation. --- src/ui/elements/ui_button.cpp | 21 ++++++--- src/ui/elements/ui_button.h | 2 + src/ui/elements/ui_element.cpp | 78 ++++++++++++++++++++++++++++------ src/ui/elements/ui_element.h | 17 ++++++-- src/ui/elements/ui_types.h | 12 ++++++ 5 files changed, 109 insertions(+), 21 deletions(-) diff --git a/src/ui/elements/ui_button.cpp b/src/ui/elements/ui_button.cpp index 9d6102e..70b0207 100644 --- a/src/ui/elements/ui_button.cpp +++ b/src/ui/elements/ui_button.cpp @@ -4,9 +4,10 @@ namespace recompui { - static const std::string hover_style_name = "hover"; + static const std::string hover_state = "hover"; + static const std::string disabled_state = "disabled"; - Button::Button(const std::string &text, ButtonStyle style, Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover), "button") { + Button::Button(const std::string &text, ButtonStyle style, Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button") { this->style = style; set_text(text); @@ -47,8 +48,15 @@ namespace recompui { break; } - add_style(hover_style_name, &hover_style); - + disabled_style.set_border_color({ 128, 128, 128, border_hover_opacity }); + disabled_style.set_background_color({ 128, 128, 128, background_hover_opacity }); + hover_disabled_style.set_border_color({ 196, 196, 196, border_hover_opacity }); + hover_disabled_style.set_background_color({ 196, 196, 196, background_hover_opacity }); + + add_style(&hover_style, { hover_state }); + add_style(&disabled_style, { disabled_state }); + add_style(&hover_disabled_style, { hover_state, disabled_state }); + // transition: color 0.05s linear-in-out, background-color 0.05s linear-in-out; } @@ -60,7 +68,10 @@ namespace recompui { } break; case EventType::Hover: - enable_style(hover_style_name, e.hover.active); + set_style_enabled(hover_state, e.hover.active); + break; + case EventType::Enable: + set_style_enabled(disabled_state, !e.enable.enable); break; default: assert(false && "Unknown event type."); diff --git a/src/ui/elements/ui_button.h b/src/ui/elements/ui_button.h index 8b02d8d..461d5ab 100644 --- a/src/ui/elements/ui_button.h +++ b/src/ui/elements/ui_button.h @@ -13,6 +13,8 @@ namespace recompui { protected: ButtonStyle style = ButtonStyle::Primary; Style hover_style; + Style disabled_style; + Style hover_disabled_style; std::list> pressed_callbacks; // Element overrides. diff --git a/src/ui/elements/ui_element.cpp b/src/ui/elements/ui_element.cpp index b97cae5..fa4de9d 100644 --- a/src/ui/elements/ui_element.cpp +++ b/src/ui/elements/ui_element.cpp @@ -67,6 +67,8 @@ void Element::set_property(Rml::PropertyId property_id, const Rml::Property &pro void Element::register_event_listeners(uint32_t events_enabled) { assert(base != nullptr); + this->events_enabled = events_enabled; + if (events_enabled & Events(EventType::Click)) { base->AddEventListener(Rml::EventId::Mousedown, this); } @@ -91,13 +93,31 @@ void Element::apply_style(Style *style) { void Element::apply_styles() { apply_style(this); - for (size_t i = 0; i < styles_active.size(); i++) { - if (styles_active[i]) { + for (size_t i = 0; i < styles_counter.size(); i++) { + if (styles_counter[i] == 0) { apply_style(styles[i]); } } } +void Element::propagate_disabled(bool disabled) { + disabled_from_parent = disabled; + + bool attribute_state = disabled_from_parent || !enabled; + if (disabled_attribute != attribute_state) { + disabled_attribute = attribute_state; + base->SetAttribute("disabled", attribute_state); + + if (events_enabled & Events(EventType::Enable)) { + process_event(Event::enable_event(!attribute_state)); + } + + for (auto &child : children) { + child->propagate_disabled(attribute_state); + } + } +} + void Element::ProcessEvent(Rml::Event &event) { // Events that are processed during any phase. switch (event.GetId()) { @@ -137,25 +157,59 @@ void Element::clear_children() { children.clear(); } -void Element::add_style(const std::string &style_name, Style *style) { - assert(style_name_index_map.find(style_name) == style_name_index_map.end()); +void Element::add_style(Style *style, const std::list &style_names) { + for (const std::string &style_name : style_names) { + style_name_index_map.emplace(style_name, styles.size()); + } - style_name_index_map[style_name] = styles.size(); styles.emplace_back(style); - styles_active.push_back(false); + + uint32_t initial_style_counter = style_names.size(); + for (const std::string &style_name : style_names) { + if (style_active_set.find(style_name) != style_active_set.end()) { + initial_style_counter--; + } + } + + styles_counter.push_back(initial_style_counter); } -void Element::enable_style(const std::string &style_name, bool enable) { - auto it = style_name_index_map.find(style_name); - assert(it != style_name_index_map.end()); +void Element::set_enabled(bool enabled) { + this->enabled = enabled; - styles_active[it->second] = enable; - - apply_styles(); + propagate_disabled(disabled_from_parent); } void Element::set_text(const std::string &text) { base->SetInnerRML(text); } +void Element::set_style_enabled(const std::string &style_name, bool enable) { + if (enable && style_active_set.find(style_name) == style_active_set.end()) { + // Style was disabled and will be enabled. + style_active_set.emplace(style_name); + + } + else if (!enable && style_active_set.find(style_name) != style_active_set.end()) { + // Style was enabled and will be disabled. + style_active_set.erase(style_name); + } + else { + // Do nothing. + return; + } + + auto range = style_name_index_map.equal_range(style_name); + for (auto it = range.first; it != range.second; it++) { + if (enable) { + styles_counter[it->second]--; + } + else { + styles_counter[it->second]++; + } + } + + apply_styles(); +} + }; \ No newline at end of file diff --git a/src/ui/elements/ui_element.h b/src/ui/elements/ui_element.h index d71b979..1c3143d 100644 --- a/src/ui/elements/ui_element.h +++ b/src/ui/elements/ui_element.h @@ -2,19 +2,23 @@ #include "ui_style.h" +#include + namespace recompui { class Element : public Style, public Rml::EventListener { friend class Element; private: std::vector