Module textual.layouts.horizontal
Expand source code
from __future__ import annotations
from fractions import Fraction
from typing import cast
from textual.geometry import Size, Region
from textual._layout import ArrangeResult, Layout, WidgetPlacement
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
) -> ArrangeResult:
placements: list[WidgetPlacement] = []
add_placement = placements.append
x = max_height = Fraction(0)
parent_size = parent.outer_size
styles = [child.styles for child in children if child.styles.width is not None]
total_fraction = sum(
[int(style.width.value) for style in styles if style.width.is_fraction]
)
fraction_unit = Fraction(size.width, total_fraction or 1)
box_models = [
widget._get_box_model(size, parent_size, fraction_unit)
for widget in cast("list[Widget]", children)
]
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 = Fraction(box_models[0].margin.left if box_models else 0)
displayed_children = [child for child in children if child.display]
_Region = Region
_WidgetPlacement = WidgetPlacement
for widget, box_model, margin in zip(children, box_models, margins):
content_width, content_height, box_margin = box_model
offset_y = box_margin.top
next_x = x + content_width
region = _Region(
int(x), offset_y, int(next_x - int(x)), int(content_height)
)
max_height = max(
max_height, content_height + offset_y + box_model.margin.bottom
)
add_placement(_WidgetPlacement(region, box_model.margin, widget, 0))
x = next_x + margin
return placements, set(displayed_children)
def get_content_width(self, widget: Widget, container: Size, viewport: Size) -> int:
"""Get the width of the content. In Horizontal layout, the content width of
a widget is the sum of the widths of its children.
Args:
widget (Widget): The container widget.
container (Size): The container size.
viewport (Size): The viewport size.
Returns:
int: Width of the content.
"""
width: int | None = None
gutter_width = widget.gutter.width
for child in widget.displayed_children:
if not child.is_container:
child_width = (
child.get_content_width(container, viewport)
+ gutter_width
+ child.gutter.width
)
if width is None:
width = child_width
else:
width += child_width
if width is None:
width = container.width
return width
Classes
class HorizontalLayout
-
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.
Expand source code
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 ) -> ArrangeResult: placements: list[WidgetPlacement] = [] add_placement = placements.append x = max_height = Fraction(0) parent_size = parent.outer_size styles = [child.styles for child in children if child.styles.width is not None] total_fraction = sum( [int(style.width.value) for style in styles if style.width.is_fraction] ) fraction_unit = Fraction(size.width, total_fraction or 1) box_models = [ widget._get_box_model(size, parent_size, fraction_unit) for widget in cast("list[Widget]", children) ] 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 = Fraction(box_models[0].margin.left if box_models else 0) displayed_children = [child for child in children if child.display] _Region = Region _WidgetPlacement = WidgetPlacement for widget, box_model, margin in zip(children, box_models, margins): content_width, content_height, box_margin = box_model offset_y = box_margin.top next_x = x + content_width region = _Region( int(x), offset_y, int(next_x - int(x)), int(content_height) ) max_height = max( max_height, content_height + offset_y + box_model.margin.bottom ) add_placement(_WidgetPlacement(region, box_model.margin, widget, 0)) x = next_x + margin return placements, set(displayed_children) def get_content_width(self, widget: Widget, container: Size, viewport: Size) -> int: """Get the width of the content. In Horizontal layout, the content width of a widget is the sum of the widths of its children. Args: widget (Widget): The container widget. container (Size): The container size. viewport (Size): The viewport size. Returns: int: Width of the content. """ width: int | None = None gutter_width = widget.gutter.width for child in widget.displayed_children: if not child.is_container: child_width = ( child.get_content_width(container, viewport) + gutter_width + child.gutter.width ) if width is None: width = child_width else: width += child_width if width is None: width = container.width return width
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 x = max_height = Fraction(0) parent_size = parent.outer_size styles = [child.styles for child in children if child.styles.width is not None] total_fraction = sum( [int(style.width.value) for style in styles if style.width.is_fraction] ) fraction_unit = Fraction(size.width, total_fraction or 1) box_models = [ widget._get_box_model(size, parent_size, fraction_unit) for widget in cast("list[Widget]", children) ] 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 = Fraction(box_models[0].margin.left if box_models else 0) displayed_children = [child for child in children if child.display] _Region = Region _WidgetPlacement = WidgetPlacement for widget, box_model, margin in zip(children, box_models, margins): content_width, content_height, box_margin = box_model offset_y = box_margin.top next_x = x + content_width region = _Region( int(x), offset_y, int(next_x - int(x)), int(content_height) ) max_height = max( max_height, content_height + offset_y + box_model.margin.bottom ) add_placement(_WidgetPlacement(region, box_model.margin, widget, 0)) x = next_x + margin return placements, set(displayed_children)
def get_content_width(self, widget: Widget, container: Size, viewport: Size) ‑> int
-
Get the width of the content. In Horizontal layout, the content width of a widget is the sum of the widths of its children.
Args
widget
:Widget
- The container widget.
container
:Size
- The container size.
viewport
:Size
- The viewport size.
Returns
int
- Width of the content.
Expand source code
def get_content_width(self, widget: Widget, container: Size, viewport: Size) -> int: """Get the width of the content. In Horizontal layout, the content width of a widget is the sum of the widths of its children. Args: widget (Widget): The container widget. container (Size): The container size. viewport (Size): The viewport size. Returns: int: Width of the content. """ width: int | None = None gutter_width = widget.gutter.width for child in widget.displayed_children: if not child.is_container: child_width = ( child.get_content_width(container, viewport) + gutter_width + child.gutter.width ) if width is None: width = child_width else: width += child_width if width is None: width = container.width return width