7#include "widget_id.hpp"
8#include "widget_mode.hpp"
9#include "widget_state.hpp"
10#include "widget_layout.hpp"
12#include "keyboard_focus_group.hpp"
14#include "widget_draw_context.hpp"
15#include "../theme/module.hpp"
16#include "../geometry/module.hpp"
17#include "../layout/module.hpp"
18#include "../observer.hpp"
19#include "../generator.hpp"
22namespace hi {
inline namespace v1 {
28 using callback_token = notifier<void()>::callback_token;
29 using awaiter_type = notifier<void()>::awaiter_type;
94 _mode_cbt =
mode.subscribe([&](
auto...) {
95 ++global_counter<
"widget:mode:constrain">;
100 widget(widget
const&) =
delete;
101 widget(widget&&) =
delete;
102 widget& operator=(widget&&) =
delete;
103 widget& operator=(widget
const&) =
delete;
107 [[nodiscard]]
virtual generator<widget const&>
children(
bool include_invisible)
const noexcept
112 [[nodiscard]] generator<widget&>
children(
bool include_invisible)
noexcept
114 for (
auto& child : const_cast<
widget const *>(this)->
children(include_invisible)) {
115 co_yield const_cast<widget&
>(child);
126 [[nodiscard]]
virtual hitbox
hitbox_test(point2 position)
const noexcept
173 virtual void layout() noexcept {}
193 auto s = theme_state{};
195 s |= theme_state::disabled;
197 s |= theme_state::active;
199 s |= theme_state::hover;
201 s |= theme_state::enabled;
205 s |= theme_state::focus;
209 s |= theme_state::on;
212 s |=
static_cast<theme_state
>((
semantic_layer % 4) * to_underlying(theme_state::layer_1));
213 return sub_theme_selector_type{s, _scale};
216 virtual bool process_event(gui_event
const& event)
const noexcept
219 return parent->process_event(event);
240 switch (event.type()) {
245 ++global_counter<
"widget:keyboard_enter:redraw">;
251 ++global_counter<
"widget:keyboard_exit:redraw">;
257 ++global_counter<
"widget:mouse_enter:redraw">;
263 ++global_counter<
"widget:mouse_exit:redraw">;
267 case gui_widget_next:
269 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::normal, keyboard_focus_direction::forward));
272 case gui_widget_prev:
274 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::normal, keyboard_focus_direction::backward));
277 case gui_activate_next:
278 process_event(gui_activate);
279 return process_event(gui_widget_next);
281 case gui_event_type::gui_toolbar_next:
283 not is_last(keyboard_focus_group::toolbar)) {
285 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::toolbar, keyboard_focus_direction::forward));
290 case gui_event_type::gui_toolbar_prev:
292 not is_first(keyboard_focus_group::toolbar)) {
294 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::toolbar, keyboard_focus_direction::backward));
317 auto handled =
false;
319 for (
auto& child :
children(false)) {
320 handled |= child.handle_event_recursive(event, reject_list);
323 if (not std::ranges::any_of(reject_list, [&](
hilet& x) {
346 widget_id current_keyboard_widget,
347 keyboard_focus_group group,
348 keyboard_focus_direction direction)
const noexcept
358 }
else if (current_keyboard_widget ==
id) {
363 for (
auto& child :
children(
false)) {
367 if (direction == keyboard_focus_direction::backward) {
371 for (
auto *child : children_) {
376 if (
auto tmp = child->find_next_widget({}, group, direction)) {
381 auto tmp = child->find_next_widget(current_keyboard_widget, group, direction);
382 if (tmp == current_keyboard_widget) {
387 }
else if (tmp !=
nullptr) {
399 return current_keyboard_widget;
405 [[nodiscard]] widget_id find_first_widget(keyboard_focus_group group)
const noexcept
409 for (
auto& child :
children(false)) {
410 if (child.accepts_keyboard_focus(group)) {
417 [[nodiscard]] widget_id find_last_widget(keyboard_focus_group group)
const noexcept
421 auto found = widget_id{};
422 for (
auto& child :
children(false)) {
423 if (child.accepts_keyboard_focus(group)) {
431 [[nodiscard]]
bool is_first(keyboard_focus_group group)
const noexcept
434 return parent->find_first_widget(group) ==
id;
437 [[nodiscard]]
bool is_last(keyboard_focus_group group)
const noexcept
440 return parent->find_last_widget(group) ==
id;
469 while (to_bool(w = w->parent)) {
487 template<forward_of<
void()> Callback>
488 [[nodiscard]] callback_token subscribe(Callback&& callback, callback_flags flags = callback_flags::synchronous)
const noexcept
490 return _state_changed.subscribe(std::forward<Callback>(callback), flags);
493 [[nodiscard]] awaiter_type
operator co_await()
const noexcept
495 return _state_changed.operator
co_await();
509 mutable notifier<void()> _state_changed;
520 [[nodiscard]] aarectangle make_overlay_rectangle(aarectangle requested_rectangle)
const noexcept
525 hilet requested_window_rectangle = translate2{layout.clipping_rectangle_on_window()} * requested_rectangle;
527 hilet window_bounds = aarectangle{layout.window_size} -
theme<
"window">.margin(
this);
528 hilet response_window_rectangle =
fit(window_bounds, requested_window_rectangle);
529 return layout.from_window * response_window_rectangle;
533 decltype(
mode)::callback_token _mode_cbt;
536inline widget *get_if(widget *start, widget_id
id,
bool include_invisible)
noexcept
540 if (start->id ==
id) {
543 for (
auto& child : start->children(include_invisible)) {
544 if (
hilet r = get_if(&child,
id, include_invisible); r !=
nullptr) {
551inline widget& get(widget& start, widget_id
id,
bool include_invisible)
553 if (
auto r = get_if(
std::addressof(start),
id, include_invisible); r !=
nullptr) {
556 throw not_found_error(
"get widget by id");
559template<std::invocable<w
idget&> F>
560inline void apply(widget& start,
bool include_invisible, F
const& f)
562 for (
auto& child : start.children(include_invisible)) {
563 apply(child, include_invisible, f);
568template<std::invocable<w
idget&> F>
569inline void apply(widget& start, F
const& f)
571 return apply(start,
true, f);
Definition of GUI event types.
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:238
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:272
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ end
Start from the end of the file.
@ begin
Start from the beginning of the file.
gui_event_type
GUI event type.
Definition gui_event_type.hpp:21
@ window_redraw
Request that part of the window gets redrawn on the next frame.
@ window_reconstrain
Request that widget get constraint on the next frame.
@ rectangle
The gui_event has rectangle data.
@ disabled
The widget is disabled.
@ partial
A widget is partially enabled.
@ enabled
The widget is fully enabled.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
aarectangle fit(aarectangle const &bounds, aarectangle const &rectangle) noexcept
Make a rectangle fit inside bounds.
@ off
The widget in the off-state.
auto theme
A tagged global variable to a theme model for a widget's component.
Definition theme_model.hpp:545
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:27
A user interface event.
Definition gui_event.hpp:75
virtual void draw(widget_draw_context &context) noexcept
Draw the widget.
Definition widget.hpp:189
virtual void scroll_to_show(hi::aarectangle rectangle) noexcept
Scroll to show the given rectangle on the window.
Definition widget.hpp:449
widget_id id
The numeric identifier of a widget.
Definition widget.hpp:35
observer< bool > hover
Mouse cursor is hovering over the widget.
Definition widget.hpp:53
virtual hitbox hitbox_test(point2 position) const noexcept
Find the widget that is under the mouse cursor.
Definition widget.hpp:126
virtual hitbox hitbox_test_from_parent(point2 position, hitbox sibling_hitbox) const noexcept
Call hitbox_test from a parent widget.
Definition widget.hpp:149
virtual void request_redraw() const noexcept
Request the widget to be redrawn on the next frame.
Definition widget.hpp:227
virtual bool handle_event_recursive(gui_event const &event, std::vector< widget_id > const &reject_list=std::vector< widget_id >{}) noexcept
Handle command recursive.
Definition widget.hpp:313
void reset_layout(gfx_surface *new_surface, float new_scale) noexcept
Reset the layout.
Definition widget.hpp:166
virtual generator< widget const & > children(bool include_invisible) const noexcept
Get a list of child widgets.
Definition widget.hpp:107
virtual bool is_tab_button() const noexcept
Check if this widget is a tab-button.
Definition widget.hpp:482
observer< bool > clicked
The widget is being clicked by the mouse.
Definition widget.hpp:57
gfx_surface * surface
The surface this widget is drawn on.
Definition widget.hpp:44
virtual bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept
Check if the widget will accept keyboard focus.
Definition widget.hpp:157
observer< widget_state > state
The state of the widget.
Definition widget.hpp:65
virtual bool handle_event(gui_event const &event) noexcept
Handle command.
Definition widget.hpp:236
virtual widget_id find_next_widget(widget_id current_keyboard_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept
Find the next widget that handles keyboard focus.
Definition widget.hpp:345
std::vector< widget_id > parent_chain() const noexcept
Get a list of parents of a given widget.
Definition widget.hpp:461
virtual hitbox hitbox_test_from_parent(point2 position) const noexcept
Call hitbox_test from a parent widget.
Definition widget.hpp:137
widget * parent
Pointer to the parent widget.
Definition widget.hpp:40
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:49
observer< bool > focus
The widget has keyboard focus.
Definition widget.hpp:61
size_t semantic_layer
The draw layer of the widget.
Definition widget.hpp:81
Draw context for drawing using the HikoGUI shaders.
Definition widget_draw_context.hpp:204
A cell in a grid.
Definition grid_cell.hpp:141
Definition theme_model.hpp:259