37 static constexpr hi::axis axis = Axis;
39 observer<float> offset;
40 observer<float> aperture;
41 observer<float> content;
45 forward_of<observer<float>>
auto&& content,
46 forward_of<observer<float>>
auto&& aperture,
47 forward_of<observer<float>>
auto&& offset) noexcept :
50 _content_cbt = this->content.subscribe([&](
auto...) {
51 ++global_counter<
"scroll_bar_widget:content:relayout">;
54 _aperture_cbt = this->aperture.subscribe([&](
auto...) {
55 ++global_counter<
"scroll_bar_widget:aperture:relayout">;
58 _offset_cbt = this->offset.subscribe([&](
auto...) {
59 ++global_counter<
"scroll_bar_widget:offset:relayout">;
71 if constexpr (axis == axis::vertical) {
72 return _constraints = {
73 {context.theme->icon_size, context.theme->size * 4.0f},
74 {context.theme->icon_size, context.theme->size * 4.0f},
75 {context.theme->icon_size, 32767.0f}};
77 return _constraints = {
78 {context.theme->size * 4.0f, context.theme->icon_size},
79 {context.theme->size * 4.0f, context.theme->icon_size},
80 {32767.0f, context.theme->icon_size}};
89 hilet slider_offset = *offset * travel_vs_hidden_content_ratio();
90 if constexpr (axis == axis::vertical) {
91 _slider_rectangle = aarectangle{0.0f, slider_offset, context.width(), slider_length()};
93 _slider_rectangle = aarectangle{slider_offset, 0.0f, slider_length(), context.height()};
97 void draw(draw_context
const& context)
noexcept override
101 draw_slider(context);
110 return {
this, position, hitbox_type::scroll_bar};
118 switch (event.type()) {
119 case gui_event_type::mouse_down:
120 if (event.mouse().cause.left_button) {
122 _offset_before_drag = *offset;
127 case gui_event_type::mouse_drag:
128 if (event.mouse().cause.left_button) {
131 hilet slider_movement = axis == axis::vertical ?
event.drag_delta().y() :
event.drag_delta().x();
132 hilet content_movement = slider_movement * hidden_content_vs_travel_ratio();
133 hilet new_offset = _offset_before_drag + content_movement;
134 offset = clamp_offset(new_offset);
150 [[nodiscard]] color background_color() const noexcept
override
152 return _layout.theme->color(semantic_color::fill,
semantic_layer);
155 [[nodiscard]] color foreground_color() const noexcept
override
158 return _layout.theme->color(semantic_color::fill,
semantic_layer + 2);
160 return _layout.theme->color(semantic_color::fill,
semantic_layer + 1);
165 aarectangle _slider_rectangle;
167 float _offset_before_drag;
169 typename decltype(content)::callback_token _content_cbt;
170 typename decltype(aperture)::callback_token _aperture_cbt;
171 typename decltype(offset)::callback_token _offset_cbt;
177 [[nodiscard]]
float clamp_offset(
float new_offset)
const noexcept
179 hilet scrollable_distance =
std::max(0.0f, *content - *aperture);
180 return std::clamp(new_offset, 0.0f, scrollable_distance);
183 [[nodiscard]]
float rail_length() const noexcept
186 return axis == axis::vertical ?
layout().height() :
layout().width();
189 [[nodiscard]]
float slider_length() const noexcept
193 hilet content_aperture_ratio = *content != 0.0f ? *aperture / *content : 1.0f;
194 hilet rail_length_ = rail_length();
195 return std::clamp(rail_length_ * content_aperture_ratio, _layout.theme->size * 2.0f, rail_length_);
200 [[nodiscard]]
float slider_travel_range() const noexcept
203 return rail_length() - slider_length();
208 [[nodiscard]]
float hidden_content() const noexcept
211 return *content - *aperture;
218 [[nodiscard]]
float hidden_content_vs_travel_ratio() const noexcept
222 hilet _slider_travel_range = slider_travel_range();
223 return _slider_travel_range != 0.0f ? hidden_content() / _slider_travel_range : 0.0f;
230 [[nodiscard]]
float travel_vs_hidden_content_ratio() const noexcept
234 hilet _hidden_content = hidden_content();
235 return _hidden_content != 0.0f ? slider_travel_range() / _hidden_content : 0.0f;
238 void draw_rails(draw_context
const& context)
noexcept
241 axis == axis::vertical ? hi::corner_radii{
layout().width() * 0.5f} : hi::corner_radii{
layout().height() * 0.5f};
245 void draw_slider(draw_context
const& context)
noexcept
247 hilet corner_radii = axis == axis::vertical ? hi::corner_radii{_slider_rectangle.width() * 0.5f} :
248 hi::corner_radii{_slider_rectangle.height() * 0.5f};
250 context.draw_box(
layout(), translate_z(0.1f) * _slider_rectangle, foreground_color(), corner_radii);