HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
widget.hpp
1// Copyright Take Vos 2019-2021.
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 "../GUI/gui_window.hpp"
8#include "../GUI/gui_device.hpp"
9#include "../GUI/mouse_event.hpp"
10#include "../GUI/hit_box.hpp"
11#include "../GUI/keyboard_event.hpp"
12#include "../GUI/theme.hpp"
13#include "../GUI/draw_context.hpp"
14#include "../GUI/keyboard_focus_direction.hpp"
15#include "../GUI/keyboard_focus_group.hpp"
16#include "../text/shaped_text.hpp"
17#include "../alignment.hpp"
18#include "../graphic_path.hpp"
19#include "../color/sfloat_rgba16.hpp"
20#include "../color/sfloat_rg32.hpp"
21#include "../geometry/transform.hpp"
22#include "../URL.hpp"
23#include "../vspan.hpp"
24#include "../utils.hpp"
25#include "../cpu_utc_clock.hpp"
26#include "../observable.hpp"
27#include "../command.hpp"
28#include "../unfair_recursive_mutex.hpp"
29#include "../interval_extent2.hpp"
30#include "../flow_layout.hpp"
31#include "../ranged_numeric.hpp"
32#include <limits>
33#include <memory>
34#include <vector>
35#include <mutex>
36#include <typeinfo>
37
38namespace tt::pipeline_image {
39struct Image;
40struct vertex;
41} // namespace tt::pipeline_image
42namespace tt::pipeline_SDF {
43struct vertex;
44}
45namespace tt::pipeline_flat {
46struct vertex;
47}
48namespace tt::pipeline_box {
49struct vertex;
50}
51
52namespace tt {
53class abstract_container_widget;
54
97class widget : public std::enable_shared_from_this<widget> {
98public:
102
106
110
111 virtual ~widget();
112 widget(const widget &) = delete;
113 widget &operator=(const widget &) = delete;
114 widget(widget &&) = delete;
115 widget &operator=(widget &&) = delete;
116
119 virtual void init() noexcept {}
120
128 [[nodiscard]] float margin() const noexcept
129 {
130 tt_axiom(gui_system_mutex.recurse_lock_count());
131 return _margin;
132 }
133
149 [[nodiscard]] float draw_layer() const noexcept
150 {
151 tt_axiom(gui_system_mutex.recurse_lock_count());
152 return _draw_layer;
153 }
154
165 [[nodiscard]] int logical_layer() const noexcept
166 {
167 tt_axiom(gui_system_mutex.recurse_lock_count());
168 return _logical_layer;
169 }
170
189 [[nodiscard]] int semantic_layer() const noexcept
190 {
191 tt_axiom(gui_system_mutex.recurse_lock_count());
192 return _semantic_layer;
193 }
194
204 [[nodiscard]] ranged_int<3> width_resistance() const noexcept
205 {
206 tt_axiom(gui_system_mutex.recurse_lock_count());
207 return _width_resistance;
208 }
209
219 [[nodiscard]] ranged_int<3> height_resistance() const noexcept
220 {
221 tt_axiom(gui_system_mutex.recurse_lock_count());
222 return _height_resistance;
223 }
224
233 [[nodiscard]] interval_extent2 preferred_size() const noexcept
234 {
235 tt_axiom(gui_system_mutex.recurse_lock_count());
236 return _preferred_size;
237 }
238
249 void
250 set_layout_parameters(geo::transformer auto const &local_to_parent, extent2 size, aarectangle const &clipping_rectangle) noexcept
251 {
252 tt_axiom(gui_system_mutex.recurse_lock_count());
253
254 _local_to_parent = local_to_parent;
255 _parent_to_local = ~local_to_parent;
256 if (auto parent = _parent.lock()) {
257 auto parent_ = reinterpret_cast<widget *>(parent.get());
258 _local_to_window = local_to_parent * parent_->local_to_window();
259 _window_to_local = ~local_to_parent * parent_->window_to_local();
260 } else {
261 _local_to_window = local_to_parent;
262 _window_to_local = ~local_to_parent;
263 }
264 _size = size;
265 _clipping_rectangle = clipping_rectangle;
266 _visible_rectangle = intersect(aarectangle{size}, clipping_rectangle);
267 }
268
269 void
270 set_layout_parameters_from_parent(aarectangle child_rectangle, aarectangle parent_clipping_rectangle, float draw_layer_delta) noexcept
271 {
272 tt_axiom(gui_system_mutex.recurse_lock_count());
273 tt_axiom(child_rectangle.extent() >= _preferred_size.minimum());
274
275 ttlet child_translate = translate2{child_rectangle};
276 ttlet child_size = child_rectangle.extent();
277 ttlet rectangle = aarectangle{child_size};
278 ttlet child_clipping_rectangle = intersect(~child_translate * parent_clipping_rectangle, expand(rectangle, margin()));
279
280 set_layout_parameters(translate_z(draw_layer_delta) * child_translate, child_size, child_clipping_rectangle);
281 }
282
283 void set_layout_parameters_from_parent(aarectangle child_rectangle) noexcept
284 {
285 tt_axiom(gui_system_mutex.recurse_lock_count());
286
287 if (auto parent = _parent.lock()) {
288 auto parent_ = reinterpret_cast<widget *>(parent.get());
289 ttlet draw_layer_delta = _draw_layer - parent_->draw_layer();
290 return set_layout_parameters_from_parent(child_rectangle, parent_->clipping_rectangle(), draw_layer_delta);
291 } else {
292 return set_layout_parameters_from_parent(child_rectangle, child_rectangle, 0.0f);
293 }
294 }
295
296 [[nodiscard]] matrix3 parent_to_local() const noexcept
297 {
298 tt_axiom(gui_system_mutex.recurse_lock_count());
299 return _parent_to_local;
300 }
301
302 [[nodiscard]] matrix3 local_to_parent() const noexcept
303 {
304 tt_axiom(gui_system_mutex.recurse_lock_count());
305 return _local_to_parent;
306 }
307
308 [[nodiscard]] matrix3 window_to_local() const noexcept
309 {
310 tt_axiom(gui_system_mutex.recurse_lock_count());
311 return _window_to_local;
312 }
313
314 [[nodiscard]] matrix3 local_to_window() const noexcept
315 {
316 tt_axiom(gui_system_mutex.recurse_lock_count());
317 return _local_to_window;
318 }
319
320 [[nodiscard]] extent2 size() const noexcept
321 {
322 tt_axiom(gui_system_mutex.recurse_lock_count());
323 return _size;
324 }
325
326 [[nodiscard]] float width() const noexcept
327 {
328 tt_axiom(gui_system_mutex.recurse_lock_count());
329 return _size.width();
330 }
331
332 [[nodiscard]] float height() const noexcept
333 {
334 tt_axiom(gui_system_mutex.recurse_lock_count());
335 return _size.height();
336 }
337
342 [[nodiscard]] aarectangle rectangle() const noexcept
343 {
344 tt_axiom(gui_system_mutex.recurse_lock_count());
345 return aarectangle{_size};
346 }
347
351 [[nodiscard]] virtual float base_line() const noexcept
352 {
353 return rectangle().middle();
354 }
355
356 [[nodiscard]] aarectangle clipping_rectangle() const noexcept
357 {
358 tt_axiom(gui_system_mutex.recurse_lock_count());
359 return _clipping_rectangle;
360 }
361
362 [[nodiscard]] gui_device *device() const noexcept;
363
371 [[nodiscard]] virtual hit_box hitbox_test(point2 position) const noexcept
372 {
373 tt_axiom(gui_system_mutex.recurse_lock_count());
374
375 if (_visible_rectangle.contains(position)) {
376 return hit_box{weak_from_this(), _draw_layer};
377 } else {
378 return {};
379 }
380 }
381
386 [[nodiscard]] virtual bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept
387 {
388 tt_axiom(gui_system_mutex.recurse_lock_count());
389 return false;
390 }
391
415 [[nodiscard]] virtual bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept;
416
435 [[nodiscard]] virtual void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept;
436
437 virtual [[nodiscard]] color background_color() const noexcept;
438
439 virtual [[nodiscard]] color foreground_color() const noexcept;
440
441 virtual [[nodiscard]] color focus_color() const noexcept;
442
443 virtual [[nodiscard]] color accent_color() const noexcept;
444
445 virtual [[nodiscard]] color label_color() const noexcept;
446
462 virtual void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
463 {
464 tt_axiom(gui_system_mutex.recurse_lock_count());
465 }
466
467 virtual void request_redraw() const noexcept
468 {
469 window.request_redraw(aarectangle{_local_to_window * _clipping_rectangle});
470 }
471
476 [[nodiscard]] virtual bool handle_event(command command) noexcept;
477
478 [[nodiscard]] virtual bool handle_event(std::vector<command> const &commands) noexcept
479 {
480 for (ttlet command : commands) {
481 if (handle_event(command)) {
482 return true;
483 }
484 }
485 return false;
486 }
487
495 [[nodiscard]] virtual bool
496 handle_command_recursive(command command, std::vector<std::shared_ptr<widget>> const &reject_list) noexcept;
497
512 [[nodiscard]] virtual bool handle_event(mouse_event const &event) noexcept;
513
520 [[nodiscard]] virtual bool handle_event(keyboard_event const &event) noexcept;
521
535 std::shared_ptr<widget> const &current_keyboard_widget,
536 keyboard_focus_group group,
537 keyboard_focus_direction direction) const noexcept;
538
542
545 [[nodiscard]] std::shared_ptr<abstract_container_widget> shared_parent() noexcept;
546
550 [[nodiscard]] abstract_container_widget const &parent() const noexcept;
551
555 [[nodiscard]] abstract_container_widget &parent() noexcept;
556
559 [[nodiscard]] bool is_first(keyboard_focus_group group) const noexcept;
560
563 [[nodiscard]] bool is_last(keyboard_focus_group group) const noexcept;
564
568 [[nodiscard]] static std::vector<std::shared_ptr<widget>>
569 parent_chain(std::shared_ptr<tt::widget> const &child_widget) noexcept;
570
571protected:
575 std::weak_ptr<abstract_container_widget> _parent;
576
579 bool _hover = false;
580
583 bool _focus = false;
584
587 matrix3 _window_to_local;
588
591 matrix3 _local_to_window;
592
595 matrix3 _parent_to_local;
596
599 matrix3 _local_to_parent;
600
603 extent2 _size;
604
607 aarectangle _clipping_rectangle;
608
614 aarectangle _visible_rectangle;
615
618 bool _request_reconstrain = true;
619
622 bool _request_relayout = true;
623
624 interval_extent2 _preferred_size;
625
626 ranged_int<3> _width_resistance = 1;
627 ranged_int<3> _height_resistance = 1;
628
629 float _margin = theme::global->margin;
630
640 float _draw_layer;
641
648 int _semantic_layer;
649
655 int _logical_layer;
656
657private:
658 typename decltype(enabled)::callback_ptr_type _enabled_callback;
659};
660
661} // namespace tt
STL namespace.
This is a RGBA floating point color.
Definition color.hpp:39
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:18
bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition axis_aligned_rectangle.hpp:222
float middle() const noexcept
The middle on the y-axis between bottom and top.
Definition axis_aligned_rectangle.hpp:194
constexpr float & width() noexcept
Access the x-as-width element from the extent.
Definition extent.hpp:91
constexpr float & height() noexcept
Access the y-as-height element from the extent.
Definition extent.hpp:102
Draw context for drawing using the TTauri shaders.
Definition draw_context.hpp:33
Definition gui_window.hpp:37
void request_redraw(aarectangle rectangle) noexcept
Request a rectangle on the window to be redrawn.
Definition gui_window.hpp:113
Definition hit_box.hpp:15
Definition keyboard_event.hpp:40
Definition mouse_event.hpp:15
Definition theme.hpp:17
Timestamp.
Definition hires_utc_clock.hpp:16
A 2D vector using interval arithmetic.
Definition interval_extent2.hpp:18
Definition observable.hpp:20
A ranged integer.
Definition ranged_numeric.hpp:21
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
Definition abstract_container_widget.hpp:11
Definition widget.hpp:97
bool is_last(keyboard_focus_group group) const noexcept
Is this widget the last widget in the parent container.
virtual void init() noexcept
Should be called right after allocating and constructing a widget.
Definition widget.hpp:119
virtual bool handle_event(mouse_event const &event) noexcept
float draw_layer() const noexcept
The first drawing layer of the widget.
Definition widget.hpp:149
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
virtual bool handle_command_recursive(command command, std::vector< std::shared_ptr< widget > > const &reject_list) noexcept
Handle command recursive.
int logical_layer() const noexcept
The logical layer of the widget.
Definition widget.hpp:165
widget(gui_window &window, std::shared_ptr< abstract_container_widget > parent) noexcept
ranged_int< 3 > width_resistance() const noexcept
Get the resistance in width.
Definition widget.hpp:204
virtual std::shared_ptr< widget > find_next_widget(std::shared_ptr< widget > const &current_keyboard_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept
Find the next widget that handles keyboard focus.
static std::vector< std::shared_ptr< widget > > parent_chain(std::shared_ptr< tt::widget > const &child_widget) noexcept
Get a list of parents of a given widget.
aarectangle rectangle() const noexcept
Get the rectangle in local coordinates.
Definition widget.hpp:342
virtual bool handle_event(command command) noexcept
Handle command.
gui_window & window
Convenient reference to the Window.
Definition widget.hpp:101
virtual float base_line() const noexcept
Return the base-line where the text should be located.
Definition widget.hpp:351
virtual void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
Draw the widget.
Definition widget.hpp:462
std::shared_ptr< abstract_container_widget const > shared_parent() const noexcept
Get a shared_ptr to the parent.
bool is_first(keyboard_focus_group group) const noexcept
Is this widget the first widget in the parent container.
virtual hit_box hitbox_test(point2 position) const noexcept
Find the widget that is under the mouse cursor.
Definition widget.hpp:371
interval_extent2 preferred_size() const noexcept
Get the size-range of the widget.
Definition widget.hpp:233
virtual bool handle_event(keyboard_event const &event) noexcept
Handle keyboard event.
virtual bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
Update the constraints of the widget.
virtual bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept
Check if the widget will accept keyboard focus.
Definition widget.hpp:386
abstract_container_widget const & parent() const noexcept
Get a reference to the parent.
int semantic_layer() const noexcept
The semantic layer of the widget.
Definition widget.hpp:189
ranged_int< 3 > height_resistance() const noexcept
Get the resistance in height.
Definition widget.hpp:219
void set_layout_parameters(geo::transformer auto const &local_to_parent, extent2 size, aarectangle const &clipping_rectangle) noexcept
Set the location and size of the widget inside the window.
Definition widget.hpp:250
Definition transform.hpp:83