37 static constexpr hi::axis axis = Axis;
39 observer<float> offset;
40 observer<float> aperture;
41 observer<float> content;
46 forward_of<observer<float>>
auto&& content,
47 forward_of<observer<float>>
auto&& aperture,
48 forward_of<observer<float>>
auto&& offset) noexcept :
53 _aperture_cbt = this->aperture.subscribe([&](
auto...){
request_relayout(); });
65 if constexpr (axis == axis::vertical) {
66 return _constraints = {
69 {
theme().icon_size, 32767.0f}};
71 return _constraints = {
74 {32767.0f,
theme().icon_size}};
83 hilet slider_offset = *offset * travel_vs_hidden_content_ratio();
84 if constexpr (axis == axis::vertical) {
85 _slider_rectangle = aarectangle{0.0f, slider_offset,
layout.width(), slider_length()};
87 _slider_rectangle = aarectangle{slider_offset, 0.0f, slider_length(),
layout.height()};
91 void draw(draw_context
const& context)
noexcept override
101 hi_axiom(is_gui_thread());
104 return {
this, position};
112 switch (event.type()) {
113 case gui_event_type::mouse_down:
114 if (event.mouse().cause.left_button) {
116 _offset_before_drag = *offset;
121 case gui_event_type::mouse_drag:
122 if (event.mouse().cause.left_button) {
125 hilet slider_movement = axis == axis::vertical ?
event.drag_delta().y() :
event.drag_delta().x();
126 hilet content_movement = slider_movement * hidden_content_vs_travel_ratio();
127 hilet new_offset = _offset_before_drag + content_movement;
128 offset = clamp_offset(new_offset);
144 [[nodiscard]] color background_color() const noexcept
override
149 [[nodiscard]] color foreground_color() const noexcept
override
159 aarectangle _slider_rectangle;
161 float _offset_before_drag;
163 typename decltype(content)::callback_token _content_cbt;
164 typename decltype(aperture)::callback_token _aperture_cbt;
165 typename decltype(offset)::callback_token _offset_cbt;
171 [[nodiscard]]
float clamp_offset(
float new_offset)
const noexcept
173 hilet scrollable_distance =
std::max(0.0f, *content - *aperture);
174 return std::clamp(new_offset, 0.0f, scrollable_distance);
177 [[nodiscard]]
float rail_length() const noexcept
179 hi_axiom(is_gui_thread());
180 return axis == axis::vertical ?
layout().height() :
layout().width();
183 [[nodiscard]]
float slider_length() const noexcept
185 hi_axiom(is_gui_thread());
187 hilet content_aperture_ratio = *content != 0.0f ? *aperture / *content : 1.0f;
188 hilet rail_length_ = rail_length();
189 return std::clamp(rail_length_ * content_aperture_ratio,
theme().size * 2.0f, rail_length_);
194 [[nodiscard]]
float slider_travel_range() const noexcept
196 hi_axiom(is_gui_thread());
197 return rail_length() - slider_length();
202 [[nodiscard]]
float hidden_content() const noexcept
204 hi_axiom(is_gui_thread());
205 return *content - *aperture;
212 [[nodiscard]]
float hidden_content_vs_travel_ratio() const noexcept
214 hi_axiom(is_gui_thread());
216 hilet _slider_travel_range = slider_travel_range();
217 return _slider_travel_range != 0.0f ? hidden_content() / _slider_travel_range : 0.0f;
224 [[nodiscard]]
float travel_vs_hidden_content_ratio() const noexcept
226 hi_axiom(is_gui_thread());
228 hilet _hidden_content = hidden_content();
229 return _hidden_content != 0.0f ? slider_travel_range() / _hidden_content : 0.0f;
232 void draw_rails(draw_context
const& context)
noexcept
235 axis == axis::vertical ? hi::corner_radii{
layout().width() * 0.5f} : hi::corner_radii{
layout().height() * 0.5f};
236 context.draw_box(
layout(),
layout().rectangle(), background_color(), corner_radii);
239 void draw_slider(draw_context
const& context)
noexcept
241 hilet corner_radii = axis == axis::vertical ? hi::corner_radii{_slider_rectangle.width() * 0.5f} :
242 hi::corner_radii{_slider_rectangle.height() * 0.5f};
244 context.draw_box(
layout(), translate_z(0.1f) * _slider_rectangle, foreground_color(), corner_radii);