Skip to content

GridWidget ​

Arrange child widgets in a two-dimensional grid with row and column spanning.

GridWidget is a layout container that positions children explicitly by row and column index. It supports fixed, content-based, and fill sizing for both columns and rows, with optional spanning across multiple rows or columns.

Basic Usage ​

Create a grid layout using the fluent API. Each cell is positioned with .Row() and .Column():

csharp
using Hex1b;
using Hex1b.Layout;

await using var terminal = Hex1bTerminal.CreateBuilder()
    .WithHex1bApp((app, options) => ctx =>
        ctx.Grid(g =>
        {
            g.Columns.Add(SizeHint.Fixed(22));
            g.Columns.Add(SizeHint.Fill);

            g.Rows.Add(SizeHint.Fixed(3));
            g.Rows.Add(SizeHint.Fill);
            g.Rows.Add(SizeHint.Fixed(1));

            return [
                g.Cell(c => c.Border(b => [
                    b.VStack(v => [
                        v.Text("📂 Files"),
                        v.Text("📊 Dashboard"),
                        v.Text("⚙️ Settings"),
                    ])
                ]).Title("Navigation")).RowSpan(0, 3).Column(0),

                g.Cell(c => c.Border(b => [
                    b.Text("Grid Layout Demo"),
                ]).Title("Header")).Row(0).Column(1),

                g.Cell(c => c.Border(b => [
                    b.Text("Main content area")
                ]).Title("Content")).Row(1).Column(1),

                g.Cell(c => c.Text(" Status: Ready")).Row(2).Column(1),
            ];
        }))
    .Build();

await terminal.RunAsync();

Simple Grid ​

Position cells by row and column index:

csharp

Cells default to row 0, column 0 with a span of 1. Use .Row(n) and .Column(n) to place them explicitly.

Row and Column Spanning ​

Cells can span multiple rows or columns using .RowSpan(row, span) and .ColumnSpan(col, span):

csharp
ctx.Grid(g => [
    // Spans rows 0 and 1 in column 0
    g.Cell(c => c.Text("Sidebar")).RowSpan(0, 2).Column(0).Width(20),

    // Spans columns 0 and 1 in row 0
    g.Cell(c => c.Text("Header")).Row(0).ColumnSpan(0, 2),
])
  • .RowSpan(row, span) — Start at row, occupy span rows
  • .ColumnSpan(col, span) — Start at col, occupy span columns
  • .Row(n) is shorthand for .RowSpan(n, 1)
  • .Column(n) is shorthand for .ColumnSpan(n, 1)

A classic application layout with sidebar, header, and content area:

csharp

The sidebar spans both rows while the header and content each occupy one row in the second column.

Sizing Columns and Rows ​

Column Width ​

Set column widths directly on cells or through explicit definitions:

csharp
  • .Width(n) — Fixed width of n characters
  • .FillWidth() — Fill remaining horizontal space
  • .FillWidth(weight) — Fill with proportional weight

Row Height ​

Similarly for row heights:

  • .Height(n) — Fixed height of n rows
  • .FillHeight() — Fill remaining vertical space
  • .FillHeight(weight) — Fill with proportional weight

Explicit Definitions ​

For more control, define columns and rows explicitly via GridContext:

csharp
ctx.Grid(g => {
    g.Columns.Add(SizeHint.Fixed(20));    // Column 0: 20 chars wide
    g.Columns.Add(SizeHint.Fill);          // Column 1: fill remaining

    g.Rows.Add(SizeHint.Fixed(3));         // Row 0: 3 rows tall
    g.Rows.Add(SizeHint.Fill);             // Row 1: fill remaining

    return [
        g.Cell(c => c.Text("Nav")).RowSpan(0, 2).Column(0),
        g.Cell(c => c.Text("Header")).Row(0).Column(1),
        g.Cell(c => c.Text("Content")).Row(1).Column(1),
    ];
})

Auto-Created Definitions

Columns and rows not covered by explicit definitions are auto-created from cell positions with Content sizing (shrink to fit). You only need explicit definitions when you want Fill or Fixed sizing.

Layout Algorithm ​

GridWidget distributes space in two passes per axis:

  1. Fixed Pass: Fixed-size columns/rows get their exact size. Content-sized columns/rows are measured from their non-spanning cells, taking the maximum.
  2. Fill Pass: Remaining space is distributed among fill columns/rows proportionally by weight.

All children receive the full width and height of their cell (accounting for any spans).

Common Patterns ​

Dashboard Layout ​

csharp
ctx.Grid(g => {
    g.Columns.Add(SizeHint.Fill);
    g.Columns.Add(SizeHint.Fill);

    g.Rows.Add(SizeHint.Fixed(1));
    g.Rows.Add(SizeHint.Fill);
    g.Rows.Add(SizeHint.Fill);

    return [
        g.Cell(c => c.Text("Dashboard")).Row(0).ColumnSpan(0, 2),
        g.Cell(c => c.Border(b => [b.Text("Chart 1")]).Title("Sales"))
            .Row(1).Column(0),
        g.Cell(c => c.Border(b => [b.Text("Chart 2")]).Title("Users"))
            .Row(1).Column(1),
        g.Cell(c => c.Border(b => [b.Text("Details")]).Title("Activity"))
            .Row(2).ColumnSpan(0, 2),
    ];
})

Form with Labels ​

csharp
ctx.Grid(g => [
    g.Cell(c => c.Text("Name:")).Row(0).Column(0).Width(12),
    g.Cell(c => c.TextBox(nameState)).Row(0).Column(1).FillWidth(),

    g.Cell(c => c.Text("Email:")).Row(1).Column(0),
    g.Cell(c => c.TextBox(emailState)).Row(1).Column(1),

    g.Cell(c => c.Text("Notes:")).Row(2).Column(0),
    g.Cell(c => c.TextBox(notesState)).Row(2).Column(1),
])

Released under the MIT License.