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 "widget.hpp"
12#include "button_delegate.hpp"
13#include "label_widget.hpp"
14#include "../algorithm/module.hpp"
15#include "../l10n/l10n.hpp"
16#include "../observer/module.hpp"
17#include "../macros.hpp"
18#include <memory>
19#include <string>
20#include <array>
21#include <optional>
22#include <future>
23
24namespace hi { inline namespace v1 {
25
26template<typename Context>
28
34public:
35 using super = widget;
36 using delegate_type = button_delegate;
37
41
45
49
53
57
60 observer<semantic_text_style> text_style = semantic_text_style::label;
61
62 notifier<void()> pressed;
63
65 {
66 hi_assert_not_null(delegate);
67 delegate->deinit(*this);
68 }
69
72 {
73 hi_assert_not_null(this->delegate);
74
75 _on_label_widget = std::make_unique<label_widget>(this, on_label, alignment, text_style);
76 _off_label_widget = std::make_unique<label_widget>(this, off_label, alignment, text_style);
77 _other_label_widget = std::make_unique<label_widget>(this, other_label, alignment, text_style);
78 _delegate_cbt = this->delegate->subscribe([&] {
79 ++global_counter<"abstract_button_widget:delegate:relayout">;
81 });
82 this->delegate->init(*this);
83 }
84
89 {
90 hi_axiom(loop::main().on_thread());
91 hi_assert_not_null(delegate);
92 return delegate->state(*this);
93 }
94
96 [[nodiscard]] box_constraints update_constraints() noexcept override
97 {
98 _layout = {};
99 _on_label_constraints = _on_label_widget->update_constraints();
100 _off_label_constraints = _off_label_widget->update_constraints();
101 _other_label_constraints = _other_label_widget->update_constraints();
102 return max(_on_label_constraints, _off_label_constraints, _other_label_constraints);
103 }
104
105 void set_layout(widget_layout const& context) noexcept override
106 {
107 auto state_ = state();
111
112 _on_label_widget->set_layout(context.transform(_on_label_shape));
113 _off_label_widget->set_layout(context.transform(_off_label_shape));
114 _other_label_widget->set_layout(context.transform(_other_label_shape));
115 }
116
117 [[nodiscard]] generator<widget_intf&> children(bool include_invisible) noexcept override
118 {
119 co_yield *_on_label_widget;
120 co_yield *_off_label_widget;
121 co_yield *_other_label_widget;
122 }
123
124 [[nodiscard]] color background_color() const noexcept override
125 {
126 hi_axiom(loop::main().on_thread());
127 if (_pressed) {
128 return theme().color(semantic_color::fill, semantic_layer + 2);
129 } else {
130 return super::background_color();
131 }
132 }
133
134 [[nodiscard]] hitbox hitbox_test(point2 position) const noexcept final
135 {
136 hi_axiom(loop::main().on_thread());
137
138 if (*mode >= widget_mode::partial and layout().contains(position)) {
139 return {id, _layout.elevation, hitbox_type::button};
140 } else {
141 return {};
142 }
143 }
144
145 [[nodiscard]] bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept override
146 {
147 hi_axiom(loop::main().on_thread());
148 return *mode >= widget_mode::partial and to_bool(group & hi::keyboard_focus_group::normal);
149 }
150
151 void activate() noexcept
152 {
153 hi_assert_not_null(delegate);
154 delegate->activate(*this);
155
156 this->pressed();
157 }
158
159 bool handle_event(gui_event const& event) noexcept override
160 {
161 hi_axiom(loop::main().on_thread());
162
163 switch (event.type()) {
164 case gui_event_type::gui_activate:
165 if (*mode >= widget_mode::partial) {
166 activate();
167 return true;
168 }
169 break;
170
171 case gui_event_type::mouse_down:
172 if (*mode >= widget_mode::partial and event.mouse().cause.left_button) {
173 _pressed = true;
175 return true;
176 }
177 break;
178
179 case gui_event_type::mouse_up:
180 if (*mode >= widget_mode::partial and event.mouse().cause.left_button) {
181 _pressed = false;
182
183 if (layout().rectangle().contains(event.mouse().position)) {
184 handle_event(gui_event_type::gui_activate);
185 }
187 return true;
188 }
189 break;
190
191 default:;
192 }
193
195 }
197protected:
198 std::unique_ptr<label_widget> _on_label_widget;
199 box_constraints _on_label_constraints;
200 box_shape _on_label_shape;
201
202 std::unique_ptr<label_widget> _off_label_widget;
203 box_constraints _off_label_constraints;
204 box_shape _off_label_shape;
205
206 std::unique_ptr<label_widget> _other_label_widget;
207 box_constraints _other_label_constraints;
208 box_shape _other_label_shape;
209
210 bool _pressed = false;
211 notifier<>::callback_token _delegate_cbt;
212
213 template<size_t I>
214 void set_attributes() noexcept
215 {
216 }
217
218 template<size_t I>
219 void set_attributes(button_widget_attribute auto&& first, button_widget_attribute auto&&...rest) noexcept
220 {
221 if constexpr (forward_of<decltype(first), observer<hi::label>>) {
222 if constexpr (I == 0) {
223 on_label = first;
224 off_label = first;
225 other_label = hi_forward(first);
226 } else if constexpr (I == 1) {
227 other_label.reset();
228 off_label.reset();
229 off_label = hi_forward(first);
230 } else if constexpr (I == 2) {
231 other_label = hi_forward(first);
232 } else {
233 hi_static_no_default();
234 }
235 set_attributes<I + 1>(hi_forward(rest)...);
236
237 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
238 alignment = hi_forward(first);
239 set_attributes<I>(hi_forward(rest)...);
240
241 } else if constexpr (forward_of<decltype(first), observer<hi::semantic_text_style>>) {
242 text_style = hi_forward(first);
243 set_attributes<I>(hi_forward(rest)...);
244
245 } else {
246 hi_static_no_default();
247 }
248 }
249
250 void draw_button(draw_context const& context) noexcept
251 {
252 _on_label_widget->draw(context);
253 _off_label_widget->draw(context);
254 _other_label_widget->draw(context);
255 }
256};
257
258}} // namespace hi::v1
Defines widget.
Defines label_widget.
Defines button_delegate and some default button delegates.
@ window_relayout
Request that widgets get laid out on the next frame.
@ rectangle
The gui_event has rectangle data.
button_state
The state of a button.
Definition button_delegate.hpp:23
@ off
The 'off' state of a button.
@ other
The other state of a button.
@ on
The 'on' state of a button.
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
@ display
The widget is in display-only mode.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Horizontal/Vertical alignment combination.
Definition alignment.hpp:242
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:23
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:28
A localizable message.
Definition txt.hpp:100
2D constraints.
Definition box_constraints.hpp:25
Base class for implementing button widgets.
Definition abstract_button_widget.hpp:33
observer< semantic_text_style > text_style
The text style to button's label.
Definition abstract_button_widget.hpp:60
observer< label > other_label
The label to show when the button is in the 'other' state.
Definition abstract_button_widget.hpp:52
std::shared_ptr< delegate_type > delegate
The delegate that controls the button widget.
Definition abstract_button_widget.hpp:40
button_state state() const noexcept
Get the current state of the button.
Definition abstract_button_widget.hpp:88
observer< label > on_label
The label to show when the button is in the 'on' state.
Definition abstract_button_widget.hpp:44
observer< label > off_label
The label to show when the button is in the 'off' state.
Definition abstract_button_widget.hpp:48
observer< alignment > alignment
The alignment of the button and on/off/other label.
Definition abstract_button_widget.hpp:56
A button delegate controls the state of a button widget.
Definition button_delegate.hpp:45
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
widget_layout const & layout() const noexcept override
Get the current layout for this widget.
Definition widget.hpp:169
int semantic_layer
The draw layer of the widget.
Definition widget.hpp:66
widget(widget *parent) noexcept
Definition widget.hpp:87
void request_redraw() const noexcept override
Request the widget to be redrawn on the next frame.
Definition widget.hpp:189
bool process_event(gui_event const &event) const noexcept override
Send a event to the window.
Definition widget.hpp:178
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:42
bool handle_event(gui_event const &event) noexcept override
Handle command.
Definition widget.hpp:198
Definition abstract_button_widget.hpp:27
Definition label_widget.hpp:27
T move(T... args)