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 {
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.");

View File

@ -13,6 +13,8 @@ namespace recompui {
protected:
ButtonStyle style = ButtonStyle::Primary;
Style hover_style;
Style disabled_style;
Style hover_disabled_style;
std::list<std::function<void()>> pressed_callbacks;
// 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) {
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<std::string> &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();
}
};

View File

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

View File

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