diff --git a/src/textual/_resolve.py b/src/textual/_resolve.py index 7fbd4751d6..dce4663281 100644 --- a/src/textual/_resolve.py +++ b/src/textual/_resolve.py @@ -196,23 +196,30 @@ def resolve_box_models( Returns: List of resolved box models. """ - margin_width, margin_height = margin - - fraction_width = Fraction(max(0, size.width - margin_width)) - fraction_height = Fraction(max(0, size.height - margin_height)) + margin_width, margin_height = margin + fraction_width = Fraction(size.width) + fraction_height = Fraction(size.height) + fraction_zero = Fraction(0) margin_size = size - margin + margins = [widget.styles.margin.totals for widget in widgets] + # Fixed box models box_models: list[BoxModel | None] = [ ( None if _dimension is not None and _dimension.is_fraction else widget._get_box_model( - size, viewport_size, fraction_width, fraction_height + size, + viewport_size, + max(fraction_zero, fraction_width - margin_width), + max(fraction_zero, fraction_height - margin_height), ) ) - for (_dimension, widget) in zip(dimensions, widgets) + for (_dimension, widget, (margin_width, margin_height)) in zip( + dimensions, widgets, margins + ) ] if None not in box_models: diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_fr_and_margin.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_fr_and_margin.svg new file mode 100644 index 0000000000..82abecfc79 --- /dev/null +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_fr_and_margin.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FRApp + + + + + + + + + + No margin - should extend to left and right                                      + + +A margin of 2, should be 2 cells around the text                             + + + + +A margin of 4, should be 4 cells around the text                         + + + + + + + + + + + + + + + + + + diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index dca33964cf..8ec68c0414 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -8,7 +8,7 @@ from textual import events, on from textual.app import App, ComposeResult from textual.binding import Binding, Keymap -from textual.containers import Center, Grid, Middle, Vertical, VerticalScroll +from textual.containers import Center, Container, Grid, Middle, Vertical, VerticalScroll from textual.pilot import Pilot from textual.renderables.gradient import LinearGradient from textual.screen import ModalScreen, Screen @@ -2336,3 +2336,41 @@ def compose(self) -> ComposeResult: yield Label("100%") assert snap_compare(BackgroundTintApp()) + + +def test_fr_and_margin(snap_compare): + """Regression test for https://github.com/Textualize/textual/issues/5116""" + + # Check margins can be independently applied to widgets with fr unites + + class FRApp(App): + CSS = """ + #first-container { + background: green; + height: auto; + } + + #second-container { + margin: 2; + background: red; + height: auto; + } + + #third-container { + margin: 4; + background: blue; + height: auto; + } + """ + + def compose(self) -> ComposeResult: + with Container(id="first-container"): + yield Label("No margin - should extend to left and right") + + with Container(id="second-container"): + yield Label("A margin of 2, should be 2 cells around the text") + + with Container(id="third-container"): + yield Label("A margin of 4, should be 4 cells around the text") + + assert snap_compare(FRApp())