Skip to content

Canvas

Module: terminaltexteffects.engine.terminal

Represents the canvas in the terminal. The canvas is the area defined by the dimensions of the input data, unless specified otherwise in the TerminalConfig.

This class provides methods for working with the canvas, such as checking if a coordinate is within the canvas, getting random coordinates within the canvas, and getting a random coordinate outside the canvas.

This class also provides attributes for the dimensions of the canvas, the extents of the text within the canvas, and the center of the canvas.

Parameters:

Name Type Description Default
top int

top row of the canvas

required
right int

right column of the canvas

required

Attributes:

Name Type Description
top int

top row of the canvas

right int

right column of the canvas

bottom int

bottom row of the canvas

left int

left column of the canvas

center_row int

row of the center of the canvas

center_column int

column of the center of the canvas

center Coord

coordinate of the center of the canvas

width int

width of the canvas

height int

height of the canvas

text_left int

left column of the text within the canvas

text_right int

right column of the text within the canvas

text_top int

top row of the text within the canvas

text_bottom int

bottom row of the text within the canvas

text_width int

width of the text within the canvas

text_height int

height of the text within the canvas

text_center_row int

row of the center of the text within the canvas

text_center_column int

column of the center of the text within the canvas

Methods:

Name Description
coord_is_in_canvas

Coord) -> bool: Checks whether a coordinate is within the canvas.

random_column

Get a random column position within the canvas.

random_row

Get a random row position within the canvas.

random_coord

Get a random coordinate within or outside the canvas.

