Module textual.layouts.vertical

Expand source code
from __future__ import annotations

from fractions import Fraction
from typing import TYPE_CHECKING

from ..geometry import Region, Size
from .._layout import ArrangeResult, Layout, WidgetPlacement

if TYPE_CHECKING:
    from ..widget import Widget


class VerticalLayout(Layout):
    """Used to layout Widgets vertically on screen, from top to bottom."""

    name = "vertical"

    def arrange(
        self, parent: Widget, children: list[Widget], size: Size
    ) -> ArrangeResult:

        placements: list[WidgetPlacement] = []
        add_placement = placements.append

        parent_size = parent.outer_size

        styles = [child.styles for child in children if child.styles.height is not None]
        total_fraction = sum(
            [int(style.height.value) for style in styles if style.height.is_fraction]
        )
        fraction_unit = Fraction(size.height, total_fraction or 1)

        box_models = [
            widget._get_box_model(size, parent_size, fraction_unit)
            for widget in children
        ]

        margins = [
            max((box1.margin.bottom, box2.margin.top))
            for box1, box2 in zip(box_models, box_models[1:])
        ]
        if box_models:
            margins.append(box_models[-1].margin.bottom)

        y = Fraction(box_models[0].margin.top if box_models else 0)

        _Region = Region
        _WidgetPlacement = WidgetPlacement
        for widget, box_model, margin in zip(children, box_models, margins):
            content_width, content_height, box_margin = box_model
            next_y = y + content_height
            region = _Region(
                box_margin.left, int(y), int(content_width), int(next_y) - int(y)
            )
            add_placement(_WidgetPlacement(region, box_model.margin, widget, 0))
            y = next_y + margin

        return placements, set(children)

Classes

class VerticalLayout

Used to layout Widgets vertically on screen, from top to bottom.

Expand source code
class VerticalLayout(Layout):
    """Used to layout Widgets vertically on screen, from top to bottom."""

    name = "vertical"

    def arrange(
        self, parent: Widget, children: list[Widget], size: Size
    ) -> ArrangeResult:

        placements: list[WidgetPlacement] = []
        add_placement = placements.append

        parent_size = parent.outer_size

        styles = [child.styles for child in children if child.styles.height is not None]
        total_fraction = sum(
            [int(style.height.value) for style in styles if style.height.is_fraction]
        )
        fraction_unit = Fraction(size.height, total_fraction or 1)

        box_models = [
            widget._get_box_model(size, parent_size, fraction_unit)
            for widget in children
        ]

        margins = [
            max((box1.margin.bottom, box2.margin.top))
            for box1, box2 in zip(box_models, box_models[1:])
        ]
        if box_models:
            margins.append(box_models[-1].margin.bottom)

        y = Fraction(box_models[0].margin.top if box_models else 0)

        _Region = Region
        _WidgetPlacement = WidgetPlacement
        for widget, box_model, margin in zip(children, box_models, margins):
            content_width, content_height, box_margin = box_model
            next_y = y + content_height
            region = _Region(
                box_margin.left, int(y), int(content_width), int(next_y) - int(y)
            )
            add_placement(_WidgetPlacement(region, box_model.margin, widget, 0))
            y = next_y + margin

        return placements, set(children)

Ancestors

  • textual._layout.Layout
  • abc.ABC

Class variables

var name : ClassVar[str]

Methods

def arrange(self, parent: Widget, children: list[Widget], size: Size) ‑> ArrangeResult

Generate a layout map that defines where on the screen the widgets will be drawn.

Args

parent : Widget
Parent widget.
size : Size
Size of container.

Returns

Iterable[WidgetPlacement]
An iterable of widget location
Expand source code
def arrange(
    self, parent: Widget, children: list[Widget], size: Size
) -> ArrangeResult:

    placements: list[WidgetPlacement] = []
    add_placement = placements.append

    parent_size = parent.outer_size

    styles = [child.styles for child in children if child.styles.height is not None]
    total_fraction = sum(
        [int(style.height.value) for style in styles if style.height.is_fraction]
    )
    fraction_unit = Fraction(size.height, total_fraction or 1)

    box_models = [
        widget._get_box_model(size, parent_size, fraction_unit)
        for widget in children
    ]

    margins = [
        max((box1.margin.bottom, box2.margin.top))
        for box1, box2 in zip(box_models, box_models[1:])
    ]
    if box_models:
        margins.append(box_models[-1].margin.bottom)

    y = Fraction(box_models[0].margin.top if box_models else 0)

    _Region = Region
    _WidgetPlacement = WidgetPlacement
    for widget, box_model, margin in zip(children, box_models, margins):
        content_width, content_height, box_margin = box_model
        next_y = y + content_height
        region = _Region(
            box_margin.left, int(y), int(content_width), int(next_y) - int(y)
        )
        add_placement(_WidgetPlacement(region, box_model.margin, widget, 0))
        y = next_y + margin

    return placements, set(children)