rsx/overlays: Implement slider control

This commit is contained in:
kd-11 2026-03-13 04:14:45 +03:00 committed by kd-11
parent 1be7b9f983
commit 63ed8881a4
4 changed files with 222 additions and 3 deletions

View file

@ -730,9 +730,10 @@ namespace rsx
return compiled_resources;
}
void layout_container::add_spacer()
void layout_container::add_spacer(u16 size)
{
std::unique_ptr<overlay_element> spacer_element = std::make_unique<spacer>();
spacer_element->set_size(size, size);
add_element(spacer_element);
}

View file

@ -265,7 +265,7 @@ namespace rsx
compiled_resource& get_compiled() override;
virtual u16 get_scroll_offset_px() = 0;
void add_spacer();
void add_spacer(u16 size = 0);
};
struct vertical_layout : public layout_container

View file

@ -1 +1,178 @@
#include "stdafx.h"
#include "overlay_slider.h"
namespace rsx::overlays
{
constexpr u16 slider_rail_thickness = 5;
constexpr u16 slider_cover_thickness = 6;
constexpr u16 slider_indicator_radius = 8;
constexpr u16 slider_indicator_dia = slider_indicator_radius * 2;
void slider::init()
{
back_color = color4f(0.3f, 0.3f, 0.3f, 0.f);
fore_color = color4f(0.5647f, 0.7922f, 0.9765f, 1.f);
auto_resize = false;
m_current_value = m_min_value;
}
void slider::set_size(u16 w, u16 h)
{
horizontal_layout::set_size(w, h);
clear_items();
// Clamp the height
h = std::max<u16>(h, 8);
// Base components
auto background = std::make_unique<rounded_rect>();
auto foreground = std::make_unique<rounded_rect>();
auto indicator = std::make_unique<rounded_rect>();
auto value_label = std::make_unique<label>();
auto min_label = std::make_unique<label>();
auto max_label = std::make_unique<label>();
indicator->radius = slider_indicator_radius;
indicator->set_size(slider_indicator_dia, slider_indicator_dia);
indicator->back_color = color4f(1.f);
background->radius = slider_rail_thickness / 2;
background->back_color = this->back_color;
background->back_color.a = 1.f;
background->set_size(w, slider_rail_thickness);
background->set_pos(0, (slider_indicator_dia / 2) - background->radius);
foreground->radius = slider_cover_thickness / 2;
foreground->back_color = this->fore_color;
foreground->set_size(0, slider_cover_thickness);
foreground->set_pos(0, (slider_indicator_dia / 2) - foreground->radius);
value_label->set_padding(2);
value_label->set_font("Arial", 10);
value_label->set_text(m_formatter(m_current_value));
value_label->auto_resize();
value_label->back_color.a = 0.f;
value_label->fore_color = color4f(1.f);
min_label->fore_color = color4f(0.75f, 0.75f, 0.75f, 1.f);
min_label->back_color.a = 0.f;
min_label->set_font("Arial", 10);
min_label->set_text(m_formatter(m_min_value));
min_label->set_pos(0, (value_label->h / 2) + slider_indicator_radius + 8); // Margin = Text Height + Indicator Rad (gets to half point) - Text Height / 2 (Offset back to box origin)
min_label->auto_resize();
max_label->fore_color = color4f(0.75f, 0.75f, 0.75f, 1.f);
max_label->back_color.a = 0.f;
max_label->set_font("Arial", 10);
max_label->set_text(m_formatter(m_max_value));
max_label->set_pos(0, (value_label->h / 2) + slider_indicator_radius + 8); // Margin
max_label->auto_resize();
const u16 horizontal_padding = slider_indicator_dia;
if (m_show_labels)
{
const u16 unusable_space = max_label->w + min_label->w + (2 * horizontal_padding);
if (unusable_space < w)
{
background->w -= unusable_space;
foreground->w = unusable_space;
}
}
// Pack the slider part
auto slider_part = std::make_unique<box_layout>();
slider_part->set_size(background->w, 8);
m_rail_component = slider_part->add_element(background);
m_slider_component = slider_part->add_element(foreground);
m_indicator_component = slider_part->add_element(indicator);
// Middle part of the sandwich
auto stack_part = std::make_unique<vertical_layout>();
m_value_component = stack_part->add_element(value_label);
stack_part->add_spacer(8);
stack_part->add_element(slider_part);
if (m_show_labels)
{
// Assemble the sandwich
add_element(min_label);
add_spacer(horizontal_padding);
add_element(stack_part);
add_spacer(horizontal_padding);
add_element(max_label);
}
else
{
add_element(stack_part);
}
update_elements();
}
void slider::set_value(f64 value)
{
value = std::clamp(value, m_min_value, m_max_value);
if (value == m_current_value)
{
return;
}
m_current_value = value;
update_elements();
}
void slider::set_show_labels(bool show)
{
if (m_show_labels == show)
{
return;
}
m_show_labels = show;
set_size(w, h);
}
void slider::update_elements()
{
if (!m_slider_component || !m_value_component || !m_rail_component)
{
return;
}
const auto slider_w = (std::abs(m_current_value - m_min_value) * m_rail_component->w) / std::abs(m_max_value - m_min_value);
const auto slider_w16 = static_cast<u16>(std::floor(slider_w));
m_slider_component->set_size(slider_w16, m_slider_component->h);
m_indicator_component->set_pos(m_slider_component->x + slider_w16 - slider_indicator_radius, m_indicator_component->y);
m_value_component->set_text(m_formatter(m_current_value));
m_value_component->auto_resize();
// If the label would touch the end, flip it
u16 offset = (slider_w16 + m_value_component->w) >= m_rail_component->w ? m_value_component->w : 0;
m_value_component->set_pos(m_slider_component->x + slider_w16 - offset, m_value_component->y);
// Hide indicator when slider is completely empty or completely full
m_value_component->visible = (m_current_value != m_min_value) && (m_current_value != m_max_value);
}
void slider::set_value_format(std::function<std::string(f64)> formatter)
{
m_formatter = formatter;
set_size(w, h);
}
compiled_resource& slider::get_compiled()
{
if (is_compiled())
{
return compiled_resources;
}
horizontal_layout::get_compiled();
m_is_compiled = true;
return compiled_resources;
}
}

View file

@ -4,7 +4,48 @@
namespace rsx::overlays
{
struct slider : public overlay_element
struct slider : public horizontal_layout
{
slider()
{
init();
}
slider(f64 min, f64 max, f64 step)
: m_min_value(min)
, m_max_value(max)
, m_step(step)
{
init();
}
void set_size(u16 w, u16 h) override;
void set_value_format(std::function<std::string(f64)> formatter);
void set_show_labels(bool show);
void inc_value() { set_value(m_current_value + m_step); }
void dec_value() { set_value(m_current_value - m_step); }
void set_value(f64 value);
compiled_resource& get_compiled() override;
private:
f64 m_min_value = 0.0;
f64 m_max_value = 100.0;
f64 m_current_value = 0.0;
f64 m_step = 1.0;
bool m_show_labels = true;
std::function<std::string(f64)> m_formatter =
[](f64 v) { return std::to_string(v); };
overlay_element* m_slider_component = nullptr;
overlay_element* m_rail_component = nullptr;
overlay_element* m_indicator_component = nullptr;
label* m_value_component = nullptr;
void init();
void update_elements();
};
}