Skip to content

Geometry

Functions and classes to manage terminal geometry (anything involving coordinates or dimensions).

NULL_OFFSET module-attribute

NULL_OFFSET: Final = Offset(0, 0)

An offset constant for (0, 0).

NULL_REGION module-attribute

NULL_REGION: Final = Region(0, 0, 0, 0)

A Region constant for a null region (at the origin, with both width and height set to zero).

NULL_SIZE module-attribute

NULL_SIZE: Final = Size(0, 0)

A Size constant for a null size (with zero area).

NULL_SPACING module-attribute

NULL_SPACING: Final = Spacing(0, 0, 0, 0)

A Spacing constant for no space.

SpacingDimensions module-attribute

SpacingDimensions: TypeAlias = Union[
    int,
    Tuple[int],
    Tuple[int, int],
    Tuple[int, int, int, int],
]

The valid ways in which you can specify spacing.

Offset class

Bases: NamedTuple

A cell offset defined by x and y coordinates.

Offsets are typically relative to the top left of the terminal or other container.

Textual prefers the names x and y, but you could consider x to be the column and y to be the row.

Offsets support addition, subtraction, multiplication, and negation.

Example
>>> from textual.geometry import Offset
>>> offset = Offset(3, 2)
>>> offset
Offset(x=3, y=2)
>>> offset += Offset(10, 0)
>>> offset
Offset(x=13, y=2)
>>> -offset
Offset(x=-13, y=-2)

clamped property

clamped: Offset

This offset with x and y restricted to values above zero.

is_origin property

is_origin: bool

Is the offset at (0, 0)?

x class-attribute instance-attribute

x: int = 0

Offset in the x-axis (horizontal)

y class-attribute instance-attribute

y: int = 0

Offset in the y-axis (vertical)

blend method

def blend(self, destination, factor):

Calculate a new offset on a line between this offset and a destination offset.

Parameters
Parameter Default Description
destination
Offset
required

Point where factor would be 1.0.

factor
float
required

A value between 0 and 1.0.

Returns
Type Description
Offset

A new point on a line between self and destination.

get_distance_to method

def get_distance_to(self, other):

Get the distance to another offset.

Parameters
Parameter Default Description
other
Offset
required

An offset.

Returns
Type Description
float

Distance to other offset.

Region class

Bases: NamedTuple

Defines a rectangular region.

A Region consists of a coordinate (x and y) and dimensions (width and height).

  (x, y)
    ┌────────────────────┐ ▲
    │                    │ │
    │                    │ │
    │                    │ height
    │                    │ │
    │                    │ │
    └────────────────────┘ ▼
    ◀─────── width ──────▶
Example
>>> from textual.geometry import Region
>>> region = Region(4, 5, 20, 10)
>>> region
Region(x=4, y=5, width=20, height=10)
>>> region.area
200
>>> region.size
Size(width=20, height=10)
>>> region.offset
Offset(x=4, y=5)
>>> region.contains(1, 2)
False
>>> region.contains(10, 8)
True

area property

area: int

The area under the region.

bottom property

bottom: int

Maximum Y value (non inclusive).

bottom_left property

bottom_left: Offset

Bottom left offset of the region.

Returns
Type Description
Offset

An offset.

bottom_right property

bottom_right: Offset

Bottom right offset of the region.

Returns
Type Description
Offset

An offset.

center property

center: tuple[float, float]

The center of the region.

Note, that this does not return an Offset, because the center may not be an integer coordinate.

Returns
Type Description
tuple[float, float]

Tuple of floats.

column_range property

column_range: range

A range object for X coordinates.

column_span property

column_span: tuple[int, int]

A pair of integers for the start and end columns (x coordinates) in this region.

The end value is exclusive.

corners property

corners: tuple[int, int, int, int]

The top left and bottom right coordinates as a tuple of four integers.

height class-attribute instance-attribute

height: int = 0

The height of the region.

line_range property

line_range: range

A range object for Y coordinates.

line_span property

line_span: tuple[int, int]

A pair of integers for the start and end lines (y coordinates) in this region.

The end value is exclusive.

offset property

offset: Offset

The top left corner of the region.

Returns
Type Description
Offset

An offset.

reset_offset property

reset_offset: Region

An region of the same size at (0, 0).

Returns
Type Description
Region

A region at the origin.

right property

right: int

Maximum X value (non inclusive).

size property

size: Size

Get the size of the region.

top_right property

top_right: Offset

