24 static constexpr hi::axis axis = Axis;
30 template<
typename Content,
typename Aperture,
typename Offset>
33 content(std::forward<Content>(content)),
34 aperture(std::forward<Aperture>(aperture)),
35 offset(std::forward<Offset>(offset))
38 _content_cbt = this->content.subscribe([&](
auto...){ request_relayout(); });
39 _aperture_cbt = this->aperture.subscribe([&](
auto...){ request_relayout(); });
40 _offset_cbt = this->offset.subscribe([&](
auto...){ request_relayout(); });
51 if constexpr (axis == axis::vertical) {
52 return _constraints = {
57 return _constraints = {
69 hilet slider_offset = *offset * travel_vs_hidden_content_ratio();
70 if constexpr (axis == axis::vertical) {
71 _slider_rectangle =
aarectangle{0.0f, slider_offset, layout.width(), slider_length()};
73 _slider_rectangle =
aarectangle{slider_offset, 0.0f, slider_length(), layout.height()};
79 if (*visible and overlaps(context, layout())) {
87 hi_axiom(is_gui_thread());
89 if (*visible and *enabled and layout().contains(position) and _slider_rectangle.contains(position)) {
90 return {
this, position};
98 hi_axiom(is_gui_thread());
99 auto handled = super::handle_event(event);
101 if (event.cause.leftButton) {
104 switch (event.type) {
105 using enum mouse_event::Type;
108 _offset_before_drag = *offset;
114 hilet slider_movement = axis == axis::vertical ?
event.delta().y() :
event.delta().x();
115 hilet content_movement = slider_movement * hidden_content_vs_travel_ratio();
116 hilet new_offset = _offset_before_drag + content_movement;
117 offset = clamp_offset(new_offset);
131 [[nodiscard]]
color background_color() const noexcept
override
133 return theme().color(theme_color::fill, semantic_layer);
136 [[nodiscard]] color foreground_color() const noexcept
override
139 return theme().color(theme_color::fill, semantic_layer + 2);
141 return theme().color(theme_color::fill, semantic_layer + 1);
146 aarectangle _slider_rectangle;
148 float _offset_before_drag;
150 typename decltype(content)::token_type _content_cbt;
151 typename decltype(aperture)::token_type _aperture_cbt;
152 typename decltype(offset)::token_type _offset_cbt;
158 [[nodiscard]]
float clamp_offset(
float new_offset)
const noexcept
160 hilet scrollable_distance =
std::max(0.0f, *content - *aperture);
161 return std::clamp(new_offset, 0.0f, scrollable_distance);
164 [[nodiscard]]
float rail_length() const noexcept
166 hi_axiom(is_gui_thread());
167 return axis == axis::vertical ? layout().height() : layout().width();
170 [[nodiscard]]
float slider_length() const noexcept
172 hi_axiom(is_gui_thread());
174 hilet content_aperture_ratio = *content != 0.0f ? *aperture / *content : 1.0f;
175 hilet rail_length_ = rail_length();
176 return std::clamp(rail_length_ * content_aperture_ratio, theme().size * 2.0f, rail_length_);
181 [[nodiscard]]
float slider_travel_range() const noexcept
183 hi_axiom(is_gui_thread());
184 return rail_length() - slider_length();
189 [[nodiscard]]
float hidden_content() const noexcept
191 hi_axiom(is_gui_thread());
192 return *content - *aperture;
199 [[nodiscard]]
float hidden_content_vs_travel_ratio() const noexcept
201 hi_axiom(is_gui_thread());
203 hilet _slider_travel_range = slider_travel_range();
204 return _slider_travel_range != 0.0f ? hidden_content() / _slider_travel_range : 0.0f;
211 [[nodiscard]]
float travel_vs_hidden_content_ratio() const noexcept
213 hi_axiom(is_gui_thread());
215 hilet _hidden_content = hidden_content();
216 return _hidden_content != 0.0f ? slider_travel_range() / _hidden_content : 0.0f;
219 void draw_rails(draw_context
const &context)
noexcept
222 axis == axis::vertical ? hi::corner_radii{layout().width() * 0.5f} : hi::corner_radii{layout().height() * 0.5f};
223 context.draw_box(layout(), layout().rectangle(), background_color(), corner_radii);
226 void draw_slider(draw_context
const &context)
noexcept
228 hilet corner_radii = axis == axis::vertical ? hi::corner_radii{_slider_rectangle.width() * 0.5f} :
229 hi::corner_radii{_slider_rectangle.height() * 0.5f};
231 context.draw_box(layout(), translate_z(0.1f) * _slider_rectangle, foreground_color(), corner_radii);