HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
checkbox_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_toggle_button_widget.hpp"
8#include "../stencils/label_stencil.hpp"
9#include "../GUI/draw_context.hpp"
10#include "../text/font_book.hpp"
11#include "../observable.hpp"
12#include "../label.hpp"
13#include <memory>
14#include <string>
15#include <array>
16#include <optional>
17#include <future>
18
19namespace tt {
20
25template<typename T>
27public:
29 using value_type = typename super::value_type;
30
31 observable<label> true_label;
32 observable<label> false_label;
33 observable<label> other_label;
34
35 template<typename Value = observable<value_type>>
39 value_type true_value,
40 value_type false_value,
41 Value &&value = {}) noexcept :
43 window,
44 parent,
45 std::move(true_value),
46 std::move(false_value),
47 std::forward<Value>(value))
48 {
49 }
50
51 void init() noexcept override
52 {
53 _true_label_callback = true_label.subscribe([this](auto...) {
54 this->_request_reconstrain = true;
55 });
56 _false_label_callback = false_label.subscribe([this](auto...) {
57 this->_request_reconstrain = true;
58 });
59 _other_label_callback = other_label.subscribe([this](auto...) {
60 this->_request_reconstrain = true;
61 });
62 }
63
64 [[nodiscard]] bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept override
65 {
66 tt_axiom(gui_system_mutex.recurse_lock_count());
67
68 if (super::update_constraints(display_time_point, need_reconstrain)) {
69 _true_label_stencil = stencil::make_unique(alignment::top_left, *true_label, theme::global->labelStyle);
70 _false_label_stencil = stencil::make_unique(alignment::top_left, *false_label, theme::global->labelStyle);
71 _other_label_stencil = stencil::make_unique(alignment::top_left, *other_label, theme::global->labelStyle);
72
73 ttlet minimum_height = std::max(
74 {_true_label_stencil->preferred_extent().height(),
75 _false_label_stencil->preferred_extent().height(),
76 _other_label_stencil->preferred_extent().height(),
77 theme::global->smallSize});
78
79 ttlet minimum_width_of_labels = std::max(
80 {_true_label_stencil->preferred_extent().width(),
81 _false_label_stencil->preferred_extent().width(),
82 _other_label_stencil->preferred_extent().width()});
83 ttlet minimum_width = theme::global->smallSize + theme::global->margin + minimum_width_of_labels;
84
85 this->_preferred_size = interval_vec2::make_minimum(minimum_width, minimum_height);
86 this->_preferred_base_line = relative_base_line{vertical_alignment::top, -theme::global->smallSize * 0.5f};
87
88 return true;
89 } else {
90 return false;
91 }
92 }
93
94 [[nodiscard]] void update_layout(hires_utc_clock::time_point displayTimePoint, bool need_layout) noexcept override
95 {
96 tt_axiom(gui_system_mutex.recurse_lock_count());
97
98 need_layout |= std::exchange(this->_request_relayout, false);
99 if (need_layout) {
100 _checkbox_rectangle = aarect{0.0f, this->base_line() - theme::global->smallSize * 0.5f, theme::global->smallSize, theme::global->smallSize};
101
102 ttlet label_x = _checkbox_rectangle.p3().x() + theme::global->margin;
103 _label_rectangle = aarect{label_x, 0.0f, this->rectangle().width() - label_x, this->rectangle().height()};
104 _true_label_stencil->set_layout_parameters(_label_rectangle, this->base_line());
105 _false_label_stencil->set_layout_parameters(_label_rectangle, this->base_line());
106 _other_label_stencil->set_layout_parameters(_label_rectangle, this->base_line());
107
108 _check_glyph = to_font_glyph_ids(elusive_icon::Ok);
109 ttlet check_glyph_bb = pipeline_SDF::device_shared::getBoundingBox(_check_glyph);
110 _check_glyph_rectangle =
111 align(_checkbox_rectangle, scale(check_glyph_bb, theme::global->small_icon_size), alignment::middle_center);
112
113 _minus_glyph = to_font_glyph_ids(elusive_icon::Minus);
114 ttlet minus_glyph_bb = pipeline_SDF::device_shared::getBoundingBox(_minus_glyph);
115 _minus_glyph_rectangle =
116 align(_checkbox_rectangle, scale(minus_glyph_bb, theme::global->small_icon_size), alignment::middle_center);
117 }
118
119 super::update_layout(displayTimePoint, need_layout);
120 }
121
122 void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept override
123 {
124 tt_axiom(gui_system_mutex.recurse_lock_count());
125
126 if (overlaps(context, this->window_clipping_rectangle())) {
127 draw_check_box(context);
128 draw_check_mark(context);
129 draw_label(context);
130 }
131
132 super::draw(std::move(context), display_time_point);
133 }
134
135private:
136 typename decltype(true_label)::callback_ptr_type _true_label_callback;
137 typename decltype(false_label)::callback_ptr_type _false_label_callback;
138 typename decltype(other_label)::callback_ptr_type _other_label_callback;
139
140 std::unique_ptr<label_stencil> _true_label_stencil;
141 std::unique_ptr<label_stencil> _false_label_stencil;
142 std::unique_ptr<label_stencil> _other_label_stencil;
143
144 font_glyph_ids _check_glyph;
145 aarect _check_glyph_rectangle;
146
147 font_glyph_ids _minus_glyph;
148 aarect _minus_glyph_rectangle;
149
150 aarect _checkbox_rectangle;
151
152 aarect _label_rectangle;
153
154 void draw_check_box(draw_context const &context) noexcept
155 {
156 tt_axiom(gui_system_mutex.recurse_lock_count());
157
158 context.draw_box_with_border_inside(_checkbox_rectangle);
159 }
160
161 void draw_check_mark(draw_context context) noexcept
162 {
163 tt_axiom(gui_system_mutex.recurse_lock_count());
164
165 context.transform = translate3{0.0, 0.0, 0.1f} * context.transform;
166
167 if (*this->enabled && this->window.active) {
168 context.line_color = theme::global->accentColor;
169 }
170
171 // Checkmark or tristate.
172 if (this->value == this->true_value) {
173 context.draw_glyph(_check_glyph, _check_glyph_rectangle);
174 } else if (this->value == this->false_value) {
175 ;
176 } else {
177 context.draw_glyph(_minus_glyph, _minus_glyph_rectangle);
178 }
179 }
180
181 void draw_label(draw_context context) noexcept
182 {
183 tt_axiom(gui_system_mutex.recurse_lock_count());
184
185 if (*this->enabled) {
186 context.line_color = theme::global->labelStyle.color;
187 }
188
189 ttlet &labelCell = this->value == this->true_value ?
190 _true_label_stencil :
191 this->value == this->false_value ? _false_label_stencil : _other_label_stencil;
192
193 labelCell->draw(context, true);
194 }
195};
196
197} // 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
static aarect getBoundingBox(font_glyph_ids const &glyphs) noexcept
Get the bounding box, including draw border of a glyph.
Definition observable.hpp:20
Definition font_glyph_ids.hpp:78
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 toggle button widget.
Definition abstract_toggle_button_widget.hpp:15
A checkbox widget.
Definition checkbox_widget.hpp:26
void update_layout(hires_utc_clock::time_point displayTimePoint, bool need_layout) noexcept override
Update the internal layout of the widget.
Definition checkbox_widget.hpp:94
void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept override
Draw the widget.
Definition checkbox_widget.hpp:122
bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept override
Update the constraints of the widget.
Definition checkbox_widget.hpp:64
void init() noexcept override
Should be called right after allocating and constructing a widget.
Definition checkbox_widget.hpp:51
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)