Layout & containers

Two-phase layout

Every widget participates in the same two-phase pass: measure asks each widget how tall it wants to be for a given width, then arrange hands each a final rectangle. Containers implement layout by measuring their children and placing them; leaves just report a size and draw. Because layout is deterministic and top-down, there is no constraint solver to reason about — a container's rule is plain code.

The containers

auto form = column(
    field("Name",     textField("ball")),
    field("Radius",   numberField(1.5f)),
    row(flex(button("Cancel"), 1), flex(button("Apply"), 2)));   // 1:2 width split

flex(child, weight) marks a row child as stretchy; fixed children take their measured width and the remainder is split by weight. Nesting columns and rows builds any form layout without absolute coordinates.

Scrolling, sections, tabs

Three containers handle overflow and grouping:

Working in points

All layout is in logical points, with the DPI scale folded in by the canvas. A single uiScale factor scales every metric and font size together (the way a desktop "UI scale" setting does), and text stays crisp because the FontBook rasterizes at the target size rather than scaling a bitmap. The result: the same layout code produces a pixel-perfect interface at any density or scale.

For arranging whole panels — resizable, tabbable, tear-off regions — rather than widgets within a panel, see docking.