HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
label_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2020-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 "text_widget.hpp"
13#include "icon_widget.hpp"
14#include "../geometry/geometry.hpp"
15#include "../layout/layout.hpp"
16#include "../l10n/l10n.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.label_widget);
26
27hi_export namespace hi { inline namespace v1 {
28
29template<typename Context>
31 forward_of<Context, observer<hi::label>, observer<hi::alignment>, observer<hi::semantic_text_style>>;
32
46class label_widget : public widget {
47public:
48 using super = widget;
49
53
71 observer<alignment> alignment = hi::alignment::top_flush();
72
75 observer<semantic_text_style> text_style = semantic_text_style::label;
76
84 template<label_widget_attribute... Attributes>
85 label_widget(widget_intf const* parent, Attributes&&...attributes) noexcept : label_widget(parent)
86 {
87 set_attributes(std::forward<Attributes>(attributes)...);
88 }
89
91 [[nodiscard]] generator<widget_intf &> children(bool include_invisible) noexcept override
92 {
93 co_yield *_icon_widget;
94 co_yield *_text_widget;
95 }
96
97 [[nodiscard]] box_constraints update_constraints() noexcept override
98 {
99 _layout = {};
100
101 // Resolve as if in left-to-right mode, the grid will flip itself.
102 auto const resolved_alignment = resolve(*alignment, true);
103
104 _grid.clear();
105 if (to_bool(label->icon) and to_bool(label->text)) {
106 // Both of the icon and text are set, so configure the grid to hold both.
107 if (resolved_alignment == horizontal_alignment::left) {
108 // icon text
109 _grid.add_cell(0, 0, _icon_widget.get());
110 _grid.add_cell(1, 0, _text_widget.get(), true);
111 } else if (resolved_alignment == horizontal_alignment::right) {
112 // text icon
113 _grid.add_cell(0, 0, _text_widget.get(), true);
114 _grid.add_cell(1, 0, _icon_widget.get());
115 } else if (resolved_alignment == vertical_alignment::top) {
116 // icon
117 // text
118 _grid.add_cell(0, 0, _icon_widget.get());
119 _grid.add_cell(0, 1, _text_widget.get(), true);
120 } else if (resolved_alignment == vertical_alignment::bottom) {
121 // text
122 // icon
123 _grid.add_cell(0, 0, _text_widget.get(), true);
124 _grid.add_cell(0, 1, _icon_widget.get());
125 } else {
126 hi_no_default("alignment is not allowed to be middle-center.");
127 }
128 } else if (to_bool(label->icon)) {
129 // Only the icon-widget is used.
130 _grid.add_cell(0, 0, _icon_widget.get());
131 } else if (to_bool(label->text)) {
132 // Only the text-widget is used.
133 _grid.add_cell(0, 0, _text_widget.get());
134 }
135
136 auto const icon_size =
137 (resolved_alignment == horizontal_alignment::center or resolved_alignment == horizontal_alignment::justified) ?
138 theme().large_icon_size() :
139 (theme().text_style(*text_style)->size * theme().pixel_density).in(pixels_per_em);
140
141 _icon_widget->minimum = extent2{icon_size, icon_size};
142 _icon_widget->maximum = extent2{icon_size, icon_size};
143
144 for (auto& cell : _grid) {
145 cell.set_constraints(cell.value->update_constraints());
146 }
147
148 return _grid.constraints(os_settings::left_to_right());
149 }
150 void set_layout(widget_layout const& context) noexcept override
151 {
152 if (compare_store(_layout, context)) {
153 _grid.set_layout(context.shape, theme().baseline_adjustment());
154 }
155
156 for (auto const& cell : _grid) {
157 cell.value->set_layout(context.transform(cell.shape, transform_command::level));
158 }
159 }
160 void draw(draw_context const& context) noexcept override
161 {
162 if (mode() > widget_mode::invisible and overlaps(context, layout())) {
163 for (auto const& cell : _grid) {
164 cell.value->draw(context);
165 }
166 }
167 }
168 [[nodiscard]] hitbox hitbox_test(point2 position) const noexcept override
169 {
170 hi_axiom(loop::main().on_thread());
171
172 if (mode() > widget_mode::invisible) {
173 return _text_widget->hitbox_test_from_parent(position);
174 } else {
175 return {};
176 }
177 }
179private:
180 float _icon_size;
181 float _inner_margin;
182
183 std::unique_ptr<icon_widget> _icon_widget;
184 std::unique_ptr<text_widget> _text_widget;
185 grid_layout<widget *> _grid;
186
187 callback<void(hi::label)> _label_cbt;
188 callback<void(semantic_text_style)> _text_style_cbt;
189 callback<void(hi::alignment)> _alignment_cbt;
190
191 void set_attributes() noexcept {}
192
193 template<label_widget_attribute First, label_widget_attribute... Rest>
194 void set_attributes(First&& first, Rest&&...rest) noexcept
195 {
196 if constexpr (forward_of<First, observer<hi::label>>) {
197 label = std::forward<First>(first);
198 } else if constexpr (forward_of<First, observer<hi::alignment>>) {
199 alignment = std::forward<First>(first);
200 } else if constexpr (forward_of<First, observer<hi::semantic_text_style>>) {
201 text_style = std::forward<First>(first);
202 } else {
203 hi_static_no_default();
204 }
205
206 set_attributes(std::forward<Rest>(rest)...);
207 }
208
209 label_widget(widget_intf const* parent) noexcept : super(parent)
210 {
211 set_mode(widget_mode::select);
212
213 _icon_widget = std::make_unique<icon_widget>(this, label.sub<"icon">());
214 _text_widget = std::make_unique<text_widget>(this, label.sub<"text">());
215 _text_widget->alignment = alignment;
216 _text_widget->text_style = text_style;
217 _text_widget->set_mode(mode());
218
219 _alignment_cbt = alignment.subscribe([this](auto...) {
221 _icon_widget->alignment = hi::alignment::middle_center();
222 } else {
223 _icon_widget->alignment = *alignment;
224 }
225 });
226 _alignment_cbt(*alignment);
227
228 _text_style_cbt = text_style.subscribe([this](auto...) {
229 switch (*text_style) {
230 case semantic_text_style::label:
231 _icon_widget->color = color::foreground();
232 break;
233 case semantic_text_style::small_label:
234 _icon_widget->color = color::foreground();
235 break;
236 case semantic_text_style::warning:
237 _icon_widget->color = color::orange();
238 break;
239 case semantic_text_style::error:
240 _icon_widget->color = color::red();
241 break;
242 case semantic_text_style::help:
243 _icon_widget->color = color::indigo();
244 break;
245 case semantic_text_style::placeholder:
246 _icon_widget->color = color::gray();
247 break;
248 case semantic_text_style::link:
249 _icon_widget->color = color::blue();
250 break;
251 default:
252 _icon_widget->color = color::foreground();
253 }
254 });
255 }
256};
257
258}} // namespace hi::v1
Defines widget.
Defines icon_widget.
Defines text_widget.
@ bottom
Align to the bottom.
@ top
Align to the top.
@ right
Align the text to the right side.
@ left
Align the text to the left side.
@ justified
Stretch the text to be flush to both sides.
@ center
Align the text in the center.
@ invisible
The widget is invisible.
@ select
The widget is selectable.
The HikoGUI namespace.
Definition array_generic.hpp:20
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:53
@ level
The child widget stays at the same elevation and layer.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Horizontal/Vertical alignment combination.
Definition alignment.hpp:244
Definition widget_intf.hpp:24
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
2D constraints.
Definition box_constraints.hpp:25
A observer pointing to the whole or part of a observed_base.
Definition observer_intf.hpp:32
callback< void(value_type)> subscribe(Func &&func, callback_flags flags=callback_flags::synchronous) noexcept
Subscribe a callback to this observer.
Definition observer_intf.hpp:456
auto sub(auto const &index) const noexcept
Create a sub-observer by indexing into the value.
Definition observer_intf.hpp:471
The GUI widget displays and lays out text together with an icon.
Definition label_widget.hpp:46
observer< label > label
The label to display.
Definition label_widget.hpp:52
label_widget(widget_intf const *parent, Attributes &&...attributes) noexcept
Construct a label widget.
Definition label_widget.hpp:85
observer< alignment > alignment
How the label and icon are aligned.
Definition label_widget.hpp:71
observer< semantic_text_style > text_style
The text style to display the label's text in and color of the label's (non-color) icon.
Definition label_widget.hpp:75
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
True if T is a forwarded type of Forward.
Definition concepts.hpp:137
Definition label_widget.hpp:30