HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
Widget.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/GUI/Window_forward.hpp"
7#include "TTauri/GUI/GUIDevice_forward.hpp"
8#include "TTauri/GUI/MouseEvent.hpp"
9#include "TTauri/GUI/HitBox.hpp"
10#include "TTauri/GUI/KeyboardEvent.hpp"
11#include "TTauri/GUI/Theme.hpp"
12#include "TTauri/Text/ShapedText.hpp"
13#include "TTauri/Foundation/attributes.hpp"
14#include "TTauri/Foundation/Path.hpp"
15#include "TTauri/Foundation/R16G16B16A16SFloat.hpp"
16#include "TTauri/Foundation/R32G32SFloat.hpp"
17#include "TTauri/Foundation/URL.hpp"
18#include "TTauri/Foundation/pickle.hpp"
19#include "TTauri/Foundation/vspan.hpp"
20#include "TTauri/Foundation/utils.hpp"
21#include "TTauri/Foundation/Trigger.hpp"
22#include "TTauri/Foundation/cpu_utc_clock.hpp"
23#include "TTauri/Foundation/observable.hpp"
24#include <rhea/constraint.hpp>
25#include <limits>
26#include <memory>
27#include <vector>
28#include <mutex>
29#include <typeinfo>
30
31namespace tt {
32class DrawContext;
33}
34namespace tt::PipelineImage {
35struct Image;
36struct Vertex;
37}
38namespace tt::PipelineSDF {
39struct Vertex;
40}
41namespace tt::PipelineFlat {
42struct Vertex;
43}
44namespace tt::PipelineBox {
45struct Vertex;
46}
47
48namespace tt {
49
50
64class Widget {
65protected:
66 mutable std::recursive_mutex mutex;
67
70 Window &window;
71
75 Widget *parent;
76
78
83 Widget *content = nullptr;
84
87 mat fromWindowTransform;
88
91 mat toWindowTransform;
92
96 vec minimumExtent;
97
98 rhea::constraint minimumWidthConstraint;
99 rhea::constraint minimumHeightConstraint;
100
104 vec preferredExtent;
105
106 rhea::constraint preferredWidthConstraint;
107 rhea::constraint preferredHeightConstraint;
108
112 vec fixedExtent;
113
114 rhea::constraint fixedWidthConstraint;
115 rhea::constraint fixedHeightConstraint;
116
119 bool hover = false;
120
123 bool focus = false;
124
125public:
129 rhea::variable const left;
130 rhea::variable const bottom;
131 rhea::variable const width;
132 rhea::variable const height;
133
134 rhea::linear_expression const right = left + width;
135 rhea::linear_expression const centre = left + width * 0.5;
136 rhea::linear_expression const top = bottom + height;
137 rhea::linear_expression const middle = bottom + height * 0.5;
138
139 float elevation;
140
142 std::atomic<R32G32SFloat> _offsetFromParent;
143 std::atomic<R32G32SFloat> _offsetFromWindow;
144
145 mutable std::atomic<bool> forceLayout = true;
146 mutable std::atomic<bool> forceRedraw = true;
147
151
154 Widget(Window &window, Widget *parent, vec defaultExtent) noexcept;
155 virtual ~Widget();
156
157 Widget(const Widget &) = delete;
158 Widget &operator=(const Widget &) = delete;
159 Widget(Widget &&) = delete;
160 Widget &operator=(Widget &&) = delete;
161
165 virtual Widget &addWidget(Alignment alignment, std::unique_ptr<Widget> childWidget) noexcept;
166
171 template<typename T, typename... Args>
172 T &makeWidgetDirectly(Args &&... args) {
173 return static_cast<T &>(
174 addWidget(Alignment::TopLeft, std::make_unique<T>(window, this, std::forward<Args>(args)...))
175 );
176 }
177
182 template<typename T, typename... Args>
183 T &makeWidget(Args &&... args) {
184 if (content != nullptr) {
185 return content->makeWidget<T>(std::forward<Args>(args)...);
186 } else {
187 return makeWidgetDirectly<T>(std::forward<Args>(args)...);
188 }
189 }
190
195 template<typename T, typename... Args>
196 T &makeAlignedWidgetDirectly(Alignment alignement, Args &&... args) {
197 return static_cast<T &>(
198 addWidget(alignement, std::make_unique<T>(window, this, std::forward<Args>(args)...))
199 );
200 }
201
206 template<typename T, typename... Args>
207 T &makeAlignedWidget(Alignment alignment, Args &&... args) {
208 if (content != nullptr) {
209 return content->makeAlignedWidget<T>(alignment, std::forward<Args>(args)...);
210 } else {
211 return makeAlignedWidgetDirectly<T>(alignment, std::forward<Args>(args)...);
212 }
213 }
214
218 aarect makeWindowRectangle() const noexcept;
219
220 void setMinimumExtent(vec newMinimumExtent) noexcept;
221 void setMinimumExtent(float width, float height) noexcept;
222
223 void setPreferredExtent(vec newPreferredExtent) noexcept;
224
225 void setFixedExtent(vec newFixedExtent) noexcept;
226 void setFixedHeight(float height) noexcept;
227 void setFixedWidth(float width) noexcept;
228
229 rhea::constraint placeBelow(Widget const &rhs, float margin=theme->margin) const noexcept;
230 rhea::constraint placeAbove(Widget const &rhs, float margin=theme->margin) const noexcept;
231
232 rhea::constraint placeLeftOf(Widget const &rhs, float margin=theme->margin) const noexcept;
233
234 rhea::constraint placeRightOf(Widget const &rhs, float margin=theme->margin) const noexcept;
235
236 rhea::constraint placeAtTop(float margin=theme->margin) const noexcept;
237
238 rhea::constraint placeAtBottom(float margin=theme->margin) const noexcept;
239
240 rhea::constraint placeLeft(float margin=theme->margin) const noexcept;
241
242 rhea::constraint placeRight(float margin=theme->margin) const noexcept;
243
244
245 [[nodiscard]] vec extent() const noexcept {
246 return static_cast<vec>(_extent.load(std::memory_order::memory_order_relaxed));
247 }
248
249 void setExtent(vec rhs) noexcept {
250 _extent.store(R32G32SFloat{rhs}, std::memory_order::memory_order_relaxed);
251 }
252
253 [[nodiscard]] vec offsetFromParent() const noexcept {
254 return static_cast<vec>(_offsetFromParent.load(std::memory_order::memory_order_relaxed));
255 }
256
257 void setOffsetFromParent(vec rhs) noexcept {
258 _offsetFromParent.store(R32G32SFloat{rhs}, std::memory_order::memory_order_relaxed);
259 }
260
261 [[nodiscard]] vec offsetFromWindow() const noexcept {
262 return static_cast<vec>(_offsetFromWindow.load(std::memory_order::memory_order_relaxed));
263 }
264
265 void setOffsetFromWindow(vec rhs) noexcept {
266 _offsetFromWindow.store(R32G32SFloat{rhs}, std::memory_order::memory_order_relaxed);
267 }
268
273 [[nodiscard]] aarect rectangle() const noexcept {
274 return aarect{extent()};
275 }
276
281 [[nodiscard]] aarect windowRectangle() const noexcept {
282 return {
283 vec::origin() + offsetFromWindow(),
284 vec{extent()}
285 };
286 }
287
292 [[nodiscard]] aarect clippingRectangle() const noexcept {
293 return expand(windowRectangle(), Theme::margin);
294 }
295
296 [[nodiscard]] GUIDevice *device() const noexcept;
297
302 [[nodiscard]] virtual HitBox hitBoxTest(vec position) const noexcept;
303
308 [[nodiscard]] virtual bool acceptsFocus() const noexcept {
309 return false;
310 }
311
314 [[nodiscard]] ssize_t nestingLevel() noexcept {
315 return numeric_cast<ssize_t>(elevation);
316 }
317
320 [[nodiscard]] float z() noexcept {
321 return elevation * 0.01f;
322 }
323
332 [[nodiscard]] virtual int needs(hires_utc_clock::time_point displayTimePoint) noexcept;
333
339 virtual void layout(hires_utc_clock::time_point displayTimePoint) noexcept;
340
347 [[nodiscard]] int layoutChildren(hires_utc_clock::time_point displayTimePoint, bool force) noexcept;
348
359 virtual void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept;
360
365 virtual void handleCommand(string_ltag command) noexcept;
366
374 virtual void handleMouseEvent(MouseEvent const &event) noexcept {
375 auto lock = std::scoped_lock(mutex);
376
377 if (event.type == MouseEvent::Type::Entered) {
378 hover = true;
379 forceRedraw = true;
380 } else if (event.type == MouseEvent::Type::Exited) {
381 hover = false;
382 forceRedraw = true;
383 }
384 }
385
386 [[nodiscard]] std::vector<Widget *> childPointers(bool reverse) const noexcept;
387
388 [[nodiscard]] virtual Widget *nextKeyboardWidget(Widget const *currentKeyboardWidget, bool reverse) const noexcept;
389
395 virtual void handleKeyboardEvent(KeyboardEvent const &event) noexcept {
396 auto lock = std::scoped_lock(mutex);
397
398 switch (event.type) {
400 focus = true;
401 forceRedraw = true;
402 break;
403
405 focus = false;
406 forceRedraw = true;
407 break;
408
410 for (ttlet command : event.getCommands()) {
411 handleCommand(command);
412 }
413 break;
414
415 default:;
416 }
417 }
418};
419
420inline Widget * const foundWidgetPtr = reinterpret_cast<Widget *>(1);
421
422}
Class which represents an axis-aligned rectangle.
Definition aarect.hpp:13
A 4x4 matrix.
Definition mat.hpp:18
Definition observable.hpp:20
Definition R32G32SFloat.hpp:13
A 4D vector.
Definition vec.hpp:37
static tt_force_inline vec origin() noexcept
Get a origin vector(0.0, 0.0, 0.0, 1.0).
Definition vec.hpp:209
Draw context for drawing using the TTauri shaders.
Definition DrawContext.hpp:30
Definition GUIDevice_vulkan.hpp:22
Definition HitBox.hpp:12
Definition KeyboardEvent.hpp:37
@ Exited
Keyboard focus was taken away.
@ Key
Key (+modifiers) was used to send a key.
@ Entered
Keyboard focus was given.
Definition MouseEvent.hpp:12
static constexpr float margin
Distance between widgets and between widgets and the border of the container.
Definition Theme.hpp:33
Definition Window_vulkan_win32.hpp:15
Definition Widget.hpp:64
float z() noexcept
Get z value for compositing order.
Definition Widget.hpp:320
virtual void handleCommand(string_ltag command) noexcept
Handle command.
virtual void handleKeyboardEvent(KeyboardEvent const &event) noexcept
Definition Widget.hpp:395
Widget(Window &window, Widget *parent, vec defaultExtent) noexcept
T & makeAlignedWidget(Alignment alignment, Args &&... args)
Add a widget directly to this widget.
Definition Widget.hpp:207
observable< bool > enabled
The widget is enabled.
Definition Widget.hpp:150
ssize_t nestingLevel() noexcept
Get nesting level used for selecting colors for the widget.
Definition Widget.hpp:314
virtual void handleMouseEvent(MouseEvent const &event) noexcept
Definition Widget.hpp:374
aarect makeWindowRectangle() const noexcept
Create a window rectangle from left, bottom, width and height Thread-safety: locks window....
virtual void layout(hires_utc_clock::time_point displayTimePoint) noexcept
Layout the widget.
T & makeAlignedWidgetDirectly(Alignment alignement, Args &&... args)
Add a widget directly to this widget.
Definition Widget.hpp:196
T & makeWidgetDirectly(Args &&... args)
Add a widget directly to this widget.
Definition Widget.hpp:172
virtual Widget & addWidget(Alignment alignment, std::unique_ptr< Widget > childWidget) noexcept
Add a widget directly to this widget.
virtual void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept
Draw widget.
virtual int needs(hires_utc_clock::time_point displayTimePoint) noexcept
Request the needs of the widget.
aarect clippingRectangle() const noexcept
Get the clipping-rectangle in window coordinates.
Definition Widget.hpp:292
T & makeWidget(Args &&... args)
Add a widget directly to this widget.
Definition Widget.hpp:183
virtual HitBox hitBoxTest(vec position) const noexcept
Find the widget that is under the mouse cursor.
virtual bool acceptsFocus() const noexcept
Check if the widget will accept keyboard focus.
Definition Widget.hpp:308
aarect rectangle() const noexcept
Get the rectangle in local coordinates.
Definition Widget.hpp:273
aarect windowRectangle() const noexcept
Get the rectangle in window coordinates.
Definition Widget.hpp:281
int layoutChildren(hires_utc_clock::time_point displayTimePoint, bool force) noexcept
Layout children of this widget.
rhea::variable const left
Location of the frame compared to the window.
Definition Widget.hpp:129
T load(T... args)
T store(T... args)