24 static constexpr tt::axis axis = Axis;
26 template<
typename Content,
typename Aperture,
typename Offset>
31 Offset &&offset) noexcept :
33 content(std::forward<Content>(content)),
34 aperture(std::forward<Aperture>(aperture)),
35 offset(std::forward<Offset>(offset))
37 _content_callback = this->content.subscribe([
this](
auto...) {
38 _request_layout =
true;
40 _aperture_callback = this->aperture.subscribe([
this](
auto...) {
41 _request_layout =
true;
43 _offset_callback = this->offset.subscribe([
this](
auto...) {
44 _request_layout =
true;
50 [[nodiscard]]
bool constrain(utc_nanoseconds display_time_point,
bool need_reconstrain)
noexcept override
52 tt_axiom(is_gui_thread());
55 if constexpr (axis == axis::vertical) {
62 tt_axiom(_minimum_size <= _preferred_size && _preferred_size <= _maximum_size);
69 [[nodiscard]]
void layout(utc_nanoseconds display_time_point,
bool need_layout)
noexcept override
71 tt_axiom(is_gui_thread());
73 need_layout |= _request_layout.exchange(
false);
75 tt_axiom(*content != 0.0f);
78 ttlet slider_offset = *offset * travel_vs_hidden_content_ratio();
80 if constexpr (axis == axis::vertical) {
94 tt_axiom(is_gui_thread());
96 if (overlaps(context, this->_clipping_rectangle) and
visible) {
105 tt_axiom(is_gui_thread());
107 if (
visible and _visible_rectangle.contains(position) and slider_rectangle.
contains(position)) {
116 tt_axiom(is_gui_thread());
119 if (event.cause.leftButton) {
122 switch (event.type) {
123 using enum mouse_event::Type;
126 offset_before_drag = *offset;
132 ttlet slider_movement = axis == axis::vertical ?
event.delta().y() :
event.delta().x();
133 ttlet content_movement = slider_movement * hidden_content_vs_travel_ratio();
134 offset = offset_before_drag + content_movement;
148 [[nodiscard]]
color background_color() const noexcept
override
153 [[nodiscard]] color foreground_color() const noexcept
override
163 observable<float> offset;
164 observable<float> aperture;
165 observable<float> content;
167 typename decltype(offset)::callback_ptr_type _offset_callback;
168 typename decltype(aperture)::callback_ptr_type _aperture_callback;
169 typename decltype(content)::callback_ptr_type _content_callback;
171 aarectangle slider_rectangle;
173 float offset_before_drag;
175 [[nodiscard]]
float rail_length() const noexcept
177 tt_axiom(is_gui_thread());
181 [[nodiscard]]
float slider_length() const noexcept
183 tt_axiom(is_gui_thread());
185 ttlet content_aperture_ratio = *aperture / *content;
186 return std::max(rail_length() * content_aperture_ratio,
theme().size * 2.0f);
191 [[nodiscard]]
float slider_travel_range() const noexcept
193 tt_axiom(is_gui_thread());
194 return rail_length() - slider_length();
199 [[nodiscard]]
float hidden_content() const noexcept
201 tt_axiom(is_gui_thread());
202 return *content - *aperture;
209 [[nodiscard]]
float hidden_content_vs_travel_ratio() const noexcept
211 tt_axiom(is_gui_thread());
213 ttlet _slider_travel_range = slider_travel_range();
214 return _slider_travel_range != 0.0f ? hidden_content() / _slider_travel_range : 0.0f;
221 [[nodiscard]]
float travel_vs_hidden_content_ratio() const noexcept
223 tt_axiom(is_gui_thread());
225 ttlet _hidden_content = hidden_content();
226 return _hidden_content != 0.0f ? slider_travel_range() / _hidden_content : 0.0f;
229 void draw_rails(draw_context context)
noexcept
231 tt_axiom(is_gui_thread());
233 ttlet corner_shapes =
235 context.draw_box(
rectangle(), background_color(), corner_shapes);
238 void draw_slider(draw_context context)
noexcept
240 tt_axiom(is_gui_thread());
242 ttlet corner_shapes = axis == axis::vertical ?
tt::corner_shapes{slider_rectangle.width() * 0.5f} :
245 context.draw_box(translate_z(0.1f) * slider_rectangle, foreground_color(), corner_shapes);