From b0c9b83bf429d32524cfdbacfc98eacc5b76a959 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Thu, 27 Jan 2022 13:07:12 +0000 Subject: [PATCH] Add horizontal layout --- src/textual/layouts/factory.py | 10 +++++-- src/textual/layouts/horizontal.py | 45 +++++++++++++++++++++++++++++++ src/textual/layouts/vertical.py | 1 - tests/test_view.py | 2 ++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/textual/layouts/horizontal.py diff --git a/src/textual/layouts/factory.py b/src/textual/layouts/factory.py index 4953fb50a..eca9e691b 100644 --- a/src/textual/layouts/factory.py +++ b/src/textual/layouts/factory.py @@ -1,5 +1,6 @@ import sys +from .horizontal import HorizontalLayout from ..layout import Layout from ..layouts.dock import DockLayout from ..layouts.grid import GridLayout @@ -10,8 +11,13 @@ if sys.version_info >= (3, 8): else: from typing_extensions import Literal -LayoutName = Literal["dock", "grid", "vertical"] -LAYOUT_MAP = {"dock": DockLayout, "grid": GridLayout, "vertical": VerticalLayout} +LayoutName = Literal["dock", "grid", "vertical", "horizontal"] +LAYOUT_MAP = { + "dock": DockLayout, + "grid": GridLayout, + "vertical": VerticalLayout, + "horizontal": HorizontalLayout, +} class MissingLayout(Exception): diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py new file mode 100644 index 000000000..f0a0e37e2 --- /dev/null +++ b/src/textual/layouts/horizontal.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +from typing import Iterable + +from textual._loop import loop_last +from textual.css.styles import Styles +from textual.geometry import SpacingDimensions, Spacing, Size, Offset, Region +from textual.layout import Layout, WidgetPlacement +from textual.view import View +from textual.widget import Widget + + +class HorizontalLayout(Layout): + def __init__( + self, + *, + z: int = 0, + gutter: SpacingDimensions = (0, 0, 0, 0), + ): + self.z = z + self.gutter = Spacing.unpack(gutter) + self._max_widget_width = 0 + super().__init__() + + def get_widgets(self, view: View) -> Iterable[Widget]: + return view.children + + def arrange( + self, view: View, size: Size, scroll: Offset + ) -> Iterable[WidgetPlacement]: + width, height = size + gutter = self.gutter + gutter_width = max(gutter.right, gutter.left) + x, y = self.gutter.top_left + + for last, widget in loop_last(view.children): + styles: Styles = widget.styles + render_height = styles.height if styles else height + if styles.width: + render_width = int(styles.width.resolve_dimension(size, view.app.size)) + else: + render_width = width + region = Region(x, y, render_width, render_height) + yield WidgetPlacement(region, widget, self.z) + x += render_width + (gutter.right if last else gutter_width) diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index 05c6a1a54..41fe94c24 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -2,7 +2,6 @@ from __future__ import annotations from typing import Iterable, TYPE_CHECKING -from textual import log from ..css.styles import Styles from ..geometry import Offset, Region, Size, Spacing, SpacingDimensions from ..layout import Layout, WidgetPlacement diff --git a/tests/test_view.py b/tests/test_view.py index 08db68d69..1eed93c6f 100644 --- a/tests/test_view.py +++ b/tests/test_view.py @@ -2,6 +2,7 @@ import pytest from textual.layouts.dock import DockLayout from textual.layouts.grid import GridLayout +from textual.layouts.horizontal import HorizontalLayout from textual.layouts.vertical import VerticalLayout from textual.view import View @@ -10,6 +11,7 @@ from textual.view import View ["dock", DockLayout], ["grid", GridLayout], ["vertical", VerticalLayout], + ["horizontal", HorizontalLayout], ]) def test_view_layout_get_and_set(layout_name, layout_type): view = View()