HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
widget_intf.hpp
1// Copyright Take Vos 2023.
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 "hitbox.hpp"
8#include "widget_layout.hpp"
9#include "widget_id.hpp"
10#include "widget_state.hpp"
11#include "keyboard_focus_group.hpp"
12#include "../layout/layout.hpp"
13#include "../GFX/GFX.hpp"
14#include "../telemetry/telemetry.hpp"
15#include "../macros.hpp"
16#include <coroutine>
17
18hi_export_module(hikogui.GUI : widget_intf);
19
20hi_export namespace hi {
21inline namespace v1 {
22class gui_window;
23
25public:
30 widget_id id = {};
31
35 widget_intf *parent = nullptr;
36
40
44
45 virtual ~widget_intf()
46 {
47 release_widget_id(id);
48 }
49
50 widget_intf(widget_intf const *parent) noexcept :
51 id(make_widget_id()), parent(const_cast<widget_intf *>(parent))
52 {
53 // This lambda allows the state to be set once before it will trigger
54 // notifications.
55 _state_cbt = state.subscribe([&](widget_state new_state) {
56 static std::optional<widget_state> old_state = std::nullopt;
57
58 if (old_state) {
59 if (need_reconstrain(*old_state, *state)) {
60 ++global_counter<"widget:state:reconstrain">;
62
63 } else if (need_relayout(*old_state, *state)) {
64 ++global_counter<"widget:state:relayout">;
66
67 } else if (need_redraw(*old_state, *state)) {
68 ++global_counter<"widget:state:redraw">;
70 }
71 }
72 old_state = *state;
73 });
74 }
75
78 template<forward_of<void()> Func>
79 [[nodiscard]] callback<void()> subscribe(Func&& func, callback_flags flags = callback_flags::synchronous) noexcept
80 {
81 return notifier.subscribe(std::forward<Func>(func), flags);
82 }
83
86 [[nodiscard]] auto operator co_await() const noexcept
87 {
88 return notifier.operator co_await();
89 }
90
91 [[nodiscard]] size_t layer() const noexcept
92 {
93 return state->layer();
94 }
95
96 void set_layer(size_t new_layer) noexcept
97 {
98 state->set_layer(new_layer);
99 }
100
101 [[nodiscard]] widget_mode mode() const noexcept
102 {
103 return state->mode();
104 }
105
106 void set_mode(widget_mode new_mode) noexcept
107 {
108 state->set_mode(new_mode);
109 }
110
111 [[nodiscard]] widget_value value() const noexcept
112 {
113 return state->value();
114 }
115
116 void set_value(widget_value new_value) noexcept
117 {
118 state->set_value(new_value);
119 }
120
121 [[nodiscard]] widget_phase phase() const noexcept
122 {
123 return state->phase();
124 }
125
126 void set_pressed(bool pressed) noexcept
127 {
128 state->set_pressed(pressed);
129 }
130
131 void set_hover(bool hover) noexcept
132 {
133 state->set_hover(hover);
134 }
135
136 void set_active(bool active) noexcept
137 {
138 state->set_active(active);
139 }
140
141 [[nodiscard]] bool focus() const noexcept
142 {
143 return state->focus();
144 }
145
146 void set_focus(bool new_focus) noexcept
147 {
148 state->set_focus(new_focus);
149 }
150
156 virtual void set_window(gui_window *window) noexcept = 0;
157
163 [[nodiscard]] virtual gui_window *window() const noexcept = 0;
164
167 [[nodiscard]] virtual generator<widget_intf&> children(bool include_invisible) noexcept = 0;
168
171 [[nodiscard]] virtual generator<widget_intf const&> children(bool include_invisible) const noexcept final
172 {
173 for (auto& child : const_cast<widget_intf *>(this)->children(include_invisible)) {
174 co_yield child;
175 }
176 }
177
189 [[nodiscard]] virtual box_constraints update_constraints() noexcept = 0;
190
202 virtual void set_layout(widget_layout const& context) noexcept = 0;
203
206 [[nodiscard]] widget_layout const& layout() const noexcept
207 {
208 return _layout;
209 }
210
225 virtual void draw(draw_context const& context) noexcept = 0;
226
234 [[nodiscard]] virtual hitbox hitbox_test(point2 position) const noexcept = 0;
235
239 [[nodiscard]] virtual bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept = 0;
240
243 virtual void request_redraw() const noexcept = 0;
244
247 virtual bool process_event(gui_event const& event) const noexcept = 0;
248
253 virtual bool handle_event(gui_event const& event) noexcept = 0;
254
263 gui_event const& event,
264 std::vector<widget_id> const& reject_list = std::vector<widget_id>{}) noexcept = 0;
265
280 [[nodiscard]] virtual widget_id find_next_widget(
281 widget_id current_keyboard_widget,
282 keyboard_focus_group group,
283 keyboard_focus_direction direction) const noexcept = 0;
284
288 [[nodiscard]] std::vector<widget_id> parent_chain() const noexcept
289 {
291
292 if (auto w = this) {
293 chain.push_back(w->id);
294 while (to_bool(w = w->parent)) {
295 chain.push_back(w->id);
296 }
297 }
298
299 return chain;
300 }
301
308 virtual void scroll_to_show(hi::aarectangle rectangle) noexcept = 0;
309
312 void scroll_to_show() noexcept
313 {
315 }
316
317protected:
318 callback<void(widget_state)> _state_cbt;
319
320 widget_layout _layout;
321};
322
323inline widget_intf *get_if(widget_intf *start, widget_id id, bool include_invisible) noexcept
324{
325 hi_assert_not_null(start);
326
327 if (start->id == id) {
328 return start;
329 }
330 for (auto& child : start->children(include_invisible)) {
331 if (auto const r = get_if(&child, id, include_invisible); r != nullptr) {
332 return r;
333 }
334 }
335 return nullptr;
336}
337
338inline widget_intf& get(widget_intf& start, widget_id id, bool include_invisible)
339{
340 if (auto r = get_if(std::addressof(start), id, include_invisible); r != nullptr) {
341 return *r;
342 }
343 throw not_found_error("get widget by id");
344}
345
346} // namespace v1
347} // namespace hi::v1
@ window_relayout
Request that widgets get laid out on the next frame.
@ window_reconstrain
Request that widget get constraint on the next frame.
@ rectangle
The gui_event has rectangle data.
widget_mode
The mode that the widget is operating at.
Definition widget_state.hpp:25
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Definition callback.hpp:77
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
A rectangle / parallelogram in 3D space.
Definition rectangle.hpp:25
Draw context for drawing using the HikoGUI shaders.
Definition draw_context_intf.hpp:209
A user interface event.
Definition gui_event.hpp:82
Definition widget_intf.hpp:24
notifier< void()> notifier
Notifier which is called after an action is completed by a widget.
Definition widget_intf.hpp:39
virtual gui_window * window() const noexcept=0
Get the window that the widget is owned by.
std::vector< widget_id > parent_chain() const noexcept
Get a list of parents of a given widget.
Definition widget_intf.hpp:288
virtual bool handle_event_recursive(gui_event const &event, std::vector< widget_id > const &reject_list=std::vector< widget_id >{}) noexcept=0
Handle command recursive.
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:30
virtual void request_redraw() const noexcept=0
Request the widget to be redrawn on the next frame.
widget_layout const & layout() const noexcept
Get the current layout for this widget.
Definition widget_intf.hpp:206
void scroll_to_show() noexcept
Scroll to show the important part of the widget.
Definition widget_intf.hpp:312
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:35
virtual bool process_event(gui_event const &event) const noexcept=0
Send a event to the window.
virtual bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept=0
Check if the widget will accept keyboard focus.
virtual box_constraints update_constraints() noexcept=0
Update the constraints of the widget.
virtual widget_id find_next_widget(widget_id current_keyboard_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept=0
Find the next widget that handles keyboard focus.
virtual void set_layout(widget_layout const &context) noexcept=0
Update the internal layout of the widget.
virtual void scroll_to_show(hi::aarectangle rectangle) noexcept=0
Scroll to show the given rectangle on the window.
virtual bool handle_event(gui_event const &event) noexcept=0
Handle command.
virtual hitbox hitbox_test(point2 position) const noexcept=0
Find the widget that is under the mouse cursor.
virtual generator< widget_intf & > children(bool include_invisible) noexcept=0
Get a list of child widgets.
virtual void draw(draw_context const &context) noexcept=0
Draw the widget.
virtual void set_window(gui_window *window) noexcept=0
Set the window for this tree of widgets.
callback< void()> subscribe(Func &&func, callback_flags flags=callback_flags::synchronous) noexcept
Subscribe a callback to be called when an action is completed by the widget.
Definition widget_intf.hpp:79
observer< widget_state > state
The current state of the widget.
Definition widget_intf.hpp:43
The layout of a widget.
Definition widget_layout.hpp:56
The state the widget is in.
Definition widget_state.hpp:104
2D constraints.
Definition box_constraints.hpp:25
A observer pointing to the whole or part of a observed_base.
Definition observer_intf.hpp:32
T addressof(T... args)
T push_back(T... args)