diff --git a/src/textual/widget.py b/src/textual/widget.py index 68c88b0f39..57243f763b 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -455,8 +455,6 @@ def __init__( self._layout_cache: dict[str, object] = {} """A dict that is refreshed when the widget is resized / refreshed.""" - self._visual_style: VisualStyle | None = None - self._render_cache = _RenderCache(_null_size, []) # Regions which need to be updated (in Widget) self._dirty_regions: set[Region] = set() @@ -721,14 +719,6 @@ def preflight_checks(self) -> None: f"'{self.__class__.__name__}.CSS' will be ignored (use 'DEFAULT_CSS' class variable for widgets)" ) - def pre_render(self) -> None: - """Called prior to rendering. - - If you implement this in a subclass, be sure to call the base class method via super. - - """ - self._visual_style = None - def _cover(self, widget: Widget) -> None: """Set a widget used to replace the visuals of this widget (used for loading indicator). @@ -4127,43 +4117,41 @@ def _scroll_update(self, virtual_size: Size) -> None: @property def visual_style(self) -> VisualStyle: - if self._visual_style is None: - background = Color(0, 0, 0, 0) - color = Color(255, 255, 255, 0) - - style = Style() - opacity = 1.0 + background = Color(0, 0, 0, 0) + color = Color(255, 255, 255, 0) - for node in reversed(self.ancestors_with_self): - styles = node.styles - has_rule = styles.has_rule - opacity *= styles.opacity - if has_rule("background"): - text_background = background + styles.background.tint( - styles.background_tint - ) - background += ( - styles.background.tint(styles.background_tint) - ).multiply_alpha(opacity) - else: - text_background = background - if has_rule("color"): - color = styles.color - style += styles.text_style - if has_rule("auto_color") and styles.auto_color: - color = text_background.get_contrast_text(color.a) + style = Style() + opacity = 1.0 - self._visual_style = VisualStyle( - background, - color, - bold=style.bold, - dim=style.dim, - italic=style.italic, - reverse=style.reverse, - underline=style.underline, - strike=style.strike, - ) - return self._visual_style + for node in reversed(self.ancestors_with_self): + styles = node.styles + has_rule = styles.has_rule + opacity *= styles.opacity + if has_rule("background"): + text_background = background + styles.background.tint( + styles.background_tint + ) + background += ( + styles.background.tint(styles.background_tint) + ).multiply_alpha(opacity) + else: + text_background = background + if has_rule("color"): + color = styles.color + style += styles.text_style + if has_rule("auto_color") and styles.auto_color: + color = text_background.get_contrast_text(color.a) + + return VisualStyle( + background, + color, + bold=style.bold, + dim=style.dim, + italic=style.italic, + reverse=style.reverse, + underline=style.underline, + strike=style.strike, + ) def get_selection(self, selection: Selection) -> tuple[str, str] | None: """Get the text under the selection. @@ -4633,7 +4621,6 @@ async def broker_event(self, event_name: str, event: events.Event) -> bool: def notify_style_update(self) -> None: self._rich_style_cache.clear() self._visual_style_cache.clear() - self._visual_style = None super().notify_style_update() async def _on_mouse_down(self, event: events.MouseDown) -> None: diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_visual_updates_after_style_changes.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_visual_updates_after_style_changes.svg new file mode 100644 index 0000000000..0b341d348b --- /dev/null +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_visual_updates_after_style_changes.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UpdateStylesApp + + + + + + + + + + + + + + + + + + + + +yellow on red + + + + + + + + + + + + + + + diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index c84b34e467..f53a320c42 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -4804,3 +4804,28 @@ async def run_before(pilot: Pilot) -> None: await pilot.press("ctrl+v") assert snap_compare(TextAreaApp(), run_before=run_before) + + +def test_visual_updates_after_style_changes(snap_compare) -> None: + """Regression test for https://github.com/Textualize/textual/issues/6289 + + You should see a widget with a red background and yellow text. + """ + + class UpdateStylesApp(App): + CSS = """ + Static { + height: 1fr; + content-align: center middle; + } + """ + + def compose(self) -> ComposeResult: + yield Static("yellow on red") + + def key_s(self) -> None: + widget = self.query_one(Static) + widget.styles.color = "yellow" + widget.styles.background = "red" + + assert snap_compare(UpdateStylesApp(), press=["s"])