Source code in terminaltexteffects/engine/terminal.py
@dataclass
class Canvas:
    """Represents the canvas in the terminal. The canvas is the area defined
    by the dimensions of the input data, unless specified otherwise in the TerminalConfig.

    This class provides methods for working with the canvas, such as checking if a coordinate is within the canvas,
    getting random coordinates within the canvas, and getting a random coordinate outside the canvas.

    This class also provides attributes for the dimensions of the canvas, the extents of the text within the canvas, and the center of the canvas.

    Args:
        top (int): top row of the canvas
        right (int): right column of the canvas

    Attributes:
        top (int): top row of the canvas
        right (int): right column of the canvas
        bottom (int): bottom row of the canvas
        left (int): left column of the canvas
        center_row (int): row of the center of the canvas
        center_column (int): column of the center of the canvas
        center (Coord): coordinate of the center of the canvas
        width (int): width of the canvas
        height (int): height of the canvas
        text_left (int): left column of the text within the canvas
        text_right (int): right column of the text within the canvas
        text_top (int): top row of the text within the canvas
        text_bottom (int): bottom row of the text within the canvas
        text_width (int): width of the text within the canvas
        text_height (int): height of the text within the canvas
        text_center_row (int): row of the center of the text within the canvas
        text_center_column (int): column of the center of the text within the canvas

    Methods:
        coord_is_in_canvas(coord: Coord) -> bool: Checks whether a coordinate is within the canvas.
        random_column() -> int: Get a random column position within the canvas.
        random_row() -> int: Get a random row position within the canvas.
        random_coord(outside_scope=False) -> Coord: Get a random coordinate within or outside the canvas.

    """

    top: int
    """int: top row of the canvas"""
    right: int
    """int: right column of the canvas"""
    bottom: int = 1
    """int: bottom row of the canvas"""
    left: int = 1
    """int: left column of the canvas"""

    def __post_init__(self) -> None:
        self.center_row = max(self.top // 2, self.bottom)
        """int: row of the center of the canvas"""
        self.center_column = max(self.right // 2, self.left)
        """int: column of the center of the canvas"""
        self.center = Coord(self.center_column, self.center_row)
        """Coord: coordinate of the center of the canvas"""
        self.width = self.right
        """int: width of the canvas"""
        self.height = self.top
        """int: height of the canvas"""
        self.text_left = 0
        """int: left column of the text within the canvas"""
        self.text_right = 0
        """int: right column of the text within the canvas"""
        self.text_top = 0
        """int: top row of the text within the canvas"""
        self.text_bottom = 0
        """int: bottom row of the text within the canvas"""
        self.text_width = 0
        """int: width of the text within the canvas"""
        self.text_height = 0
        """int: height of the text within the canvas"""
        self.text_center_row = 0
        """int: row of the center of the text within the canvas"""
        self.text_center_column = 0
        """int: column of the center of the text within the canvas"""

    def _anchor_text(
        self, characters: list[EffectCharacter], anchor: Literal["n", "ne", "e", "se", "s", "sw", "w", "nw", "c"]
    ) -> list[EffectCharacter]:
        """Anchors the text within the canvas based on the specified anchor point.

        Args:
            characters (list[EffectCharacter]): _description_
            anchor (Literal["n", "ne", "e", "se", "s", "sw", "w", "nw", "c"]): Anchor point for the text within the Canvas.

        Returns:
            list[EffectCharacter]: List of characters anchored within the canvas. Only returns characters with
            coordinates within the canvas after anchoring.
        """
        # translate coordinate based on anchor within the canvas
        input_width = max([character._input_coord.column for character in characters])
        input_height = max([character._input_coord.row for character in characters])

        column_delta = row_delta = 0
        if input_width != self.width:
            if anchor in ("s", "n", "c"):
                column_delta = self.center_column - (input_width // 2)
            elif anchor in ("se", "e", "ne"):
                column_delta = self.right - input_width
            elif anchor in ("sw", "w", "nw"):
                column_delta = self.left - 1
        if input_height != self.height:
            if anchor in ("w", "e", "c"):
                row_delta = self.center_row - (input_height // 2)
            elif anchor in ("nw", "n", "ne"):
                row_delta = self.top - input_height
            elif anchor in ("sw", "s", "se"):
                row_delta = self.bottom - 1

        for character in characters:
            current_coord = character.input_coord
            anchored_coord = Coord(current_coord.column + column_delta, current_coord.row + row_delta)
            character._input_coord = anchored_coord
            character.motion.set_coordinate(anchored_coord)

        characters = [character for character in characters if self.coord_is_in_canvas(character.input_coord)]

        # get text dimensions, centers, and extents
        self.text_left = min([character.input_coord.column for character in characters])
        self.text_right = max([character.input_coord.column for character in characters])
        self.text_top = max([character.input_coord.row for character in characters])
        self.text_bottom = min([character.input_coord.row for character in characters])
        self.text_width = max(self.text_right - self.text_left + 1, 1)
        self.text_height = max(self.text_top - self.text_bottom + 1, 1)
        self.text_center_row = self.text_bottom + ((self.text_top - self.text_bottom) // 2)
        self.text_center_column = self.text_left + ((self.text_right - self.text_left) // 2)

        return characters

    def coord_is_in_canvas(self, coord: Coord) -> bool:
        """Checks whether a coordinate is within the canvas.

        Args:
            coord (Coord): coordinate to check

        Returns:
            bool: whether the coordinate is within the canvas
        """
        return self.left <= coord.column <= self.right and self.bottom <= coord.row <= self.top

    def random_column(self) -> int:
        """Get a random column position. Position is within the canvas.

        Returns:
            int: a random column position (1 <= x <= canvas.right)"""
        return random.randint(self.left, self.right)

    def random_row(self) -> int:
        """Get a random row position. Position is within the canvas.

        Returns:
            int: a random row position (1 <= x <= terminal.canvas.top)"""
        return random.randint(self.bottom, self.top)

    def random_coord(self, outside_scope=False) -> Coord:
        """Get a random coordinate. Coordinate is within the canvas unless outside_scope is True.

        Args:
            outside_scope (bool, optional): whether the coordinate should fall outside the canvas. Defaults to False.

        Returns:
            Coord: a random coordinate . Coordinate is within the canvas unless outside_scope is True."""
        if outside_scope is True:
            random_coord_above = Coord(self.random_column(), self.top + 1)
            random_coord_below = Coord(self.random_column(), self.bottom - 1)
            random_coord_left = Coord(self.left - 1, self.random_row())
            random_coord_right = Coord(self.right + 1, self.random_row())
            return random.choice([random_coord_above, random_coord_below, random_coord_left, random_coord_right])
        else:
            return Coord(self.random_column(), self.random_row())

bottom: int = 1 class-attribute instance-attribute

int: bottom row of the canvas

left: int = 1 class-attribute instance-attribute

int: left column of the canvas

right: int instance-attribute

int: right column of the canvas

top: int instance-attribute

int: top row of the canvas

coord_is_in_canvas(coord)

Checks whether a coordinate is within the canvas.

Parameters:

Name Type Description Default
coord Coord

coordinate to check

required

Returns:

Name Type Description
bool bool

whether the coordinate is within the canvas

Source code in terminaltexteffects/engine/terminal.py
def coord_is_in_canvas(self, coord: Coord) -> bool:
    """Checks whether a coordinate is within the canvas.

    Args:
        coord (Coord): coordinate to check

    Returns:
        bool: whether the coordinate is within the canvas
    """
    return self.left <= coord.column <= self.right and self.bottom <= coord.row <= self.top

random_column()

Get a random column position. Position is within the canvas.

Returns:

Name Type Description
int int

a random column position (1 <= x <= canvas.right)

Source code in terminaltexteffects/engine/terminal.py
def random_column(self) -> int:
    """Get a random column position. Position is within the canvas.

    Returns:
        int: a random column position (1 <= x <= canvas.right)"""
    return random.randint(self.left, self.right)

random_coord(outside_scope=False)

Get a random coordinate. Coordinate is within the canvas unless outside_scope is True.

Parameters:

Name Type Description Default
outside_scope bool

whether the coordinate should fall outside the canvas. Defaults to False.

False

Returns:

Name Type Description
Coord Coord

a random coordinate . Coordinate is within the canvas unless outside_scope is True.

Source code in terminaltexteffects/engine/terminal.py
def random_coord(self, outside_scope=False) -> Coord:
    """Get a random coordinate. Coordinate is within the canvas unless outside_scope is True.

    Args:
        outside_scope (bool, optional): whether the coordinate should fall outside the canvas. Defaults to False.

    Returns:
        Coord: a random coordinate . Coordinate is within the canvas unless outside_scope is True."""
    if outside_scope is True:
        random_coord_above = Coord(self.random_column(), self.top + 1)
        random_coord_below = Coord(self.random_column(), self.bottom - 1)
        random_coord_left = Coord(self.left - 1, self.random_row())
        random_coord_right = Coord(self.right + 1, self.random_row())
        return random.choice([random_coord_above, random_coord_below, random_coord_left, random_coord_right])
    else:
        return Coord(self.random_column(), self.random_row())

random_row()

Get a random row position. Position is within the canvas.

Returns:

Name Type Description
int int

a random row position (1 <= x <= terminal.canvas.top)

Source code in terminaltexteffects/engine/terminal.py
def random_row(self) -> int:
    """Get a random row position. Position is within the canvas.

    Returns:
        int: a random row position (1 <= x <= terminal.canvas.top)"""
    return random.randint(self.bottom, self.top)