Skip to content

Commit d11ff24

Browse files
authored
Merge pull request #4979 from Textualize/app-focus-style
2 parents 05fe60d + ef2281c commit d11ff24

File tree

4 files changed

+213
-3
lines changed

4 files changed

+213
-3
lines changed

src/textual/app.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ class App(Generic[ReturnType], DOMNode):
312312
App {
313313
background: $background;
314314
color: $text;
315+
316+
/* When a widget is maximized */
315317
Screen.-maximized-view {
316318
layout: vertical !important;
317319
hatch: right $panel;
@@ -321,6 +323,10 @@ class App(Generic[ReturnType], DOMNode):
321323
dock: initial !important;
322324
}
323325
}
326+
/* Fade the header title when app is blurred */
327+
&:blur HeaderTitle {
328+
text-opacity: 50%;
329+
}
324330
}
325331
*:disabled:can-focus {
326332
opacity: 0.7;
@@ -820,6 +826,17 @@ def _context(self) -> Generator[None, None, None]:
820826
active_message_pump.reset(message_pump_reset_token)
821827
active_app.reset(app_reset_token)
822828

829+
def get_pseudo_classes(self) -> Iterable[str]:
830+
"""Pseudo classes for a widget.
831+
832+
Returns:
833+
Names of the pseudo classes.
834+
"""
835+
yield "focus" if self.app_focus else "blur"
836+
yield "dark" if self.dark else "light"
837+
if self.is_inline:
838+
yield "inline"
839+
823840
def animate(
824841
self,
825842
attribute: str,
@@ -3617,6 +3634,7 @@ def post_mount() -> None:
36173634

36183635
def _watch_app_focus(self, focus: bool) -> None:
36193636
"""Respond to changes in app focus."""
3637+
self.screen._update_styles()
36203638
if focus:
36213639
# If we've got a last-focused widget, if it still has a screen,
36223640
# and if the screen is still the current screen and if nothing
Lines changed: 152 additions & 0 deletions
Loading

tests/snapshot_tests/test_snapshots.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from rich.text import Text
77

88
from tests.snapshot_tests.language_snippets import SNIPPETS
9+
from textual import events
910
from textual.app import App, ComposeResult
1011
from textual.binding import Binding
1112
from textual.containers import Vertical
@@ -124,7 +125,9 @@ async def run_before(pilot):
124125
pilot.app.query(Input).first().cursor_blink = False
125126

126127
assert snap_compare(
127-
SNAPSHOT_APPS_DIR / "masked_input.py", press=["A","B","C","0","1","-","D","E"], run_before=run_before
128+
SNAPSHOT_APPS_DIR / "masked_input.py",
129+
press=["A", "B", "C", "0", "1", "-", "D", "E"],
130+
run_before=run_before,
128131
)
129132

130133

@@ -1820,3 +1823,39 @@ def on_mount(self) -> None:
18201823

18211824
# ctrl+m to maximize, escape *should* minimize
18221825
assert snap_compare(TextAreaExample(), press=["ctrl+m", "escape"])
1826+
1827+
1828+
def test_app_focus_style(snap_compare):
1829+
"""Test that app blur style can be selected."""
1830+
1831+
class FocusApp(App):
1832+
CSS = """
1833+
Label {
1834+
padding: 1 2;
1835+
margin: 1 2;
1836+
background: $panel;
1837+
border: $primary;
1838+
}
1839+
App:focus {
1840+
.blurred {
1841+
visibility: hidden;
1842+
}
1843+
}
1844+
1845+
App:blur {
1846+
.focussed {
1847+
visibility: hidden;
1848+
}
1849+
}
1850+
1851+
"""
1852+
1853+
def compose(self) -> ComposeResult:
1854+
yield Label("BLURRED", classes="blurred")
1855+
yield Label("FOCUSED", classes="focussed")
1856+
1857+
async def run_before(pilot: Pilot) -> None:
1858+
pilot.app.post_message(events.AppBlur())
1859+
await pilot.pause()
1860+
1861+
assert snap_compare(FocusApp(), run_before=run_before)

tests/test_test_runner.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ def on_key(self, event: events.Key) -> None:
1212

1313
app = TestApp()
1414
async with app.run_test() as pilot:
15-
assert (
16-
str(pilot) == "<Pilot app=TestApp(title='TestApp', classes={'-dark-mode'})>"
15+
assert str(pilot) in (
16+
"<Pilot app=TestApp(title='TestApp', classes={'-dark-mode'}, pseudo_classes={'dark', 'focus'})>",
17+
"<Pilot app=TestApp(title='TestApp', classes={'-dark-mode'}, pseudo_classes={'focus', 'dark'})>",
1718
)
1819
await pilot.press("tab", *"foo")
1920
await pilot.exit("bar")

0 commit comments

Comments
 (0)