TermUI.Layout.Solver (TermUI v0.2.0)

View Source

Constraint 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:

  1. Fixed pass - allocate length constraints exactly
  2. Percentage pass - calculate from total available space
  3. 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

direction()

@type direction() :: :horizontal | :vertical

rect()

@type rect() :: %{x: integer(), y: integer(), width: integer(), height: integer()}

solve_opts()

@type solve_opts() :: [
  direction: direction(),
  gap: non_neg_integer(),
  cross_axis: non_neg_integer() | nil
]

Functions

solve(constraints, available)

Solves constraints and returns a list of sizes.

Parameters

  • constraints - list of constraints to solve
  • available - 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]

solve_horizontal(constraints, area, opts \\ [])

@spec solve_horizontal([TermUI.Layout.Constraint.t()], rect(), keyword()) :: [rect()]

Solves horizontal layout (widths) with explicit cross-axis height.

Parameters

  • constraints - width constraints
  • area - bounding rectangle
  • opts - options including :gap

Returns

List of rectangles positioned horizontally.

solve_to_rects(constraints, area, opts \\ [])

@spec solve_to_rects([TermUI.Layout.Constraint.t()], rect(), solve_opts()) :: [rect()]

Solves constraints and returns positioned rectangles.

Parameters

  • constraints - list of constraints to solve
  • area - bounding rectangle with x, y, width, height
  • opts - 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}
]

solve_vertical(constraints, area, opts \\ [])

@spec solve_vertical([TermUI.Layout.Constraint.t()], rect(), keyword()) :: [rect()]

Solves vertical layout (heights) with explicit cross-axis width.

Parameters

  • constraints - height constraints
  • area - bounding rectangle
  • opts - options including :gap

Returns

List of rectangles positioned vertically.