HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
toggle_widget.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "abstract_bool_toggle_button_widget.hpp"
8#include "../label.hpp"
9#include "../stencils/label_stencil.hpp"
10#include "../GUI/draw_context.hpp"
11#include "../observable.hpp"
12#include <memory>
13#include <string>
14#include <array>
15#include <optional>
16#include <future>
17
18namespace tt {
19
21public:
23
24 observable<label> on_label;
25 observable<label> off_label;
26
27 template<typename Value = observable<bool>>
31 Value &&value = observable<bool>{}) noexcept :
32 super(window, parent, std::forward<Value>(value))
33 {
34 _on_label_callback = this->on_label.subscribe([this](auto...) {
35 _request_reconstrain = true;
36 });
37 _off_label_callback = this->off_label.subscribe([this](auto...) {
38 _request_reconstrain = true;
39 });
40 }
41
43
44 [[nodiscard]] bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept override
45 {
46 tt_axiom(gui_system_mutex.recurse_lock_count());
47
48 if (super::update_constraints(display_time_point, need_reconstrain)) {
49 _on_label_stencil = stencil::make_unique(alignment::top_left, *on_label, theme::global->labelStyle);
50 _off_label_stencil = stencil::make_unique(alignment::top_left, *off_label, theme::global->labelStyle);
51
52 ttlet minimumHeight = std::max(
53 {_on_label_stencil->preferred_extent().height(),
54 _off_label_stencil->preferred_extent().height(),
55 theme::global->smallSize});
56
57 ttlet minimumWidth =
58 std::max({_on_label_stencil->preferred_extent().width(), _off_label_stencil->preferred_extent().width()}) +
59 theme::global->smallSize * 2.0f + theme::global->margin;
60
61 _preferred_size = interval_vec2::make_minimum(minimumWidth, minimumHeight);
62 _preferred_base_line = relative_base_line{vertical_alignment::top, -theme::global->smallSize * 0.5f};
63
64 return true;
65 } else {
66 return false;
67 }
68 }
69
70 [[nodiscard]] void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept override
71 {
72 tt_axiom(gui_system_mutex.recurse_lock_count());
73
74 need_layout |= std::exchange(_request_relayout, false);
75 if (need_layout) {
76 _rail_rectangle = aarect{
77 -0.5f, // Expand horizontally due to rounded shape
78 base_line() - theme::global->smallSize * 0.5f,
79 theme::global->smallSize * 2.0f + 1.0f, // Expand horizontally due to rounded shape
80 theme::global->smallSize};
81
82 ttlet labelX = theme::global->smallSize * 2.0f + theme::global->margin;
83 _label_rectangle = aarect{labelX, 0.0f, rectangle().width() - labelX, rectangle().height()};
84 _on_label_stencil->set_layout_parameters(_label_rectangle, base_line());
85 _off_label_stencil->set_layout_parameters(_label_rectangle, base_line());
86
87 _slider_rectangle =
88 shrink(aarect{0.0f, _rail_rectangle.y(), _rail_rectangle.height(), _rail_rectangle.height()}, 1.5f);
89
90 ttlet sliderMoveWidth = theme::global->smallSize * 2.0f - (_slider_rectangle.x() * 2.0f);
91 _slider_move_range = sliderMoveWidth - _slider_rectangle.width();
92 }
93
94 super::update_layout(display_time_point, need_layout);
95 }
96
97 void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept override
98 {
99 tt_axiom(gui_system_mutex.recurse_lock_count());
100
101 if (overlaps(context, this->window_clipping_rectangle())) {
102 draw_rail(context);
103 draw_slider(context);
104 draw_label(context);
105 }
106
107 super::draw(std::move(context), display_time_point);
108 }
109
110private:
111 static constexpr hires_utc_clock::duration _animation_duration = 150ms;
112
113 aarect _rail_rectangle;
114
115 aarect _slider_rectangle;
116 float _slider_move_range;
117
118 aarect _label_rectangle;
119
120 std::unique_ptr<label_stencil> _on_label_stencil;
121 std::unique_ptr<label_stencil> _off_label_stencil;
122
123 decltype(value)::callback_ptr_type _value_callback;
124 decltype(on_label)::callback_ptr_type _on_label_callback;
125 decltype(off_label)::callback_ptr_type _off_label_callback;
126
127 void draw_rail(draw_context drawContext) noexcept
128 {
129 tt_axiom(gui_system_mutex.recurse_lock_count());
130
131 drawContext.corner_shapes = f32x4::broadcast(_rail_rectangle.height() * 0.5f);
132 drawContext.draw_box_with_border_inside(_rail_rectangle);
133 }
134
135 void draw_slider(draw_context drawContext) noexcept
136 {
137 tt_axiom(gui_system_mutex.recurse_lock_count());
138
139 // Prepare animation values.
140 ttlet animationProgress = value.animation_progress(_animation_duration);
141 if (animationProgress < 1.0f) {
143 }
144
145 ttlet animatedValue = to_float(value, _animation_duration);
146
147 ttlet positionedSliderRectangle = translate2(_slider_move_range * animatedValue, 0.0f) * _slider_rectangle;
148
149 if (*value) {
150 if (*enabled && window.active) {
151 drawContext.line_color = theme::global->accentColor;
152 }
153 } else {
154 if (*enabled && window.active) {
155 drawContext.line_color =
156 _hover ? theme::global->borderColor(_semantic_layer + 1) : theme::global->borderColor(_semantic_layer);
157 }
158 }
159 std::swap(drawContext.line_color, drawContext.fill_color);
160 drawContext.transform = translate3{0.0f, 0.0f, 0.1f} * drawContext.transform;
161 drawContext.corner_shapes = f32x4::broadcast(positionedSliderRectangle.height() * 0.5f);
162 drawContext.draw_box_with_border_inside(positionedSliderRectangle);
163 }
164
165 void draw_label(draw_context drawContext) noexcept
166 {
167 tt_axiom(gui_system_mutex.recurse_lock_count());
168
169 if (*enabled) {
170 drawContext.line_color = theme::global->labelStyle.color;
171 }
172
173 ttlet &label_stencil = *value ? _on_label_stencil : _off_label_stencil;
174
175 label_stencil->draw(drawContext, true);
176 }
177};
178
179} // namespace tt
Definition alignment.hpp:104
Draw context for drawing using the TTauri shaders.
Definition draw_context.hpp:33
Definition gui_window.hpp:39
std::atomic< bool > active
Definition gui_window.hpp:71
void request_redraw(aarect rectangle=aarect::infinity()) noexcept
Request a rectangle on the window to be redrawn.
Definition gui_window.hpp:115
Definition observable.hpp:20
float animation_progress(duration animation_duration) const noexcept
The relative time since the start of the animation.
Definition observable.hpp:108
int recurse_lock_count() const noexcept
This function should be used in tt_axiom() to check if the lock is held by current thread.
Definition unfair_recursive_mutex.hpp:60
An abstract boolean toggle button widget.
Definition abstract_bool_toggle_button_widget.hpp:14
Definition toggle_widget.hpp:20
bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept override
Update the constraints of the widget.
Definition toggle_widget.hpp:44
void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept override
Update the internal layout of the widget.
Definition toggle_widget.hpp:70
void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept override
Draw the widget.
Definition toggle_widget.hpp:97
float margin() const noexcept
Get the margin around the Widget.
Definition widget.hpp:128
virtual void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
Update the internal layout of the widget.
observable< bool > enabled
The widget is enabled.
Definition widget.hpp:105
gui_window & window
Convenient reference to the Window.
Definition widget.hpp:100
virtual void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
Draw the widget.
Definition widget.hpp:460
float base_line() const noexcept
Get the base-line in local coordinates.
Definition widget.hpp:350
virtual bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
Update the constraints of the widget.
abstract_container_widget const & parent() const noexcept
Get a reference to the parent.
virtual aarect window_clipping_rectangle() const noexcept
Get the clipping-rectangle in window coordinates.
Definition widget.hpp:320
aarect rectangle() const noexcept
Get the rectangle in local coordinates.
Definition widget.hpp:340
T max(T... args)
T move(T... args)
T swap(T... args)