Haiku BGridLayout: Stable Rows, Spans, and Responsive Forms
Build Haiku forms with BGridLayout's zero-based cells, spans, row and column constraints, while accounting for its current API status.
BGridLayout arranges Interface Kit layout items in rows and columns, with each item able to span multiple cells. It is useful for forms and compact panels where labels, controls, and help text align in a table-like structure. Unlike fixed coordinates, a grid can let controls participate in minimum-size calculations and respond to localization or window resizing.
The current Haiku GridLayout.dox contains an important warning: BGridLayout is not yet finalized and developers using it should assume the API may change in the future. It is available and documented, but code should isolate grid-specific construction so migration is manageable. Do not describe it as an immutable compatibility contract.
Coordinate and span semantics
Rows and columns are zero-based, starting in the upper-left corner. The overload AddView(view, column, row, columnCount, rowCount) places a view in that grid region. A control spanning two columns occupies a rectangular region and affects the size constraints for both columns. Empty cells are allowed. The layout expands to include added items; it does not require a perfectly filled matrix.
For a form, a clear pattern is a label in column zero and its editor in column one. Put explanatory text under the editor by using a third column or a row span deliberately. Keep each row’s semantic meaning obvious in the code; scattered numeric coordinates become difficult to review as forms evolve.
An illustrative setup is:
BGridView* form = new BGridView(8.0f, 4.0f);
BGridLayout* grid = form->GridLayout();
grid->AddView(nameLabel, 0, 0);
grid->AddView(nameControl, 1, 0);
grid->AddView(pathLabel, 0, 1);
grid->AddView(pathControl, 1, 1);
grid->SetColumnWeight(1, 1.0f);
This uses the public BGridView::GridLayout() accessor and grid insertion overloads. The example omits view construction and window attachment. Check each pointer allocation in production code, and add controls before the containing view is attached if the ownership flow requires it. Grid coordinates in the API are (column, row), not (row, column).
AddView() returns a BLayoutItem*; check that result when building a form dynamically so a rejected or failed insertion does not leave the UI model claiming that a field is visible when it is not. Keep the model update and layout insertion in one helper, and unwind any partially constructed row if a later control cannot be inserted.
BGridView is a convenience container
BGridView is a BView configured with a BGridLayout. Its public docs describe it as a convenience class for a table-like arrangement. Use it when a grid is the natural container; set the background and view name intentionally, then add child views through its layout. SetLayout() expects a BGridLayout or derivative; other layout types are ignored according to current documentation.
If the parent already owns a custom layout hierarchy, BGridLayout can be used directly rather than wrapping the same content in an unnecessary nested BGridView. Avoid redundant containers that add extra insets, preferred-size calculations, and focus-navigation boundaries without a clear purpose.
Spacing, weights, and constraints
The constructor accepts horizontal and vertical spacing. These settings determine inter-column and inter-row gaps, not the padding inside each control. Match spacing to the rest of the native UI and allow controls to report their preferred sizes. Hard-coded spacing that is too narrow can collide with localized text; one global large value can waste space in compact preferences.
Column and row weights guide how extra space is distributed. Assign expansion weight to the column or row that should grow, such as a long text field, rather than making every column expand equally. Minimum and maximum row/column sizes can constrain geometry, but should not be used to force a control smaller than its readable preferred size. Test both a narrow window and a wide one to detect a grid that only works at one size.
Spanned views complicate sizing because their preferred size is distributed over several rows or columns. Use spans for semantically related content such as help text or a full-width separator, not to compensate for an unclear form layout. If one spanning item creates unexpected column widths, isolate its constraints and compare with a simpler non-spanning test case.
Dynamic forms and mutation
When adding or removing rows at runtime, update the model and layout as one coherent operation. Avoid leaving a label in one row and its input in another after deletion. A helper that constructs a whole logical row can reduce index mistakes; store the returned layout item or stable model key when later mutation is needed.
Do not use a displayed row number as an item identity. Insertions shift later coordinates. Rebuild the layout from the form model for substantial structural changes, or maintain a mapping from logical field IDs to grid cell positions. Check insertion results when using AddItem() overloads; duplicate or overlapping cells may be rejected by the grid layout.
For accessibility and keyboard use, add controls in a deliberate focus order and give each control a label or accessible meaning through the supported APIs. Visual alignment does not automatically associate a label with an editor or make tab navigation sensible. Test navigation after insertion/removal and when optional fields are hidden.
Layout API interaction
BGridLayout is one member of Haiku’s layout system, not a replacement for every layout. A vertical or horizontal group is clearer for a simple stack. A grid is appropriate when consistent columns/rows matter. Use nested layouts to express mixed structures: a grid for field rows with a vertical group for action buttons, for example. Keep the hierarchy shallow enough to understand but expressive enough that resizing is not based on arbitrary pixel positions.
Views and layout items have ownership rules. Adding a view to a layout affects the parent view tree; do not delete a child as if it were an independent top-level object while the layout still owns it. Remove or detach using the relevant layout/view API and update references before destruction. If a callback refers to a field by pointer, clear it when removing that field.
Known API status and future-proofing
Because Haiku’s documentation currently marks BGridLayout as not finalized, isolate creation behind a small helper or form builder. Do not expose BGridLayout internals through a large public application model. Keep tests that assert user-visible behavior rather than exact internal cell counts where possible. When upgrading Haiku headers, review the current GridLayout.h, GridView.h, and implementation before relying on old code.
This warning does not mean a developer should avoid the class categorically. It means compatibility risk should be acknowledged. If a project targets a fixed Haiku revision, pin the supported API and test that target. If it supports multiple revisions, compile and exercise the layout against each supported SDK.
Verification matrix
Test every field at minimum and preferred widths, long translated labels, large font settings, hidden/optional controls, and multi-line help text. Resize the window from minimum to maximum and confirm the expanding columns behave as intended. Test spans, empty cells, row insertion/removal, disabled fields, and focus traversal. Verify that a label remains visually connected to its field at both narrow and wide sizes.
Record Haiku revision and target architecture when a layout differs across builds. A grid geometry issue may come from a changed API, a child control’s preferred size, the selected font, or a stale constraint. Inspect those variables before replacing the entire layout with fixed coordinates.
BGridLayout is a strong fit for structured, resizable forms when its zero-based coordinate model, spanning behavior, and size constraints are explicit. BGridView supplies a convenient owning container; the parent layout system handles preferred-size negotiation; the application must keep logical form structure and focus order correct. Because the API is documented as not finalized, isolating its use is part of production readiness.
Related:
- How to Build Resizable Haiku Interfaces with BLayout Instead of Fixed Coordinates
- Haiku BWindow View Transactions: Batch Drawing Without Misusing the Lock
Sources: