diff --git a/CHANGELOG.md b/CHANGELOG.md index 2531e0c14f..fa947c651b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Eager tasks are now enabled On Python3.12 and above https://github.com/Textualize/textual/pull/6102 +- `Widget._arrange` is now public (as `Widget.arrange`) https://github.com/Textualize/textual/pull/6108 +- Reduced number of layout operations required to update the screen https://github.com/Textualize/textual/pull/6108 ### Added diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index b8e1b044ec..6566aa759e 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -597,7 +597,7 @@ def add_widget( if widget.is_container: # Arrange the layout - arrange_result = widget._arrange(child_region.size) + arrange_result = widget.arrange(child_region.size) arranged_widgets = arrange_result.widgets widgets.update(arranged_widgets) diff --git a/src/textual/layout.py b/src/textual/layout.py index fe7ca4335b..61655cb73e 100644 --- a/src/textual/layout.py +++ b/src/textual/layout.py @@ -240,7 +240,7 @@ def get_content_width(self, widget: Widget, container: Size, viewport: Size) -> if not widget._nodes: width = 0 else: - arrangement = widget._arrange( + arrangement = widget.arrange( Size(0 if widget.shrink else container.width, 0), optimal=True, ) @@ -266,9 +266,9 @@ def get_content_height( child.styles.is_dynamic_height for child in widget.displayed_children ): # An exception for containers with all dynamic height widgets - arrangement = widget._arrange(Size(width, container.height)) + arrangement = widget.arrange(Size(width, container.height)) else: - arrangement = widget._arrange(Size(width, 0)) + arrangement = widget.arrange(Size(width, 0)) height = arrangement.total_region.height else: height = 0 diff --git a/src/textual/layouts/stream.py b/src/textual/layouts/stream.py index 9665f408f6..aa8b03e1a6 100644 --- a/src/textual/layouts/stream.py +++ b/src/textual/layouts/stream.py @@ -6,7 +6,6 @@ from textual.layout import ArrangeResult, Layout, WidgetPlacement if TYPE_CHECKING: - from textual.widget import Widget @@ -110,7 +109,7 @@ def get_content_height( Content height (in lines). """ if widget._nodes: - arrangement = widget._arrange(Size(width, 0)) + arrangement = widget.arrange(Size(width, 0)) height = arrangement.total_region.height else: height = 0 diff --git a/src/textual/screen.py b/src/textual/screen.py index f721a3913f..cefb45eeec 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -468,7 +468,7 @@ def active_bindings(self) -> dict[str, ActiveBinding]: return bindings_map - def _arrange(self, size: Size) -> DockArrangeResult: + def arrange(self, size: Size) -> DockArrangeResult: """Arrange children. Args: diff --git a/src/textual/widget.py b/src/textual/widget.py index ae298fe121..a35683690e 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -460,7 +460,7 @@ def __init__( self._content_height_cache: tuple[object, int] = (None, 0) self._arrangement_cache: FIFOCache[ - tuple[Size, int, Widget | None], DockArrangeResult + tuple[Size, int, bool], DockArrangeResult ] = FIFOCache(4) self._styles_cache = StylesCache() @@ -1264,11 +1264,14 @@ def render_str(self, text_content: str | Content) -> Content: return text_content return Content.from_markup(text_content) - def _arrange(self, size: Size, optimal: bool = False) -> DockArrangeResult: - """Arrange children. + def arrange(self, size: Size, optimal: bool = False) -> DockArrangeResult: + """Arrange child widgets. + + This method is best left along, unless you have a deep understanding of what it does. Args: size: Size of container. + optimal: Whether fr units should expand the widget (`False`) or avoid expanding the widget (`True`). Returns: Widget locations. @@ -4201,6 +4204,8 @@ def refresh( if not isinstance(ancestor, Widget): break ancestor._clear_arrangement_cache() + if not ancestor.styles.auto_dimensions: + break if recompose: self._recompose_required = True