ai-station/.venv/lib/python3.12/site-packages/textual/layouts/vertical.py

125 lines
3.8 KiB
Python

from __future__ import annotations
from fractions import Fraction
from typing import TYPE_CHECKING
from textual._resolve import resolve_box_models
from textual.geometry import NULL_OFFSET, Region, Size
from textual.layout import ArrangeResult, Layout, WidgetPlacement
if TYPE_CHECKING:
from textual.geometry import Spacing
from textual.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, greedy: bool = True
) -> ArrangeResult:
parent.pre_layout(self)
placements: list[WidgetPlacement] = []
add_placement = placements.append
viewport = parent.app.viewport_size
child_styles = [child.styles for child in children]
box_margins: list[Spacing] = [
styles.margin for styles in child_styles if styles.overlay != "screen"
]
if box_margins:
resolve_margin = Size(
max(
[
margin_right + margin_left
for _, margin_right, _, margin_left in box_margins
]
),
sum(
[
bottom if bottom > top else top
for (_, _, bottom, _), (top, _, _, _) in zip(
box_margins, box_margins[1:]
)
]
)
+ (box_margins[0].top + box_margins[-1].bottom),
)
else:
resolve_margin = Size(0, 0)
box_models = resolve_box_models(
[styles.height for styles in child_styles],
children,
size,
parent.app.size,
resolve_margin,
resolve_dimension="height",
greedy=greedy,
)
margins = [
(
margin_bottom
if (margin_bottom := margin1.bottom) > (margin_top := margin2.top)
else margin_top
)
for (_, _, margin1), (_, _, margin2) in zip(box_models, box_models[1:])
]
if box_models:
margins.append(box_models[-1].margin.bottom)
y = next(
(
Fraction(box_model.margin.top)
for box_model, child in zip(box_models, children)
if child.styles.overlay != "screen"
),
Fraction(0),
)
_Region = Region
_WidgetPlacement = WidgetPlacement
_Size = Size
for widget, (content_width, content_height, box_margin), margin in zip(
children, box_models, margins
):
styles = widget.styles
overlay = styles.overlay == "screen"
next_y = y + content_height
offset = (
styles.offset.resolve(
_Size(content_width.__floor__(), content_height.__floor__()),
viewport,
)
if styles.has_rule("offset")
else NULL_OFFSET
)
region = _Region(
box_margin.left,
y.__floor__(),
content_width.__floor__(),
next_y.__floor__() - y.__floor__(),
)
absolute = styles.has_rule("position") and styles.position == "absolute"
add_placement(
_WidgetPlacement(
region,
offset,
box_margin,
widget,
0,
False,
overlay,
absolute,
)
)
if not overlay and not absolute:
y = next_y + margin
return placements