diff --git a/src/ui/elements/ui_radio.cpp b/src/ui/elements/ui_radio.cpp index f4ed112..6cd1423 100644 --- a/src/ui/elements/ui_radio.cpp +++ b/src/ui/elements/ui_radio.cpp @@ -37,6 +37,10 @@ namespace recompui { pressed_callback = callback; } + void RadioOption::set_focus_callback(std::function callback) { + focus_callback = callback; + } + void RadioOption::set_selected_state(bool enable) { set_style_enabled(checked_state, enable); } @@ -67,6 +71,9 @@ namespace recompui { if (active) { queue_update(); } + if (focus_callback != nullptr) { + focus_callback(active); + } } break; case EventType::Update: @@ -124,6 +131,9 @@ namespace recompui { blur(); queue_child_focus(); } + if (focus_callback != nullptr) { + focus_callback(std::get(e.variant).active); + } } break; case EventType::Update: @@ -141,6 +151,11 @@ namespace recompui { void Radio::add_option(std::string_view name) { RadioOption *option = get_current_context().create_element(this, name, uint32_t(options.size())); option->set_pressed_callback([this](uint32_t index){ options[index]->focus(); option_selected(index); }); + option->set_focus_callback([this](bool active) { + if (focus_callback != nullptr) { + focus_callback(active); + } + }); options.emplace_back(option); // The first option was added, select it. @@ -165,6 +180,10 @@ namespace recompui { void Radio::add_index_changed_callback(std::function callback) { index_changed_callbacks.emplace_back(callback); } + + void Radio::set_focus_callback(std::function callback) { + focus_callback = callback; + } void Radio::set_nav_auto(NavDirection dir) { Element::set_nav_auto(dir); @@ -246,4 +265,4 @@ namespace recompui { } } -}; \ No newline at end of file +}; diff --git a/src/ui/elements/ui_radio.h b/src/ui/elements/ui_radio.h index d3cb54d..490bdab 100644 --- a/src/ui/elements/ui_radio.h +++ b/src/ui/elements/ui_radio.h @@ -10,6 +10,7 @@ namespace recompui { Style checked_style; Style pulsing_style; std::function pressed_callback = nullptr; + std::function focus_callback = nullptr; uint32_t index = 0; protected: virtual void process_event(const Event &e) override; @@ -17,6 +18,7 @@ namespace recompui { public: RadioOption(Element *parent, std::string_view name, uint32_t index); void set_pressed_callback(std::function callback); + void set_focus_callback(std::function callback); void set_selected_state(bool enable); }; @@ -25,6 +27,7 @@ namespace recompui { std::vector options; uint32_t index = 0; std::vector> index_changed_callbacks; + std::function focus_callback = nullptr; bool child_focus_queued = false; void set_index_internal(uint32_t index, bool setup, bool trigger_callbacks); @@ -42,6 +45,7 @@ namespace recompui { void set_index(uint32_t index); uint32_t get_index() const; void add_index_changed_callback(std::function callback); + void set_focus_callback(std::function callback); size_t num_options() const { return options.size(); } RadioOption* get_option_element(size_t option_index) { return options[option_index]; } RadioOption* get_current_option_element() { return options.empty() ? nullptr : options[index]; } @@ -51,4 +55,4 @@ namespace recompui { void set_nav_manual(NavDirection dir, const std::string& target) override; }; -} // namespace recompui \ No newline at end of file +} // namespace recompui diff --git a/src/ui/elements/ui_slider.cpp b/src/ui/elements/ui_slider.cpp index 90a65a7..c77b45d 100644 --- a/src/ui/elements/ui_slider.cpp +++ b/src/ui/elements/ui_slider.cpp @@ -81,6 +81,9 @@ namespace recompui { if (active) { queue_update(); } + if (focus_callback != nullptr) { + focus_callback(active); + } } break; case EventType::Update: @@ -219,6 +222,10 @@ namespace recompui { value_changed_callbacks.emplace_back(callback); } + void Slider::set_focus_callback(std::function callback) { + focus_callback = callback; + } + void Slider::do_step(bool increment) { double new_value = value; if (increment) { @@ -233,4 +240,4 @@ namespace recompui { } } -} // namespace recompui \ No newline at end of file +} // namespace recompui diff --git a/src/ui/elements/ui_slider.h b/src/ui/elements/ui_slider.h index b5697ed..7fbd62e 100644 --- a/src/ui/elements/ui_slider.h +++ b/src/ui/elements/ui_slider.h @@ -23,6 +23,7 @@ namespace recompui { double max_value = 100.0; double step_value = 0.0; std::vector> value_changed_callbacks; + std::function focus_callback = nullptr; void set_value_internal(double v, bool setup, bool trigger_callbacks); void bar_pressed(float x, float y); @@ -51,6 +52,7 @@ namespace recompui { double get_step_value() const; void add_value_changed_callback(std::function callback); void do_step(bool increment); + void set_focus_callback(std::function callback); }; } // namespace recompui diff --git a/src/ui/elements/ui_text_input.cpp b/src/ui/elements/ui_text_input.cpp index 77ac093..b496728 100644 --- a/src/ui/elements/ui_text_input.cpp +++ b/src/ui/elements/ui_text_input.cpp @@ -16,12 +16,19 @@ namespace recompui { break; } + case EventType::Focus: { + const EventFocus &event = std::get(e.variant); + if (focus_callback != nullptr) { + focus_callback(event.active); + } + break; + } default: break; } } - TextInput::TextInput(Element *parent, bool text_visible) : Element(parent, Events(EventType::Text), "input") { + TextInput::TextInput(Element *parent, bool text_visible) : Element(parent, Events(EventType::Text, EventType::Focus), "input") { if (!text_visible) { set_attribute("type", "password"); } @@ -48,4 +55,7 @@ namespace recompui { text_changed_callbacks.emplace_back(callback); } -}; \ No newline at end of file + void TextInput::set_focus_callback(std::function callback) { + focus_callback = callback; + } +}; diff --git a/src/ui/elements/ui_text_input.h b/src/ui/elements/ui_text_input.h index 43764b8..5d0024f 100644 --- a/src/ui/elements/ui_text_input.h +++ b/src/ui/elements/ui_text_input.h @@ -8,6 +8,7 @@ namespace recompui { private: std::string text; std::vector> text_changed_callbacks; + std::function focus_callback = nullptr; protected: virtual void process_event(const Event &e) override; std::string_view get_type_name() override { return "TextInput"; } @@ -16,6 +17,7 @@ namespace recompui { void set_text(std::string_view text); const std::string &get_text(); void add_text_changed_callback(std::function callback); + void set_focus_callback(std::function callback); }; } // namespace recompui diff --git a/src/ui/ui_config_sub_menu.cpp b/src/ui/ui_config_sub_menu.cpp index 35907a7..75eb5b7 100644 --- a/src/ui/ui_config_sub_menu.cpp +++ b/src/ui/ui_config_sub_menu.cpp @@ -13,6 +13,9 @@ namespace recompui { void ConfigOptionElement::process_event(const Event &e) { switch (e.type) { case EventType::Hover: + if (hover_callback == nullptr) { + break; + } hover_callback(this, std::get(e.variant).active); break; case EventType::Update: @@ -53,6 +56,10 @@ void ConfigOptionElement::set_hover_callback(std::function callback) { + focus_callback = callback; +} + const std::string &ConfigOptionElement::get_description() const { return description; } @@ -73,6 +80,9 @@ ConfigOptionSlider::ConfigOptionSlider(Element *parent, double value, double min slider->set_step_value(step_value); slider->set_value(value); slider->add_value_changed_callback([this](double v){ slider_value_changed(v); }); + slider->set_focus_callback([this](bool active) { + focus_callback(option_id, active); + }); } // ConfigOptionTextInput @@ -88,6 +98,9 @@ ConfigOptionTextInput::ConfigOptionTextInput(Element *parent, std::string_view v text_input->set_max_width(400.0f); text_input->set_text(value); text_input->add_text_changed_callback([this](const std::string &text){ text_changed(text); }); + text_input->set_focus_callback([this](bool active) { + focus_callback(option_id, active); + }); } // ConfigOptionRadio @@ -100,6 +113,9 @@ ConfigOptionRadio::ConfigOptionRadio(Element *parent, uint32_t value, const std: this->callback = callback; radio = get_current_context().create_element(this); + radio->set_focus_callback([this](bool active) { + focus_callback(option_id, active); + }); radio->add_index_changed_callback([this](uint32_t index){ index_changed(index); }); for (std::string_view option : options) { radio->add_option(option); @@ -122,19 +138,19 @@ void ConfigSubMenu::back_button_pressed() { recompui::focus_mod_configure_button(); } -void ConfigSubMenu::option_hovered(ConfigOptionElement *option, bool active) { +void ConfigSubMenu::set_description_option_element(ConfigOptionElement *option, bool active) { if (active) { - hover_option_elements.emplace(option); + description_option_element = option; } - else { - hover_option_elements.erase(option); + else if (description_option_element == option) { + description_option_element = nullptr; } - if (hover_option_elements.empty()) { + if (description_option_element == nullptr) { description_label->set_text(""); } else { - description_label->set_text((*hover_option_elements.begin())->get_description()); + description_label->set_text(description_option_element->get_description()); } } @@ -190,14 +206,15 @@ void ConfigSubMenu::enter(std::string_view title) { void ConfigSubMenu::clear_options() { config_scroll_container->clear_children(); config_option_elements.clear(); - hover_option_elements.clear(); + description_option_element = nullptr; } void ConfigSubMenu::add_option(ConfigOptionElement *option, std::string_view id, std::string_view name, std::string_view description) { option->set_option_id(id); option->set_name(name); option->set_description(description); - option->set_hover_callback([this](ConfigOptionElement *option, bool active){ option_hovered(option, active); }); + option->set_hover_callback([this](ConfigOptionElement *option, bool active){ set_description_option_element(option, active); }); + option->set_focus_callback([this, option](const std::string &id, bool active) { set_description_option_element(option, active); }); if (config_option_elements.empty()) { back_button->set_nav(NavDirection::Down, option->get_focus_element()); option->set_nav(NavDirection::Up, back_button); diff --git a/src/ui/ui_config_sub_menu.h b/src/ui/ui_config_sub_menu.h index 93c8647..79278c9 100644 --- a/src/ui/ui_config_sub_menu.h +++ b/src/ui/ui_config_sub_menu.h @@ -20,6 +20,7 @@ protected: std::string name; std::string description; std::function hover_callback = nullptr; + std::function focus_callback = nullptr; virtual void process_event(const Event &e) override; std::string_view get_type_name() override { return "ConfigOptionElement"; } @@ -30,6 +31,7 @@ public: void set_name(std::string_view name); void set_description(std::string_view description); void set_hover_callback(std::function callback); + void set_focus_callback(std::function callback); const std::string &get_description() const; void set_nav_auto(NavDirection dir) override { get_focus_element()->set_nav_auto(dir); } void set_nav_none(NavDirection dir) override { get_focus_element()->set_nav_none(dir); } @@ -84,10 +86,10 @@ private: Container *config_container = nullptr; ScrollContainer *config_scroll_container = nullptr; std::vector config_option_elements; - std::unordered_set hover_option_elements; + ConfigOptionElement * description_option_element = nullptr; void back_button_pressed(); - void option_hovered(ConfigOptionElement *option, bool active); + void set_description_option_element(ConfigOptionElement *option, bool active); void add_option(ConfigOptionElement *option, std::string_view id, std::string_view name, std::string_view description); protected: std::string_view get_type_name() override { return "ConfigSubMenu"; } @@ -112,4 +114,4 @@ private: }; } -#endif \ No newline at end of file +#endif