Top right offset of the region.

Returns
Type Description
Offset

An offset.

width class-attribute instance-attribute

width: int = 0

The width of the region.

x class-attribute instance-attribute

x: int = 0

Offset in the x-axis (horizontal).

y class-attribute instance-attribute

y: int = 0

Offset in the y-axis (vertical).

at_offset method

def at_offset(self, offset):

Get a new Region with the same size at a given offset.

Parameters
Parameter Default Description
offset
tuple[int, int]
required

An offset.

Returns
Type Description
Region

New Region with adjusted offset.

clip method

def clip(self, width, height):

Clip this region to fit within width, height.

Parameters
Parameter Default Description
width
int
required

Width of bounds.

height
int
required

Height of bounds.

Returns
Type Description
Region

Clipped region.

clip_size method

def clip_size(self, size):

Clip the size to fit within minimum values.

Parameters
Parameter Default Description
size
tuple[int, int]
required

Maximum width and height.

Returns
Type Description
Region

No region, not bigger than size.

contains method

def contains(self, x, y):

Check if a point is in the region.

Parameters
Parameter Default Description
x
int
required

X coordinate.

y
int
required

Y coordinate.

Returns
Type Description
bool

True if the point is within the region.

contains_point method

def contains_point(self, point):

Check if a point is in the region.

Parameters
Parameter Default Description
point
tuple[int, int]
required

A tuple of x and y coordinates.

Returns
Type Description
bool

True if the point is within the region.

contains_region cached

def contains_region(self, other):

Check if a region is entirely contained within this region.

Parameters
Parameter Default Description
other
Region
required

A region.

Returns
Type Description
bool

True if the other region fits perfectly within this region.

crop_size method

def crop_size(self, size):

Get a region with the same offset, with a size no larger than size.

Parameters
Parameter Default Description
size
tuple[int, int]
required

Maximum width and height (WIDTH, HEIGHT).

Returns
Type Description
Region

New region that could fit within size.

expand method

def expand(self, size):

Increase the size of the region by adding a border.

Parameters
Parameter Default Description
size
tuple[int, int]
required

Additional width and height.

Returns
Type Description
Region

A new region.

from_corners classmethod

def from_corners(cls, x1, y1, x2, y2):

Construct a Region form the top left and bottom right corners.

Parameters
Parameter Default Description
x1
int
required

Top left x.

y1
int
required

Top left y.

x2
int
required

Bottom right x.

y2
int
required

Bottom right y.

Returns
Type Description
Region

A new region.

from_offset classmethod

def from_offset(cls, offset, size):

Create a region from offset and size.

Parameters
Parameter Default Description
offset
tuple[int, int]
required

Offset (top left point).

size
tuple[int, int]
required

Dimensions of region.

Returns
Type Description
Region

A region instance.

from_union classmethod

def from_union(cls, regions):

Create a Region from the union of other regions.

Parameters
Parameter Default Description
regions
Collection[Region]
required

One or more regions.

Returns
Type Description
Region

A Region that encloses all other regions.

get_scroll_to_visible classmethod

def get_scroll_to_visible(
    cls, window_region, region, *, top=False
):

Calculate the smallest offset required to translate a window so that it contains another region.

This method is used to calculate the required offset to scroll something in to view.

Parameters
Parameter Default Description
window_region
Region
required

The window region.

region
Region
required

The region to move inside the window.

top
bool
False

Get offset to top of window.

Returns
Type Description
Offset

An offset required to add to region to move it inside window_region.

grow cached

def grow(self, margin):

Grow a region by adding spacing.

Parameters
Parameter Default Description
margin
tuple[int, int, int, int]
required

Grow space by (<top>, <right>, <bottom>, <left>).

Returns
Type Description
Region

New region.

inflect method

def inflect(self, x_axis=+1, y_axis=+1, margin=None):

Inflect a region around one or both axis.

The x_axis and y_axis parameters define which direction to move the region. A positive value will move the region right or down, a negative value will move the region left or up. A value of 0 will leave that axis unmodified.

╔══════════╗    │
║          ║
║   Self   ║    │
║          ║
╚══════════╝    │

─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─

                │    ┌──────────┐
                     │          │
                │    │  Result  │
                     │          │
                │    └──────────┘
Parameters
Parameter Default Description
x_axis
int
+1

+1 to inflect in the positive direction, -1 to inflect in the negative direction.

y_axis
int
+1

+1 to inflect in the positive direction, -1 to inflect in the negative direction.

