diff --git a/src/ui/elements/ui_container.cpp b/src/ui/elements/ui_container.cpp index 5b4e30d..f3e67e9 100644 --- a/src/ui/elements/ui_container.cpp +++ b/src/ui/elements/ui_container.cpp @@ -4,7 +4,7 @@ namespace recompui { - Container::Container(Element *parent, FlexDirection direction, JustifyContent justify_content) : Element(parent) { + Container::Container(Element *parent, FlexDirection direction, JustifyContent justify_content, uint32_t events_enabled) : Element(parent, events_enabled) { set_display(Display::Flex); set_flex_direction(direction); set_justify_content(justify_content); diff --git a/src/ui/elements/ui_container.h b/src/ui/elements/ui_container.h index 2ec0c1a..89b0e84 100644 --- a/src/ui/elements/ui_container.h +++ b/src/ui/elements/ui_container.h @@ -8,7 +8,7 @@ namespace recompui { protected: std::string_view get_type_name() override { return "Container"; } public: - Container(Element* parent, FlexDirection direction, JustifyContent justify_content); + Container(Element* parent, FlexDirection direction, JustifyContent justify_content, uint32_t events_enabled = 0); }; } // namespace recompui diff --git a/src/ui/elements/ui_element.cpp b/src/ui/elements/ui_element.cpp index 2f5cc97..5e9ba8e 100644 --- a/src/ui/elements/ui_element.cpp +++ b/src/ui/elements/ui_element.cpp @@ -456,6 +456,10 @@ void Element::focus() { base->Focus(); } +void Element::blur() { + base->Blur(); +} + void Element::queue_update() { ContextId cur_context = get_current_context(); diff --git a/src/ui/elements/ui_element.h b/src/ui/elements/ui_element.h index 22c3c82..6e2ce16 100644 --- a/src/ui/elements/ui_element.h +++ b/src/ui/elements/ui_element.h @@ -89,6 +89,7 @@ public: float get_client_height(); void enable_focus(); void focus(); + void blur(); void queue_update(); void register_callback(ContextId context, PTR(void) callback, PTR(void) userdata); uint32_t get_input_value_u32(); diff --git a/src/ui/elements/ui_radio.cpp b/src/ui/elements/ui_radio.cpp index 9128f79..5d3e98a 100644 --- a/src/ui/elements/ui_radio.cpp +++ b/src/ui/elements/ui_radio.cpp @@ -67,6 +67,10 @@ namespace recompui { apply_styles(); queue_update(); } + if (focus_queued) { + focus_queued = false; + focus(); + } break; default: break; @@ -102,9 +106,23 @@ namespace recompui { }, val); } - Radio::Radio(Element *parent) : Container(parent, FlexDirection::Row, JustifyContent::FlexStart) { + Radio::Radio(Element *parent) : Container(parent, FlexDirection::Row, JustifyContent::FlexStart, Events(EventType::Focus)) { set_gap(24.0f); set_align_items(AlignItems::FlexStart); + enable_focus(); + } + + void Radio::process_event(const Event &e) { + switch (e.type) { + case EventType::Focus: + if (!options.empty()) { + if (std::get(e.variant).active) { + blur(); + options[index]->queue_focus(); + } + } + break; + } } Radio::~Radio() { @@ -120,6 +138,11 @@ namespace recompui { if (options.size() == 1) { set_index_internal(0, true, false); } + // At least one other option already existed, so set up navigation. + else { + options[options.size() - 2]->set_nav(NavDirection::Right, options[options.size() - 1]); + options[options.size() - 1]->set_nav(NavDirection::Left, options[options.size() - 2]); + } } void Radio::set_index(uint32_t index) { @@ -133,5 +156,85 @@ namespace recompui { void Radio::add_index_changed_callback(std::function callback) { index_changed_callbacks.emplace_back(callback); } + + void Radio::set_nav_auto(NavDirection dir) { + Element::set_nav_auto(dir); + if (!options.empty()) { + switch (dir) { + case NavDirection::Up: + case NavDirection::Down: + for (Element* e : options) { + e->set_nav_auto(dir); + } + break; + case NavDirection::Left: + options.front()->set_nav_auto(dir); + break; + case NavDirection::Right: + options.back()->set_nav_auto(dir); + break; + } + } + } + + void Radio::set_nav_none(NavDirection dir) { + Element::set_nav_none(dir); + if (!options.empty()) { + switch (dir) { + case NavDirection::Up: + case NavDirection::Down: + for (Element* e : options) { + e->set_nav_none(dir); + } + break; + case NavDirection::Left: + options.front()->set_nav_none(dir); + break; + case NavDirection::Right: + options.back()->set_nav_none(dir); + break; + } + } + } + + void Radio::set_nav(NavDirection dir, Element* element) { + Element::set_nav(dir, element); + if (!options.empty()) { + switch (dir) { + case NavDirection::Up: + case NavDirection::Down: + for (Element* e : options) { + e->set_nav(dir, element); + } + break; + case NavDirection::Left: + options.front()->set_nav(dir, element); + break; + case NavDirection::Right: + options.back()->set_nav(dir, element); + break; + } + } + } + + void Radio::set_nav_manual(NavDirection dir, const std::string& target) { + Element::set_nav_manual(dir, target); + if (!options.empty()) { + switch (dir) { + case NavDirection::Up: + case NavDirection::Down: + for (Element* e : options) { + e->set_nav_manual(dir, target); + } + break; + case NavDirection::Left: + options.front()->set_nav_manual(dir, target); + break; + case NavDirection::Right: + options.back()->set_nav_manual(dir, target); + break; + } + } + } }; \ No newline at end of file diff --git a/src/ui/elements/ui_radio.h b/src/ui/elements/ui_radio.h index 6f57026..f5b7dc9 100644 --- a/src/ui/elements/ui_radio.h +++ b/src/ui/elements/ui_radio.h @@ -11,6 +11,7 @@ namespace recompui { Style pulsing_style; std::function pressed_callback = nullptr; uint32_t index = 0; + bool focus_queued = false; protected: virtual void process_event(const Event &e) override; std::string_view get_type_name() override { return "LabelRadioOption"; } @@ -18,6 +19,7 @@ namespace recompui { RadioOption(Element *parent, std::string_view name, uint32_t index); void set_pressed_callback(std::function callback); void set_selected_state(bool enable); + void queue_focus() { focus_queued = true; queue_update(); } }; class Radio : public Container { @@ -31,6 +33,7 @@ namespace recompui { void set_input_value(const ElementValue& val) override; ElementValue get_element_value() override { return get_index(); } protected: + virtual void process_event(const Event &e) override; std::string_view get_type_name() override { return "LabelRadio"; } public: Radio(Element *parent); @@ -39,6 +42,13 @@ namespace recompui { void set_index(uint32_t index); uint32_t get_index() const; void add_index_changed_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]; } + void set_nav_auto(NavDirection dir) override; + void set_nav_none(NavDirection dir) override; + void set_nav(NavDirection dir, Element* element) override; + void set_nav_manual(NavDirection dir, const std::string& target) override; }; } // namespace recompui \ No newline at end of file diff --git a/src/ui/elements/ui_style.h b/src/ui/elements/ui_style.h index c87be42..372fa6d 100644 --- a/src/ui/elements/ui_style.h +++ b/src/ui/elements/ui_style.h @@ -94,10 +94,10 @@ namespace recompui { void set_drag(Drag drag); void set_tab_index(TabIndex focus); void set_font_family(std::string_view family); - void set_nav_auto(NavDirection dir); - void set_nav_none(NavDirection dir); - void set_nav(NavDirection dir, Element* element); - void set_nav_manual(NavDirection dir, const std::string& target); + virtual void set_nav_auto(NavDirection dir); + virtual void set_nav_none(NavDirection dir); + virtual void set_nav(NavDirection dir, Element* element); + virtual void set_nav_manual(NavDirection dir, const std::string& target); void set_tab_index_auto(); void set_tab_index_none(); void set_focusable(bool focusable); diff --git a/src/ui/ui_config_sub_menu.cpp b/src/ui/ui_config_sub_menu.cpp index 55baea5..cc9ab63 100644 --- a/src/ui/ui_config_sub_menu.cpp +++ b/src/ui/ui_config_sub_menu.cpp @@ -172,6 +172,8 @@ ConfigSubMenu::ConfigSubMenu(Element *parent) : Element(parent) { description_label = context.create_element