Skip to content

Layout

Layout controls how widgets are sized and positioned inside a container. Vextr has three layout types: Stack, Grid, and Absolute.

Children line up vertically or horizontally. This is what you’ll use most of the time.

// vertical stack, 1-cell gap between children
auto container = std::make_shared<Container>(
std::make_shared<StackLayout>(Axis::Vertical, 1)
);
// horizontal stack, no gap
auto toolbar = std::make_shared<Container>(
std::make_shared<StackLayout>(Axis::Horizontal, 0)
);
Vertical (Axis::Vertical, gap=1) Horizontal (Axis::Horizontal, gap=0)
┌─────────────┐ ┌──────┬──────┬──────┐
│ widget 1 │ │ w1 │ w2 │ w3 │
├─────────────┤ ← gap └──────┴──────┴──────┘
│ widget 2 │
├─────────────┤ ← gap
│ widget 3 │
└─────────────┘

By default, children share the available space equally via ratio = 1.0. Pass a LayoutSpec to addChild() to override this.

Pin a widget to an exact number of rows or columns using cells():

root->addChild(header, { .fixedH = cells(1) }); // always 1 row tall
root->addChild(content); // fills remaining space
root->addChild(footer, { .fixedH = cells(1) }); // always 1 row tall
┌─────────────┐ ← header (fixedH = 1)
├─────────────┤
│ │
│ content │ ← fills everything left over
│ │
├─────────────┤
└─────────────┘ ← footer (fixedH = 1)

This header/content/footer pattern appears in almost every Vextr app.

Share remaining space proportionally between children:

container->addChild(sidebar, { .ratio = 1.0f }); // 1/3 of space
container->addChild(main, { .ratio = 2.0f }); // 2/3 of space

Constrain how small or large a widget can grow:

container->addChild(widget, { .minW = cells(20), .maxW = cells(60) });

When a widget is smaller than its slot, align it:

container->addChild(widget, {
.sizeW = cells(20), // widget is 20 cols wide
.alignH = Align::Center, // centered horizontally in its slot
});
FieldWhat it does
fixedWFixed width in terminal columns
fixedHFixed height in terminal rows
ratioProportional share of remaining space (default 1)
sizeWWidget width inside its slot
sizeHWidget height inside its slot
minW/minHMinimum size
maxW/maxHMaximum size
alignHHorizontal alignment within slot
alignVVertical alignment within slot
marginSpace around the widget

Children fill a grid of rows and columns.

auto grid = std::make_shared<Container>(
std::make_shared<GridLayout>(2, 3) // 2 rows, 3 columns
);

Place children at specific cells using col and row:

grid->addChild(widget, { .col = 0, .row = 0 });
grid->addChild(widget, { .col = 1, .row = 0 });
grid->addChild(widget, { .col = 0, .row = 1 });

Span multiple cells with colSpan and rowSpan:

grid->addChild(header, { .col = 0, .row = 0, .colSpan = 3 }); // full width
┌──────┬──────┬──────┐
│ header (span 3) │
├──────┼──────┼──────┤
│ w1 │ w2 │ w3 │
└──────┴──────┴──────┘

Children are placed at explicit coordinates. Useful for overlays and floating elements.

auto canvas = std::make_shared<Container>(
std::make_shared<AbsoluteLayout>()
);
canvas->addChild(widget, { .absX = cells(10), .absY = cells(5) });

Children can overlap - later children render on top of earlier ones.