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.
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
6
7#pragma once
8
9#include "widget.hpp"
10#include "row_column_delegate.hpp"
11#include "grid_layout.hpp"
12#include "../GUI/theme.hpp"
13#include "../geometry/axis.hpp"
14#include <memory>
15
16namespace hi::inline v1 {
17
36template<axis Axis>
37class row_column_widget final : public widget {
38public:
39 static_assert(Axis == axis::horizontal or Axis == axis::vertical);
40
41 using super = widget;
43 static constexpr hi::axis axis = Axis;
44
46 {
47 if (auto delegate = _delegate.lock()) {
48 delegate->deinit(*this);
49 }
50 }
51
59 row_column_widget(gui_window &window, widget *parent, std::weak_ptr<delegate_type> delegate = {}) noexcept :
60 super(window, parent), _delegate(std::move(delegate))
61 {
62 hi_axiom(is_gui_thread());
63
64 if (parent) {
65 semantic_layer = parent->semantic_layer;
66 }
67 if (auto d = _delegate.lock()) {
68 d->init(*this);
69 }
70 }
71
84 template<typename Widget, typename... Args>
85 Widget &make_widget(Args &&...args)
86 {
87 auto tmp = std::make_unique<Widget>(window, this, std::forward<Args>(args)...);
88 auto &ref = *tmp;
89 _children.push_back(std::move(tmp));
90 request_reconstrain();
91 return ref;
92 }
93
96 void clear() noexcept
97 {
98 hi_axiom(is_gui_thread());
99 _children.clear();
100 request_reconstrain();
101 }
102
104 [[nodiscard]] generator<widget *> children() const noexcept override
105 {
106 for (hilet &child : _children) {
107 co_yield child.get();
108 }
109 }
110
111 widget_constraints const &set_constraints() noexcept override
112 {
113 _layout = {};
114
115 ssize_t index = 0;
116
117 auto minimum_thickness = 0.0f;
118 auto preferred_thickness = 0.0f;
119 auto maximum_thickness = 0.0f;
120 float margin_before_thickness = 0.0f;
121 float margin_after_thickness = 0.0f;
122
123 _grid_layout.clear();
124 for (hilet &child : _children) {
125 update_constraints_for_child(*child, index++, minimum_thickness, preferred_thickness, maximum_thickness, margin_before_thickness, margin_after_thickness);
126 }
127 _grid_layout.commit_constraints();
128
129 hi_axiom(index == ssize(_children));
130
131 if constexpr (axis == axis::row) {
132 return _constraints = {
133 {_grid_layout.minimum(), minimum_thickness},
134 {_grid_layout.preferred(), preferred_thickness},
135 {_grid_layout.maximum(), maximum_thickness},
136 {_grid_layout.margin_before(), margin_before_thickness, _grid_layout.margin_after(), margin_after_thickness}};
137 } else {
138 return _constraints = {
139 {minimum_thickness, _grid_layout.minimum()},
140 {preferred_thickness, _grid_layout.preferred()},
141 {maximum_thickness, _grid_layout.maximum()},
142 {margin_before_thickness, _grid_layout.margin_before(), margin_after_thickness, _grid_layout.margin_after()}};
143 }
144 }
145
146 void set_layout(widget_layout const &layout) noexcept override
147 {
148 if (compare_store(_layout, layout)) {
149 _grid_layout.layout(axis == axis::row ? layout.width() : layout.height());
150 }
151
152 ssize_t index = 0;
153 for (hilet &child : _children) {
154 update_layout_for_child(*child, index++, layout);
155 }
156
157 hi_axiom(index == ssize(_children));
158 }
159
160 void draw(draw_context const &context) noexcept override
161 {
162 if (*visible) {
163 for (hilet &child : _children) {
164 child->draw(context);
165 }
166 }
167 }
168
169 hitbox hitbox_test(point3 position) const noexcept override
170 {
171 hi_axiom(is_gui_thread());
172
173 if (*visible and *enabled) {
174 auto r = hitbox{};
175 for (hilet &child : _children) {
176 r = child->hitbox_test_from_parent(position, r);
177 }
178 return r;
179 } else {
180 return {};
181 }
182 }
184private:
187 grid_layout _grid_layout;
188
189 void update_constraints_for_child(
190 widget &child,
191 ssize_t index,
192 float &minimum_thickness,
193 float &preferred_thickness,
194 float &maximum_thickness,
195 float &margin_before_thickness,
196 float &margin_after_thickness) noexcept
197 {
198 hi_axiom(is_gui_thread());
199
200 hilet &child_constraints = child.set_constraints();
201 if (axis == axis::row) {
202 _grid_layout.add_constraint(
203 index,
204 child_constraints.minimum.width(),
205 child_constraints.preferred.width(),
206 child_constraints.maximum.width(),
207 child_constraints.margins.left(),
208 child_constraints.margins.right());
209
210 inplace_max(minimum_thickness, child_constraints.minimum.height());
211 inplace_max(preferred_thickness, child_constraints.preferred.height());
212 inplace_max(maximum_thickness, child_constraints.maximum.height());
213 inplace_max(margin_before_thickness, child_constraints.margins.top());
214 inplace_max(margin_after_thickness, child_constraints.margins.bottom());
215
216 } else {
217 _grid_layout.add_constraint(
218 index,
219 child_constraints.minimum.height(),
220 child_constraints.preferred.height(),
221 child_constraints.maximum.height(),
222 child_constraints.margins.top(),
223 child_constraints.margins.bottom());
224
225 inplace_max(minimum_thickness, child_constraints.minimum.width());
226 inplace_max(preferred_thickness, child_constraints.preferred.width());
227 inplace_max(maximum_thickness, child_constraints.maximum.width());
228 inplace_max(margin_before_thickness, child_constraints.margins.left());
229 inplace_max(margin_after_thickness, child_constraints.margins.right());
230 }
231 }
232
233 void update_layout_for_child(widget &child, ssize_t index, widget_layout const &context) const noexcept
234 {
235 hi_axiom(is_gui_thread());
236
237 hilet[child_position, child_length] = _grid_layout.get_position_and_size(index);
238
239 hilet child_rectangle = axis == axis::row ?
240 aarectangle{child_position, 0.0f, child_length, layout().height()} :
241 aarectangle{0.0f, layout().height() - child_position - child_length, layout().width(), child_length};
242
243 child.set_layout(context.transform(child_rectangle, 0.0f));
244 }
245};
246
250
254
255} // namespace hi::inline v1
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition required.hpp:37
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
STL namespace.
A return value for a generator-function.
Definition generator.hpp:27
Definition gui_window.hpp:40
A row/column widget lays out child widgets along a row or column.
Definition row_column_widget.hpp:37
void clear() noexcept
Remove and deallocate all child widgets.
Definition row_column_widget.hpp:96
Widget & make_widget(Args &&...args)
Add a widget directly to this grid-widget.
Definition row_column_widget.hpp:85
row_column_widget(gui_window &window, widget *parent, std::weak_ptr< delegate_type > delegate={}) noexcept
Constructs an empty row/column widget.
Definition row_column_widget.hpp:59
Definition row_column_delegate.hpp:16
An interactive graphical object as part of the user-interface.
Definition widget.hpp:40
int semantic_layer
The draw layer of the widget.
Definition widget.hpp:87
T move(T... args)