TermUI.Layout.Solver (TermUI v0.2.0)
View SourceConstraint solver for the layout system.
Translates constraints into concrete cell positions and sizes using a Cassowary-inspired greedy multi-pass algorithm.
Algorithm
The solver processes constraints in priority order:
- Fixed pass - allocate length constraints exactly
- Percentage pass - calculate from total available space
- Ratio/Fill pass - distribute remaining space proportionally
Examples
# Three-pane layout
constraints = [
Constraint.length(20),
Constraint.ratio(1),
Constraint.ratio(2)
]
sizes = Solver.solve(constraints, 100)
# => [20, 27, 53]
# Get positioned rectangles
rects = Solver.solve_to_rects(constraints, %{x: 0, y: 0, width: 100, height: 10})
# => [
# %{x: 0, y: 0, width: 20, height: 10},
# %{x: 20, y: 0, width: 27, height: 10},
# %{x: 47, y: 0, width: 53, height: 10}
# ]
Summary
Functions
Solves constraints and returns a list of sizes.
Solves horizontal layout (widths) with explicit cross-axis height.
Solves constraints and returns positioned rectangles.
Solves vertical layout (heights) with explicit cross-axis width.
Types
@type direction() :: :horizontal | :vertical
@type solve_opts() :: [ direction: direction(), gap: non_neg_integer(), cross_axis: non_neg_integer() | nil ]
Functions
@spec solve([TermUI.Layout.Constraint.t()], non_neg_integer()) :: [non_neg_integer()]
Solves constraints and returns a list of sizes.
Parameters
constraints- list of constraints to solveavailable- total available space in cells
Returns
List of solved sizes (non-negative integers) in same order as constraints.
Examples
iex> Solver.solve([Constraint.length(20), Constraint.fill()], 100)
[20, 80]
iex> Solver.solve([Constraint.percentage(50), Constraint.percentage(50)], 100)
[50, 50]
iex> Solver.solve([Constraint.ratio(1), Constraint.ratio(2)], 90)
[30, 60]
@spec solve_horizontal([TermUI.Layout.Constraint.t()], rect(), keyword()) :: [rect()]
Solves horizontal layout (widths) with explicit cross-axis height.
Parameters
constraints- width constraintsarea- bounding rectangleopts- options including:gap
Returns
List of rectangles positioned horizontally.
@spec solve_to_rects([TermUI.Layout.Constraint.t()], rect(), solve_opts()) :: [rect()]
Solves constraints and returns positioned rectangles.
Parameters
constraints- list of constraints to solvearea- bounding rectangle with x, y, width, heightopts- solving options:direction-:horizontal(default) or:vertical:gap- spacing between elements (default 0):cross_axis- size on cross axis (default uses area dimension)
Returns
List of rectangles with x, y, width, height.
Examples
iex> Solver.solve_to_rects(
...> [Constraint.length(20), Constraint.fill()],
...> %{x: 0, y: 0, width: 100, height: 10}
...> )
[
%{x: 0, y: 0, width: 20, height: 10},
%{x: 20, y: 0, width: 80, height: 10}
]
@spec solve_vertical([TermUI.Layout.Constraint.t()], rect(), keyword()) :: [rect()]
Solves vertical layout (heights) with explicit cross-axis width.
Parameters
constraints- height constraintsarea- bounding rectangleopts- options including:gap
Returns
List of rectangles positioned vertically.