8 const std::size_t count =
_last.size();
9 for (std::size_t i = 0; i < count; ++i) {
10 const std::size_t index = (
_cursor + i) % count;
11 if (
_last[index].
id ==
id) {
21 const Entry* entry = find(w.
id());
22 if (entry !=
nullptr && entry->
forced == current) {
30 _next.push_back({ .id = w.
id(), .natural = natural, .forced = forced });
35 if (
const Entry* entry = find(w.
id())) {
36 _next.push_back(*entry);
50 const auto& area = transform;
53 float along = (vertical ? area.position.y : area.position.x) + padding;
54 const float across_start = (vertical ? area.position.x : area.position.y) + padding;
55 const float across_size = (vertical ? area.size.x : area.size.y) - (padding * 2.0F);
57 for (
auto const& c : children()) {
64 auto& t = c->transform;
65 float& child_across_size = vertical ? t.size.x : t.size.y;
66 const float natural = _across.natural(*c, child_across_size);
67 child_across_size = align ==
Align::Stretch ? across_size : natural;
68 _across.record(*c, natural, child_across_size);
70 float across = across_start;
72 across += (across_size - child_across_size) / 2.0F;
74 across += across_size - child_across_size;
78 t.position = { across, along };
80 t.position = { along, across };
84 along += (vertical ? t.size.y : t.size.x) + gap;
92 const std::size_t cols = std::max<std::size_t>(columns, 1);
93 const float inner_w = transform.size.x - (padding * 2.0F);
95 = std::max(0.0F, (inner_w - (gap *
static_cast<float>(cols - 1))) /
static_cast<float>(cols));
98 auto& natural_h = _natural_h;
101 for (
auto const& c : children()) {
104 shown.push_back(c.get());
105 natural_h.push_back(_heights.natural(*c, c->transform.size.y));
111 float y = transform.position.y + padding;
112 for (std::size_t row = 0; row * cols < shown.size(); ++row) {
113 const std::size_t first = row * cols;
114 const std::size_t last = std::min(first + cols, shown.size());
116 float h = row_height;
118 for (std::size_t i = first; i < last; ++i) {
119 h = std::max(h, natural_h[i]);
123 for (std::size_t i = first; i < last; ++i) {
124 const auto col =
static_cast<float>(i - first);
125 auto& t = shown[i]->transform;
126 t.position = { transform.position.x + padding + (col * (cell_w + gap)), y };
127 t.size = { cell_w, h };
128 _heights.record(*shown[i], natural_h[i], h);
129 shown[i]->layout(ctx);
141 if (parent ==
nullptr) {
145 const auto* stack =
dynamic_cast<const Stack*
>(parent);
146 const auto* grid =
dynamic_cast<const Grid*
>(parent);
148 || (grid !=
nullptr && grid->columns > 1);
153 return std::ranges::any_of(parent->
children(), [&w](
const std::unique_ptr<Widget>& c) {
154 return c.get() != &w && c->visible && c->enabled && c->focusable;
Shared state for the UI system.
Places children in a grid, filling each row left to right, e.g. a level select or a 2 by 2 menu.
void layout(Context &ctx) override
Place the children.
Places children one after another, top to bottom or left to right.
void layout(Context &ctx) override
Place the children.
std::vector< Entry > _last
void keep(const Widget &w)
Keep last layout's record for a child skipped this layout, e.g. a hidden one.
void finish()
End the layout. Records not made or kept this layout are dropped.
const Entry * find(WidgetId id) const
float natural(const Widget &w, float current) const
The child's own size: its current size, unless that is still the size this layout forced on it last t...
void record(const Widget &w, float natural, float forced)
Record the size forced on a child this layout.
Layout widgets for the ASW UI module.
bool in_row_with_focusables(const Widget &w)
Whether a widget sits in a row with other widgets that can take focus: its parent is a horizontal Sta...
uint32_t WidgetId
Unique identifier type for widgets.
@ Stretch
Children fill the stack across.