class RatatuiRuby::Layout::Layout
Divides an area into smaller chunks.
Terminal screens vary in size. Hardcoded positions break when the window resizes. You need a way to organize space dynamically.
This class manages geometry. It splits a given area into multiple sections based on a list of constraints.
Use layouts to build responsive grids. Stack sections vertically for a sidebar-main structure. Partition them horizontally for headers and footers. Let the layout engine do the math.
Example
Run the interactive demo from the terminal:
ruby examples/widget_layout_split/app.rb
Constants
- DIRECTION_HORIZONTAL
-
Direction: split horizontally (left to right).
- DIRECTION_VERTICAL
-
Direction: split vertically (top to bottom).
- FLEX_CENTER
-
Flex: center alignment.
- FLEX_END
-
Flex: align to end.
- FLEX_LEGACY
-
Flex: use legacy sizing (default).
- FLEX_SPACE_AROUND
-
Flex: space around elements.
- FLEX_SPACE_BETWEEN
-
Flex: space between elements.
- FLEX_SPACE_EVENLY
-
Flex: space evenly between elements.
- FLEX_START
-
Flex: align to start.
Attributes
Widgets to render in each section (optional).
If provided, ‘children` is rendered into the area defined by `constraints`.
Array of rules defining section sizes.
Direction of the split.
Either :vertical (top to bottom) or :horizontal (left to right).
layout.direction # => :vertical
Margin around the layout area.
Either a single Integer for uniform margin on all sides, or a Hash with :horizontal and :vertical keys.
layout.margin # => 2
Gap between segments (in cells).
A positive integer that specifies the number of cells between each segment.
layout.spacing # => 1
Public Class Methods
Source
# File lib/ratatui_ruby/layout/layout.rb, line 114 def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy, margin: 0, spacing: 0) super end
Creates a new Layout.
- direction
-
:verticalor:horizontal(default::vertical). - constraints
-
list of
Constraintobjects. - children
-
List of widgets to render (optional).
- flex
-
Flex mode for spacing (default:
:legacy). - margin
-
Edge margin in cells (default:
0). - spacing
-
Gap between segments in cells (default:
0).
Source
# File lib/ratatui_ruby/layout/layout.rb, line 156 def self.split(area, direction: :vertical, constraints:, flex: :legacy) # Coerce area to Rect for type safety (supports duck typing via _RectLike interface) rect = case area when Rect area when Hash Rect.new( x: Integer(area.fetch(:x, 0)), y: Integer(area.fetch(:y, 0)), width: Integer(area.fetch(:width, 0)), height: Integer(area.fetch(:height, 0)) ) else # Duck typing: accept any object responding to x, y, width, height if area.respond_to?(:x) && area.respond_to?(:y) && area.respond_to?(:width) && area.respond_to?(:height) # @type var rect_like: _RectLike rect_like = area Rect.new(x: rect_like.x, y: rect_like.y, width: rect_like.width, height: rect_like.height) else raise ArgumentError, "area must be a Rect, Hash, or respond to x/y/width/height, got #{area.class}" end end raw_rects = _split(rect, direction, constraints, flex) raw_rects.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) } end
Splits an area into multiple rectangles.
This is a pure calculation helper for hit testing. It computes where widgets would be placed without actually rendering them.
rects = Layout::Layout.split( area, direction: :horizontal, constraints: [Layout::Constraint.percentage(50), Layout::Constraint.percentage(50)] ) left, right = rects
- area
-
The area to split. Can be a
Rector aHashcontaining:x,:y,:width, and:height. - direction
-
:verticalor:horizontal(default::vertical). - constraints
-
Array of
Constraintobjects defining section sizes. - flex
-
Flex mode for spacing (default:
:legacy).
Returns an Array of Rect objects.
Source
# File lib/ratatui_ruby/layout/layout.rb, line 231 def self.split_with_spacers(area, direction: :vertical, constraints:, flex: :legacy) # Coerce area to Rect for type safety rect = case area when Rect area when Hash Rect.new( x: Integer(area.fetch(:x, 0)), y: Integer(area.fetch(:y, 0)), width: Integer(area.fetch(:width, 0)), height: Integer(area.fetch(:height, 0)) ) else if area.respond_to?(:x) && area.respond_to?(:y) && area.respond_to?(:width) && area.respond_to?(:height) rect_like = area Rect.new(x: rect_like.x, y: rect_like.y, width: rect_like.width, height: rect_like.height) else raise ArgumentError, "area must be a Rect, Hash, or respond to x/y/width/height, got #{area.class}" end end raw_segments, raw_spacers = _split_with_spacers(rect, direction, constraints, flex) segments = raw_segments.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) } spacers = raw_spacers.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) } [segments, spacers] end
Splits an area into multiple rectangles, returning both segments and spacers.
Layout splitting returns only the content areas. But some designs need to render content in the gaps (dividers, separators, decorations).
This method returns both the segments (content areas) and the spacers (gaps between segments) as separate arrays. The spacers are the Rects that represent the spacing between each segment.
Use it to render custom separators or to calculate layout with spacing.
- area
-
The area to split. Can be a
Rector aHashcontaining:x,:y,:width, and:height. - direction
-
:verticalor:horizontal(default::vertical). - constraints
-
Array of
Constraintobjects defining section sizes. - flex
-
Flex mode for spacing (default:
:legacy).
Returns an Array of two Arrays: [segments, spacers], each containing Rect objects.
Example
area = Rect.new(x: 0, y: 0, width: 100, height: 10) segments, spacers = Layout.split_with_spacers( area, direction: :horizontal, constraints: [Constraint.length(40), Constraint.length(40)], flex: :space_around ) # segments: 2 Rects for content # spacers: Rects for gaps between/around segments
