Skip to content

Layout ​

Any component can arrange its children. Set its layout and add children; willowui positions them on the next update. Leave layout at LAYOUT_NONE and you place children yourself with setPosition.

The layout modes ​

ModeConstantXMLWhat it does
NoneLAYOUT_NONE(default)Children stay where you put them.
Vertical boxLAYOUT_VBOXlayout="vbox"Children in a column, top to bottom.
Horizontal boxLAYOUT_HBOXlayout="hbox"Children in a row, left to right.
GridLAYOUT_GRIDlayout="grid"Children in rows of gridColumns cells.
FlowLAYOUT_FLOWlayout="flow"A row that wraps onto the next line when it runs out of width, like words in a paragraph.
AnchorLAYOUT_ANCHORlayout="anchor"Each child is pinned to a corner, an edge or the center, with pixel offsets.

newVBox(name), newHBox(name) and newFlow(name) make a plain component with that layout already set.

A column of buttons ​

ts
import { Button, DEFAULT_STAGE, LAYOUT_VBOX, Panel, Screen } from "willowui";

const screen: Screen = new Screen();

const menu: Panel = new Panel("menu");
menu.layout = LAYOUT_VBOX;
menu.spacing = 8.0;
menu.setPadding(16.0, 16.0, 16.0, 16.0);
menu.setPosition(40.0, 40.0);

for (const title of ["New game", "Continue", "Settings", "Quit"]) {
    const b: Button = new Button(title, title, "default", 16.0);
    b.setSize(200.0, 40.0);
    menu.addChild(b);
}
menu.sizeToContent();
screen.add(menu);

DEFAULT_STAGE.setScene(engine.root2d);
DEFAULT_STAGE.add(screen);
App.onFrame((dt: float): void => { DEFAULT_STAGE.update(dt); });

sizeToContent() resizes the panel to fit its children. A template does this for you whenever a container has children but no size.

Box settings ​

These fields live on every component. Set them on the container (spacing, padding, align, justify) or on a child (fill, grow, margin, size limits).

FieldXML attributeApplies toMeaning
spacingspacing="8"containerGap between children along the main axis.
paddingpadding="12"containerSpace inside the edge. One value, "vertical,horizontal", or "top,right,bottom,left". On a Panel use setPadding(top, right, bottom, left) so the padding survives theme changes.
alignalign="center"containerCross-axis alignment: start, center, end.
justifyjustify="end"containerMain-axis alignment: start, center, end, space-between.
gridColumnsgridColumns="3"grid containerNumber of columns.
flowRowGapflow-row-gap="6"flow containerGap between wrapped rows. Falls back to spacing when zero.
marginmargin="4"childSpace around the child.
fillfill="width"childStretch to the parent's content area: width, height or both (FILL_WIDTH, FILL_HEIGHT, FILL_BOTH).
growgrow="1"child of a vbox or hboxShare of the space left after fixed-size children. Two children with grow="1" split it evenly; grow="2" takes twice as much.
minWidth, minHeight, maxWidth, maxHeightsame nameschildSize limits. A max of zero means no limit.

The alignment constants are ALIGN_START, ALIGN_CENTER, ALIGN_END and ALIGN_SPACE_BETWEEN.

After changing a layout field in code, call component.markLayoutDirty() so the next update lays it out again. The XML setters do this for you.

Anchors ​

An anchor layout pins each child to one of nine points of the parent: ANCHOR_TOP_LEFT, ANCHOR_TOP_CENTER, ANCHOR_TOP_RIGHT, ANCHOR_MIDDLE_LEFT, ANCHOR_CENTER, ANCHOR_MIDDLE_RIGHT, ANCHOR_BOTTOM_LEFT, ANCHOR_BOTTOM_CENTER, ANCHOR_BOTTOM_RIGHT. It suits game HUDs: health in one corner, a minimap in another.

ts
import { ANCHOR_BOTTOM_RIGHT, ANCHOR_TOP_LEFT, Component, DEFAULT_STAGE, LAYOUT_ANCHOR, Label, Screen } from "willowui";

const screen: Screen = new Screen();
const hud: Component = new Component("hud");
hud.layout = LAYOUT_ANCHOR;
hud.setSize(800.0, 600.0);

const health: Label = new Label("health", "HP 100", "default", 18.0);
hud.addAnchoredChild(health, ANCHOR_TOP_LEFT, 12.0, 12.0);

const gold: Label = new Label("gold", "Gold 250", "default", 18.0);
hud.addAnchoredChild(gold, ANCHOR_BOTTOM_RIGHT, -12.0, -12.0);

screen.add(hud);
DEFAULT_STAGE.setScene(engine.root2d);
DEFAULT_STAGE.add(screen);
App.onFrame((dt: float): void => { DEFAULT_STAGE.update(dt); });

setAnchor(child, anchor, offsetX, offsetY) moves a child that is already anchored. The AnchorLayout widget is the same idea with a background and border.

Two columns of label and field ​

TwoColumnLayout lines up pairs: a label on the left, a control on the right. Add rows with addRow(left, right). Its settings are gap (between the columns), rowSpacing, leftWidth or columnRatio, and leftAlign / rightAlign. It is the quickest way to build a settings form; see Recipe: a form.

Scrolling ​

Put content taller than the view in a ScrollPanel, give the panel its visible size with setSize, and tell it the content size with setContentSize(w, h). It draws scroll bars and scrolls with the mouse wheel. List, TreeList, TileList and DataTable scroll on their own.

Layout in XML ​

Every attribute above has the same name in XML. Layout from XML shows each mode as a template.