Layout
A frame is built top-down: you ask the terminal for the root area, split it into sub-areas, optionally take the "inner" rectangle of a bordered block, and draw widgets into those areas.
Root Area
uint root = term.RootArea;
This is the full terminal rectangle (Cols × Rows). Every layout starts here.
Splitting
Split(area, direction, constraints…) returns child area IDs in declaration order.
// Top bar (3 rows) + main content (rest)
var rows = term.Split(root, Direction.Vertical,
Constraint.Length(3),
Constraint.Min(0));
uint topBar = rows[0];
uint main = rows[1];
Always guard against degenerate sizes:
if (rows.Length < 2) return;
When the terminal is too small to satisfy every constraint, Split may return fewer areas than requested.
Constraint Types
| Constraint | Meaning |
|---|---|
Constraint.Length(n) |
Exactly n rows/columns |
Constraint.Min(n) |
At least n, grows to absorb leftover space |
Constraint.Max(n) |
At most n, shrinks if needed |
Constraint.Percentage(p) |
Percent of parent area (0–100) |
Constraint.Fill(weight) |
Proportional fill against other Fill siblings |
Example with mixed types:
var cols = term.Split(main, Direction.Horizontal,
Constraint.Length(20), // fixed 20-col sidebar
Constraint.Percentage(60), // 60% of remaining
Constraint.Min(10)); // at least 10, takes leftover
Borders + Inner
Block draws a bordered frame; Inner(area) returns the rectangle inside the border so children don't overdraw the frame.
term.Block(area, "Title", Borders.All);
uint inner = term.Inner(area);
term.Paragraph(inner, "Body text inside the bordered block.");
Borders is a flag enum: Borders.Top | Borders.Bottom, Borders.Left | Borders.Right, Borders.All, Borders.None.
Area Hit-Testing
Every area ID can be reverse-queried for its terminal rectangle, useful for mouse input:
if (term.TryGetAreaRect(inner, out int x, out int y, out int w, out int h))
{
// x, y, w, h in terminal cells
}
See Input Handling for using these IDs in mouse routing.
Nested Example
protected override void BuildFrame(RatatuiTerminal term)
{
uint root = term.RootArea;
// Header + body
var outerRows = term.Split(root, Direction.Vertical,
Constraint.Length(3),
Constraint.Min(0));
if (outerRows.Length < 2) return;
// Two-column body
var bodyCols = term.Split(outerRows[1], Direction.Horizontal,
Constraint.Percentage(30),
Constraint.Percentage(70));
if (bodyCols.Length < 2) return;
term.Block(outerRows[0], "Header", Borders.All);
term.Block(bodyCols[0], "Sidebar", Borders.All);
term.Block(bodyCols[1], "Content", Borders.All);
term.Paragraph(term.Inner(bodyCols[1]), "Hello, layout.");
}