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 "../GUI/module.hpp"
12#include "text_widget.hpp"
13#include "icon_widget.hpp"
14#include "../geometry/module.hpp"
15#include "../layout/grid_layout.hpp"
16#include "../label.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>
26concept label_widget_attribute = forward_of<Context, observer<hi::label>, observer<hi::alignment>>;
27
41template<fixed_string Name = "">
42class label_widget final : public widget {
43public:
44 using super = widget;
45 constexpr static auto prefix = Name / "label";
46
49 observer<label> label;
50
68 observer<alignment> alignment = hi::alignment::top_flush();
69
78 {
79 set_attributes(hi_forward(attributes)...);
80 }
81
83 [[nodiscard]] generator<widget const&> children(bool include_invisible) const noexcept override
84 {
85 co_yield *_icon_widget;
86 co_yield *_text_widget;
87 }
88
89 [[nodiscard]] box_constraints update_constraints() noexcept override
90 {
91 // Resolve as if in left-to-right mode, the grid will flip itself.
92 hilet resolved_alignment = resolve(*alignment, true);
93
94 _grid.clear();
95 if (to_bool(label->icon) and to_bool(label->text)) {
96 // Both of the icon and text are set, so configure the grid to hold both.
97 if (resolved_alignment == horizontal_alignment::left) {
98 // icon text
99 _grid.add_cell(0, 0, _icon_widget.get());
100 _grid.add_cell(1, 0, _text_widget.get(), true);
101 } else if (resolved_alignment == horizontal_alignment::right) {
102 // text icon
103 _grid.add_cell(0, 0, _text_widget.get(), true);
104 _grid.add_cell(1, 0, _icon_widget.get());
105 } else if (resolved_alignment == vertical_alignment::top) {
106 // icon
107 // text
108 _grid.add_cell(0, 0, _icon_widget.get());
109 _grid.add_cell(0, 1, _text_widget.get(), true);
110 } else if (resolved_alignment == vertical_alignment::bottom) {
111 // text
112 // icon
113 _grid.add_cell(0, 0, _text_widget.get(), true);
114 _grid.add_cell(0, 1, _icon_widget.get());
115 } else {
116 hi_no_default("alignment is not allowed to be middle-center.");
117 }
118 } else if (to_bool(label->icon)) {
119 // Only the icon-widget is used.
120 _grid.add_cell(0, 0, _icon_widget.get());
121 } else if (to_bool(label->text)) {
122 // Only the text-widget is used.
123 _grid.add_cell(0, 0, _text_widget.get());
124 }
125
126 hilet icon_size =
127 (resolved_alignment == horizontal_alignment::center or resolved_alignment == horizontal_alignment::justified) ?
128 theme<prefix>.size(this) :
129 extent2i{theme<prefix>.line_height(this), theme<prefix>.line_height(this)};
130
131 _icon_widget->minimum = icon_size;
132 _icon_widget->maximum = icon_size;
133
134 for (auto& cell : _grid) {
135 cell.set_constraints(cell.value->update_constraints());
136 }
137
138 return _grid.constraints(os_settings::left_to_right());
139 }
140
141 void set_layout(widget_layout const& context) noexcept override
142 {
143 if (compare_store(layout, context)) {
144 _grid.set_layout(context.shape, theme<prefix>.cap_height(this));
145 }
146
147 for (hilet& cell : _grid) {
148 cell.value->set_layout(context.transform(cell.shape, 0.0f));
149 }
150 }
151
152 void draw(widget_draw_context& context) noexcept override
153 {
154 if (*mode > widget_mode::invisible and overlaps(context, layout)) {
155 for (hilet& cell : _grid) {
156 cell.value->draw(context);
157 }
158 }
159 }
160
161 [[nodiscard]] hitbox hitbox_test(point2i position) const noexcept override
162 {
163 hi_axiom(loop::main().on_thread());
164
166 return _text_widget->hitbox_test_from_parent(position);
167 } else {
168 return {};
169 }
170 }
172private:
173 float _icon_size;
174 float _inner_margin;
175
176 decltype(label)::callback_token _label_cbt;
177 decltype(alignment)::callback_token _alignment_cbt;
178
181 grid_layout<widget *> _grid;
182
183 void set_attributes() noexcept {}
184 void set_attributes(label_widget_attribute auto&& first, label_widget_attribute auto&&...rest) noexcept
185 {
186 if constexpr (forward_of<decltype(first), observer<hi::label>>) {
187 label = hi_forward(first);
188 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
189 alignment = hi_forward(first);
190 } else {
192 }
193
194 set_attributes(hi_forward(rest)...);
195 }
196
197 label_widget(widget *parent) noexcept : super(parent)
198 {
200
201 _icon_widget = std::make_unique<icon_widget<prefix>>(this, label.get<"icon">());
202 _text_widget = std::make_unique<text_widget<prefix>>(this, label.get<"text">());
203 _text_widget->alignment = alignment;
204 _text_widget->mode = mode;
205
206 _alignment_cbt = alignment.subscribe([this](auto...) {
207 if (alignment == horizontal_alignment::center or alignment == horizontal_alignment::justified) {
208 _icon_widget->alignment = hi::alignment::middle_center();
209 } else {
210 _icon_widget->alignment = *alignment;
211 }
212 });
213 (*_alignment_cbt)(*alignment);
214 }
215};
216
217}} // namespace hi::v1
Functionality for labels, text and icons.
Defines icon_widget.
Defines text_widget.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
geo::extent< int, 2 > extent2i
A 2D extent.
Definition extent.hpp:512
@ invisible
The widget is invisible.
@ select
The widget is selectable.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition utility.hpp:212
Definition widget.hpp:26
widget * parent
Pointer to the parent widget.
Definition widget.hpp:40
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:49
2D constraints.
Definition box_constraints.hpp:22
The GUI widget displays and lays out text together with an icon.
Definition label_widget.hpp:42
label_widget(widget *parent, label_widget_attribute auto &&...attributes) noexcept
Construct a label widget.
Definition label_widget.hpp:77
observer< label > label
The label to display.
Definition label_widget.hpp:49
observer< alignment > alignment
How the label and icon are aligned.
Definition label_widget.hpp:68
Definition label_widget.hpp:26