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
| Mode | Constant | XML | What it does |
|---|---|---|---|
| None | LAYOUT_NONE | (default) | Children stay where you put them. |
| Vertical box | LAYOUT_VBOX | layout="vbox" | Children in a column, top to bottom. |
| Horizontal box | LAYOUT_HBOX | layout="hbox" | Children in a row, left to right. |
| Grid | LAYOUT_GRID | layout="grid" | Children in rows of gridColumns cells. |
| Flow | LAYOUT_FLOW | layout="flow" | A row that wraps onto the next line when it runs out of width, like words in a paragraph. |
| Anchor | LAYOUT_ANCHOR | layout="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).
| Field | XML attribute | Applies to | Meaning |
|---|---|---|---|
spacing | spacing="8" | container | Gap between children along the main axis. |
padding | padding="12" | container | Space 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. |
align | align="center" | container | Cross-axis alignment: start, center, end. |
justify | justify="end" | container | Main-axis alignment: start, center, end, space-between. |
gridColumns | gridColumns="3" | grid container | Number of columns. |
flowRowGap | flow-row-gap="6" | flow container | Gap between wrapped rows. Falls back to spacing when zero. |
margin | margin="4" | child | Space around the child. |
fill | fill="width" | child | Stretch to the parent's content area: width, height or both (FILL_WIDTH, FILL_HEIGHT, FILL_BOTH). |
grow | grow="1" | child of a vbox or hbox | Share 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, maxHeight | same names | child | Size 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.