HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
abstract_button_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
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
9#pragma once
10
11#include "button_delegate.hpp"
12#include "label_widget.hpp"
13#include "../GUI/module.hpp"
14#include "../utility/module.hpp"
15#include "../animator.hpp"
16#include "../notifier.hpp"
17#include <memory>
18#include <string>
19#include <array>
20#include <optional>
21#include <future>
22
23namespace hi { inline namespace v1 {
24
25template<typename Context>
27
32template<fixed_string Prefix>
34public:
35 using super = widget;
36 using delegate_type = button_delegate;
37
38 constexpr static auto prefix = Prefix;
39
43
46 observer<label> on_label = tr("on");
47
50 observer<label> off_label = tr("off");
51
54 observer<label> other_label = tr("other");
55
58 observer<hi::alignment> alignment;
59
61 {
63 delegate->deinit(*this);
64 }
65
68 {
69 hi_assert_not_null(this->delegate);
70
71 _on_label_widget = std::make_unique<label_widget<prefix / "on">>(this, on_label, alignment);
72 _off_label_widget = std::make_unique<label_widget<prefix / "off">>(this, off_label, alignment);
73 _other_label_widget = std::make_unique<label_widget<prefix / "other">>(this, other_label, alignment);
74
75 _delegate_cbt = this->delegate->subscribe([&] {
76 ++global_counter<"abstract_button_widget:delegate:redraw">;
77 hi_assert_not_null(this->delegate);
78 state = this->delegate->state(this);
79 process_event({gui_event_type::window_redraw});
80 });
81 this->delegate->init(*this);
82 }
83
85 [[nodiscard]] box_constraints update_constraints() noexcept override
86 {
87 _on_label_constraints = _on_label_widget->update_constraints();
88 _off_label_constraints = _off_label_widget->update_constraints();
89 _other_label_constraints = _other_label_widget->update_constraints();
90 return max(_on_label_constraints, _off_label_constraints, _other_label_constraints);
91 }
92
93 void set_layout(widget_layout const& context) noexcept override
94 {
97 _other_label_widget->mode = *state == widget_state::other ? widget_mode::display : widget_mode::invisible;
98
99 _on_label_widget->set_layout(context.transform(_on_label_shape));
100 _off_label_widget->set_layout(context.transform(_off_label_shape));
101 _other_label_widget->set_layout(context.transform(_other_label_shape));
102 }
103
104 [[nodiscard]] generator<widget const&> children(bool include_invisible) const noexcept override
105 {
106 co_yield *_on_label_widget;
107 co_yield *_off_label_widget;
108 co_yield *_other_label_widget;
109 }
110
111 [[nodiscard]] hitbox hitbox_test(point2i position) const noexcept final
112 {
113 hi_axiom(loop::main().on_thread());
114
115 if (*mode >= widget_mode::partial and layout.contains(position)) {
116 return {id, layout.elevation, hitbox_type::button};
117 } else {
118 return {};
119 }
120 }
121
122 [[nodiscard]] bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept override
123 {
124 hi_axiom(loop::main().on_thread());
125 return *mode >= widget_mode::partial and to_bool(group & hi::keyboard_focus_group::normal);
126 }
127
128 void activate() noexcept
129 {
131 delegate->activate(*this);
132 this->_state_changed();
133 }
134
135 bool handle_event(gui_event const& event) noexcept override
136 {
137 hi_axiom(loop::main().on_thread());
138
139 switch (event.type()) {
140 case gui_event_type::gui_activate:
141 if (*mode >= widget_mode::partial) {
142 activate();
143 return true;
144 }
145 break;
146
147 case gui_event_type::mouse_down:
148 if (*mode >= widget_mode::partial and event.mouse().cause.left_button) {
149 clicked = true;
151 return true;
152 }
153 break;
154
155 case gui_event_type::mouse_up:
156 if (*mode >= widget_mode::partial and event.mouse().cause.left_button) {
157 clicked = false;
158
159 if (layout.rectangle().contains(event.mouse().position)) {
160 handle_event(gui_event_type::gui_activate);
161 }
163 return true;
164 }
165 break;
166
167 default:;
168 }
169
170 return super::handle_event(event);
171 }
173protected:
174 std::unique_ptr<label_widget<join_path(prefix, "on")>> _on_label_widget;
175 box_constraints _on_label_constraints;
176 box_shape _on_label_shape;
177
178 std::unique_ptr<label_widget<join_path(prefix, "off")>> _off_label_widget;
179 box_constraints _off_label_constraints;
180 box_shape _off_label_shape;
181
182 std::unique_ptr<label_widget<join_path(prefix, "other")>> _other_label_widget;
183 box_constraints _other_label_constraints;
184 box_shape _other_label_shape;
185
186 bool _pressed = false;
187 notifier<>::callback_token _delegate_cbt;
188
189 template<size_t I>
190 void set_attributes() noexcept
191 {
192 }
193
194 template<size_t I>
195 void set_attributes(button_widget_attribute auto&& first, button_widget_attribute auto&&...rest) noexcept
196 {
197 if constexpr (forward_of<decltype(first), observer<hi::label>>) {
198 if constexpr (I == 0) {
199 on_label = first;
200 off_label = first;
201 other_label = hi_forward(first);
202 } else if constexpr (I == 1) {
203 other_label.reset();
204 off_label.reset();
205 off_label = hi_forward(first);
206 } else if constexpr (I == 2) {
207 other_label = hi_forward(first);
208 } else {
210 }
211 set_attributes<I + 1>(hi_forward(rest)...);
212
213 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
214 alignment = hi_forward(first);
215 set_attributes<I>(hi_forward(rest)...);
216
217 } else {
219 }
220 }
221
222 void draw_button(widget_draw_context& context) noexcept
223 {
224 _on_label_widget->draw(context);
225 _off_label_widget->draw(context);
226 _other_label_widget->draw(context);
227 }
228};
229
230}} // namespace hi::v1
Defines label_widget.
Defines button_delegate and some default button delegates.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#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_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
@ window_redraw
Request that part of the window gets redrawn on the next frame.
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
@ display
The widget is in display-only mode.
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr auto join_path(fixed_string< L > const &lhs, fixed_string< R > const &rhs) noexcept
lhs / rhs
Definition fixed_string.hpp:273
geometry/margins.hpp
Definition cache.hpp:11
@ off
The widget in the off-state.
@ other
The widget is in the other-state.
@ on
The widget is in the on-state.
constexpr bool contains(point< value_type, 2 > const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition axis_aligned_rectangle.hpp:265
Definition widget.hpp:26
widget_id id
The numeric identifier of a widget.
Definition widget.hpp:35
virtual void request_redraw() const noexcept
Request the widget to be redrawn on the next frame.
Definition widget.hpp:265
observer< bool > clicked
The widget is being clicked by the mouse.
Definition widget.hpp:57
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:274
widget * parent
Pointer to the parent widget.
Definition widget.hpp:40
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:49
constexpr bool contains(point3i mouse_position) const noexcept
Check if the mouse position is inside the widget.
Definition widget_layout.hpp:126
float elevation
The elevation of the widget above the window.
Definition widget_layout.hpp:72
Base class for implementing button widgets.
Definition abstract_button_widget.hpp:33
observer< hi::alignment > alignment
The alignment of the button and on/off/other label.
Definition abstract_button_widget.hpp:58
observer< label > on_label
The label to show when the button is in the 'on' state.
Definition abstract_button_widget.hpp:46
observer< label > other_label
The label to show when the button is in the 'other' state.
Definition abstract_button_widget.hpp:54
std::shared_ptr< delegate_type > delegate
The delegate that controls the button widget.
Definition abstract_button_widget.hpp:42
observer< label > off_label
The label to show when the button is in the 'off' state.
Definition abstract_button_widget.hpp:50
A button delegate controls the state of a button widget.
Definition button_delegate.hpp:23
The GUI widget displays and lays out text together with an icon.
Definition label_widget.hpp:42
Definition abstract_button_widget.hpp:26
Definition label_widget.hpp:26
T max(T... args)
T move(T... args)