#include "overloaded.h" #include "ui_radio.h" #include "../ui_utils.h" namespace recompui { // RadioOption RadioOption::RadioOption(Element *parent, std::string_view name, uint32_t index) : Element(parent, Events(EventType::MouseButton, EventType::Click, EventType::Focus, EventType::Hover, EventType::Enable, EventType::Update), "label", true) { this->index = index; enable_focus(); set_text(name); set_cursor(Cursor::Pointer); set_font_size(20.0f); set_letter_spacing(2.8f); set_line_height(20.0f); set_font_weight(400); set_font_style(FontStyle::Normal); set_border_color(ThemeColor::Text, 0); set_border_bottom_width(1.0f); set_color(ThemeColor::TextInactive); set_padding_bottom(8.0f); set_text_transform(TextTransform::Uppercase); set_height_auto(); hover_style.set_color(ThemeColor::WhiteA80); checked_style.set_color(ThemeColor::White); checked_style.set_border_color(ThemeColor::Text); pulsing_style.set_border_color(ThemeColor::SecondaryA80); add_style(&hover_style, { hover_state }); add_style(&checked_style, { checked_state }); add_style(&pulsing_style, { focus_state }); } void RadioOption::set_pressed_callback(std::function callback) { 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); } void RadioOption::process_event(const Event &e) { switch (e.type) { case EventType::MouseButton: { const EventMouseButton &mousebutton = std::get(e.variant); if (mousebutton.button == MouseButton::Left && mousebutton.pressed) { pressed_callback(index); } } break; case EventType::Click: pressed_callback(index); break; case EventType::Hover: set_style_enabled(hover_state, std::get(e.variant).active); break; case EventType::Enable: set_style_enabled(disabled_state, !std::get(e.variant).active); break; case EventType::Focus: { bool active = std::get(e.variant).active; set_style_enabled(focus_state, active); if (active) { queue_update(); } if (focus_callback != nullptr) { focus_callback(active); } } break; case EventType::Update: if (is_style_enabled(focus_state)) { pulsing_style.set_color(recompui::get_pulse_color(750)); apply_styles(); queue_update(); } break; default: break; } } // Radio void Radio::set_index_internal(uint32_t index, bool setup, bool trigger_callbacks) { if (this->index != index || setup) { options[this->index]->set_selected_state(false); this->index = index; options[index]->set_selected_state(true); if (trigger_callbacks) { for (const auto &function : index_changed_callbacks) { function(index); } } } } void Radio::option_selected(uint32_t index) { set_index_internal(index, false, true); } void Radio::set_input_value(const ElementValue& val) { std::visit(overloaded { [this](uint32_t u) { set_index(u); }, [this](float f) { set_index(f); }, [this](double d) { set_index(d); }, [](std::monostate) {} }, val); } Radio::Radio(Element *parent) : Container(parent, FlexDirection::Row, JustifyContent::FlexStart, Events(EventType::Focus, EventType::Update)) { 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(); queue_child_focus(); } if (focus_callback != nullptr) { focus_callback(std::get(e.variant).active); } } break; case EventType::Update: if (child_focus_queued) { child_focus_queued = false; options[index]->focus(); } } } Radio::~Radio() { } 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. 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) { set_index_internal(index, false, false); } uint32_t Radio::get_index() const { return index; } 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); 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; } } } };