diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa2248a71..3ab64b336b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [6.12.0] - 2025-01-02 + +### Fixed + +- Fixed unnecessary style update when popping screens, which may have caused noticable pauses changing screens (with a lot of widgets) https://github.com/Textualize/textual/pull/6304 + +### Changed + +- Promoted private `_update_styes` to `update_node_styles` https://github.com/Textualize/textual/pull/6304 + ## [6.11.0] - 2025-12-18 ### Added diff --git a/pyproject.toml b/pyproject.toml index 9a0c582945..212e0eecfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "textual" -version = "6.11.0" +version = "6.12.0" homepage = "https://github.com/Textualize/textual" repository = "https://github.com/Textualize/textual" documentation = "https://textual.textualize.io/" diff --git a/src/textual/app.py b/src/textual/app.py index 0bc273f165..d071562714 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -3045,9 +3045,9 @@ def _set_mouse_over( if hover_widget is not None: hover_widget.mouse_hover = True if hover_widget._has_hover_style: - hover_widget._update_styles() + hover_widget.update_node_styles() if current_hover_over is not None and current_hover_over._has_hover_style: - current_hover_over._update_styles() + current_hover_over.update_node_styles() self.hover_over = hover_widget def _update_mouse_over(self, screen: Screen) -> None: @@ -4247,7 +4247,7 @@ def post_mount() -> None: def _watch_app_focus(self, focus: bool) -> None: """Respond to changes in app focus.""" - self.screen._update_styles() + self.screen.update_node_styles() if focus: # If we've got a last-focused widget, if it still has a screen, # and if the screen is still the current screen and if nothing diff --git a/src/textual/dom.py b/src/textual/dom.py index b359059790..92dfbd5cd6 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -125,7 +125,7 @@ def __set__(self, obj: DOMNode, classes: str | Iterable[str]) -> None: class_names = set(classes) check_identifiers("class name", *class_names) obj._classes = class_names - obj._update_styles() + obj.update_node_styles() @rich.repr.auto @@ -1733,10 +1733,10 @@ def set_classes(self, classes: str | Iterable[str]) -> Self: self.classes = classes return self - def _update_styles(self) -> None: + def update_node_styles(self) -> None: """Request an update of this node's styles. - Should be called whenever CSS classes / pseudo classes change. + Called by Textual whenever CSS classes / pseudo classes change. """ try: self.app.update_styles(self) @@ -1759,7 +1759,7 @@ def add_class(self, *class_names: str, update: bool = True) -> Self: if old_classes == self._classes: return self if update: - self._update_styles() + self.update_node_styles() return self def remove_class(self, *class_names: str, update: bool = True) -> Self: @@ -1778,7 +1778,7 @@ def remove_class(self, *class_names: str, update: bool = True) -> Self: if old_classes == self._classes: return self if update: - self._update_styles() + self.update_node_styles() return self def toggle_class(self, *class_names: str) -> Self: @@ -1795,7 +1795,7 @@ def toggle_class(self, *class_names: str) -> Self: self._classes.symmetric_difference_update(class_names) if old_classes == self._classes: return self - self._update_styles() + self.update_node_styles() return self def has_pseudo_class(self, class_name: str) -> bool: diff --git a/src/textual/screen.py b/src/textual/screen.py index b21f964d8a..a92776d659 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -1441,7 +1441,8 @@ def _on_screen_resume(self) -> None: if self.is_attached: self._compositor_refresh() - self.app.stylesheet.update(self) + if self.stack_updates == 1: + self.app.stylesheet.update(self) self._refresh_layout(size) self.refresh() diff --git a/src/textual/widget.py b/src/textual/widget.py index 9f6d28b056..38cfb6ae5f 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -1445,11 +1445,11 @@ def update_styles(children: list[DOMNode]) -> None: # we need to update both odd/even, first-of-type/last-of-type and first-child/last-child for child in children: if child._has_order_style or child._has_odd_or_even: - child._update_styles() + child.update_node_styles() else: for child in children: if child._has_order_style: - child._update_styles() + child.update_node_styles() self.call_later(update_styles, self.displayed_children) await_mount = AwaitMount(self, mounted) @@ -4026,7 +4026,7 @@ def post_render( def watch_has_focus(self, _has_focus: bool) -> None: """Update from CSS if has focus state changes.""" - self._update_styles() + self.update_node_styles() def watch_disabled(self, disabled: bool) -> None: """Update the styles of the widget and its children when disabled is toggled.""" @@ -4046,7 +4046,7 @@ def watch_disabled(self, disabled: bool) -> None: except (ScreenStackError, NoActiveAppError, NoScreen): pass - self._update_styles() + self.update_node_styles() def _size_updated( self, size: Size, virtual_size: Size, container_size: Size, layout: bool = True @@ -4475,7 +4475,7 @@ def _check_refresh(self) -> None: else: if self._refresh_styles_required: self._refresh_styles_required = False - self.call_later(self._update_styles) + self.call_later(self.update_node_styles) if self._scroll_required: self._scroll_required = False if not self._layout_required: