diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py index 210ee95d34..87ab7c28c3 100644 --- a/src/textual/layouts/horizontal.py +++ b/src/textual/layouts/horizontal.py @@ -72,20 +72,12 @@ def get_content_width(self, widget: Widget, container: Size, 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: + if not widget.displayed_children: width = container.width - + else: + placements, *_ = widget._arrange(container) + width = max( + placement.region.right + placement.margin.right + for placement in placements + ) return width diff --git a/tests/layouts/test_horizontal.py b/tests/layouts/test_horizontal.py index 5a7aad388c..05ce4c8905 100644 --- a/tests/layouts/test_horizontal.py +++ b/tests/layouts/test_horizontal.py @@ -1,46 +1,29 @@ -from textual.geometry import Size -from textual.layouts.horizontal import HorizontalLayout -from textual.widget import Widget - - -class SizedWidget(Widget): - """Simple Widget wrapped allowing you to modify the return values for - get_content_width and get_content_height via the constructor.""" - - def __init__( - self, - *children: Widget, - content_width: int = 10, - content_height: int = 5, - ): - super().__init__(*children) - self.content_width = content_width - self.content_height = content_height - - def get_content_width(self, container: Size, viewport: Size) -> int: - return self.content_width +import pytest - def get_content_height(self, container: Size, viewport: Size, width: int) -> int: - return self.content_height - - -CHILDREN = [ - SizedWidget(content_width=10, content_height=5), - SizedWidget(content_width=4, content_height=2), - SizedWidget(content_width=12, content_height=3), -] - - -def test_horizontal_get_content_width(): - parent = Widget(*CHILDREN) - layout = HorizontalLayout() - width = layout.get_content_width(widget=parent, container=Size(), viewport=Size()) - assert width == sum(child.content_width for child in CHILDREN) +from textual.app import App, ComposeResult +from textual.containers import Horizontal +from textual.widget import Widget -def test_horizontal_get_content_width_no_children(): - parent = Widget() - layout = HorizontalLayout() - container_size = Size(24, 24) - width = layout.get_content_width(widget=parent, container=container_size, viewport=Size()) - assert width == container_size.width +@pytest.fixture +async def app(): + class HorizontalAutoWidth(App): + def compose(self) -> ComposeResult: + child1 = Widget(id="child1") + child1.styles.width = 4 + child2 = Widget(id="child2") + child2.styles.width = 6 + child3 = Widget(id="child3") + child3.styles.width = 5 + self.horizontal = Horizontal(child1, child2, child3) + yield self.horizontal + + app = HorizontalAutoWidth() + async with app.run_test(): + yield app + + +async def test_horizontal_get_content_width(app): + size = app.screen.size + width = app.horizontal.get_content_width(size, size) + assert width == 15 diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index b10be936dd..cb6252b33e 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -5849,6 +5849,164 @@ ''' # --- +# name: test_horizontal_layout_width_auto_dock + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HorizontalAutoWidth + + + + + + + + + + Docke + Widget 1Widget 2 + left  + 1Docked left 2 + + + + + + + + + + + + + + + + + + + + + + + + + ''' +# --- # name: test_input_and_focus ''' diff --git a/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.css b/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.css new file mode 100644 index 0000000000..50ea9edff1 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.css @@ -0,0 +1,24 @@ +.widget { + background: olivedrab; + width: 10; + margin: 1; +} + +#dock-1 { + dock: left; + background: dodgerblue; + width: 5; +} + +#dock-2 { + dock: left; + background: mediumvioletred; + margin: 3; + width: 20; +} + +#horizontal { + width: auto; + height: auto; + background: darkslateblue; +} \ No newline at end of file diff --git a/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.py b/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.py new file mode 100644 index 0000000000..ef0528fa9b --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/horizontal_auto_width.py @@ -0,0 +1,22 @@ +from textual.app import App, ComposeResult +from textual.containers import Horizontal +from textual.widgets import Static + + +class HorizontalAutoWidth(App): + """ + Checks that the auto width of the parent Horizontal is correct. + """ + def compose(self) -> ComposeResult: + yield Horizontal( + Static("Docked left 1", id="dock-1"), + Static("Docked left 2", id="dock-2"), + Static("Widget 1", classes="widget"), + Static("Widget 2", classes="widget"), + id="horizontal", + ) + + +app = HorizontalAutoWidth(css_path="horizontal_auto_width.css") +if __name__ == '__main__': + app.run() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 41846ae117..95e83c278a 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2,9 +2,11 @@ import pytest +# These paths should be relative to THIS directory. WIDGET_EXAMPLES_DIR = Path("../../docs/examples/widgets") LAYOUT_EXAMPLES_DIR = Path("../../docs/examples/guide/layout") STYLES_EXAMPLES_DIR = Path("../../docs/examples/styles") +SNAPSHOT_APPS_DIR = Path("./snapshot_apps") # --- Layout related stuff --- @@ -29,6 +31,10 @@ def test_horizontal_layout(snap_compare): assert snap_compare(LAYOUT_EXAMPLES_DIR / "horizontal_layout.py") +def test_horizontal_layout_width_auto_dock(snap_compare): + assert snap_compare(SNAPSHOT_APPS_DIR / "horizontal_auto_width.py") + + def test_vertical_layout(snap_compare): assert snap_compare(LAYOUT_EXAMPLES_DIR / "vertical_layout.py")