C+
Packages · View as Markdown

flex_layout

Pure-C+ layout engine: CSS Flexbox + CSS Grid, optional @flex DSL and HIG presets. UI-kit-agnostic — computes frames; an adapter applies them. Nodes can hide and show themselves by named size band, resolved against the box they actually sit in.

[dependencies]
flex_layout = "*"
import "flex_layout/flex_layout" as flex;

var root: flex::Node = flex::Node::new();
root.set_flex_direction(flex::FlexDirection::Row);

var sidebar: flex::Node = flex::Node::new();
sidebar.set_width(flex::StyleLength::points(200.0f64));
root.add_child(sidebar);

var content: flex::Node = flex::Node::new();
content.set_flex_grow(1.0f64);
root.add_child(content);

root.calculate_layout(1024.0f64, 768.0f64, flex::Direction::LTR);

Conditional visibility

A node can state when it should be present, and the layout pass enforces it — no size observer, no callback, no re-evaluation by hand:

import "flex_layout/bands" as bands;

var set: bands::BandSet = bands::BandSet::defaults();
set.set("watch", max_width: 120.0f64, max_height: 120.0f64);   // or add your own

var sidebar: flex::Node = flex::Node::new().hide("compact");

root.calculate_layout(width: w, height: h, bands: #addr_of(set));

A band is a named box constraint (min_width / max_width / min_height / max_height, each optional). Six ship pre-registered — tiny, compact, medium, expanded, large, xlarge — so a shared vocabulary exists without setup; naming the threshold once is what stops two screens disagreeing about where a phone stops being a phone.

The band is measured against the node's nearest contained ancestor — the closest box up the tree whose size does not depend on its own contents — never the window. An app in Split View or on half a foldable was handed a box, and the screen's width would answer a question nobody asked.

Passing no bands skips the mechanism entirely, so rules cost nothing until a set is supplied.

Responsive configuration (superseded)

flex_layout/responsive still ships for existing callers; prefer bands above in new code. The host supplies the viewport size and chooses every class name and threshold, and reapplying the styles stays the host's job:

import "flex_layout/responsive" as responsive;

var screens: responsive::ResponsiveConfig =
    responsive::ResponsiveConfig::new("desktop");
screens.add_breakpoint("mobile", 300.0f64);  // width <= 300
screens.add_breakpoint("tablet", 900.0f64);  // 300 < width <= 900

let env: responsive::LayoutEnvironment = screens.resolve(view_width, view_height);
if env.is("mobile") {
    // Configure/build the compact form.
}

The module knows no devices, platforms, windows, or UI toolkits. On resize, resolve again. If next.is_same_class(previous) is true, recalculate the existing fluid layout; otherwise reapply class-specific styles or rebuild it. Thresholds use the same logical unit as the supplied viewport (points, CSS pixels, or another host-selected unit), never physical-screen detection.

Docs

File Role
docs/tutorial.md Fast path
docs/guide.md Flex, grid, bands, measure, DSL/HIG, adapters
docs/ref.md Types, enums, methods

Tests

cd vendor/flex_layout && cpc test