mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Add ability to switch between modes.
This commit is contained in:
@@ -159,10 +159,18 @@ class ScreenStackError(ScreenError):
|
|||||||
"""Raised when attempting to pop the last screen from the stack."""
|
"""Raised when attempting to pop the last screen from the stack."""
|
||||||
|
|
||||||
|
|
||||||
class UnknownModeError(Exception):
|
class ModeError(Exception):
|
||||||
|
"""Base class for exceptions related to modes."""
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownModeError(ModeError):
|
||||||
"""Raised when attempting to use a mode that is not known."""
|
"""Raised when attempting to use a mode that is not known."""
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveModeError(ModeError):
|
||||||
|
"""Raised when attempting to remove the currently active mode."""
|
||||||
|
|
||||||
|
|
||||||
class CssPathError(Exception):
|
class CssPathError(Exception):
|
||||||
"""Raised when supplied CSS path(s) are invalid."""
|
"""Raised when supplied CSS path(s) are invalid."""
|
||||||
|
|
||||||
@@ -216,6 +224,8 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
MODES: ClassVar[set[str]] = set()
|
||||||
|
"""Modes associated with the app for the lifetime of the app."""
|
||||||
SCREENS: ClassVar[dict[str, Screen | Callable[[], Screen]]] = {}
|
SCREENS: ClassVar[dict[str, Screen | Callable[[], Screen]]] = {}
|
||||||
"""Screens associated with the app for the lifetime of the app."""
|
"""Screens associated with the app for the lifetime of the app."""
|
||||||
_BASE_PATH: str | None = None
|
_BASE_PATH: str | None = None
|
||||||
@@ -1335,6 +1345,63 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
"""
|
"""
|
||||||
return self.mount(*widgets, before=before, after=after)
|
return self.mount(*widgets, before=before, after=after)
|
||||||
|
|
||||||
|
def _init_mode(self, mode: str) -> None:
|
||||||
|
"""Do internal initialisation of a new screen stack mode."""
|
||||||
|
|
||||||
|
screen = Screen(id=f"_default_{mode}")
|
||||||
|
self._register(self, screen)
|
||||||
|
self._screen_stacks[mode] = [screen]
|
||||||
|
|
||||||
|
def switch_mode(self, mode: str) -> None:
|
||||||
|
"""Switch to a given mode.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mode: The mode to switch to.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
UnknownModeError: If trying to switch to an unknown mode.
|
||||||
|
"""
|
||||||
|
if mode not in self.MODES:
|
||||||
|
raise UnknownModeError(f"No known mode {mode!r}")
|
||||||
|
|
||||||
|
self.screen.post_message(events.ScreenSuspend())
|
||||||
|
self.screen.refresh()
|
||||||
|
|
||||||
|
if mode not in self._screen_stacks:
|
||||||
|
self._init_mode(mode)
|
||||||
|
self._current_mode = mode
|
||||||
|
self.screen._screen_resized(self.size)
|
||||||
|
self.screen.post_message(events.ScreenResume())
|
||||||
|
self.log.system(f"{self.screen} is active")
|
||||||
|
|
||||||
|
def add_mode(self, mode: str) -> None:
|
||||||
|
"""Adds a mode to the app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mode: The new mode.
|
||||||
|
"""
|
||||||
|
self.MODES.add(mode)
|
||||||
|
|
||||||
|
def remove_mode(self, mode: str) -> None:
|
||||||
|
"""Removes a mode from the app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mode: The mode to remove. It can't be the active mode.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ActiveModeError: If trying to remove the active mode.
|
||||||
|
UnknownModeError: If trying to remove an unknown mode.
|
||||||
|
"""
|
||||||
|
if mode == self._current_mode:
|
||||||
|
raise ActiveModeError(f"Can't remove active mode {mode!r}")
|
||||||
|
elif mode not in self.MODES:
|
||||||
|
raise UnknownModeError(f"Unknown mode {mode!r}")
|
||||||
|
|
||||||
|
stack = self._screen_stacks.get(mode, [])
|
||||||
|
while stack:
|
||||||
|
self._replace_screen(stack.pop())
|
||||||
|
self.MODES.remove(mode)
|
||||||
|
|
||||||
def is_screen_installed(self, screen: Screen | str) -> bool:
|
def is_screen_installed(self, screen: Screen | str) -> bool:
|
||||||
"""Check if a given screen has been installed.
|
"""Check if a given screen has been installed.
|
||||||
|
|
||||||
@@ -2144,7 +2211,7 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
# Handle input events that haven't been forwarded
|
# Handle input events that haven't been forwarded
|
||||||
# If the event has been forwarded it may have bubbled up back to the App
|
# If the event has been forwarded it may have bubbled up back to the App
|
||||||
if isinstance(event, events.Compose):
|
if isinstance(event, events.Compose):
|
||||||
screen = Screen(id=f"_default_{self._current_mode}")
|
screen = Screen(id=f"_default")
|
||||||
self._register(self, screen)
|
self._register(self, screen)
|
||||||
self._screen_stacks[self._current_mode].append(screen)
|
self._screen_stacks[self._current_mode].append(screen)
|
||||||
await super().on_event(event)
|
await super().on_event(event)
|
||||||
|
|||||||
Reference in New Issue
Block a user