Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,10 +1019,11 @@ def _end_batch(self) -> None:
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.
Expand All @@ -1035,7 +1036,7 @@ def end_batch() -> None:
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]:
Expand Down
2 changes: 1 addition & 1 deletion src/textual/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,7 @@ def _select_or_command(
# 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)

Expand Down
11 changes: 3 additions & 8 deletions src/textual/widgets/_footer.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def render(self) -> Text:
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:
Expand Down Expand Up @@ -332,7 +332,7 @@ async def bindings_changed(self, screen: Screen) -> None:
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:
Expand All @@ -351,12 +351,7 @@ def _on_mouse_scroll_up(self, event: events.MouseScrollUp) -> None:
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)
5 changes: 4 additions & 1 deletion src/textual/widgets/_help_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 5 additions & 5 deletions src/textual/widgets/_key_panel.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -164,16 +163,17 @@ def compose(self) -> ComposeResult:
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)
Expand Down
5 changes: 3 additions & 2 deletions tests/test_modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading