HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
abstract_container_widget.hpp
1// Copyright Take Vos 2020-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 "widget.hpp"
8
9namespace tt {
10
12public:
13 using super = widget;
14
17 {
18 if (parent) {
19 // Most containers will not draw itself, only its children.
20 ttlet lock = std::scoped_lock(gui_system_mutex);
21 _semantic_layer = parent->semantic_layer();
22 }
23 _margin = 0.0f;
24 }
25
27
30 void clear() noexcept
31 {
32 _children.clear();
33 _request_reconstrain = true;
34 }
35
40 {
41 ttlet lock = std::scoped_lock(gui_system_mutex);
42
43 tt_axiom(&widget->parent() == this);
44 _children.push_back(widget);
45 _request_reconstrain = true;
46 window.requestLayout = true;
47 return widget;
48 }
49
50 [[nodiscard]] widget &front() noexcept
51 {
52 return *_children.front();
53 }
54
55 [[nodiscard]] widget const &front() const noexcept
56 {
57 return *_children.front();
58 }
59
60 [[nodiscard]] widget &back() noexcept
61 {
62 return *_children.back();
63 }
64
65 [[nodiscard]] widget const &back() const noexcept
66 {
67 return *_children.back();
68 }
69
70 [[nodiscard]] std::shared_ptr<abstract_container_widget const> shared_from_this() const noexcept
71 {
72 return std::static_pointer_cast<abstract_container_widget const>(super::shared_from_this());
73 }
74
75 [[nodiscard]] std::shared_ptr<abstract_container_widget> shared_from_this() noexcept
76 {
77 return std::static_pointer_cast<abstract_container_widget>(super::shared_from_this());
78 }
79
82 template<typename T, typename... Args>
84 {
85 auto tmp = std::make_shared<T>(
86 window, shared_from_this(), std::forward<Args>(args)...);
87 tmp->init();
88 return std::static_pointer_cast<T>(add_widget(std::move(tmp)));
89 }
90
91 [[nodiscard]] virtual bool is_toolbar() const noexcept
92 {
93 return parent().is_toolbar();
94 }
95
96 [[nodiscard]] bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
97 {
98 tt_axiom(gui_system_mutex.recurse_lock_count());
99
100 auto has_constrainted = super::update_constraints(display_time_point, need_reconstrain);
101
102 for (auto &&child : _children) {
103 tt_axiom(child);
104 tt_axiom(&child->parent() == this);
105 has_constrainted |= child->update_constraints(display_time_point, need_reconstrain);
106 }
107
108 return has_constrainted;
109 }
110
111 void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
112 {
113 tt_axiom(gui_system_mutex.recurse_lock_count());
114
115 need_layout |= std::exchange(_request_relayout, false);
116 for (auto &&child : _children) {
117 tt_axiom(child);
118 tt_axiom(&child->parent() == this);
119 child->update_layout(display_time_point, need_layout);
120 }
121
122 super::update_layout(display_time_point, need_layout);
123 }
124
125 void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
126 {
127 tt_axiom(gui_system_mutex.recurse_lock_count());
128
129 for (auto &child : _children) {
130 tt_axiom(child);
131 tt_axiom(&child->parent() == this);
132 child->draw(child->make_draw_context(context), display_time_point);
133 }
134
135 super::draw(std::move(context), display_time_point);
136 }
137
138 bool handle_command_recursive(command command, std::vector<std::shared_ptr<widget>> const &reject_list) noexcept override
139 {
140 tt_axiom(gui_system_mutex.recurse_lock_count());
141
142 auto handled = false;
143 for (auto &child : _children) {
144 tt_axiom(child);
145 tt_axiom(&child->parent() == this);
146 handled |= child->handle_command_recursive(command, reject_list);
147 }
148 handled |= super::handle_command_recursive(command, reject_list);
149 return handled;
150 }
151
152 hit_box hitbox_test(f32x4 window_position) const noexcept
153 {
154 ttlet lock = std::scoped_lock(gui_system_mutex);
155
156 auto r = hit_box{};
157 for (ttlet &child : _children) {
158 tt_axiom(child);
159 tt_axiom(&child->parent() == this);
160 r = std::max(r, child->hitbox_test(window_position));
161 }
162 return r;
163 }
164
165 std::shared_ptr<widget const> find_first_widget(keyboard_focus_group group) const noexcept
166 {
167 for (ttlet child : _children) {
168 if (child->accepts_keyboard_focus(group)) {
169 return child;
170 }
171 }
172 return {};
173 }
174
175 std::shared_ptr<widget const> find_last_widget(keyboard_focus_group group) const noexcept
176 {
177 for (ttlet child : std::views::reverse(_children)) {
178 if (child->accepts_keyboard_focus(group)) {
179 return child;
180 }
181 }
182 return {};
183 }
184
186 std::shared_ptr<widget> const &current_keyboard_widget,
187 keyboard_focus_group group,
188 keyboard_focus_direction direction) const noexcept
189 {
190 ttlet lock = std::scoped_lock(gui_system_mutex);
191 tt_axiom(direction != keyboard_focus_direction::current);
192
193 // If current_keyboard_widget is empty, then we need to find the first widget that accepts focus.
194 auto found = !current_keyboard_widget;
195
196 // The container widget itself accepts focus.
197 if (found && direction == keyboard_focus_direction::forward && accepts_keyboard_focus(group)) {
198 return std::const_pointer_cast<widget>(super::shared_from_this());
199 }
200
201 ssize_t first = direction == keyboard_focus_direction::forward ? 0 : ssize(_children) - 1;
202 ssize_t last = direction == keyboard_focus_direction::forward ? ssize(_children) : -1;
203 ssize_t step = direction == keyboard_focus_direction::forward ? 1 : -1;
204 for (ssize_t i = first; i != last; i += step) {
205 auto &&child = _children[i];
206 tt_axiom(child);
207
208 if (found) {
209 // Find the first focus accepting widget.
210 if (auto tmp = child->find_next_widget({}, group, direction)) {
211 return tmp;
212 }
213
214 } else {
215 auto tmp = child->find_next_widget(current_keyboard_widget, group, direction);
216 if (tmp == current_keyboard_widget) {
217 // The current widget was found, but no next widget available in the child.
218 found = true;
219
220 } else if (tmp) {
221 return tmp;
222 }
223 }
224 }
225
226 // The container widget itself accepts focus.
227 if (found && direction == keyboard_focus_direction::backward && accepts_keyboard_focus(group)) {
228 return std::const_pointer_cast<widget>(super::shared_from_this());
229 }
230
231 return found ? current_keyboard_widget : std::shared_ptr<widget>{};
232 }
233
234protected:
236};
237
238} // namespace tt
STL namespace.
Draw context for drawing using the TTauri shaders.
Definition draw_context.hpp:33
Definition gui_window.hpp:39
std::atomic< bool > requestLayout
When set to true the widgets will be layed out.
Definition gui_window.hpp:56
Definition hit_box.hpp:15
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
std::shared_ptr< T > make_widget(Args &&...args)
Add a widget directly to this widget.
Definition abstract_container_widget.hpp:83
void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
Update the internal layout of the widget.
Definition abstract_container_widget.hpp:111
void clear() noexcept
Remove and deallocate all child widgets.
Definition abstract_container_widget.hpp:30
void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
Draw the widget.
Definition abstract_container_widget.hpp:125
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.
Definition abstract_container_widget.hpp:185
hit_box hitbox_test(f32x4 window_position) const noexcept
Find the widget that is under the mouse cursor.
Definition abstract_container_widget.hpp:152
bool handle_command_recursive(command command, std::vector< std::shared_ptr< widget > > const &reject_list) noexcept override
Handle command recursive.
Definition abstract_container_widget.hpp:138
std::shared_ptr< widget > add_widget(std::shared_ptr< widget > widget) noexcept
Add a widget directly to this widget.
Definition abstract_container_widget.hpp:39
bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
Update the constraints of the widget.
Definition abstract_container_widget.hpp:96
Definition widget.hpp:96
virtual void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
Update the internal layout of the widget.
virtual bool handle_command_recursive(command command, std::vector< std::shared_ptr< widget > > const &reject_list) noexcept
Handle command recursive.
widget(gui_window &window, std::shared_ptr< abstract_container_widget > parent) noexcept
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
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:381
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
T max(T... args)
T move(T... args)
T reverse(T... args)