mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge pull request #6137 from Textualize/alternative-footer-flicker-fix
delay update for footer
This commit is contained in:
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Reduced number of layout operations required to update the screen https://github.com/Textualize/textual/pull/6108
|
||||
- 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
|
||||
- The footer key hover background is more visible https://github.com/Textualize/textual/pull/6132
|
||||
- Made `App.delay_update` public https://github.com/Textualize/textual/pull/6137
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@@ -1019,10 +1019,11 @@ class App(Generic[ReturnType], DOMNode):
|
||||
if not self._batch_count:
|
||||
self.check_idle()
|
||||
|
||||
def _delay_update(self, delay: float = 0.05) -> None:
|
||||
def delay_update(self, delay: float = 0.05) -> None:
|
||||
"""Delay updates for a short period of time.
|
||||
|
||||
May be used to mask a brief transition.
|
||||
Consider this method only if you aren't able to use `App.batch_update`.
|
||||
|
||||
Args:
|
||||
delay: Delay before updating.
|
||||
@@ -1035,7 +1036,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
if not self._batch_count:
|
||||
self.screen.refresh()
|
||||
|
||||
self.set_timer(delay, end_batch, name="_delay_update")
|
||||
self.set_timer(delay, end_batch, name="delay_update")
|
||||
|
||||
@contextmanager
|
||||
def _context(self) -> Generator[None, None, None]:
|
||||
|
||||
@@ -1230,7 +1230,7 @@ class CommandPalette(SystemModalScreen[None]):
|
||||
# decide what to do with it (hopefully it'll run it).
|
||||
self._cancel_gather_commands()
|
||||
self.app.post_message(CommandPalette.Closed(option_selected=True))
|
||||
self.app._delay_update()
|
||||
self.app.delay_update()
|
||||
self.dismiss()
|
||||
self.app.call_later(self._selected_command.command)
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ class FooterKey(Widget):
|
||||
label_text.stylize_before(self.rich_style)
|
||||
return label_text
|
||||
|
||||
async def on_mouse_down(self) -> None:
|
||||
def on_mouse_down(self) -> None:
|
||||
if self._disabled:
|
||||
self.app.bell()
|
||||
else:
|
||||
@@ -332,7 +332,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
if not screen.app.app_focus:
|
||||
return
|
||||
if self.is_attached and screen is self.screen:
|
||||
await self.recompose()
|
||||
self.call_after_refresh(self.recompose)
|
||||
|
||||
def _on_mouse_scroll_down(self, event: events.MouseScrollDown) -> None:
|
||||
if self.allow_horizontal_scroll:
|
||||
@@ -351,12 +351,7 @@ class Footer(ScrollableContainer, can_focus=False, can_focus_children=False):
|
||||
async def on_mount(self) -> None:
|
||||
await asyncio.sleep(0)
|
||||
self.call_next(self.bindings_changed, self.screen)
|
||||
|
||||
def bindings_changed(screen: Screen) -> None:
|
||||
"""Update bindings after a short delay to avoid flicker."""
|
||||
self.call_after_refresh(self.bindings_changed, screen)
|
||||
|
||||
self.screen.bindings_updated_signal.subscribe(self, bindings_changed)
|
||||
self.screen.bindings_updated_signal.subscribe(self, self.bindings_changed)
|
||||
|
||||
def on_unmount(self) -> None:
|
||||
self.screen.bindings_updated_signal.unsubscribe(self)
|
||||
|
||||
@@ -79,7 +79,10 @@ class HelpPanel(Widget):
|
||||
DEFAULT_CLASSES = "-textual-system"
|
||||
|
||||
def on_mount(self):
|
||||
self.watch(self.screen, "focused", self.update_help)
|
||||
def update_help(focused_widget: Widget | None):
|
||||
self.update_help(focused_widget)
|
||||
|
||||
self.watch(self.screen, "focused", update_help)
|
||||
|
||||
def update_help(self, focused_widget: Widget | None) -> None:
|
||||
"""Update the help for the focused widget.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -164,16 +163,17 @@ class KeyPanel(VerticalScroll, can_focus=False):
|
||||
yield BindingsTable(shrink=True, expand=False)
|
||||
|
||||
async def on_mount(self) -> None:
|
||||
mount_screen = self.screen
|
||||
|
||||
async def bindings_changed(screen: Screen) -> None:
|
||||
"""Update bindings."""
|
||||
if not screen.app.app_focus:
|
||||
return
|
||||
if self.is_attached and screen is self.screen:
|
||||
self.refresh(recompose=True)
|
||||
if self.is_attached and screen is mount_screen:
|
||||
await self.recompose()
|
||||
|
||||
def _bindings_changed(screen: Screen) -> None:
|
||||
"""Update bindings after a short delay."""
|
||||
screen.set_timer(1 / 20, partial(bindings_changed, screen))
|
||||
self.call_after_refresh(bindings_changed, screen)
|
||||
|
||||
self.set_class(self.app.ansi_color, "-ansi-scrollbar")
|
||||
self.screen.bindings_updated_signal.subscribe(self, _bindings_changed)
|
||||
|
||||
@@ -89,10 +89,11 @@ async def test_modal_pop_screen():
|
||||
app = ModalApp()
|
||||
async with app.run_test() as pilot:
|
||||
# Pause to ensure the footer is fully composed to avoid flakiness in CI
|
||||
await pilot.pause(0.4)
|
||||
await pilot.pause()
|
||||
await app.wait_for_refresh()
|
||||
await pilot.pause()
|
||||
# Check clicking the footer brings up the quit screen
|
||||
await pilot.click(Footer)
|
||||
await pilot.click(Footer, offset=(1, 0))
|
||||
await pilot.pause()
|
||||
assert isinstance(pilot.app.screen, QuitScreen)
|
||||
# Check activating the quit button exits the app
|
||||
|
||||
Reference in New Issue
Block a user