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/algorithm.hpp"
15#include "../l10n/l10n.hpp"
16#include "../observer/observer.hpp"
17#include "../macros.hpp"
18#include <memory>
19#include <string>
20#include <array>
21#include <optional>
22#include <future>
23#include <coroutine>
24
25hi_export_module(hikogui.widgets.abstract_button_widget);
26
27hi_export namespace hi { inline namespace v1 {
28
29template<typename Context>
31
37public:
38 using super = widget;
39 using delegate_type = button_delegate;
40
44
48
52
56
60
63 observer<semantic_text_style> text_style = semantic_text_style::label;
64
66 {
67 hi_assert_not_null(delegate);
68 delegate->deinit(*this);
69 }
70
73 {
74 hi_assert_not_null(this->delegate);
75
76 _on_label_widget = std::make_unique<label_widget>(this, on_label, alignment, text_style);
77 _off_label_widget = std::make_unique<label_widget>(this, off_label, alignment, text_style);
78 _other_label_widget = std::make_unique<label_widget>(this, other_label, alignment, text_style);
79
80 this->delegate->init(*this);
81 _delegate_cbt = this->delegate->subscribe([&] {
82 set_value(this->delegate->state(*this));
83 });
84 _delegate_cbt();
85 }
86
88 [[nodiscard]] box_constraints update_constraints() noexcept override
89 {
90 _layout = {};
91 _on_label_constraints = _on_label_widget->update_constraints();
92 _off_label_constraints = _off_label_widget->update_constraints();
93 _other_label_constraints = _other_label_widget->update_constraints();
94 return max(_on_label_constraints, _off_label_constraints, _other_label_constraints);
95 }
96
97 void set_layout(widget_layout const& context) noexcept override
98 {
99 _on_label_widget->set_mode(value() == widget_value::on ? widget_mode::display : widget_mode::invisible);
100 _off_label_widget->set_mode(value() == widget_value::off ? widget_mode::display : widget_mode::invisible);
101 _other_label_widget->set_mode(value() == widget_value::other ? widget_mode::display : widget_mode::invisible);
102
103 _on_label_widget->set_layout(context.transform(_on_label_shape));
104 _off_label_widget->set_layout(context.transform(_off_label_shape));
105 _other_label_widget->set_layout(context.transform(_other_label_shape));
106 }
107
108 [[nodiscard]] generator<widget_intf&> children(bool include_invisible) noexcept override
109 {
110 co_yield *_on_label_widget;
111 co_yield *_off_label_widget;
112 co_yield *_other_label_widget;
113 }
114
115 [[nodiscard]] color background_color() const noexcept override
116 {
117 hi_axiom(loop::main().on_thread());
118 if (phase() == widget_phase::pressed) {
119 return theme().color(semantic_color::fill, _layout.layer + 2);
120 } else {
121 return super::background_color();
122 }
123 }
124
125 [[nodiscard]] hitbox hitbox_test(point2 position) const noexcept override
126 {
127 hi_axiom(loop::main().on_thread());
128
129 if (mode() >= widget_mode::partial and layout().contains(position)) {
130 return {id, _layout.elevation, hitbox_type::button};
131 } else {
132 return {};
133 }
134 }
135
136 [[nodiscard]] bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept override
137 {
138 hi_axiom(loop::main().on_thread());
139 return mode() >= widget_mode::partial and to_bool(group & hi::keyboard_focus_group::normal);
140 }
141
142 void activate() noexcept
143 {
144 hi_assert_not_null(delegate);
145 delegate->activate(*this);
146
147 notifier();
148 }
149
150 bool handle_event(gui_event const& event) noexcept override
151 {
152 hi_axiom(loop::main().on_thread());
153
154 switch (event.type()) {
155 case gui_event_type::gui_activate:
156 if (mode() >= widget_mode::partial) {
157 activate();
158 return true;
159 }
160 break;
161
162 case gui_event_type::mouse_down:
163 if (mode() >= widget_mode::partial and event.mouse().cause.left_button) {
164 set_pressed(true);
165 return true;
166 }
167 break;
168
169 case gui_event_type::mouse_up:
170 if (mode() >= widget_mode::partial and event.mouse().cause.left_button) {
171 set_pressed(false);
172
173 if (layout().rectangle().contains(event.mouse().position)) {
174 handle_event(gui_event_type::gui_activate);
175 }
176 return true;
177 }
178 break;
179
180 default:;
181 }
182
183 return super::handle_event(event);
184 }
186protected:
187 std::unique_ptr<label_widget> _on_label_widget;
188 box_constraints _on_label_constraints;
189 box_shape _on_label_shape;
190
191 std::unique_ptr<label_widget> _off_label_widget;
192 box_constraints _off_label_constraints;
193 box_shape _off_label_shape;
194
195 std::unique_ptr<label_widget> _other_label_widget;
196 box_constraints _other_label_constraints;
197 box_shape _other_label_shape;
198
199 callback<void()> _delegate_cbt;
200
201 template<size_t I>
202 void set_attributes() noexcept
203 {
204 }
205
206 template<size_t I, button_widget_attribute First, button_widget_attribute... Rest>
207 void set_attributes(First&& first, Rest&&...rest) noexcept
208 {
209 if constexpr (forward_of<First, observer<hi::label>>) {
210 if constexpr (I == 0) {
211 on_label = first;
212 off_label = first;
213 other_label = std::forward<First>(first);
214 } else if constexpr (I == 1) {
217 off_label = std::forward<First>(first);
218 } else if constexpr (I == 2) {
219 other_label = std::forward<First>(first);
220 } else {
221 hi_static_no_default();
222 }
223 set_attributes<I + 1>(std::forward<Rest>(rest)...);
224
225 } else if constexpr (forward_of<First, observer<hi::alignment>>) {
226 alignment = std::forward<First>(first);
227 set_attributes<I>(std::forward<Rest>(rest)...);
228
229 } else if constexpr (forward_of<First, observer<hi::semantic_text_style>>) {
230 text_style = std::forward<First>(first);
231 set_attributes<I>(std::forward<Rest>(rest)...);
232
233 } else {
234 hi_static_no_default();
235 }
236 }
237
238 void draw_button(draw_context const& context) noexcept
239 {
240 _on_label_widget->draw(context);
241 _off_label_widget->draw(context);
242 _other_label_widget->draw(context);
243 }
244};
245
246}} // namespace hi::v1
Defines widget.
Defines label_widget.
Defines button_delegate and some default button delegates.
@ rectangle
The gui_event has rectangle data.
widget_mode
The mode that the widget is operating at.
Definition widget_state.hpp:25
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
@ display
The widget is in display-only mode.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Horizontal/Vertical alignment combination.
Definition alignment.hpp:244
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
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:30
widget_layout const & layout() const noexcept
Get the current layout for this widget.
Definition widget_intf.hpp:206
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:35
A localizable message.
Definition txt.hpp:100
A observer pointing to the whole or part of a observed_base.
Definition observer_intf.hpp:32
void reset() noexcept
Reset the observer.
Definition observer_intf.hpp:421
Base class for implementing button widgets.
Definition abstract_button_widget.hpp:36
observer< semantic_text_style > text_style
The text style to button's label.
Definition abstract_button_widget.hpp:63
observer< label > other_label
The label to show when the button is in the 'other' state.
Definition abstract_button_widget.hpp:55
std::shared_ptr< delegate_type > delegate
The delegate that controls the button widget.
Definition abstract_button_widget.hpp:43
observer< label > on_label
The label to show when the button is in the 'on' state.
Definition abstract_button_widget.hpp:47
observer< label > off_label
The label to show when the button is in the 'off' state.
Definition abstract_button_widget.hpp:51
observer< alignment > alignment
The alignment of the button and on/off/other label.
Definition abstract_button_widget.hpp:59
A button delegate controls the state of a button widget.
Definition button_delegate.hpp:28
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
widget() noexcept
Constructor for creating sub views.
Definition widget.hpp:55
bool handle_event(gui_event const &event) noexcept override
Handle command.
Definition widget.hpp:150
Definition abstract_button_widget.hpp:30
Definition label_widget.hpp:30
T move(T... args)