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>(window, shared_from_this(), std::forward<Args>(args)...);
86 tmp->init();
87 return std::static_pointer_cast<T>(add_widget(std::move(tmp)));
88 }
89
90 [[nodiscard]] virtual bool is_toolbar() const noexcept
91 {
92 return parent().is_toolbar();
93 }
94
95 [[nodiscard]] bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
96 {
97 tt_axiom(gui_system_mutex.recurse_lock_count());
98
99 auto has_constrainted = super::update_constraints(display_time_point, need_reconstrain);
100
101 for (auto &&child : _children) {
102 tt_axiom(child);
103 tt_axiom(&child->parent() == this);
104 has_constrainted |= child->update_constraints(display_time_point, need_reconstrain);
105 }
106
107 return has_constrainted;
108 }
109
110 void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
111 {
112 tt_axiom(gui_system_mutex.recurse_lock_count());
113
114 need_layout |= std::exchange(_request_relayout, false);
115 for (auto &&child : _children) {
116 tt_axiom(child);
117 tt_axiom(&child->parent() == this);
118 child->update_layout(display_time_point, need_layout);
119 }
120
121 super::update_layout(display_time_point, need_layout);
122 }
123
124 void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
125 {
126 tt_axiom(gui_system_mutex.recurse_lock_count());
127
128 for (auto &child : _children) {
129 tt_axiom(child);
130 tt_axiom(&child->parent() == this);
131
132 auto child_context =
133 context.make_child_context(child->parent_to_local(), child->local_to_window(), child->clipping_rectangle());
134 child->draw(child_context, display_time_point);
135 }
136
137 super::draw(std::move(context), display_time_point);
138 }
139
140 bool handle_command_recursive(command command, std::vector<std::shared_ptr<widget>> const &reject_list) noexcept override
141 {
142 tt_axiom(gui_system_mutex.recurse_lock_count());
143
144 auto handled = false;
145 for (auto &child : _children) {
146 tt_axiom(child);
147 tt_axiom(&child->parent() == this);
148 handled |= child->handle_command_recursive(command, reject_list);
149 }
150 handled |= super::handle_command_recursive(command, reject_list);
151 return handled;
152 }
153
154 [[nodiscard]] hit_box hitbox_test(point2 position) const noexcept override
155 {
156 tt_axiom(gui_system_mutex.recurse_lock_count());
157
158 auto r = hit_box{};
159 for (ttlet &child : _children) {
160 tt_axiom(child);
161 tt_axiom(&child->parent() == this);
162 r = std::max(r, child->hitbox_test(point2{child->parent_to_local() * position}));
163 }
164 return r;
165 }
166
167 std::shared_ptr<widget const> find_first_widget(keyboard_focus_group group) const noexcept
168 {
169 for (ttlet child : _children) {
170 if (child->accepts_keyboard_focus(group)) {
171 return child;
172 }
173 }
174 return {};
175 }
176
177 std::shared_ptr<widget const> find_last_widget(keyboard_focus_group group) const noexcept
178 {
179 for (ttlet child : std::views::reverse(_children)) {
180 if (child->accepts_keyboard_focus(group)) {
181 return child;
182 }
183 }
184 return {};
185 }
186
188 std::shared_ptr<widget> const &current_keyboard_widget,
189 keyboard_focus_group group,
190 keyboard_focus_direction direction) const noexcept
191 {
192 ttlet lock = std::scoped_lock(gui_system_mutex);
193 tt_axiom(direction != keyboard_focus_direction::current);
194
195 // If current_keyboard_widget is empty, then we need to find the first widget that accepts focus.
196 auto found = !current_keyboard_widget;
197
198 // The container widget itself accepts focus.
199 if (found && direction == keyboard_focus_direction::forward && accepts_keyboard_focus(group)) {
200 return std::const_pointer_cast<widget>(super::shared_from_this());
201 }
202
203 ssize_t first = direction == keyboard_focus_direction::forward ? 0 : ssize(_children) - 1;
204 ssize_t last = direction == keyboard_focus_direction::forward ? ssize(_children) : -1;
205 ssize_t step = direction == keyboard_focus_direction::forward ? 1 : -1;
206 for (ssize_t i = first; i != last; i += step) {
207 auto &&child = _children[i];
208 tt_axiom(child);
209
210 if (found) {
211 // Find the first focus accepting widget.
212 if (auto tmp = child->find_next_widget({}, group, direction)) {
213 return tmp;
214 }
215
216 } else {
217 auto tmp = child->find_next_widget(current_keyboard_widget, group, direction);
218 if (tmp == current_keyboard_widget) {
219 // The current widget was found, but no next widget available in the child.
220 found = true;
221
222 } else if (tmp) {
223 return tmp;
224 }
225 }
226 }
227
228 // The container widget itself accepts focus.
229 if (found && direction == keyboard_focus_direction::backward && accepts_keyboard_focus(group)) {
230 return std::const_pointer_cast<widget>(super::shared_from_this());
231 }
232
233 return found ? current_keyboard_widget : std::shared_ptr<widget>{};
234 }
235
236protected:
238};
239
240} // namespace tt
STL namespace.
Draw context for drawing using the TTauri shaders.
Definition draw_context.hpp:33
Definition gui_window.hpp:37
std::atomic< bool > requestLayout
When set to true the widgets will be layed out.
Definition gui_window.hpp:54
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:110
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:124
hit_box hitbox_test(point2 position) const noexcept override
Find the widget that is under the mouse cursor.
Definition abstract_container_widget.hpp:154
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:187
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:140
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:95
Definition widget.hpp:97
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:101
virtual void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
Draw the widget.
Definition widget.hpp:462
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
T max(T... args)
T move(T... args)
T reverse(T... args)