margin
Spacing | None
None

Additional margin.

Returns
Type Description
Region

A new region.

intersection cached

def intersection(self, region):

Get the overlapping portion of the two regions.

Parameters
Parameter Default Description
region
Region
required

A region that overlaps this region.

Returns
Type Description
Region

A new region that covers when the two regions overlap.

overlaps cached

def overlaps(self, other):

Check if another region overlaps this region.

Parameters
Parameter Default Description
other
Region
required

A Region.

Returns
Type Description
bool

True if other region shares any cells with this region.

shrink cached

def shrink(self, margin):

Shrink a region by subtracting spacing.

Parameters
Parameter Default Description
margin
tuple[int, int, int, int]
required

Shrink space by (<top>, <right>, <bottom>, <left>).

Returns
Type Description
Region

The new, smaller region.

split cached

def split(self, cut_x, cut_y):

Split a region in to 4 from given x and y offsets (cuts).

           cut_x ↓
        ┌────────┐ ┌───┐
        │        │ │   │
        │    0   │ │ 1 │
        │        │ │   │
cut_y → └────────┘ └───┘
        ┌────────┐ ┌───┐
        │    2   │ │ 3 │
        └────────┘ └───┘
Parameters
Parameter Default Description
cut_x
int
required

Offset from self.x where the cut should be made. If negative, the cut is taken from the right edge.

cut_y
int
required

Offset from self.y where the cut should be made. If negative, the cut is taken from the lower edge.

Returns
Type Description
tuple[Region, Region, Region, Region]

Four new regions which add up to the original (self).

split_horizontal cached

def split_horizontal(self, cut):

Split a region in to two, from a given y offset.

            ┌─────────┐
            │    0    │
            │         │
    cut →   └─────────┘
            ┌─────────┐
            │    1    │
            └─────────┘
Parameters
Parameter Default Description
cut
int
required

An offset from self.y where the cut should be made. May be negative, for the offset to start from the lower edge.

Returns
Type Description
tuple[Region, Region]

Two regions, which add up to the original (self).

split_vertical cached

def split_vertical(self, cut):

Split a region in to two, from a given x offset.

         cut ↓
    ┌────────┐┌───┐
    │    0   ││ 1 │
    │        ││   │
    └────────┘└───┘
Parameters
Parameter Default Description
cut
int
required

An offset from self.x where the cut should be made. If cut is negative, it is taken from the right edge.

Returns
Type Description
tuple[Region, Region]

Two regions, which add up to the original (self).

translate cached

def translate(self, offset):

Move the offset of the Region.

Parameters
Parameter Default Description
offset
tuple[int, int]
required

Offset to add to region.

Returns
Type Description
Region

A new region shifted by (x, y)

translate_inside method

def translate_inside(self, container, x_axis=True, y_axis=True):

Translate this region, so it fits within a container.

This will ensure that there is as little overlap as possible. The top left of the returned region is guaranteed to be within the container.

┌──────────────────┐         ┌──────────────────┐
│    container     │         │    container     │
│                  │         │    ┌─────────────┤
│                  │   ──▶   │    │    return   │
│       ┌──────────┴──┐      │    │             │
│       │    self     │      │    │             │
└───────┤             │      └────┴─────────────┘
        │             │
        └─────────────┘
Parameters
Parameter Default Description
container
Region
required

A container region.

x_axis
bool
True

Allow translation of X axis.

y_axis
bool
True

Allow translation of Y axis.

Returns
Type Description
Region

A new region with same dimensions that fits with inside container.

union cached

def union(self, region):

Get the smallest region that contains both regions.

Parameters
Parameter Default Description
region
Region
required

Another region.

Returns
Type Description
Region

An optimally sized region to cover both regions.

Size class

Bases: NamedTuple

The dimensions (width and height) of a rectangular region.

Example
>>> from textual.geometry import Size
>>> size = Size(2, 3)
>>> size
Size(width=2, height=3)
>>> size.area
6
>>> size + Size(10, 20)
Size(width=12, height=23)

area property

area: int

The area occupied by a region of this size.

height class-attribute instance-attribute

height: int = 0

The height in cells.

line_range property

line_range: range

A range object that covers values between 0 and height.

region property

region: Region

A region of the same size, at the origin.

width class-attribute instance-attribute

width: int = 0

The width in cells.

contains method

def contains(self, x, y):

Check if a point is in area defined by the size.

