Make auto-focus a class var.

Related comments: https://github.com/Textualize/textual/pull/2527\#discussion_r1188776849
This commit is contained in:
Rodrigo Girão Serrão
2023-05-09 16:44:37 +01:00
parent 8d3f69a04d
commit 3245eb38bb
2 changed files with 14 additions and 13 deletions

View File

@@ -9,6 +9,7 @@ from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Awaitable, Awaitable,
Callable, Callable,
ClassVar,
Generic, Generic,
Iterable, Iterable,
Iterator, Iterator,
@@ -93,6 +94,13 @@ class ResultCallback(Generic[ScreenResultType]):
class Screen(Generic[ScreenResultType], Widget): class Screen(Generic[ScreenResultType], Widget):
"""The base class for screens.""" """The base class for screens."""
AUTO_FOCUS: ClassVar[str | None] = "*"
"""A selector to determine what to focus automatically when the screen is activated.
The widget focused is the first that matches the given [CSS selector](/guide/queries/#query-selectors).
Set to `None` to disable auto focus.
"""
DEFAULT_CSS = """ DEFAULT_CSS = """
Screen { Screen {
layout: vertical; layout: vertical;
@@ -100,13 +108,6 @@ class Screen(Generic[ScreenResultType], Widget):
background: $surface; background: $surface;
} }
""" """
auto_focus: str | None = "*"
"""A selector to determine what to focus automatically when the screen is activated.
The widget focused is the first that matches the given [CSS selector](/guide/queries/#query-selectors).
Set to `None` to disable auto focus.
"""
focused: Reactive[Widget | None] = Reactive(None) focused: Reactive[Widget | None] = Reactive(None)
"""The focused [widget][textual.widget.Widget] or `None` for no focus.""" """The focused [widget][textual.widget.Widget] or `None` for no focus."""
stack_updates: Reactive[int] = Reactive(0, repaint=False) stack_updates: Reactive[int] = Reactive(0, repaint=False)
@@ -665,9 +666,9 @@ class Screen(Generic[ScreenResultType], Widget):
"""Screen has resumed.""" """Screen has resumed."""
self.stack_updates += 1 self.stack_updates += 1
size = self.app.size size = self.app.size
if self.auto_focus is not None and self.focused is None: if self.AUTO_FOCUS is not None and self.focused is None:
try: try:
to_focus = self.query(self.auto_focus).first() to_focus = self.query(self.AUTO_FOCUS).first()
except NoMatches: except NoMatches:
pass pass
else: else:

View File

@@ -170,24 +170,24 @@ async def test_auto_focus():
assert isinstance(app.focused, Button) assert isinstance(app.focused, Button)
app.pop_screen() app.pop_screen()
MyScreen.auto_focus = None MyScreen.AUTO_FOCUS = None
await app.push_screen(MyScreen()) await app.push_screen(MyScreen())
assert app.focused is None assert app.focused is None
app.pop_screen() app.pop_screen()
MyScreen.auto_focus = "Input" MyScreen.AUTO_FOCUS = "Input"
await app.push_screen(MyScreen()) await app.push_screen(MyScreen())
assert isinstance(app.focused, Input) assert isinstance(app.focused, Input)
assert app.focused.id == "one" assert app.focused.id == "one"
app.pop_screen() app.pop_screen()
MyScreen.auto_focus = "#two" MyScreen.AUTO_FOCUS = "#two"
await app.push_screen(MyScreen()) await app.push_screen(MyScreen())
assert isinstance(app.focused, Input) assert isinstance(app.focused, Input)
assert app.focused.id == "two" assert app.focused.id == "two"
# If we push and pop another screen, focus should be preserved for #two. # If we push and pop another screen, focus should be preserved for #two.
MyScreen.auto_focus = None MyScreen.AUTO_FOCUS = None
await app.push_screen(MyScreen()) await app.push_screen(MyScreen())
assert app.focused is None assert app.focused is None
app.pop_screen() app.pop_screen()