Skip to content

Commit 288c309

Browse files
authored
Merge pull request #6137 from Textualize/alternative-footer-flicker-fix
delay update for footer
2 parents 6e9408c + 6b98201 commit 288c309

File tree

7 files changed

+20
-19
lines changed

7 files changed

+20
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1414
- Reduced number of layout operations required to update the screen https://github.com/Textualize/textual/pull/6108
1515
- The :hover pseudo-class no applies to the first widget under the mouse with a hover style set https://github.com/Textualize/textual/pull/6132
1616
- The footer key hover background is more visible https://github.com/Textualize/textual/pull/6132
17+
- Made `App.delay_update` public https://github.com/Textualize/textual/pull/6137
1718

1819
### Added
1920

src/textual/app.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,10 +1019,11 @@ def _end_batch(self) -> None:
10191019
if not self._batch_count:
10201020
self.check_idle()
10211021

1022-
def _delay_update(self, delay: float = 0.05) -> None:
1022+
def delay_update(self, delay: float = 0.05) -> None:
10231023
"""Delay updates for a short period of time.
10241024
10251025
May be used to mask a brief transition.
1026+
Consider this method only if you aren't able to use `App.batch_update`.
10261027
10271028
Args:
10281029
delay: Delay before updating.
@@ -1035,7 +1036,7 @@ def end_batch() -> None:
10351036
if not self._batch_count:
10361037
self.screen.refresh()
10371038

1038-
self.set_timer(delay, end_batch, name="_delay_update")
1039+
self.set_timer(delay, end_batch, name="delay_update")
10391040

10401041
@contextmanager
10411042
def _context(self) -> Generator[None, None, None]:

src/textual/command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ def _select_or_command(
12301230
# decide what to do with it (hopefully it'll run it).
12311231
self._cancel_gather_commands()
12321232
self.app.post_message(CommandPalette.Closed(option_selected=True))
1233-
self.app._delay_update()
1233+
self.app.delay_update()
12341234
self.dismiss()
12351235
self.app.call_later(self._selected_command.command)
12361236

src/textual/widgets/_footer.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def render(self) -> Text:
130130
label_text.stylize_before(self.rich_style)
131131
return label_text
132132

133-
async def on_mouse_down(self) -> None:
133+
def on_mouse_down(self) -> None:
134134
if self._disabled:
135135
self.app.bell()
136136
else:
@@ -332,7 +332,7 @@ async def bindings_changed(self, screen: Screen) -> None:
332332
if not screen.app.app_focus:
333333
return
334334
if self.is_attached and screen is self.screen:
335-
await self.recompose()
335+
self.call_after_refresh(self.recompose)
336336

337337
def _on_mouse_scroll_down(self, event: events.MouseScrollDown) -> None:
338338
if self.allow_horizontal_scroll:
@@ -351,12 +351,7 @@ def _on_mouse_scroll_up(self, event: events.MouseScrollUp) -> None:
351351
async def on_mount(self) -> None:
352352
await asyncio.sleep(0)
353353
self.call_next(self.bindings_changed, self.screen)
354-
355-
def bindings_changed(screen: Screen) -> None:
356-
"""Update bindings after a short delay to avoid flicker."""
357-
self.call_after_refresh(self.bindings_changed, screen)
358-
359-
self.screen.bindings_updated_signal.subscribe(self, bindings_changed)
354+
self.screen.bindings_updated_signal.subscribe(self, self.bindings_changed)
360355

361356
def on_unmount(self) -> None:
362357
self.screen.bindings_updated_signal.unsubscribe(self)

src/textual/widgets/_help_panel.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ class HelpPanel(Widget):
7979
DEFAULT_CLASSES = "-textual-system"
8080

8181
def on_mount(self):
82-
self.watch(self.screen, "focused", self.update_help)
82+
def update_help(focused_widget: Widget | None):
83+
self.update_help(focused_widget)
84+
85+
self.watch(self.screen, "focused", update_help)
8386

8487
def update_help(self, focused_widget: Widget | None) -> None:
8588
"""Update the help for the focused widget.

src/textual/widgets/_key_panel.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
from collections import defaultdict
4-
from functools import partial
54
from itertools import groupby
65
from operator import itemgetter
76
from typing import TYPE_CHECKING
@@ -164,16 +163,17 @@ def compose(self) -> ComposeResult:
164163
yield BindingsTable(shrink=True, expand=False)
165164

166165
async def on_mount(self) -> None:
166+
mount_screen = self.screen
167+
167168
async def bindings_changed(screen: Screen) -> None:
168169
"""Update bindings."""
169170
if not screen.app.app_focus:
170171
return
171-
if self.is_attached and screen is self.screen:
172-
self.refresh(recompose=True)
172+
if self.is_attached and screen is mount_screen:
173+
await self.recompose()
173174

174175
def _bindings_changed(screen: Screen) -> None:
175-
"""Update bindings after a short delay."""
176-
screen.set_timer(1 / 20, partial(bindings_changed, screen))
176+
self.call_after_refresh(bindings_changed, screen)
177177

178178
self.set_class(self.app.ansi_color, "-ansi-scrollbar")
179179
self.screen.bindings_updated_signal.subscribe(self, _bindings_changed)

tests/test_modal.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@ async def test_modal_pop_screen():
8989
app = ModalApp()
9090
async with app.run_test() as pilot:
9191
# Pause to ensure the footer is fully composed to avoid flakiness in CI
92-
await pilot.pause(0.4)
92+
await pilot.pause()
9393
await app.wait_for_refresh()
94+
await pilot.pause()
9495
# Check clicking the footer brings up the quit screen
95-
await pilot.click(Footer)
96+
await pilot.click(Footer, offset=(1, 0))
9697
await pilot.pause()
9798
assert isinstance(pilot.app.screen, QuitScreen)
9899
# Check activating the quit button exits the app

0 commit comments

Comments
 (0)