HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
row_column_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 "grid_layout.hpp"
13#include "../GUI/theme.hpp"
14#include "../geometry/axis.hpp"
15#include <memory>
16
17namespace hi { inline namespace v1 {
18
38template<axis Axis>
39class row_column_widget final : public widget {
40public:
41 static_assert(Axis == axis::horizontal or Axis == axis::vertical);
42
43 using super = widget;
44 static constexpr hi::axis axis = Axis;
45
47
54 {
55 hi_axiom(is_gui_thread());
56
57 if (parent) {
59 }
60 }
61
74 template<typename Widget, typename... Args>
75 Widget& make_widget(Args&&...args)
76 {
77 auto tmp = std::make_unique<Widget>(window, this, std::forward<Args>(args)...);
78 auto& ref = *tmp;
79 _children.push_back(std::move(tmp));
80 hi_request_reconstrain("row_column_widget::make_widget()");
81 return ref;
82 }
83
86 void clear() noexcept
87 {
88 hi_axiom(is_gui_thread());
89 _children.clear();
90 hi_request_reconstrain("row_column_widget::clear()");
91 }
92
94 [[nodiscard]] generator<widget *> children() const noexcept override
95 {
96 for (hilet& child : _children) {
97 co_yield child.get();
98 }
99 }
100
101 widget_constraints const& set_constraints() noexcept override
102 {
103 _layout = {};
104
105 ssize_t index = 0;
106
107 auto minimum_thickness = 0.0f;
108 auto preferred_thickness = 0.0f;
109 auto maximum_thickness = 0.0f;
110 float margin_before_thickness = 0.0f;
111 float margin_after_thickness = 0.0f;
112 widget_baseline baseline = {};
113
114 _grid_layout.clear();
115 for (hilet& child : _children) {
116 update_constraints_for_child(
117 *child,
118 index++,
119 minimum_thickness,
120 preferred_thickness,
121 maximum_thickness,
122 margin_before_thickness,
123 margin_after_thickness,
124 baseline);
125 }
126 _grid_layout.commit_constraints();
127
128 hi_axiom(index == ssize(_children));
129
130 if constexpr (axis == axis::row) {
131 return _constraints = {
132 {_grid_layout.minimum(), minimum_thickness},
133 {_grid_layout.preferred(), preferred_thickness},
134 {_grid_layout.maximum(), maximum_thickness},
135 {_grid_layout.margin_before(),
136 margin_before_thickness,
137 _grid_layout.margin_after(),
138 margin_after_thickness},
139 baseline};
140 } else {
141 return _constraints = {
142 {minimum_thickness, _grid_layout.minimum()},
143 {preferred_thickness, _grid_layout.preferred()},
144 {maximum_thickness, _grid_layout.maximum()},
145 {margin_before_thickness,
146 _grid_layout.margin_before(),
147 margin_after_thickness,
148 _grid_layout.margin_after()}};
149 }
150 }
151
152 void set_layout(widget_layout const& layout) noexcept override
153 {
154 if (compare_store(_layout, layout)) {
155 _grid_layout.layout(axis == axis::row ? layout.width() : layout.height());
156 }
157
158 ssize_t index = 0;
159 for (hilet& child : _children) {
160 update_layout_for_child(*child, index++, layout);
161 }
162
163 hi_axiom(index == ssize(_children));
164 }
165
166 void draw(draw_context const& context) noexcept override
167 {
169 for (hilet& child : _children) {
170 child->draw(context);
171 }
172 }
173 }
174
175 hitbox hitbox_test(point3 position) const noexcept override
176 {
177 hi_axiom(is_gui_thread());
178
179 if (*mode >= widget_mode::partial) {
180 auto r = hitbox{};
181 for (hilet& child : _children) {
182 r = child->hitbox_test_from_parent(position, r);
183 }
184 return r;
185 } else {
186 return {};
187 }
188 }
190private:
192 grid_layout _grid_layout;
193
194 void update_constraints_for_child(
195 widget& child,
196 ssize_t index,
197 float& minimum_thickness,
198 float& preferred_thickness,
199 float& maximum_thickness,
200 float& margin_before_thickness,
201 float& margin_after_thickness,
202 widget_baseline& baseline) noexcept
203 {
204 hi_axiom(is_gui_thread());
205
206 hilet& child_constraints = child.set_constraints();
207 if (axis == axis::row) {
208 _grid_layout.add_constraint(
209 index,
210 child_constraints.minimum.width(),
211 child_constraints.preferred.width(),
212 child_constraints.maximum.width(),
213 child_constraints.margins.left(),
214 child_constraints.margins.right());
215
216 inplace_max(minimum_thickness, child_constraints.minimum.height());
217 inplace_max(preferred_thickness, child_constraints.preferred.height());
218 inplace_max(maximum_thickness, child_constraints.maximum.height());
219 inplace_max(margin_before_thickness, child_constraints.margins.top());
220 inplace_max(margin_after_thickness, child_constraints.margins.bottom());
221 inplace_max(baseline, child_constraints.baseline);
222
223 } else {
224 _grid_layout.add_constraint(
225 index,
226 child_constraints.minimum.height(),
227 child_constraints.preferred.height(),
228 child_constraints.maximum.height(),
229 child_constraints.margins.top(),
230 child_constraints.margins.bottom(),
231 child_constraints.baseline);
232
233 inplace_max(minimum_thickness, child_constraints.minimum.width());
234 inplace_max(preferred_thickness, child_constraints.preferred.width());
235 inplace_max(maximum_thickness, child_constraints.maximum.width());
236 inplace_max(margin_before_thickness, child_constraints.margins.left());
237 inplace_max(margin_after_thickness, child_constraints.margins.right());
238 }
239 }
240
241 void update_layout_for_child(widget& child, ssize_t index, widget_layout const& context) const noexcept
242 {
243 hi_axiom(is_gui_thread());
244
245 hilet[child_position, child_length] = _grid_layout.get_position_and_size(index);
246
247 if (axis == axis::row) {
248 hilet child_rectangle = aarectangle{child_position, 0.0f, child_length, layout().height()};
249 // The baseline for a row widget is inherited from the context received from the parent.
250 child.set_layout(context.transform(child_rectangle, 0.0f));
251
252 } else {
253 hilet child_rectangle =
254 aarectangle{0.0f, layout().height() - child_position - child_length, layout().width(), child_length};
255 child.set_layout(context.transform(child_rectangle, 0.0f, _grid_layout.get_baseline(index)));
256 }
257 }
258};
259
264
269
270}} // namespace hi::v1
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
Defines widget.
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
DOXYGEN BUG.
Definition algorithm.hpp:15
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition utils.hpp:27
The HikoGUI namespace.
Definition ascii.hpp:19
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition utility.hpp:162
void commit_constraints() noexcept
Commit all the constraints.
float maximum() const noexcept
The minimum size of the total grid_layout.
Definition grid_layout.hpp:129
void clear() noexcept
Clear the list of widgets in the layout.
Definition grid_layout.hpp:34
void layout(float size) noexcept
Layout the cells based on the total size.
float preferred() const noexcept
The minimum size of the total grid_layout.
Definition grid_layout.hpp:120
float minimum() const noexcept
The minimum size of the total grid_layout.
Definition grid_layout.hpp:111
A row/column widget lays out child widgets along a row or column.
Definition row_column_widget.hpp:39
Widget & make_widget(Args &&...args)
Add a widget directly to this grid-widget.
Definition row_column_widget.hpp:75
void clear() noexcept
Remove and deallocate all child widgets.
Definition row_column_widget.hpp:86
row_column_widget(gui_window &window, widget *parent) noexcept
Constructs an empty row/column widget.
Definition row_column_widget.hpp:53
An interactive graphical object as part of the user-interface.
Definition widget.hpp:44
widget_layout const & layout() const noexcept
Get the current layout for this widget.
Definition widget.hpp:198
int semantic_layer
The draw layer of the widget.
Definition widget.hpp:86
widget *const parent
Pointer to the parent widget.
Definition widget.hpp:53
widget(gui_window &window, widget *parent) noexcept
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:62
gui_window & window
Convenient reference to the Window.
Definition widget.hpp:48
T move(T... args)