Multi-style state and disabled state propagation.

This commit is contained in:
Dario 2025-01-16 20:31:47 -03:00 committed by Mr-Wiseguy
parent 97998956bb
commit 0a7ad6eadf
5 changed files with 109 additions and 21 deletions

View file

@ -4,9 +4,10 @@
namespace recompui { 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; this->style = style;
set_text(text); set_text(text);
@ -47,8 +48,15 @@ namespace recompui {
break; 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; // transition: color 0.05s linear-in-out, background-color 0.05s linear-in-out;
} }
@ -60,7 +68,10 @@ namespace recompui {
} }
break; break;
case EventType::Hover: 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; break;
default: default:
assert(false && "Unknown event type."); assert(false && "Unknown event type.");

View file

@ -13,6 +13,8 @@ namespace recompui {
protected: protected:
ButtonStyle style = ButtonStyle::Primary; ButtonStyle style = ButtonStyle::Primary;
Style hover_style; Style hover_style;
Style disabled_style;
Style hover_disabled_style;
std::list<std::function<void()>> pressed_callbacks; std::list<std::function<void()>> pressed_callbacks;
// Element overrides. // Element overrides.

View file

@ -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) { void Element::register_event_listeners(uint32_t events_enabled) {
assert(base != nullptr); assert(base != nullptr);
this->events_enabled = events_enabled;
if (events_enabled & Events(EventType::Click)) { if (events_enabled & Events(EventType::Click)) {
base->AddEventListener(Rml::EventId::Mousedown, this); base->AddEventListener(Rml::EventId::Mousedown, this);
} }
@ -91,13 +93,31 @@ void Element::apply_style(Style *style) {
void Element::apply_styles() { void Element::apply_styles() {
apply_style(this); apply_style(this);
for (size_t i = 0; i < styles_active.size(); i++) { for (size_t i = 0; i < styles_counter.size(); i++) {
if (styles_active[i]) { if (styles_counter[i] == 0) {
apply_style(styles[i]); 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) { void Element::ProcessEvent(Rml::Event &event) {
// Events that are processed during any phase. // Events that are processed during any phase.
switch (event.GetId()) { switch (event.GetId()) {
@ -137,25 +157,59 @@ void Element::clear_children() {
children.clear(); children.clear();
} }
void Element::add_style(const std::string &style_name, Style *style) { void Element::add_style(Style *style, const std::list<std::string> &style_names) {
assert(style_name_index_map.find(style_name) == style_name_index_map.end()); 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.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) { void Element::set_enabled(bool enabled) {
auto it = style_name_index_map.find(style_name); this->enabled = enabled;
assert(it != style_name_index_map.end());
styles_active[it->second] = enable; propagate_disabled(disabled_from_parent);
apply_styles();
} }
void Element::set_text(const std::string &text) { void Element::set_text(const std::string &text) {
base->SetInnerRML(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();
}
}; };

View file

@ -2,19 +2,23 @@
#include "ui_style.h" #include "ui_style.h"
#include <unordered_set>
namespace recompui { namespace recompui {
class Element : public Style, public Rml::EventListener { class Element : public Style, public Rml::EventListener {
friend class Element; friend class Element;
private: private:
std::vector<Style *> styles; std::vector<Style *> styles;
std::vector<bool> styles_active; std::vector<uint32_t> styles_counter;
std::map<std::string, uint32_t> style_name_index_map; std::unordered_set<std::string> style_active_set;
std::unordered_multimap<std::string, uint32_t> style_name_index_map;
void add_child(Element *child); void add_child(Element *child);
void register_event_listeners(uint32_t events_enabled); void register_event_listeners(uint32_t events_enabled);
void apply_style(Style *style); void apply_style(Style *style);
void apply_styles(); void apply_styles();
void propagate_disabled(bool disabled);
// Style overrides. // Style overrides.
virtual void set_property(Rml::PropertyId property_id, const Rml::Property &property, Animation animation) override; virtual void set_property(Rml::PropertyId property_id, const Rml::Property &property, Animation animation) override;
@ -24,8 +28,12 @@ private:
protected: protected:
Rml::Element *base = nullptr; Rml::Element *base = nullptr;
std::vector<std::unique_ptr<Element>> children; std::vector<std::unique_ptr<Element>> children;
uint32_t events_enabled = 0;
bool owner = false; bool owner = false;
bool orphaned = false; bool orphaned = false;
bool enabled = true;
bool disabled_attribute = false;
bool disabled_from_parent = false;
virtual void process_event(const Event &e); virtual void process_event(const Event &e);
public: public:
@ -36,9 +44,10 @@ public:
Element(Element *parent, uint32_t events_enabled = 0, Rml::String base_class = "div"); Element(Element *parent, uint32_t events_enabled = 0, Rml::String base_class = "div");
virtual ~Element(); virtual ~Element();
void clear_children(); void clear_children();
void add_style(const std::string &style_name, Style *style); void add_style(Style *style, const std::list<std::string> &style_names);
void enable_style(const std::string &style_name, bool enable); void set_enabled(bool enabled);
void set_text(const std::string &text); void set_text(const std::string &text);
void set_style_enabled(const std::string &style_name, bool enabled);
}; };
} // namespace recompui } // namespace recompui

View file

@ -21,6 +21,7 @@ namespace recompui {
Click, Click,
Focus, Focus,
Hover, Hover,
Enable,
Count Count
}; };
@ -54,6 +55,10 @@ namespace recompui {
struct { struct {
bool active; bool active;
} hover; } hover;
struct {
bool enable;
} enable;
}; };
static Event click_event(float x, float y) { static Event click_event(float x, float y) {
@ -77,6 +82,13 @@ namespace recompui {
e.focus.active = active; e.focus.active = active;
return e; return e;
} }
static Event enable_event(bool enable) {
Event e = {};
e.type = EventType::Enable;
e.enable.enable = enable;
return e;
}
}; };
enum class Display { enum class Display {