Mega UI
Rows and cards
How things end up where they do, and the one trick that means you never measure text.
Things stack down
Every call you make adds one thing below the last. There is no coordinate, no width and no margin to pass — the order you write is the order it appears.
ui.Header("Warehouse");
ui.Label("Everything currently in storage.");
ui.Button("Refresh", Report.Refresh);Rows lay out sideways
Inside a Row, things sit left to right instead of stacking.
ui.Row(r =>
{
r.Icon("package");
r.Label("Boxes");
r.Value(() => Warehouse.Count.ToString());
});Spacer is the whole trick
A label on the left and a number on the right is the most-wanted layout there is, and writing it
by hand means measuring the text to know where the number starts — which then breaks in
German, or in Japanese, or when the number goes from 7 to 1,204.
Spacer removes the measuring entirely. Everything before it anchors to the
left, everything after it to the right. Nobody measures anything
and the middle can be any size.
ui.Row(r =>
{
r.Label("Boxes in storage");
r.Spacer();
r.Value(() => Warehouse.Count.ToString());
});| Boxes in storage 1,204 |
\__ anchored left anchored right __/You can put a Spacer anywhere, including first — that pushes the whole row to
the right edge.
Cards group things
A Card is a panel with its own background. It sizes itself to whatever you put
inside, and everything works in there: rows, headers, even another card.
ui.Card(c =>
{
c.Header("Today");
c.Row(r =>
{
r.Label("Sold");
r.Spacer();
r.Value(() => Day.Sold.ToString());
});
c.Row(r =>
{
r.Label("Restocked");
r.Spacer();
r.Value(() => Day.Restocked.ToString());
});
});Columns split it sideways
Where a Row is one line, Columns is two or more stacks beside
each other. Each column is a full builder, and they all end up as tall as the tallest.
ui.Columns(
left =>
{
left.Header("Stock");
left.Row(r => { r.Label("Boxes"); r.Spacer(); r.Value(() => "..."); });
},
right =>
{
right.Header("Staff");
right.Row(r => { r.Label("On shift"); r.Spacer(); r.Value(() => "..."); });
});Long screens scroll by themselves
There is no Scrollable option, and that is deliberate. Whether a screen fits depends
on the shape of the player's monitor and on their language — the same screen
fits in English and overflows in German, where the words are longer and one label wraps onto an extra
line.
Nobody wins that guess while writing the mod. The library measures the real window, compares it to the real height of what you built, and turns scrolling on only when it is needed. The bar floats over the content rather than reserving a strip, so nothing reflows when it appears.
A window remembers nothing about where it was scrolled to. Reopening halfway down a list reads as a bug — the player does not remember scrolling, sees a cut-off header, and concludes the screen opened wrong.
For a drawing that is bigger than the window on both axes — a tree, a floor plan — you want a region instead, which the player drags and zooms.
Sizing something to the window
ui.Area is the visible area in pixels. It is what you need when a widget should fill
what is left rather than a number you guessed.
ui.Diagram(ui.Area.y, DrawEverything, bleed: true);Separators and gaps
| Call | What you get |
|---|---|
ui.Separator() | A horizontal line, with breathing room either side |
ui.Gap() | Blank vertical space — 12 pixels, or pass your own |
r.Gap() | The same, sideways, inside a row — 8 pixels by default |
What the layout deliberately does not do
There is no flex, no weight, no grid and no second measuring pass. Position is accumulated, not solved: each widget knows its own height, and the running total is the height of your screen.
It is the dumbest model that covers the job, and that is on purpose. A real layout engine would solve screens nobody is going to build inside a shop monitor, and it would buy an edge-case bug that nobody can debug from in there.
Unity ships one and it nearly works. Two problems: it runs at the end of the frame, so reading your height right after building returns zero and the window is the wrong size until the next frame; and it fights the scale bridge that maps pixels onto the computer's world-space units. Positioning by hand costs one file and gives a correct height in the same frame.