Class: RatatuiRuby::Layout::Rect

Inherits:
Object
  • Object
show all
Defined in:
lib/ratatui_ruby/layout/rect.rb

Overview

Defines a rectangular area in the terminal grid.

Geometry management involves passing groups of four integers (‘x, y, width, height`) repeatedly. This is verbose and prone to parameter mismatch errors.

This class encapsulates the geometry. It provides a standard primitive for passing area definitions between layout engines and rendering functions.

Use it when manual positioning is required or when querying layout results.

Examples

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

area = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
puts area.width # => 80

– SPDX-SnippetEnd ++

Instance Method Summary collapse

Constructor Details

#initialize(x: 0, y: 0, width: 0, height: 0) ⇒ Rect

Creates a new Rect.

All parameters accept any object responding to to_int or to_i (duck-typed).

x

Column index (Numeric).

y

Row index (Numeric).

width

Width in columns (Numeric).

height

Height in rows (Numeric).



57
58
59
60
61
62
63
64
# File 'lib/ratatui_ruby/layout/rect.rb', line 57

def initialize(x: 0, y: 0, width: 0, height: 0)
  super(
    x: Integer(x),
    y: Integer(y),
    width: Integer(width),
    height: Integer(height)
  )
end

Instance Method Details

#areaObject

Total area in cells.

Size comparisons and allocation calculations need area. Computing width * height inline is noisy and error-prone.

This method does the multiplication once.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 10, height: 5)
rect.area # => 50

– SPDX-SnippetEnd ++



286
287
288
# File 'lib/ratatui_ruby/layout/rect.rb', line 286

def area
  width * height
end

#as_positionObject Also known as: position

Extracts the position (x, y) from this rect.

Layout code sometimes separates position from size. Extracting x and y into multiple variables is verbose.

This method returns a Position object containing just the coordinates.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.as_position # => Position(x: 10, y: 5)

– SPDX-SnippetEnd ++



596
597
598
# File 'lib/ratatui_ruby/layout/rect.rb', line 596

def as_position
  Position.new(x:, y:)
end

#as_sizeObject Also known as: size

Extracts the size (width, height) from this rect.

Layout code sometimes separates size from position. Extracting width and height into multiple variables is verbose.

This method returns a Size object containing just the dimensions.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.as_size # => Size(width: 80, height: 24)

– SPDX-SnippetEnd ++



619
620
621
# File 'lib/ratatui_ruby/layout/rect.rb', line 619

def as_size
  Size.new(width:, height:)
end

#bottomObject

Bottom edge coordinate.

Bounds checks compare edges. Writing y + height inline clutters conditions. Errors creep in when you forget the addition.

This method computes and names the boundary. Returns the first row outside the rect.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.bottom # => 29

– SPDX-SnippetEnd ++



263
264
265
# File 'lib/ratatui_ruby/layout/rect.rb', line 263

def bottom
  y + height
end

#centered(horizontal_constraint, vertical_constraint) ⇒ Object

Returns a new Rect, centered both horizontally and vertically within this rect.

Modal dialogs often need exact centering on both axes. Computing both offsets manually is tedious.

This method chains centered_horizontally and centered_vertically.

horizontal_constraint

Constraint defining the width of the centered area.

vertical_constraint

Constraint defining the height of the centered area.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 100, height: 100)
rect.centered(Constraint.length(40), Constraint.length(20))
# => Rect(x: 30, y: 40, width: 40, height: 20)

– SPDX-SnippetEnd ++



700
701
702
# File 'lib/ratatui_ruby/layout/rect.rb', line 700

def centered(horizontal_constraint, vertical_constraint)
  centered_horizontally(horizontal_constraint).centered_vertically(vertical_constraint)
end

#centered_horizontally(constraint) ⇒ Object

Returns a new Rect, centered horizontally within this rect based on the constraint.

Modal dialogs and centered content need horizontal centering. Computing the left offset manually is error-prone.

This method uses Layout to compute the centered position.

constraint

Constraint defining the width of the centered area.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 100, height: 24)
rect.centered_horizontally(Constraint.length(40))
# => Rect(x: 30, y: 0, width: 40, height: 24)

– SPDX-SnippetEnd ++



645
646
647
648
# File 'lib/ratatui_ruby/layout/rect.rb', line 645

def centered_horizontally(constraint)
  areas = Layout.split(self, direction: :horizontal, constraints: [constraint], flex: :center)
  areas.first
end

#centered_vertically(constraint) ⇒ Object

Returns a new Rect, centered vertically within this rect based on the constraint.

Modal dialogs and centered content need vertical centering. Computing the top offset manually is error-prone.

This method uses Layout to compute the centered position.

constraint

Constraint defining the height of the centered area.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 80, height: 100)
rect.centered_vertically(Constraint.length(20))
# => Rect(x: 0, y: 40, width: 80, height: 20)

– SPDX-SnippetEnd ++



672
673
674
675
# File 'lib/ratatui_ruby/layout/rect.rb', line 672

def centered_vertically(constraint)
  areas = Layout.split(self, direction: :vertical, constraints: [constraint], flex: :center)
  areas.first
end

#clamp(other) ⇒ Object

Constrains the rect to fit inside bounds.

Popups and tooltips may extend beyond screen edges. Manually clamping x, y, width, and height is verbose and error-prone.

This method repositions and shrinks the rect to stay within bounds.

other

Bounding Rect.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

screen = Layout::Rect.new(x: 0, y: 0, width: 100, height: 100)
popup = Layout::Rect.new(x: 80, y: 80, width: 30, height: 30)
popup.clamp(screen) # => Rect(x: 70, y: 70, width: 30, height: 30)

– SPDX-SnippetEnd ++



487
488
489
490
491
492
493
494
# File 'lib/ratatui_ruby/layout/rect.rb', line 487

def clamp(other)
  clamped_width = [width, other.width].min
  clamped_height = [height, other.height].min
  clamped_x = x.clamp(other.left, other.right - clamped_width)
  clamped_y = y.clamp(other.top, other.bottom - clamped_height)

  Rect.new(x: clamped_x, y: clamped_y, width: clamped_width, height: clamped_height)
end

#columnsObject

Iterates over vertical slices.

Grids render column by column. Looping width.times and constructing rects inline is noisy.

This method yields each column as a Rect with width 1. Returns an Enumerator if no block given.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 5, height: 3)
rect.columns.map { |c| c.x } # => [0, 1, 2, 3, 4]

– SPDX-SnippetEnd ++



540
541
542
543
544
545
546
# File 'lib/ratatui_ruby/layout/rect.rb', line 540

def columns
  return to_enum(:columns) unless block_given?

  width.times do |i|
    yield Rect.new(x: x + i, y:, width: 1, height:)
  end
end

#contains?(px, py) ⇒ Boolean

Tests whether a point is inside this rectangle.

Essential for hit testing mouse clicks against layout regions.

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

area = Layout::Rect.new(x: 10, y: 5, width: 20, height: 10)
area.contains?(15, 8) # => true
area.contains?(5, 8)  # => false

– SPDX-SnippetEnd ++

px

X coordinate to test (column).

py

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

Y coordinate to test (row).

– SPDX-SnippetEnd ++ Returns true if the point (px, py) is within the rectangle bounds.

Returns:

  • (Boolean)


96
97
98
# File 'lib/ratatui_ruby/layout/rect.rb', line 96

def contains?(px, py)
  px >= x && px < x + width && py >= y && py < y + height
end

#empty?Boolean

True when the rect has zero area.

Zero-width or zero-height rects break layout math. Checking width == 0 || height == 0 inline is tedious and easy to forget.

Guard clauses call empty? to skip degenerate rects.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

Layout::Rect.new(width: 0, height: 10).empty? # => true
Layout::Rect.new(width: 10, height: 5).empty? # => false

– SPDX-SnippetEnd ++

Returns:

  • (Boolean)


309
310
311
# File 'lib/ratatui_ruby/layout/rect.rb', line 309

def empty?
  width.zero? || height.zero?
end

#inner(margin) ⇒ Object

Shrinks the rect by a uniform margin on all sides.

Widgets render text inside borders. Subtracting margin from all four edges inline is verbose. Off-by-one errors happen when you forget to double the margin.

This method computes the content area. Returns a zero-area rect if margin exceeds dimensions.

margin

Integer padding on all sides.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 20, height: 10)
rect.inner(2) # => Rect(x: 2, y: 2, width: 16, height: 6)

– SPDX-SnippetEnd ++



370
371
372
373
374
375
376
377
378
379
380
# File 'lib/ratatui_ruby/layout/rect.rb', line 370

def inner(margin)
  doubled = margin * 2
  return Rect.new(x: 0, y: 0, width: 0, height: 0) if width < doubled || height < doubled

  Rect.new(
    x: x + margin,
    y: y + margin,
    width: width - doubled,
    height: height - doubled
  )
end

#intersection(other) ⇒ Object

Returns the overlapping area between this rectangle and another.

Essential for calculating visible portions of widgets inside scroll views.

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

viewport = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
widget = Layout::Rect.new(x: 70, y: 20, width: 20, height: 10)
visible = viewport.intersection(widget)
# => Rect(x: 70, y: 20, width: 10, height: 4)

– SPDX-SnippetEnd ++

other

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

Another Rect to intersect with.

– SPDX-SnippetEnd ++ Returns a new Rect representing the intersection, or nil if no overlap.



164
165
166
167
168
169
170
171
172
173
# File 'lib/ratatui_ruby/layout/rect.rb', line 164

def intersection(other)
  return nil unless intersects?(other)

  new_x = [x, other.x].max
  new_y = [y, other.y].max
  new_right = [x + width, other.x + other.width].min
  new_bottom = [y + height, other.y + other.height].min

  Rect.new(x: new_x, y: new_y, width: new_right - new_x, height: new_bottom - new_y)
end

#intersects?(other) ⇒ Boolean

Tests whether this rectangle overlaps with another.

Essential for determining if a widget is visible within a viewport or clipping area.

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

viewport = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
widget = Layout::Rect.new(x: 70, y: 20, width: 20, height: 10)
viewport.intersects?(widget) # => true (partial overlap)

– SPDX-SnippetEnd ++

other

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

Another Rect to test against.

– SPDX-SnippetEnd ++ Returns true if the rectangles overlap.

Returns:

  • (Boolean)


128
129
130
131
132
133
# File 'lib/ratatui_ruby/layout/rect.rb', line 128

def intersects?(other)
  x < other.x + other.width &&
    x + width > other.x &&
    y < other.y + other.height &&
    y + height > other.y
end

#leftObject

Left edge coordinate.

Layout algorithms compute bounding boxes and check overlaps. Reading rect.x forces you to remember that x means “left.”

Call left instead. Your code reads like prose.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.left # => 10

– SPDX-SnippetEnd ++



194
195
196
# File 'lib/ratatui_ruby/layout/rect.rb', line 194

def left
  x
end

#offset(dx, dy) ⇒ Object

Moves the rect without changing size.

Animations and drag-and-drop shift widgets. Adding offsets to x and y inline clutters the code.

This method returns a translated copy.

dx

Horizontal shift (positive moves right).

dy

Vertical shift (positive moves down).

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 20, height: 10)
rect.offset(5, 3) # => Rect(x: 15, y: 8, width: 20, height: 10)

– SPDX-SnippetEnd ++



435
436
437
# File 'lib/ratatui_ruby/layout/rect.rb', line 435

def offset(dx, dy)
  Rect.new(x: x + dx, y: y + dy, width:, height:)
end

#outer(margin) ⇒ Object

Expands the rect by a uniform margin on all sides.

Containers wrap content with decorations. Adding margin to all four edges inline is verbose. Off-by-one errors happen when you forget to double the margin.

This method computes the outer area. Saturates x/y at 0 when margin exceeds position. Use Rect#clamp to constrain the result if it may exceed screen bounds.

margin

Integer expansion on all sides.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 10, width: 20, height: 10)
rect.outer(5) # => Rect(x: 5, y: 5, width: 30, height: 20)

– SPDX-SnippetEnd ++



404
405
406
407
408
409
410
411
# File 'lib/ratatui_ruby/layout/rect.rb', line 404

def outer(margin)
  new_x = [x - margin, 0].max
  new_y = [y - margin, 0].max
  new_width = right + margin - new_x
  new_height = bottom + margin - new_y

  Rect.new(x: new_x, y: new_y, width: new_width, height: new_height)
end

#positionsObject

Iterates over every cell in row-major order.

Hit testing and pixel rendering touch every position. Nested loops with manual coordinate math are verbose.

This method yields [x, y] pairs. Returns an Enumerator if no block given.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 2, height: 2)
rect.positions.to_a # => [[0, 0], [1, 0], [0, 1], [1, 1]]

– SPDX-SnippetEnd ++



567
568
569
570
571
572
573
574
575
# File 'lib/ratatui_ruby/layout/rect.rb', line 567

def positions
  return to_enum(:positions) unless block_given?

  height.times do |row|
    width.times do |col|
      yield [x + col, y + row]
    end
  end
end

#resize(new_size) ⇒ Object

Changes dimensions while preserving position.

Window resizing and responsive layouts adjust size mid-session. Creating a new rect with the same position but different size is common.

This method returns a resized copy. Position unchanged.

new_size

Size object with new dimensions.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 20, height: 10)
rect.resize(Size.new(width: 40, height: 20))
# => Rect(x: 10, y: 5, width: 40, height: 20)

– SPDX-SnippetEnd ++



461
462
463
# File 'lib/ratatui_ruby/layout/rect.rb', line 461

def resize(new_size)
  Rect.new(x:, y:, width: new_size.width, height: new_size.height)
end

#rightObject

Right edge coordinate.

Bounds checks compare edges. Writing x + width inline clutters conditions. Errors creep in when you forget the addition.

This method computes and names the boundary. Returns the first column outside the rect.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.right # => 90

– SPDX-SnippetEnd ++



217
218
219
# File 'lib/ratatui_ruby/layout/rect.rb', line 217

def right
  x + width
end

#rowsObject

Iterates over horizontal slices.

Lists render line by line. Looping height.times and constructing rects inline is noisy.

This method yields each row as a Rect with height 1. Returns an Enumerator if no block given.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 0, y: 0, width: 5, height: 3)
rect.rows.map { |r| r.y } # => [0, 1, 2]

– SPDX-SnippetEnd ++



514
515
516
517
518
519
520
# File 'lib/ratatui_ruby/layout/rect.rb', line 514

def rows
  return to_enum(:rows) unless block_given?

  height.times do |i|
    yield Rect.new(x:, y: y + i, width:, height: 1)
  end
end

#to_aryObject

Enables array destructuring of the rectangle.

Inline viewports and layout code often need position and size together. Accessing x, y, width, height individually is verbose.

This method allows convenient array destructuring.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

area = tui.viewport_area
x, y, width, height = area
# Now you can use x, y, width, height directly

– SPDX-SnippetEnd ++



724
725
726
# File 'lib/ratatui_ruby/layout/rect.rb', line 724

def to_ary
  [x, y, width, height]
end

#topObject

Top edge coordinate.

Layout algorithms compute bounding boxes and check overlaps. Reading rect.y forces you to remember that y means “top.”

Call top instead. Your code reads like prose.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
rect.top # => 5

– SPDX-SnippetEnd ++



240
241
242
# File 'lib/ratatui_ruby/layout/rect.rb', line 240

def top
  y
end

#union(other) ⇒ Object

Bounding box containing both rectangles.

Damage tracking and hit testing combine rects. Computing min/max of all four edges inline is tedious and error-prone.

This method returns the smallest rect that encloses both.

other

Rect to merge.

Example

– SPDX-SnippetBegin SPDX-FileCopyrightText: 2026 Kerrick Long SPDX-License-Identifier: MIT-0 ++

r1 = Layout::Rect.new(x: 0, y: 0, width: 10, height: 10)
r2 = Layout::Rect.new(x: 5, y: 5, width: 10, height: 10)
r1.union(r2) # => Rect(x: 0, y: 0, width: 15, height: 15)

– SPDX-SnippetEnd ++



335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/ratatui_ruby/layout/rect.rb', line 335

def union(other)
  new_x = [left, other.left].min
  new_y = [top, other.top].min
  new_right = [right, other.right].max
  new_bottom = [bottom, other.bottom].max

  Rect.new(
    x: new_x,
    y: new_y,
    width: new_right - new_x,
    height: new_bottom - new_y
  )
end