Class: RatatuiRuby::Layout::Layout
- Inherits:
-
Object
- Object
- RatatuiRuby::Layout::Layout
- Defined in:
- lib/ratatui_ruby/layout/layout.rb
Overview
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//app.rb
Constant Summary collapse
- FLEX_MODES =
:attr_reader: flex Strategy for distributing extra space.
One of
:legacy,:start,:center,:end,:space_between,:space_around. %i[legacy start center end space_between space_around space_evenly].freeze
- DIRECTION_VERTICAL =
Direction: split vertically (top to bottom).
:vertical- DIRECTION_HORIZONTAL =
Direction: split horizontally (left to right).
:horizontal- FLEX_LEGACY =
Flex: use legacy sizing (default).
:legacy- FLEX_START =
Flex: align to start.
:start- FLEX_CENTER =
Flex: center alignment.
:center- FLEX_END =
Flex: align to end.
:end- FLEX_SPACE_BETWEEN =
Flex: space between elements.
:space_between- FLEX_SPACE_AROUND =
Flex: space around elements.
:space_around- FLEX_SPACE_EVENLY =
Flex: space evenly between elements.
:space_evenly
Class Method Summary collapse
-
.split(area, direction: :vertical, constraints:, flex: :legacy) ⇒ Object
Splits an area into multiple rectangles.
-
.split_with_spacers(area, direction: :vertical, constraints:, flex: :legacy) ⇒ Object
Splits an area into multiple rectangles, returning both segments and spacers.
Instance Method Summary collapse
-
#initialize(direction: :vertical, constraints: [], children: [], flex: :legacy, margin: 0, spacing: 0) ⇒ Layout
constructor
Creates a new Layout.
Constructor Details
#initialize(direction: :vertical, constraints: [], children: [], flex: :legacy, margin: 0, spacing: 0) ⇒ Layout
Creates a new Layout.
- direction
-
:verticalor:horizontal(default::vertical). - constraints
-
list of Constraint objects.
- 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).
114 115 116 |
# File 'lib/ratatui_ruby/layout/layout.rb', line 114 def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy, margin: 0, spacing: 0) super end |
Class Method Details
.split(area, direction: :vertical, constraints:, flex: :legacy) ⇒ Object
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.
– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++
rects = Layout::Layout.split(
area,
direction: :horizontal,
constraints: [Layout::Constraint.percentage(50), Layout::Constraint.percentage(50)]
)
left, right = rects
– SPDX-SnippetEnd ++
- 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
-
– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++
Flex mode for spacing (default: <tt>:legacy</tt>).– SPDX-SnippetEnd ++ Returns an Array of
Rectobjects.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# 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 |
.split_with_spacers(area, direction: :vertical, constraints:, flex: :legacy) ⇒ Object
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
-
– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++
Flex mode for spacing (default: <tt>:legacy</tt>).– SPDX-SnippetEnd ++ Returns an Array of two Arrays:
[segments, spacers], each containingRectobjects.Example
– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++
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– SPDX-SnippetEnd ++
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# 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 |
