#include "overloaded.h" #include "ui_slider.h" #include "../ui_utils.h" #include #include namespace recompui { void Slider::set_value_internal(double v, bool setup, bool trigger_callbacks) { if (step_value != 0.0) { v = std::lround(v / step_value) * step_value; } if (value != v || setup) { value = v; update_circle_position(); update_label_text(); if (trigger_callbacks) { for (auto callback : value_changed_callbacks) { callback(v); } } } } void Slider::bar_pressed(float x, float) { update_value_from_mouse(x); } void Slider::bar_dragged(float x, float, DragPhase) { update_value_from_mouse(x); } void Slider::circle_dragged(float x, float, DragPhase) { update_value_from_mouse(x); } void Slider::update_value_from_mouse(float x) { double left = slider_element->get_absolute_left(); double width = slider_element->get_client_width(); double ratio = std::clamp((x - left) / width, 0.0, 1.0); set_value_internal(min_value + ratio * (max_value - min_value), false, true); } void Slider::update_circle_position() { double ratio = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0); circle_element->set_left(ratio * 100.0, Unit::Percent); } void Slider::update_label_text() { char text_buffer[32]; if (type == SliderType::Double) { std::snprintf(text_buffer, sizeof(text_buffer), "%.1f", value); } else if (type == SliderType::Percent) { std::snprintf(text_buffer, sizeof(text_buffer), "%d%%", static_cast(value)); } else { std::snprintf(text_buffer, sizeof(text_buffer), "%d", static_cast(value)); } value_label->set_text(text_buffer); } void Slider::set_input_value(const ElementValue& val) { std::visit(overloaded { [this](uint32_t u) { set_value(u); }, [this](float f) { set_value(f); }, [this](double d) { set_value(d); }, [](std::monostate) {} }, val); } void Slider::process_event(const Event& e) { switch (e.type) { case EventType::Focus: { bool active = std::get(e.variant).active; circle_element->set_style_enabled(focus_state, active); if (active) { queue_update(); } if (focus_callback != nullptr) { focus_callback(active); } } break; case EventType::Update: if (is_enabled()) { if (circle_element->is_style_enabled(focus_state)) { circle_element->set_background_color(recompui::get_pulse_color(750)); queue_update(); } else { circle_element->set_background_color(theme::color::TextDim); } } else { circle_element->set_background_color(theme::color::BW25); } break; case EventType::Navigate: { NavDirection dir = std::get(e.variant).direction; if (dir == NavDirection::Left) { do_step(false); } else if (dir == NavDirection::Right) { do_step(true); } } break; case EventType::Enable: { bool enable_active = std::get(e.variant).active; circle_element->set_enabled(enable_active); if (enable_active) { set_cursor(Cursor::Pointer); set_focusable(true); circle_element->set_background_color(theme::color::TextDim); } else { set_cursor(Cursor::None); set_focusable(false); circle_element->set_background_color(theme::color::BW25); } } break; default: break; } } Slider::Slider(Element *parent, SliderType type) : Element(parent, Events(EventType::Focus, EventType::Update, EventType::Navigate, EventType::Enable)) { this->type = type; set_cursor(Cursor::Pointer); set_display(Display::Flex); set_flex_direction(FlexDirection::Row); set_text_align(TextAlign::Left); set_min_width(120.0f); enable_focus(); set_nav_none(NavDirection::Left); set_nav_none(NavDirection::Right); ContextId context = get_current_context(); value_label = context.create_element