Parameters
Parameter Default Description
x
int
required

X coordinate.

y
int
required

Y coordinate.

Returns
Type Description
bool

True if the point is within the region.

contains_point method

def contains_point(self, point):

Check if a point is in the area defined by the size.

Parameters
Parameter Default Description
point
tuple[int, int]
required

A tuple of x and y coordinates.

Returns
Type Description
bool

True if the point is within the region.

with_height method

def with_height(self, height):

Get a new Size with just the height changed.

Parameters
Parameter Default Description
width
required

New height.

Returns
Type Description
Size

New Size instance.

with_width method

def with_width(self, width):

Get a new Size with just the width changed.

Parameters
Parameter Default Description
width
int
required

New width.

Returns
Type Description
Size

New Size instance.

Spacing class

Bases: NamedTuple

The spacing around a renderable, such as padding and border.

Spacing is defined by four integers for the space at the top, right, bottom, and left of a region.

┌ ─ ─ ─ ─ ─ ─ ─▲─ ─ ─ ─ ─ ─ ─ ─ ┐
               │ top
│        ┏━━━━━▼━━━━━━┓         │
 ◀──────▶┃            ┃◀───────▶
│  left  ┃            ┃ right   │
         ┃            ┃
│        ┗━━━━━▲━━━━━━┛         │
               │ bottom
└ ─ ─ ─ ─ ─ ─ ─▼─ ─ ─ ─ ─ ─ ─ ─ ┘
Example
>>> from textual.geometry import Region, Spacing
>>> region = Region(2, 3, 20, 10)
>>> spacing = Spacing(1, 2, 3, 4)
>>> region.grow(spacing)
Region(x=-2, y=2, width=26, height=14)
>>> region.shrink(spacing)
Region(x=6, y=4, width=14, height=6)
>>> spacing.css
'1 2 3 4'

bottom class-attribute instance-attribute

bottom: int = 0

Space from the bottom of a region.

bottom_right property

bottom_right: tuple[int, int]

A pair of integers for the right, and bottom space.

css property

css: str

A string containing the spacing in CSS format.

For example: "1" or "2 4" or "4 2 8 2".

height property

height: int

Total space in the y axis.

left class-attribute instance-attribute

left: int = 0

Space from the left of a region.

right class-attribute instance-attribute

right: int = 0

Space from the right of a region.

top class-attribute instance-attribute

top: int = 0

Space from the top of a region.

top_left property

top_left: tuple[int, int]

A pair of integers for the left, and top space.

totals property

totals: tuple[int, int]

A pair of integers for the total horizontal and vertical space.

width property

width: int

Total space in the x axis.

all classmethod

def all(cls, amount):

Construct a Spacing with a given amount of spacing on all edges.

Parameters
Parameter Default Description
amount
int
required

The magnitude of spacing to apply to all edges.

Returns
Type Description
Spacing

Spacing(amount, amount, amount, amount)

grow_maximum method

def grow_maximum(self, other):

Grow spacing with a maximum.

Parameters
Parameter Default Description
other
Spacing
required

Spacing object.

Returns
Type Description
Spacing

New spacing where the values are maximum of the two values.

horizontal classmethod

def horizontal(cls, amount):

Construct a Spacing with a given amount of spacing on horizontal edges, and no vertical spacing.

Parameters
Parameter Default Description
amount
int
required

The magnitude of spacing to apply to horizontal edges.

Returns
Type Description
Spacing

Spacing(0, amount, 0, amount)

unpack classmethod

def unpack(cls, pad):

Unpack padding specified in CSS style.

Parameters
Parameter Default Description
pad
SpacingDimensions
required

An integer, or tuple of 1, 2, or 4 integers.

Raises
Type Description
ValueError

If pad is an invalid value.

Returns
Type Description
Spacing

New Spacing object.

vertical classmethod

def vertical(cls, amount):

Construct a Spacing with a given amount of spacing on vertical edges, and no horizontal spacing.

Parameters
Parameter Default Description
amount
int
required

The magnitude of spacing to apply to vertical edges.

Returns
Type Description
Spacing

Spacing(amount, 0, amount, 0)

clamp function

def clamp(value, minimum, maximum):

Adjust a value so it is not less than a minimum and not greater than a maximum value.

Parameters
Parameter Default Description
value
T
required

A value.

minimum
T
required

Minimum value.

maximum
T
required

Maximum value.

Returns
Type Description
T

New value that is not less than the minimum or greater than the maximum.