Foundations
Layout and Cell Management
NAppGUI's layout system is a recursive grid composer. Layout owns the rows, columns,
and cells; Cell stores per-item visibility, alignment, sizing, padding, and DBind state;
Panel and Window host the final composed tree.
_layout_compose() explicitly describes the engine as a
constraint-satisfaction algorithm with separate compose and locate phases.
Relevant Source Files
Layout and Cell Model
A Layout is created with a fixed grid size and each position is represented by a
Cell. A cell can hold either a GuiComponent, another nested Layout,
or remain empty. The public surface reflects that model through paired setters/getters such as
layout_button(...) and layout_get_button(...).
Beyond content, each cell tracks enabled/visible state, tabstop participation, per-axis alignment,
forced size, computed final size/origin, and padding. The surrounding Layout tracks line sizes,
expand weights, margins, background/stroke colors, DBind metadata, and a pointer back to its owning panel.
Compose Algorithm
Composition happens in two distinct phases. First, _layout_natural() walks the tree to compute
the natural width and height. Then _layout_expand() grows or shrinks each dimension to satisfy an
externally required size. Only after that does _layout_locate() assign final origins and call the
component-specific frame setters.
Width is solved before height because some widgets have height that depends on width, especially multi-line text. The code comment is explicit about the intent: compose manipulates numbers only, so it stays fast and defers native window/control updates to the locate pass.
Sizing, Alignment, and Visibility Controls
| Area | Representative API | Effect |
|---|---|---|
| Grid shape | layout_insert_col, layout_remove_row |
Changes the logical matrix after creation. |
| Explicit sizing | layout_hsize, layout_vsize, cell_force_size |
Overrides natural size for lines or individual cells. |
| Expansion | layout_hexpand*, layout_vexpand* |
Assigns resize weights when a window or panel is larger than natural size. |
| Alignment and padding | layout_halign, layout_valign, cell_padding* |
Controls where the composed content sits inside each partition. |
| Visibility and tab order | layout_show_col, layout_show_row, layout_taborder, layout_tabstop |
Removes lines from layout flow and controls keyboard navigation order. |
Panels Are Layout Hosts, Not Just Containers
A Panel does not own just one layout. Internally it keeps an ArrPt(Layout) plus
visible_layout and active_layout indices. panel_layout(...) appends layouts,
and panel_visible_layout(...) switches which one is active. When the active layout changes, the panel
re-attaches the right children and composes the new tree.
That matters because it means panel-level view switching is a first-class feature of the library, not a user-built convention. Scroll sizes, invalidation, and child attachment are all managed at the panel layer.
Window Integration
window_panel(...) does not attach a panel directly. It creates an internal 1x1 layout,
places the panel in cell (0, 0), and makes that layout the window's main_layout. On resize,
the window asks _layout_compose() to negotiate a constrained content size and then runs
_layout_locate() to push frames into the real controls.
This explains why layout behavior is the same whether the tree is nested inside another layout, mounted into a panel, or used as the root content of a top-level window.