diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 9ccb73099f..f1aaf4681a 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -559,6 +559,8 @@ def _arrange_root( map: CompositorMap = {} widgets: set[Widget] = set() add_new_widget = widgets.add + invisible_widgets: set[Widget] = set() + add_new_invisible_widget = invisible_widgets.add layer_order: int = 0 no_clip = size.region @@ -595,6 +597,8 @@ def add_widget( if visible: add_new_widget(widget) + else: + add_new_invisible_widget(widget) styles_offset = styles.offset layout_offset = ( styles_offset.resolve(region.size, clip.size) @@ -740,6 +744,7 @@ def add_widget( True, NULL_SPACING, ) + widgets -= invisible_widgets return map, widgets @property diff --git a/tests/test_widget_visibility.py b/tests/test_widget_visibility.py new file mode 100644 index 0000000000..c625771ff0 --- /dev/null +++ b/tests/test_widget_visibility.py @@ -0,0 +1,34 @@ +from textual.app import App, ComposeResult +from textual.widgets import Label + + +async def test_hide() -> None: + """Check that setting visibility produces Hide messages.""" + # https://github.com/Textualize/textual/issues/3460 + visibility: list[bool] = [] + + class ShowHideLabel(Label): + def on_show(self) -> None: + visibility.append(True) + + def on_hide(self) -> None: + visibility.append(False) + + class ShowHideApp(App[None]): + BINDINGS = [("space", "toggle_label")] + + def compose(self) -> ComposeResult: + yield ShowHideLabel("Here I am") + + def action_toggle_label(self) -> None: + self.query_one(ShowHideLabel).visible = not self.query_one( + ShowHideLabel + ).visible + + app = ShowHideApp() + async with app.run_test() as pilot: + assert visibility == [True] + await pilot.press("space") + assert visibility == [True, False] + await pilot.press("space") + assert visibility == [True, False, True]