diff --git a/src/textual/_layout.py b/src/textual/_layout.py index 312f8c9fe5..8b5bb066dc 100644 --- a/src/textual/_layout.py +++ b/src/textual/_layout.py @@ -213,7 +213,13 @@ def render_keyline(self, container: Widget) -> StripRenderable: container_offset = container.content_region.offset - def get_rectangle(region: Region) -> Rectangle: + def get_keyline_widgets(widget: Widget) -> Iterable[Widget]: + for child in widget.children: + if child.visible: + yield child + yield from get_keyline_widgets(child) + + def get_rectangle(widget: Widget) -> Rectangle: """Get a canvas Rectangle that wraps a region. Args: @@ -222,14 +228,15 @@ def get_rectangle(region: Region) -> Rectangle: Returns: A Rectangle that encloses the widget. """ + region = widget.region offset = region.offset - container_offset - (1, 1) width, height = region.size return Rectangle(offset, width + 2, height + 2, keyline_color, line_style) primitives = [ - get_rectangle(widget.region) - for widget in container.children - if widget.visible + get_rectangle(widget) + for widget in container.screen.walk_children(reverse=True) ] + container.log(primitives) canvas_renderable = canvas.render(primitives, container.rich_style) return canvas_renderable diff --git a/src/textual/dom.py b/src/textual/dom.py index 1a6d969cf3..71c6ef91ba 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -1095,6 +1095,16 @@ def ancestors(self) -> list[DOMNode]: """ return self.ancestors_with_self[1:] + @property + def widget_ancestors(self) -> Iterable[Widget]: + import itertools + + from textual.widget import Widget + + return itertools.takewhile( + lambda node: isinstance(node, Widget), self.ancestors_with_self[1:] + ) + @property def displayed_children(self) -> list[Widget]: """The child nodes which will be displayed. diff --git a/src/textual/widget.py b/src/textual/widget.py index 33c143095c..f678aa9e22 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -603,6 +603,10 @@ def clear_cached_dimensions(self) -> None: self._content_width_cache = (None, 0) self._content_height_cache = (None, 0) + @property + def has_keyline(self) -> bool: + return self.styles.keyline[0] != "none" + def get_loading_widget(self) -> Widget: """Get a widget to display a loading indicator.