Stack¶
Header: winui/ui/panels/Stack.hpp. Spec: winui/ui/panels/Stack.hpp.
Lays its children out in a single column or row, spacing apart.
The panel owns its children (add() takes a unique_ptr and hands back a non-owning observer). Each child is measured unbounded along the stack and gets the panel's full cross extent, where its own alignment places it. The declarative forms are ui::VerticalStack and ui::HorizontalStack.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
stack->set_spacing(12.0f);
ui::TextControl* label = stack->add(std::make_unique<ui::TextControl>("Clicks: 0"));
ui::ButtonControl* click = stack->add(std::make_unique<ui::ButtonControl>("Click me"));
click->on_click([label, n = 0]() mutable { label->set_text(std::format("Clicks: {}", ++n)); });
window.set_content(std::move(stack)); // the window takes ownership of the whole subtree
// The same tree, declared:
ui::Property<int> clicks{0};
window.set_content(ui::VerticalStack{
.spacing = 12,
.content = {
ui::Text{ .text = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); }) },
ui::Button{ .text = "Click me", .on_click = [&] { ++clicks; } },
},
});
ui::VerticalStack¶
A column of children. Builds a ui::StackControl with vertical orientation.
Children are measured with unbounded height and stacked top to bottom; child_alignment decides their horizontal placement (a child's own horizontal_alignment still applies inside that).
Example:
ui::Property<int> clicks{0};
window.set_content(ui::VerticalStack{
.spacing = 12,
.child_alignment = ui::Alignment::Leading,
.margin = ui::Thickness{24.0f},
.content = {
ui::Text{.text = "Appearance", .role = ui::TextRole::Subtitle},
ui::Text{.text = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); })},
ui::HorizontalStack{.spacing = 8, .content = {
ui::Button{.text = "Click me", .on_click = [&] { ++clicks; }},
ui::Button{.text = "Reset", .on_click = [&] { clicks = 0; }},
}},
},
});
Every field, in the order a designated initializer names them:
ui::VerticalStack{
.spacing, .child_alignment, .children_transitions, .background, .background_transition,
.border_brush, .border_thickness, .corner_radius, .padding, .style, .margin, .width,
.height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_pointer_entered,
.on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control,
.content
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
spacing |
ui::Binding<float> |
{0.0f} |
Gap between adjacent children, DIPs. |
child_alignment |
ui::Binding<ui::Alignment> |
{ui::Alignment::Stretch} |
Where children sit across the stack axis; Stretch (the default) sizes them to the panel. |
children_transitions |
ui::Binding<ui::TransitionList> |
Transitions every child runs: an EntranceTransition as each is first laid out, a RepositionTransition as layout moves it. | |
background |
ui::Binding<ui::Paint> |
Background behind the children: a Color, or a ThemeColor read from the theme; empty (the default) draws nothing. | |
background_transition |
ui::Binding<std::optional<ui::BrushTransition>> |
Animates a background change (Animation.hpp's BrushTransition). | |
border_brush |
ui::Binding<ui::Paint> |
Border color, a Color or a ThemeColor; empty (the default) draws no border. | |
border_thickness |
ui::Binding<ui::Thickness> |
{ui::Thickness{}} |
Border width per edge, DIPs; it insets the children like padding. |
corner_radius |
ui::Binding<float> |
{0.0f} |
Corner radius of the background and the border, DIPs. |
padding |
ui::Binding<ui::Thickness> |
{ui::Thickness{}} |
Room between the border and the children, DIPs. |
on_pointer_entered |
ui::Action |
The pointer moved onto the control. | |
on_pointer_exited |
ui::Action |
The pointer left the control. | |
on_got_focus |
ui::Action |
Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this. | |
on_lost_focus |
ui::Action |
Keyboard focus left the control and everything inside it. | |
on_key_down |
ui::Callback<ui::Handling(const ui::KeyEvent&)> |
A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()). | |
on_wheel |
ui::Callback<ui::Handling(const ui::PointerEvent&)> |
A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()). | |
control |
ui::ControlOut<ui::VerticalStack> |
Out: the handle that receives the built control. | |
content |
ui::SpecList |
The stacked children, top to bottom. |
Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).
build¶
Consumes the spec and returns the built ui::StackControl; the caller owns it.
ui::HorizontalStack¶
A row of children. Builds a ui::StackControl with horizontal orientation.
The mirror of ui::VerticalStack: children stack left to right and child_alignment places them vertically.
Example:
window.set_content(ui::HorizontalStack{
.spacing = 8,
.child_alignment = ui::Alignment::Center,
.content = {
ui::Icon{.source = ui::Symbol::Save},
ui::Text{.text = "Unsaved changes"},
ui::Button{.text = "Save", .on_click = [&] { save(); }},
},
});
Every field, in the order a designated initializer names them:
ui::HorizontalStack{
.spacing, .child_alignment, .children_transitions, .background, .background_transition,
.border_brush, .border_thickness, .corner_radius, .padding, .style, .margin, .width,
.height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_pointer_entered,
.on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control,
.content
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
spacing |
ui::Binding<float> |
{0.0f} |
Gap between adjacent children, DIPs. |
child_alignment |
ui::Binding<ui::Alignment> |
{ui::Alignment::Stretch} |
Where children sit across the stack axis; Stretch (the default) sizes them to the panel. |
children_transitions |
ui::Binding<ui::TransitionList> |
Transitions every child runs: an EntranceTransition as each is first laid out, a RepositionTransition as layout moves it. | |
background |
ui::Binding<ui::Paint> |
Background behind the children: a Color, or a ThemeColor read from the theme; empty (the default) draws nothing. | |
background_transition |
ui::Binding<std::optional<ui::BrushTransition>> |
Animates a background change (Animation.hpp's BrushTransition). | |
border_brush |
ui::Binding<ui::Paint> |
Border color, a Color or a ThemeColor; empty (the default) draws no border. | |
border_thickness |
ui::Binding<ui::Thickness> |
{ui::Thickness{}} |
Border width per edge, DIPs; it insets the children like padding. |
corner_radius |
ui::Binding<float> |
{0.0f} |
Corner radius of the background and the border, DIPs. |
padding |
ui::Binding<ui::Thickness> |
{ui::Thickness{}} |
Room between the border and the children, DIPs. |
on_pointer_entered |
ui::Action |
The pointer moved onto the control. | |
on_pointer_exited |
ui::Action |
The pointer left the control. | |
on_got_focus |
ui::Action |
Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this. | |
on_lost_focus |
ui::Action |
Keyboard focus left the control and everything inside it. | |
on_key_down |
ui::Callback<ui::Handling(const ui::KeyEvent&)> |
A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()). | |
on_wheel |
ui::Callback<ui::Handling(const ui::PointerEvent&)> |
A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()). | |
control |
ui::ControlOut<ui::HorizontalStack> |
Out: the handle that receives the built control. | |
content |
ui::SpecList |
The stacked children, left to right. |
Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).
build¶
Consumes the spec and returns the built ui::StackControl; the caller owns it.
ui::StackControl¶
Derives from ui::Element.
Lays its children out in a single column or row, spacing apart.
The panel owns its children (add() takes a unique_ptr and hands back a non-owning observer). Each child is measured unbounded along the stack and gets the panel's full cross extent, where its own alignment places it. The declarative forms are ui::VerticalStack and ui::HorizontalStack.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
stack->set_spacing(12.0f);
ui::TextControl* label = stack->add(std::make_unique<ui::TextControl>("Clicks: 0"));
ui::ButtonControl* click = stack->add(std::make_unique<ui::ButtonControl>("Click me"));
click->on_click([label, n = 0]() mutable { label->set_text(std::format("Clicks: {}", ++n)); });
window.set_content(std::move(stack)); // the window takes ownership of the whole subtree
// The same tree, declared:
ui::Property<int> clicks{0};
window.set_content(ui::VerticalStack{
.spacing = 12,
.content = {
ui::Text{ .text = ui::bind(clicks, [](int n) { return std::format("Clicks: {}", n); }) },
ui::Button{ .text = "Click me", .on_click = [&] { ++clicks; } },
},
});
StackControl¶
An empty vertical panel, no spacing, no background.
StackControl¶
An empty panel stacking in orientation.
add¶
Takes ownership of a child, appends it after the last one, and returns a non-owning observer to it. The panel is the sole owner, so the pointer is valid only while the child is in the panel. Invalidates layout.
add¶
The declarative overload: builds spec (or takes the node a ui::Spec holds) and adds it as add() does a control. Returns the built node as an Element, or nullptr for an empty ui::Spec, which adds nothing; a spec's .control field gives a typed observer.
insert¶
add() at index (clamped to the end) instead of after the last child.
children¶
The children in stacking order (owned by the panel).
remove¶
Destroys child if it is one of this panel's. False when it is not. Any observer to it dangles afterwards. With an AddRemoveTransition in children_transitions(), the child leaves visibly. It drops out of layout, input and the tab ring at once, fades out where it was, and is destroyed when the fade has played.
orphan¶
Takes child out of the panel alive and hands it back, for adding somewhere else. Focus inside it is cleared and it plays no exit transition. Null when it is not one of this panel's children.
clear¶
Destroys every child, each one leaving as it does with remove().
orientation¶
The stacking direction; Vertical by default.
set_orientation¶
Changes the direction; invalidates layout.
spacing¶
The gap between neighboring children, in DIPs; 0 by default.
set_spacing¶
Changes the gap; invalidates layout.
background¶
The background, filled behind the children; nullopt (the default) draws nothing. A ThemeColor is a theme resource, re-read whenever it is drawn (ui/BackgroundBrush.hpp).
background_resource¶
The theme resource the background follows, when set_background(ThemeColor) set one.
set_background¶
A fixed background color (nullopt clears it); redraws.
set_background¶
A theme-resource background, re-read on every theme change; redraws.
background_transition¶
With a transition set, a later change of what the background draws (a new color, or a resource under a new theme) blends from the color on screen (Animation.hpp's BrushTransition). nullopt (the default) changes it at once.
set_background_transition¶
Sets or clears the transition used by later background changes.
border_brush¶
The outline color; nullopt (the default) draws no border even with a non-zero border_thickness(). Nullopt as well while a ThemeColor is set.
border_brush_resource¶
The theme resource the border is drawn from, or null.
set_border_brush¶
A fixed outline color; replaces any resource. Redraws.
set_border_brush¶
An outline color read from the theme each time it is drawn; replaces any fixed color. Redraws.
border_thickness¶
The border width in DIPs per side (default zero); it insets the children like padding.
set_border_thickness¶
Sets the border width; updates the layout and redraws.
corner_radius¶
The corner radius in DIPs, uniform for all four corners (default 0, square). It rounds the background and the border; the children are not clipped.
set_corner_radius¶
Sets the corner radius; redraws.
padding¶
The room in DIPs between the border and the children (default zero).
set_padding¶
Sets the padding and updates the layout.
child_alignment¶
How children are placed across the stack. With Stretch, the default, every child gets the panel's full cross extent and its own horizontal_alignment() / vertical_alignment() positions it within that. Leading, Center and Trailing place every child at its desired cross size, and a child's own alignment then has no effect.
set_child_alignment¶
Changes child_alignment(); invalidates layout.
parallel_measure_safe¶
True: measuring touches only the panel and its children.
for_each_child¶
Lists the children in stacking order.
measure_override¶
Measures each child unbounded along the stack and bounded across it, caching the sizes; returns their sum along the stack (plus spacing) by the largest across.
arrange_override¶
Places the children one after another from the cached sizes, aligned per child_alignment().
render_override¶
Fills the background, then renders every child in order.
tick_override¶
Advances the background and exit transitions, then ticks every child.
Aliases¶
VerticalStackControl¶
The control a ui::VerticalStack builds: a StackControl whose orientation is Vertical.
HorizontalStackControl¶
The control a ui::HorizontalStack builds: a StackControl whose orientation is Horizontal.
Tests¶
tests/test_stack.cpp