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

121 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 HorizontalLayout(Layout):
"""Used to layout Widgets horizontally on screen, from left to right. Since Widgets naturally
fill the space of their parent container, all widgets used in a horizontal layout should have a specified.
"""
name = "horizontal"
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(
sum(
[
max(margin1[1], margin2[3])
for margin1, margin2 in zip(box_margins, box_margins[1:])
]
)
+ (box_margins[0].left + box_margins[-1].right),
max(
[
margin_top + margin_bottom
for margin_top, _, margin_bottom, _ in box_margins
]
),
)
else:
resolve_margin = Size(0, 0)
box_models = resolve_box_models(
[styles.width for styles in child_styles],
children,
size,
viewport,
resolve_margin,
resolve_dimension="width",
greedy=greedy,
)
margins = [
max((box1.margin.right, box2.margin.left))
for box1, box2 in zip(box_models, box_models[1:])
]
if box_models:
margins.append(box_models[-1].margin.right)
x = next(
(
Fraction(box_model.margin.left)
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"
offset = (
styles.offset.resolve(
_Size(content_width.__floor__(), content_height.__floor__()),
viewport,
)
if styles.has_rule("offset")
else NULL_OFFSET
)
offset_y = box_margin.top
next_x = x + content_width
region = _Region(
x.__floor__(),
offset_y,
(next_x - x.__floor__()).__floor__(),
content_height.__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:
x = next_x + margin
return placements