Skip to content

Commit 13fc61c

Browse files
committed
dismiss change
1 parent 07bb4af commit 13fc61c

File tree

4 files changed

+31
-11
lines changed

4 files changed

+31
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Changed
1111

1212
- `get_content_height` will now return 0 if the renderable is Falsey https://github.com/Textualize/textual/pull/4617
13+
- Buttons may not be pressed within their "active_effect_duration" to prevent inadvertent activations
14+
- `Screen.dismiss` is now a noop if the screen isn't active. Previously it would raise a `ScreenStackError`, now it returns `False`.
15+
16+
### Added
17+
18+
- Added `Screen.is_active`
1319

1420
## [0.65.2] - 2023-06-06
1521

src/textual/screen.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ def active_bindings(self) -> dict[str, ActiveBinding]:
342342

343343
return bindings_map
344344

345+
@property
346+
def is_active(self) -> bool:
347+
"""Is the screen active (i.e. visible and top of the stack)?"""
348+
try:
349+
return self.app.screen is self
350+
except Exception:
351+
return False
352+
345353
def render(self) -> RenderableType:
346354
"""Render method inherited from widget, used to render the screen's background.
347355
@@ -1215,29 +1223,34 @@ def _forward_event(self, event: events.Event) -> None:
12151223
class _NoResult:
12161224
"""Class used to mark that there is no result."""
12171225

1218-
def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> None:
1226+
def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> bool:
12191227
"""Dismiss the screen, optionally with a result.
12201228
1229+
!!! note
1230+
1231+
Only the active screen may be dismissed. If you try to dismiss a screen that isn't active,
1232+
this method will return `False`.
1233+
12211234
If `result` is provided and a callback was set when the screen was [pushed][textual.app.App.push_screen], then
12221235
the callback will be invoked with `result`.
12231236
12241237
Args:
12251238
result: The optional result to be passed to the result callback.
12261239
1240+
Returns:
1241+
`True` if the Screen was dismissed, or `False` if the Screen wasn't dismissed due to not being active.
1242+
12271243
Raises:
12281244
ScreenStackError: If trying to dismiss a screen that is not at the top of
12291245
the stack.
12301246
12311247
"""
1232-
if self is not self.app.screen:
1233-
from .app import ScreenStackError
1234-
1235-
raise ScreenStackError(
1236-
f"Can't dismiss screen {self} that's not at the top of the stack."
1237-
)
1248+
if not self.is_active:
1249+
return False
12381250
if result is not self._NoResult and self._result_callbacks:
12391251
self._result_callbacks[-1](cast(ScreenResultType, result))
12401252
self.app.pop_screen()
1253+
return True
12411254

12421255
def action_dismiss(
12431256
self, result: ScreenResultType | Type[_NoResult] = _NoResult

src/textual/widgets/_button.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ def post_render(self, renderable: RenderableType) -> ConsoleRenderable:
250250

251251
async def _on_click(self, event: events.Click) -> None:
252252
event.stop()
253-
self.press()
253+
if not self.has_class("-active"):
254+
self.press()
254255

255256
def press(self) -> Self:
256257
"""Animate the button and send the [Pressed][textual.widgets.Button.Pressed] message.
@@ -278,7 +279,8 @@ def _start_active_affect(self) -> None:
278279

279280
def action_press(self) -> None:
280281
"""Activate a press of the button."""
281-
self.press()
282+
if not self.has_class("-active"):
283+
self.press()
282284

283285
@classmethod
284286
def success(

tests/test_screens.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,7 @@ async def key_p(self) -> None:
300300
app = MyApp()
301301
async with app.run_test() as pilot:
302302
await pilot.press("p")
303-
with pytest.raises(ScreenStackError):
304-
app.bottom.dismiss()
303+
assert not app.bottom.dismiss()
305304

306305

307306
async def test_dismiss_action():

0 commit comments

Comments
 (0)