mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'main' into no-container-scroll
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- `textual run` execs apps in a new context.
|
- `textual run` execs apps in a new context.
|
||||||
|
- Textual console no longer parses console markup.
|
||||||
- Breaking change: `Container` no longer shows required scrollbars by default https://github.com/Textualize/textual/issues/2361
|
- Breaking change: `Container` no longer shows required scrollbars by default https://github.com/Textualize/textual/issues/2361
|
||||||
- Breaking change: `VerticalScroll` no longer shows a required horizontal scrollbar by default
|
- Breaking change: `VerticalScroll` no longer shows a required horizontal scrollbar by default
|
||||||
- Breaking change: `HorizontalScroll` no longer shows a required vertical scrollbar by default
|
- Breaking change: `HorizontalScroll` no longer shows a required vertical scrollbar by default
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Simulates a screenshot of the Textual devtools
|
Simulates a screenshot of the Textual devtools
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from textual.app import App
|
from textual.app import App
|
||||||
|
|
||||||
from textual.devtools.renderables import DevConsoleHeader
|
from textual.devtools.renderables import DevConsoleHeader
|
||||||
from textual.widgets import Static
|
from textual.widgets import Static
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.widgets import Static, Header
|
from textual.widgets import Header, Static
|
||||||
|
|
||||||
TEXT = """\
|
TEXT = """\
|
||||||
Docking a widget removes it from the layout and fixes its position, aligned to either the top, right, bottom, or left edges of a container.
|
Docking a widget removes it from the layout and fixes its position, aligned to either the top, right, bottom, or left edges of a container.
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ class ListViewExample(App):
|
|||||||
)
|
)
|
||||||
yield Footer()
|
yield Footer()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ Code browser example.
|
|||||||
Run with:
|
Run with:
|
||||||
|
|
||||||
python code_browser.py PATH
|
python code_browser.py PATH
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ class GameCell(Button):
|
|||||||
Args:
|
Args:
|
||||||
row (int): The row of the cell.
|
row (int): The row of the cell.
|
||||||
col (int): The column of the cell.
|
col (int): The column of the cell.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super().__init__("", id=self.at(row, col))
|
super().__init__("", id=self.at(row, col))
|
||||||
self.row = row
|
self.row = row
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ class BoundAnimator:
|
|||||||
delay: A delay (in seconds) before the animation starts.
|
delay: A delay (in seconds) before the animation starts.
|
||||||
easing: An easing method.
|
easing: An easing method.
|
||||||
on_complete: A callable to invoke when the animation is finished.
|
on_complete: A callable to invoke when the animation is finished.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
start_value = getattr(self._obj, attribute)
|
start_value = getattr(self._obj, attribute)
|
||||||
if isinstance(value, str) and hasattr(start_value, "parse"):
|
if isinstance(value, str) and hasattr(start_value, "parse"):
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Compatibility layer for asyncio.
|
Compatibility layer for asyncio.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ Note that stdlib's @lru_cache is implemented in C and faster! It's best to use
|
|||||||
@lru_cache where you are caching things that are fairly quick and called many times.
|
@lru_cache where you are caching things that are fairly quick and called many times.
|
||||||
Use LRUCache where you want increased flexibility and you are caching slow operations
|
Use LRUCache where you want increased flexibility and you are caching slow operations
|
||||||
where the overhead of the cache is a small fraction of the total processing time.
|
where the overhead of the cache is a small fraction of the total processing time.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -35,7 +34,6 @@ class LRUCache(Generic[CacheKey, CacheValue]):
|
|||||||
|
|
||||||
Each entry is stored as [PREV, NEXT, KEY, VALUE] where PREV is a reference
|
Each entry is stored as [PREV, NEXT, KEY, VALUE] where PREV is a reference
|
||||||
to the previous entry, and NEXT is a reference to the next value.
|
to the previous entry, and NEXT is a reference to the next value.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = [
|
__slots__ = [
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ queries regarding the widget under an offset, or the style under an offset.
|
|||||||
|
|
||||||
Additionally, the compositor can render portions of the screen which may have updated,
|
Additionally, the compositor can render portions of the screen which may have updated,
|
||||||
without having to render the entire screen.
|
without having to render the entire screen.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -410,7 +409,6 @@ class Compositor:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Set of widgets that were exposed by the scroll.
|
Set of widgets that were exposed by the scroll.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._cuts = None
|
self._cuts = None
|
||||||
self._layers = None
|
self._layers = None
|
||||||
@@ -790,7 +788,6 @@ class Compositor:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Widget's composition information.
|
Widget's composition information.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.root is None:
|
if self.root is None:
|
||||||
raise errors.NoWidget("Widget is not in layout")
|
raise errors.NoWidget("Widget is not in layout")
|
||||||
@@ -932,7 +929,6 @@ class Compositor:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A ChopsUpdate if there is anything to update, otherwise `None`.
|
A ChopsUpdate if there is anything to update, otherwise `None`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
screen_region = self.size.region
|
screen_region = self.size.region
|
||||||
update_regions = self._dirty_regions.copy()
|
update_regions = self._dirty_regions.copy()
|
||||||
@@ -1019,7 +1015,6 @@ class Compositor:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
widgets: Set of Widgets to update.
|
widgets: Set of Widgets to update.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# If there are any *new* widgets we need to invalidate the full map
|
# If there are any *new* widgets we need to invalidate the full map
|
||||||
if not self._full_map_invalidated and not widgets.issubset(
|
if not self._full_map_invalidated and not widgets.issubset(
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ def _duration_as_seconds(duration: str) -> float:
|
|||||||
DurationParseError: If the argument ``duration`` is not a valid duration string.
|
DurationParseError: If the argument ``duration`` is not a valid duration string.
|
||||||
Returns:
|
Returns:
|
||||||
The duration in seconds.
|
The duration in seconds.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
match = _match_duration(duration)
|
match = _match_duration(duration)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class NodeList(Sequence["Widget"]):
|
|||||||
A container for widgets that forms one level of hierarchy.
|
A container for widgets that forms one level of hierarchy.
|
||||||
|
|
||||||
Although named a list, widgets may appear only once, making them more like a set.
|
Although named a list, widgets may appear only once, making them more like a set.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Timer context manager, only used in debug.
|
Timer context manager, only used in debug.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class SpatialMap(Generic[ValueType]):
|
|||||||
|
|
||||||
The SpatialMap is able to quickly retrieve the values under a given "window" region
|
The SpatialMap is able to quickly retrieve the values under a given "window" region
|
||||||
by combining the values in the grid squares under the visible area.
|
by combining the values in the grid squares under the visible area.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, grid_width: int = 100, grid_height: int = 20) -> None:
|
def __init__(self, grid_width: int = 100, grid_height: int = 20) -> None:
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class StylesCache:
|
|||||||
┃ ┃
|
┃ ┃
|
||||||
┗━━━━━━━━━━━━━━━━━━━━━━┛
|
┗━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
A version of `time.sleep` that is more accurate than the standard library (even on Python 3.11).
|
A version of `time.sleep` that is more accurate than the standard library (even on Python 3.11).
|
||||||
|
|
||||||
This should only be imported on Windows.
|
This should only be imported on Windows.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from time import sleep as time_sleep
|
from time import sleep as time_sleep
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
A decorator used to create [workers](/guide/workers).
|
A decorator used to create [workers](/guide/workers).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +67,6 @@ def work(
|
|||||||
group: A short string to identify a group of workers.
|
group: A short string to identify a group of workers.
|
||||||
exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.
|
exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.
|
||||||
exclusive: Cancel all workers in the same group.
|
exclusive: Cancel all workers in the same group.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def decorator(
|
def decorator(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
A class to manage [workers](/guide/workers) for an app.
|
A class to manage [workers](/guide/workers) for an app.
|
||||||
|
|
||||||
You access this object via [App.workers][textual.app.App.workers] or [Widget.workers][textual.dom.DOMNode.workers].
|
You access this object via [App.workers][textual.app.App.workers] or [Widget.workers][textual.dom.DOMNode.workers].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -28,7 +27,6 @@ class WorkerManager:
|
|||||||
|
|
||||||
You will not have to construct this class manually, as widgets, screens, and apps
|
You will not have to construct this class manually, as widgets, screens, and apps
|
||||||
have a worker manager accessibly via a `workers` attribute.
|
have a worker manager accessibly via a `workers` attribute.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, app: App) -> None:
|
def __init__(self, app: App) -> None:
|
||||||
@@ -163,7 +161,6 @@ class WorkerManager:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of cancelled workers.
|
List of cancelled workers.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
workers = [worker for worker in self._workers if worker.node == node]
|
workers = [worker for worker in self._workers if worker.node == node]
|
||||||
for worker in workers:
|
for worker in workers:
|
||||||
|
|||||||
@@ -231,7 +231,6 @@ class XTermParser(Parser[events.Event]):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Keys
|
Keys
|
||||||
|
|
||||||
"""
|
"""
|
||||||
keys = ANSI_SEQUENCES_KEYS.get(sequence)
|
keys = ANSI_SEQUENCES_KEYS.get(sequence)
|
||||||
if keys is not None:
|
if keys is not None:
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
Here you will find the [App][textual.app.App] class, which is the base class for Textual apps.
|
Here you will find the [App][textual.app.App] class, which is the base class for Textual apps.
|
||||||
|
|
||||||
See [app basics](/guide/app) for how to build Textual apps.
|
See [app basics](/guide/app) for how to build Textual apps.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -248,7 +247,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
```python
|
```python
|
||||||
self.app.dark = not self.app.dark # Toggle dark mode
|
self.app.dark = not self.app.dark # Toggle dark mode
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -403,7 +401,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An object to manage workers.
|
An object to manage workers.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._workers
|
return self._workers
|
||||||
|
|
||||||
@@ -412,7 +409,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
"""The return value of the app, or `None` if it as not yet been set.
|
"""The return value of the app, or `None` if it as not yet been set.
|
||||||
|
|
||||||
The return value is set when calling [exit][textual.app.App.exit].
|
The return value is set when calling [exit][textual.app.App.exit].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._return_value
|
return self._return_value
|
||||||
|
|
||||||
@@ -425,7 +421,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A sequence of widgets.
|
A sequence of widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return (self.screen,)
|
return (self.screen,)
|
||||||
@@ -477,7 +472,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
delay: A delay (in seconds) before the animation starts.
|
delay: A delay (in seconds) before the animation starts.
|
||||||
easing: An easing method.
|
easing: An easing method.
|
||||||
on_complete: A callable to invoke when the animation is finished.
|
on_complete: A callable to invoke when the animation is finished.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._animate(
|
self._animate(
|
||||||
attribute,
|
attribute,
|
||||||
@@ -500,7 +494,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
"""Is the driver running in 'headless' mode?
|
"""Is the driver running in 'headless' mode?
|
||||||
|
|
||||||
Headless mode is used when running tests with [run_test][textual.app.App.run_test].
|
Headless mode is used when running tests with [run_test][textual.app.App.run_test].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return False if self._driver is None else self._driver.is_headless
|
return False if self._driver is None else self._driver.is_headless
|
||||||
|
|
||||||
@@ -510,7 +503,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A snapshot of the current state of the screen stack.
|
A snapshot of the current state of the screen stack.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._screen_stack.copy()
|
return self._screen_stack.copy()
|
||||||
|
|
||||||
@@ -537,7 +529,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The currently focused widget, or `None` if nothing is focused.
|
The currently focused widget, or `None` if nothing is focused.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.screen.focused
|
return self.screen.focused
|
||||||
|
|
||||||
@@ -553,7 +544,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
A mapping of keys on to node + binding.
|
A mapping of keys on to node + binding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
namespace_binding_map: dict[str, tuple[DOMNode, Binding]] = {}
|
namespace_binding_map: dict[str, tuple[DOMNode, Binding]] = {}
|
||||||
@@ -571,7 +561,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
"""Yield child widgets for a container.
|
"""Yield child widgets for a container.
|
||||||
|
|
||||||
This method should be implemented in a subclass.
|
This method should be implemented in a subclass.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
yield from ()
|
yield from ()
|
||||||
|
|
||||||
@@ -591,7 +580,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
This method handles the transition between light and dark mode when you
|
This method handles the transition between light and dark mode when you
|
||||||
change the [dark][textual.app.App.dark] attribute.
|
change the [dark][textual.app.App.dark] attribute.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.set_class(dark, "-dark-mode")
|
self.set_class(dark, "-dark-mode")
|
||||||
self.set_class(not dark, "-light-mode")
|
self.set_class(not dark, "-light-mode")
|
||||||
@@ -692,7 +680,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Size of the terminal.
|
Size of the terminal.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._driver is not None and self._driver._size is not None:
|
if self._driver is not None and self._driver._size is not None:
|
||||||
width, height = self._driver._size
|
width, height = self._driver._size
|
||||||
@@ -712,7 +699,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Textual logger.
|
A Textual logger.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._logger
|
return self._logger
|
||||||
|
|
||||||
@@ -837,7 +823,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
title: The title of the exported screenshot or None
|
title: The title of the exported screenshot or None
|
||||||
to use app title.
|
to use app title.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert self._driver is not None, "App must be running"
|
assert self._driver is not None, "App must be running"
|
||||||
width, height = self.size
|
width, height = self.size
|
||||||
@@ -985,8 +970,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
headless: Run in headless mode (no output or input).
|
headless: Run in headless mode (no output or input).
|
||||||
size: Force terminal size to `(WIDTH, HEIGHT)`,
|
size: Force terminal size to `(WIDTH, HEIGHT)`,
|
||||||
or None to auto-detect.
|
or None to auto-detect.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from .pilot import Pilot
|
from .pilot import Pilot
|
||||||
|
|
||||||
@@ -1364,7 +1347,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A screen instance and an awaitable that awaits the children mounting.
|
A screen instance and an awaitable that awaits the children mounting.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_screen = self.get_screen(screen)
|
_screen = self.get_screen(screen)
|
||||||
if not _screen.is_running:
|
if not _screen.is_running:
|
||||||
@@ -1385,7 +1367,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The screen that was replaced.
|
The screen that was replaced.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._screen_stack:
|
if self._screen_stack:
|
||||||
self.screen.refresh()
|
self.screen.refresh()
|
||||||
@@ -1432,7 +1413,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
screen: Either a Screen object or screen name (the `name` argument when installed).
|
screen: Either a Screen object or screen name (the `name` argument when installed).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(screen, (Screen, str)):
|
if not isinstance(screen, (Screen, str)):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
@@ -1770,7 +1750,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
"""Called immediately prior to processing messages.
|
"""Called immediately prior to processing messages.
|
||||||
|
|
||||||
May be used as a hook for any operations that should run first.
|
May be used as a hook for any operations that should run first.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def take_screenshot() -> None:
|
async def take_screenshot() -> None:
|
||||||
@@ -1859,7 +1838,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
after: A location to mount after.
|
after: A location to mount after.
|
||||||
Returns:
|
Returns:
|
||||||
List of modified widgets.
|
List of modified widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not widgets:
|
if not widgets:
|
||||||
@@ -2061,8 +2039,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
For terminals that support a bell, this typically makes a notification or error sound.
|
For terminals that support a bell, this typically makes a notification or error sound.
|
||||||
Some terminals may make no sound or display a visual bell indicator, depending on configuration.
|
Some terminals may make no sound or display a visual bell indicator, depending on configuration.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self.is_headless and self._driver is not None:
|
if not self.is_headless and self._driver is not None:
|
||||||
self._driver.write("\07")
|
self._driver.write("\07")
|
||||||
@@ -2345,7 +2321,6 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The child widgets of root.
|
The child widgets of root.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
stack: list[Widget] = [root]
|
stack: list[Widget] = [root]
|
||||||
pop = stack.pop
|
pop = stack.pop
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
An *optionally* awaitable object returned by methods that remove widgets.
|
An *optionally* awaitable object returned by methods that remove widgets.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from asyncio import Event, Task
|
from asyncio import Event, Task
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
A binding maps a key press on to an action.
|
A binding maps a key press on to an action.
|
||||||
|
|
||||||
See [bindings](/guide/input#bindings) in the guide for details.
|
See [bindings](/guide/input#bindings) in the guide for details.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ Functions to run Textual apps with an updated environment.
|
|||||||
|
|
||||||
Note that these methods will execute apps in a new process, and abandon the current process.
|
Note that these methods will execute apps in a new process, and abandon the current process.
|
||||||
This means that (if they succeed) they will never return.
|
This means that (if they succeed) they will never return.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -98,7 +97,6 @@ def exec_python(args: list[str], environment: dict[str, str]) -> NoReturn:
|
|||||||
Args:
|
Args:
|
||||||
args: Additional arguments.
|
args: Additional arguments.
|
||||||
environment: Environment variables.
|
environment: Environment variables.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_flush()
|
_flush()
|
||||||
os.execvpe(sys.executable, ["python", *args], environment)
|
os.execvpe(sys.executable, ["python", *args], environment)
|
||||||
@@ -148,7 +146,6 @@ def exec_import(
|
|||||||
import_name: The Python import.
|
import_name: The Python import.
|
||||||
args: Command line arguments.
|
args: Command line arguments.
|
||||||
environment: Environment variables.
|
environment: Environment variables.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
module, _colon, app = import_name.partition(":")
|
module, _colon, app = import_name.partition(":")
|
||||||
app = app or "app"
|
app = app or "app"
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ class Bar(Widget):
|
|||||||
background: $surface;
|
background: $surface;
|
||||||
color: $success;
|
color: $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def watch_animation_running(self, running: bool) -> None:
|
def watch_animation_running(self, running: bool) -> None:
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ for name, triplet in sorted(COLOR_NAME_TO_RGB.items()):
|
|||||||
)
|
)
|
||||||
output = table
|
output = table
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -158,7 +156,6 @@ class Color(NamedTuple):
|
|||||||
>>> color + color_with_alpha
|
>>> color + color_with_alpha
|
||||||
Color(177, 25, 12)
|
Color(177, 25, 12)
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
r: int
|
r: int
|
||||||
@@ -204,7 +201,6 @@ class Color(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Inverse color.
|
Inverse color.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, a = self
|
r, g, b, a = self
|
||||||
return Color(255 - r, 255 - g, 255 - b, a)
|
return Color(255 - r, 255 - g, 255 - b, a)
|
||||||
@@ -245,7 +241,6 @@ class Color(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Normalized components.
|
Normalized components.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, _a = self
|
r, g, b, _a = self
|
||||||
return (r / 255, g / 255, b / 255)
|
return (r / 255, g / 255, b / 255)
|
||||||
@@ -264,7 +259,6 @@ class Color(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Color encoded in HSL format.
|
Color encoded in HSL format.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b = self.normalized
|
r, g, b = self.normalized
|
||||||
h, l, s = rgb_to_hls(r, g, b)
|
h, l, s = rgb_to_hls(r, g, b)
|
||||||
@@ -276,7 +270,6 @@ class Color(NamedTuple):
|
|||||||
|
|
||||||
A value of 1 is returned for pure white, and 0 for pure black.
|
A value of 1 is returned for pure white, and 0 for pure black.
|
||||||
Other colors lie on a gradient between the two extremes.
|
Other colors lie on a gradient between the two extremes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b = self.normalized
|
r, g, b = self.normalized
|
||||||
brightness = (299 * r + 587 * g + 114 * b) / 1000
|
brightness = (299 * r + 587 * g + 114 * b) / 1000
|
||||||
@@ -287,7 +280,6 @@ class Color(NamedTuple):
|
|||||||
"""The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA.
|
"""The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA.
|
||||||
|
|
||||||
For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha.
|
For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, a = self.clamped
|
r, g, b, a = self.clamped
|
||||||
return (
|
return (
|
||||||
@@ -301,7 +293,6 @@ class Color(NamedTuple):
|
|||||||
"""The color in CSS hex form, with 6 digits for RGB. Alpha is ignored.
|
"""The color in CSS hex form, with 6 digits for RGB. Alpha is ignored.
|
||||||
|
|
||||||
For example, `"#46b3de"`.
|
For example, `"#46b3de"`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, _a = self.clamped
|
r, g, b, _a = self.clamped
|
||||||
return f"#{r:02X}{g:02X}{b:02X}"
|
return f"#{r:02X}{g:02X}{b:02X}"
|
||||||
@@ -311,7 +302,6 @@ class Color(NamedTuple):
|
|||||||
"""The color in CSS RGB or RGBA form.
|
"""The color in CSS RGB or RGBA form.
|
||||||
|
|
||||||
For example, `"rgb(10,20,30)"` for an RGB color, or `"rgb(50,70,80,0.5)"` for an RGBA color.
|
For example, `"rgb(10,20,30)"` for an RGB color, or `"rgb(50,70,80,0.5)"` for an RGBA color.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, a = self
|
r, g, b, a = self
|
||||||
return f"rgb({r},{g},{b})" if a == 1 else f"rgba({r},{g},{b},{a})"
|
return f"rgb({r},{g},{b})" if a == 1 else f"rgba({r},{g},{b},{a})"
|
||||||
@@ -322,7 +312,6 @@ class Color(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The monochrome (black and white) version of this color.
|
The monochrome (black and white) version of this color.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
r, g, b, a = self
|
r, g, b, a = self
|
||||||
gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722)
|
gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Constants that we might want to expose via the public API.
|
Constants that we might want to expose via the public API.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Container widgets for quick styling.
|
Container widgets for quick styling.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
A class to store a coordinate, used by the [DataTable][textual.widgets.DataTable].
|
A class to store a coordinate, used by the [DataTable][textual.widgets.DataTable].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ setting attributes. This gives the developer more freedom in how to express styl
|
|||||||
|
|
||||||
Descriptors also play nicely with Mypy, which is aware that attributes can have different types
|
Descriptors also play nicely with Mypy, which is aware that attributes can have different types
|
||||||
when setting and getting.
|
when setting and getting.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -383,7 +382,6 @@ class BorderProperty:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
layout: True if the layout should be refreshed after setting, False otherwise.
|
layout: True if the layout should be refreshed after setting, False otherwise.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, layout: bool) -> None:
|
def __init__(self, layout: bool) -> None:
|
||||||
|
|||||||
@@ -227,7 +227,6 @@ def _unresolved(variable_name: str, variables: Iterable[str], token: Token) -> N
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
UnresolvedVariableError: Always raises a TokenError.
|
UnresolvedVariableError: Always raises a TokenError.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
message = f"reference to undefined variable '${variable_name}'"
|
message = f"reference to undefined variable '${variable_name}'"
|
||||||
suggested_variable = get_suggestion(variable_name, list(variables))
|
suggested_variable = get_suggestion(variable_name, list(variables))
|
||||||
|
|||||||
@@ -770,7 +770,6 @@ class Styles(StylesBase):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An iterable of CSS declarations.
|
An iterable of CSS declarations.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
has_rule = rules.__contains__
|
has_rule = rules.__contains__
|
||||||
@@ -1119,7 +1118,6 @@ class RenderStyles(StylesBase):
|
|||||||
delay: A delay (in seconds) before the animation starts.
|
delay: A delay (in seconds) before the animation starts.
|
||||||
easing: An easing method.
|
easing: An easing method.
|
||||||
on_complete: A callable to invoke when the animation is finished.
|
on_complete: A callable to invoke when the animation is finished.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._animate is None:
|
if self._animate is None:
|
||||||
assert self.node is not None
|
assert self.node is not None
|
||||||
|
|||||||
@@ -333,7 +333,6 @@ class Stylesheet:
|
|||||||
Raises:
|
Raises:
|
||||||
StylesheetError: If the CSS could not be read.
|
StylesheetError: If the CSS could not be read.
|
||||||
StylesheetParseError: If the CSS is invalid.
|
StylesheetParseError: If the CSS is invalid.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Do this in a fresh Stylesheet so if there are errors we don't break self.
|
# Do this in a fresh Stylesheet so if there are errors we don't break self.
|
||||||
stylesheet = Stylesheet(variables=self._variables)
|
stylesheet = Stylesheet(variables=self._variables)
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ WELCOME_MD = """
|
|||||||
## Textual Demo
|
## Textual Demo
|
||||||
|
|
||||||
**Welcome**! Textual is a framework for creating sophisticated applications with the terminal.
|
**Welcome**! Textual is a framework for creating sophisticated applications with the terminal.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -83,8 +82,6 @@ Textual is built on **Rich**, the popular Python library for advanced terminal o
|
|||||||
Add content to your Textual App with Rich *renderables* (this text is written in Markdown and formatted with Rich's Markdown class).
|
Add content to your Textual App with Rich *renderables* (this text is written in Markdown and formatted with Rich's Markdown class).
|
||||||
|
|
||||||
Here are some examples:
|
Here are some examples:
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CSS_MD = """
|
CSS_MD = """
|
||||||
@@ -95,7 +92,6 @@ Textual uses Cascading Stylesheets (CSS) to create Rich interactive User Interfa
|
|||||||
- **Live editing** - see your changes without restarting the app!
|
- **Live editing** - see your changes without restarting the app!
|
||||||
|
|
||||||
Here's an example of some CSS used in this app:
|
Here's an example of some CSS used in this app:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -143,7 +139,6 @@ Build your own or use the builtin widgets.
|
|||||||
- **Tree** An generic tree with expandable nodes.
|
- **Tree** An generic tree with expandable nodes.
|
||||||
- **DirectoryTree** A tree of file and folders.
|
- **DirectoryTree** A tree of file and folders.
|
||||||
- *... many more planned ...*
|
- *... many more planned ...*
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -160,7 +155,6 @@ Here are some links. You can click these!
|
|||||||
|
|
||||||
|
|
||||||
Built with ♥ by [@click="app.open_link('https://www.textualize.io')"]Textualize.io[/]
|
Built with ♥ by [@click="app.open_link('https://www.textualize.io')"]Textualize.io[/]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ class ColorSystem:
|
|||||||
|
|
||||||
Primary is the main theme color
|
Primary is the main theme color
|
||||||
Secondary is a second theme color
|
Secondary is a second theme color
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COLOR_NAMES = [
|
COLOR_NAMES = [
|
||||||
@@ -96,7 +94,6 @@ class ColorSystem:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A mapping of color name on to a CSS-style encoded color
|
A mapping of color name on to a CSS-style encoded color
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
primary = self.primary
|
primary = self.primary
|
||||||
@@ -134,7 +131,6 @@ class ColorSystem:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Iterable of tuples (<SHADE SUFFIX, LUMINOSITY DELTA>)
|
Iterable of tuples (<SHADE SUFFIX, LUMINOSITY DELTA>)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
luminosity_step = spread / 2
|
luminosity_step = spread / 2
|
||||||
for n in range(-NUMBER_OF_SHADES, +NUMBER_OF_SHADES + 1):
|
for n in range(-NUMBER_OF_SHADES, +NUMBER_OF_SHADES + 1):
|
||||||
@@ -196,7 +192,6 @@ def show_design(light: ColorSystem, dark: ColorSystem) -> Table:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Table showing all colors.
|
Table showing all colors.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@group()
|
@group()
|
||||||
|
|||||||
@@ -211,9 +211,9 @@ class DevtoolsClient:
|
|||||||
log: The log to write to devtools
|
log: The log to write to devtools
|
||||||
"""
|
"""
|
||||||
if isinstance(log.objects_or_string, str):
|
if isinstance(log.objects_or_string, str):
|
||||||
self.console.print(log.objects_or_string)
|
self.console.print(log.objects_or_string, markup=False)
|
||||||
else:
|
else:
|
||||||
self.console.print(*log.objects_or_string)
|
self.console.print(*log.objects_or_string, markup=False)
|
||||||
|
|
||||||
segments = self.console.export_segments()
|
segments = self.console.export_segments()
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
A DOMNode is a base class for any object within the Textual Document Object Model,
|
A DOMNode is a base class for any object within the Textual Document Object Model,
|
||||||
which includes all Widgets, Screens, and Apps.
|
which includes all Widgets, Screens, and Apps.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +72,6 @@ def check_identifiers(description: str, *names: str) -> None:
|
|||||||
Args:
|
Args:
|
||||||
description: Description of where identifier is used for error message.
|
description: Description of where identifier is used for error message.
|
||||||
*names: Identifiers to check.
|
*names: Identifiers to check.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
match = _re_identifier.match
|
match = _re_identifier.match
|
||||||
for name in names:
|
for name in names:
|
||||||
@@ -203,7 +200,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The node's children.
|
The node's children.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._nodes
|
return self._nodes
|
||||||
|
|
||||||
@@ -328,7 +324,6 @@ class DOMNode(MessagePump):
|
|||||||
"""Called after styles are updated.
|
"""Called after styles are updated.
|
||||||
|
|
||||||
Implement this in a subclass if you want to clear any cached data when the CSS is reloaded.
|
Implement this in a subclass if you want to clear any cached data when the CSS is reloaded.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -450,7 +445,6 @@ class DOMNode(MessagePump):
|
|||||||
"""The parent node.
|
"""The parent node.
|
||||||
|
|
||||||
All nodes have parent once added to the DOM, with the exception of the App which is the *root* node.
|
All nodes have parent once added to the DOM, with the exception of the App which is the *root* node.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return cast("DOMNode | None", self._parent)
|
return cast("DOMNode | None", self._parent)
|
||||||
|
|
||||||
@@ -463,7 +457,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
NoScreen: If this node isn't mounted (and has no screen).
|
NoScreen: If this node isn't mounted (and has no screen).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Get the node by looking up a chain of parents
|
# Get the node by looking up a chain of parents
|
||||||
# Note that self.screen may not be the same as self.app.screen
|
# Note that self.screen may not be the same as self.app.screen
|
||||||
@@ -490,7 +483,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If the ID has already been set.
|
ValueError: If the ID has already been set.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
check_identifiers("id", new_id)
|
check_identifiers("id", new_id)
|
||||||
|
|
||||||
@@ -520,7 +512,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Rich Text object.
|
A Rich Text object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
tokens = Text.styled(self.__class__.__name__)
|
tokens = Text.styled(self.__class__.__name__)
|
||||||
if self.id is not None:
|
if self.id is not None:
|
||||||
@@ -584,7 +575,6 @@ class DOMNode(MessagePump):
|
|||||||
```python
|
```python
|
||||||
my_widget.display = False # Hide my_widget
|
my_widget.display = False # Hide my_widget
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.styles.display != "none" and not (self._closing or self._closed)
|
return self.styles.display != "none" and not (self._closing or self._closed)
|
||||||
|
|
||||||
@@ -616,7 +606,6 @@ class DOMNode(MessagePump):
|
|||||||
May be set to a boolean to make the node visible (`True`) or invisible (`False`), or to any valid value for the `visibility` rule.
|
May be set to a boolean to make the node visible (`True`) or invisible (`False`), or to any valid value for the `visibility` rule.
|
||||||
|
|
||||||
When a node is invisible, Textual will reserve space for it, but won't display anything there.
|
When a node is invisible, Textual will reserve space for it, but won't display anything there.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.styles.visibility != "hidden"
|
return self.styles.visibility != "hidden"
|
||||||
|
|
||||||
@@ -645,7 +634,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Tree renderable.
|
A Tree renderable.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def render_info(node: DOMNode) -> Pretty:
|
def render_info(node: DOMNode) -> Pretty:
|
||||||
@@ -745,7 +733,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Rich style.
|
A Rich style.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
background = Color(0, 0, 0, 0)
|
background = Color(0, 0, 0, 0)
|
||||||
color = Color(255, 255, 255, 0)
|
color = Color(255, 255, 255, 0)
|
||||||
@@ -775,7 +762,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Rich style.
|
A Rich style.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
styles = self.styles
|
styles = self.styles
|
||||||
if styles.auto_border_title_color:
|
if styles.auto_border_title_color:
|
||||||
@@ -798,7 +784,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Rich style.
|
A Rich style.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
styles = self.styles
|
styles = self.styles
|
||||||
if styles.auto_border_subtitle_color:
|
if styles.auto_border_subtitle_color:
|
||||||
@@ -817,7 +802,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
`(<background color>, <color>)`
|
`(<background color>, <color>)`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
base_background = background = BLACK
|
base_background = background = BLACK
|
||||||
for node in reversed(self.ancestors_with_self):
|
for node in reversed(self.ancestors_with_self):
|
||||||
@@ -832,7 +816,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
`(<parent background>, <parent color>, <background>, <color>)`
|
`(<parent background>, <parent color>, <background>, <color>)`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
base_background = background = WHITE
|
base_background = background = WHITE
|
||||||
base_color = color = BLACK
|
base_color = color = BLACK
|
||||||
@@ -873,7 +856,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A list of nodes.
|
A list of nodes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.ancestors_with_self[1:]
|
return self.ancestors_with_self[1:]
|
||||||
|
|
||||||
@@ -883,7 +865,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A list of nodes.
|
A list of nodes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return [child for child in self._nodes if child.display]
|
return [child for child in self._nodes if child.display]
|
||||||
|
|
||||||
@@ -995,7 +976,6 @@ class DOMNode(MessagePump):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A list of nodes.
|
A list of nodes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
check_type = filter_type or DOMNode
|
check_type = filter_type or DOMNode
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ Verbose events are excluded from the textual console, unless you explicit reques
|
|||||||
```
|
```
|
||||||
textual console -v
|
textual console -v
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -50,15 +49,6 @@ class Callback(Event, bubble=False, verbose=True):
|
|||||||
yield "callback", self.callback
|
yield "callback", self.callback
|
||||||
|
|
||||||
|
|
||||||
class InvokeCallbacks(Event, bubble=False, verbose=True):
|
|
||||||
"""An internal event, sent to the screen to run callbacks.
|
|
||||||
|
|
||||||
- [ ] Bubbles
|
|
||||||
- [X] Verbose
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class ShutdownRequest(Event):
|
class ShutdownRequest(Event):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -76,7 +66,6 @@ class Load(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -88,7 +77,6 @@ class Idle(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -113,7 +101,6 @@ class Resize(Event, bubble=False):
|
|||||||
size: The new size of the Widget.
|
size: The new size of the Widget.
|
||||||
virtual_size: The virtual size (scrollable size) of the Widget.
|
virtual_size: The virtual size (scrollable size) of the Widget.
|
||||||
container_size: The size of the Widget's container widget.
|
container_size: The size of the Widget's container widget.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ["size", "virtual_size", "container_size"]
|
__slots__ = ["size", "virtual_size", "container_size"]
|
||||||
@@ -143,7 +130,6 @@ class Compose(Event, bubble=False, verbose=True):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +138,6 @@ class Mount(Event, bubble=False, verbose=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -161,7 +146,6 @@ class Unmount(Mount, bubble=False, verbose=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -170,7 +154,6 @@ class Show(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +165,6 @@ class Hide(Event, bubble=False):
|
|||||||
|
|
||||||
A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout,
|
A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout,
|
||||||
or if it has been offset beyond the edges of the terminal.
|
or if it has been offset beyond the edges of the terminal.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -191,7 +173,6 @@ class Ready(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -206,7 +187,6 @@ class MouseCapture(Event, bubble=False):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
mouse_position: The position of the mouse when captured.
|
mouse_position: The position of the mouse when captured.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, mouse_position: Offset) -> None:
|
def __init__(self, mouse_position: Offset) -> None:
|
||||||
@@ -318,7 +298,6 @@ class MouseEvent(InputEvent, bubble=True):
|
|||||||
screen_x: The absolute x coordinate.
|
screen_x: The absolute x coordinate.
|
||||||
screen_y: The absolute y coordinate.
|
screen_y: The absolute y coordinate.
|
||||||
style: The Rich Style under the mouse cursor.
|
style: The Rich Style under the mouse cursor.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = [
|
__slots__ = [
|
||||||
@@ -399,7 +378,6 @@ class MouseEvent(InputEvent, bubble=True):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Mouse coordinate.
|
Mouse coordinate.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Offset(self.x, self.y)
|
return Offset(self.x, self.y)
|
||||||
|
|
||||||
@@ -418,7 +396,6 @@ class MouseEvent(InputEvent, bubble=True):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Mouse coordinate.
|
Mouse coordinate.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Offset(self.delta_x, self.delta_y)
|
return Offset(self.delta_x, self.delta_y)
|
||||||
|
|
||||||
@@ -466,7 +443,6 @@ class MouseMove(MouseEvent, bubble=False, verbose=True):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -476,7 +452,6 @@ class MouseDown(MouseEvent, bubble=True, verbose=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -486,7 +461,6 @@ class MouseUp(MouseEvent, bubble=True, verbose=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -496,7 +470,6 @@ class MouseScrollDown(MouseEvent, bubble=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -506,7 +479,6 @@ class MouseScrollUp(MouseEvent, bubble=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -515,7 +487,6 @@ class Click(MouseEvent, bubble=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -525,8 +496,6 @@ class Timer(Event, bubble=False, verbose=True):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ["time", "count", "callback"]
|
__slots__ = ["time", "count", "callback"]
|
||||||
@@ -554,7 +523,6 @@ class Enter(Event, bubble=False, verbose=True):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -563,7 +531,6 @@ class Leave(Event, bubble=False, verbose=True):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -572,7 +539,6 @@ class Focus(Event, bubble=False):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -581,7 +547,6 @@ class Blur(Event, bubble=False):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -590,7 +555,6 @@ class DescendantFocus(Event, bubble=True, verbose=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -599,7 +563,6 @@ class DescendantBlur(Event, bubble=True, verbose=True):
|
|||||||
|
|
||||||
- [X] Bubbles
|
- [X] Bubbles
|
||||||
- [X] Verbose
|
- [X] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -631,7 +594,6 @@ class ScreenResume(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -640,5 +602,4 @@ class ScreenSuspend(Event, bubble=False):
|
|||||||
|
|
||||||
- [ ] Bubbles
|
- [ ] Bubbles
|
||||||
- [ ] Verbose
|
- [ ] Verbose
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
Functions and classes to manage terminal geometry (anything involving coordinates or dimensions).
|
Functions and classes to manage terminal geometry (anything involving coordinates or dimensions).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -75,7 +74,6 @@ class Offset(NamedTuple):
|
|||||||
>>> -offset
|
>>> -offset
|
||||||
Offset(x=-13, y=-2)
|
Offset(x=-13, y=-2)
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
x: int = 0
|
x: int = 0
|
||||||
@@ -167,7 +165,6 @@ class Size(NamedTuple):
|
|||||||
>>> size + Size(10, 20)
|
>>> size + Size(10, 20)
|
||||||
Size(width=12, height=23)
|
Size(width=12, height=23)
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
width: int = 0
|
width: int = 0
|
||||||
@@ -283,7 +280,6 @@ class Region(NamedTuple):
|
|||||||
>>> region.contains(10, 8)
|
>>> region.contains(10, 8)
|
||||||
True
|
True
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
x: int = 0
|
x: int = 0
|
||||||
@@ -407,7 +403,6 @@ class Region(NamedTuple):
|
|||||||
"""A pair of integers for the start and end columns (x coordinates) in this region.
|
"""A pair of integers for the start and end columns (x coordinates) in this region.
|
||||||
|
|
||||||
The end value is *exclusive*.
|
The end value is *exclusive*.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return (self.x, self.x + self.width)
|
return (self.x, self.x + self.width)
|
||||||
|
|
||||||
@@ -416,7 +411,6 @@ class Region(NamedTuple):
|
|||||||
"""A pair of integers for the start and end lines (y coordinates) in this region.
|
"""A pair of integers for the start and end lines (y coordinates) in this region.
|
||||||
|
|
||||||
The end value is *exclusive*.
|
The end value is *exclusive*.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return (self.y, self.y + self.height)
|
return (self.y, self.y + self.height)
|
||||||
|
|
||||||
@@ -441,7 +435,6 @@ class Region(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An offset.
|
An offset.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Offset(*self[:2])
|
return Offset(*self[:2])
|
||||||
|
|
||||||
@@ -461,7 +454,6 @@ class Region(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An offset.
|
An offset.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
x, y, width, _height = self
|
x, y, width, _height = self
|
||||||
return Offset(x + width, y)
|
return Offset(x + width, y)
|
||||||
@@ -472,7 +464,6 @@ class Region(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An offset.
|
An offset.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
x, y, width, height = self
|
x, y, width, height = self
|
||||||
return Offset(x + width, y + height)
|
return Offset(x + width, y + height)
|
||||||
@@ -504,7 +495,6 @@ class Region(NamedTuple):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A region at the origin.
|
A region at the origin.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_, _, width, height = self
|
_, _, width, height = self
|
||||||
return Region(0, 0, width, height)
|
return Region(0, 0, width, height)
|
||||||
@@ -894,7 +884,6 @@ class Spacing(NamedTuple):
|
|||||||
>>> spacing.css
|
>>> spacing.css
|
||||||
'1 2 3 4'
|
'1 2 3 4'
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
top: int = 0
|
top: int = 0
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ class GridLayout(Layout):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
column_count: Number of columns
|
column_count: Number of columns
|
||||||
|
|
||||||
"""
|
"""
|
||||||
row = 0
|
row = 0
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ A Textual Logging handler.
|
|||||||
If there is an active Textual app, then log messages will go via the app (and logged via textual console).
|
If there is an active Textual app, then log messages will go via the app (and logged via textual console).
|
||||||
|
|
||||||
If there is *no* active app, then log messages will go to stderr or stdout, depending on configuration.
|
If there is *no* active app, then log messages will go to stderr or stdout, depending on configuration.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
The base class for all messages (including events).
|
The base class for all messages (including events).
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
A message pump is a base class for any object which processes messages, which includes Widget, Screen, and App.
|
A message pump is a base class for any object which processes messages, which includes Widget, Screen, and App.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -47,7 +46,6 @@ class MessagePumpClosed(Exception):
|
|||||||
class _MessagePumpMeta(type):
|
class _MessagePumpMeta(type):
|
||||||
"""Metaclass for message pump. This exists to populate a Message inner class of a Widget with the
|
"""Metaclass for message pump. This exists to populate a Message inner class of a Widget with the
|
||||||
parent classes' name.
|
parent classes' name.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(
|
def __new__(
|
||||||
@@ -122,7 +120,6 @@ class MessagePump(metaclass=_MessagePumpMeta):
|
|||||||
with self.prevent(Input.Changed):
|
with self.prevent(Input.Changed):
|
||||||
input.value = "foo"
|
input.value = "foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if message_types:
|
if message_types:
|
||||||
prevent_stack = self._prevent_message_types_stack
|
prevent_stack = self._prevent_message_types_stack
|
||||||
@@ -374,6 +371,7 @@ class MessagePump(metaclass=_MessagePumpMeta):
|
|||||||
**kwargs: Keyword arguments to pass to the callable.
|
**kwargs: Keyword arguments to pass to the callable.
|
||||||
"""
|
"""
|
||||||
self._next_callbacks.append(partial(callback, *args, **kwargs))
|
self._next_callbacks.append(partial(callback, *args, **kwargs))
|
||||||
|
self.check_idle()
|
||||||
|
|
||||||
def _on_invoke_later(self, message: messages.InvokeLater) -> None:
|
def _on_invoke_later(self, message: messages.InvokeLater) -> None:
|
||||||
# Forward InvokeLater message to the Screen
|
# Forward InvokeLater message to the Screen
|
||||||
@@ -506,6 +504,7 @@ class MessagePump(metaclass=_MessagePumpMeta):
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
self.app._handle_exception(error)
|
self.app._handle_exception(error)
|
||||||
break
|
break
|
||||||
|
await self._flush_next_callbacks()
|
||||||
|
|
||||||
async def _flush_next_callbacks(self) -> None:
|
async def _flush_next_callbacks(self) -> None:
|
||||||
"""Invoke pending callbacks in next callbacks queue."""
|
"""Invoke pending callbacks in next callbacks queue."""
|
||||||
@@ -545,7 +544,6 @@ class MessagePump(metaclass=_MessagePumpMeta):
|
|||||||
Args:
|
Args:
|
||||||
method_name: Handler method name.
|
method_name: Handler method name.
|
||||||
message: Message object.
|
message: Message object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
private_method = f"_{method_name}"
|
private_method = f"_{method_name}"
|
||||||
for cls in self.__class__.__mro__:
|
for cls in self.__class__.__mro__:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
The pilot object is used by [App.run_test][textual.app.App.run_test] to programmatically operate an app.
|
The pilot object is used by [App.run_test][textual.app.App.run_test] to programmatically operate an app.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -63,7 +62,6 @@ class Pilot(Generic[ReturnType]):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keys: Keys to press.
|
*keys: Keys to press.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if keys:
|
if keys:
|
||||||
await self._app._press_keys(keys)
|
await self._app._press_keys(keys)
|
||||||
@@ -100,11 +98,11 @@ class Pilot(Generic[ReturnType]):
|
|||||||
target_widget, offset, button=1, shift=shift, meta=meta, control=control
|
target_widget, offset, button=1, shift=shift, meta=meta, control=control
|
||||||
)
|
)
|
||||||
app.post_message(MouseDown(**message_arguments))
|
app.post_message(MouseDown(**message_arguments))
|
||||||
await self.pause()
|
await self.pause(0.1)
|
||||||
app.post_message(MouseUp(**message_arguments))
|
app.post_message(MouseUp(**message_arguments))
|
||||||
await self.pause()
|
await self.pause(0.1)
|
||||||
app.post_message(Click(**message_arguments))
|
app.post_message(Click(**message_arguments))
|
||||||
await self.pause()
|
await self.pause(0.1)
|
||||||
|
|
||||||
async def hover(
|
async def hover(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
The `Reactive` class implements [reactivity](/guide/reactivity/).
|
The `Reactive` class implements [reactivity](/guide/reactivity/).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -227,7 +226,6 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
watch_function: A watch function, which may be sync or async.
|
watch_function: A watch function, which may be sync or async.
|
||||||
old_value: The old value of the attribute.
|
old_value: The old value of the attribute.
|
||||||
value: The new value of the attribute.
|
value: The new value of the attribute.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_rich_traceback_omit = True
|
_rich_traceback_omit = True
|
||||||
param_count = count_parameters(watch_function)
|
param_count = count_parameters(watch_function)
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class TextOpacity:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Segments with applied opacity.
|
Segments with applied opacity.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_Segment = Segment
|
_Segment = Segment
|
||||||
_from_color = Style.from_color
|
_from_color = Style.from_color
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ class Tint:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Segments with applied tint.
|
Segments with applied tint.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from_rich_color = Color.from_rich_color
|
from_rich_color = Color.from_rich_color
|
||||||
style_from_color = Style.from_color
|
style_from_color = Style.from_color
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
The `Screen` class is a special widget which represents the content in the terminal. See [Screens](/guide/screens/) for details.
|
The `Screen` class is a special widget which represents the content in the terminal. See [Screens](/guide/screens/) for details.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -444,15 +443,12 @@ class Screen(Generic[ScreenResultType], Widget):
|
|||||||
or self._dirty_widgets
|
or self._dirty_widgets
|
||||||
):
|
):
|
||||||
self._update_timer.resume()
|
self._update_timer.resume()
|
||||||
|
return
|
||||||
|
|
||||||
# The Screen is idle - a good opportunity to invoke the scheduled callbacks
|
await self._invoke_and_clear_callbacks()
|
||||||
|
|
||||||
if self._callbacks:
|
|
||||||
self._on_timer_update()
|
|
||||||
|
|
||||||
def _on_timer_update(self) -> None:
|
def _on_timer_update(self) -> None:
|
||||||
"""Called by the _update_timer."""
|
"""Called by the _update_timer."""
|
||||||
|
|
||||||
self._update_timer.pause()
|
self._update_timer.pause()
|
||||||
if self.is_current:
|
if self.is_current:
|
||||||
if self._layout_required:
|
if self._layout_required:
|
||||||
@@ -465,12 +461,11 @@ class Screen(Generic[ScreenResultType], Widget):
|
|||||||
self._scroll_required = False
|
self._scroll_required = False
|
||||||
|
|
||||||
if self._repaint_required:
|
if self._repaint_required:
|
||||||
self._update_timer.resume()
|
|
||||||
self._dirty_widgets.clear()
|
self._dirty_widgets.clear()
|
||||||
self._dirty_widgets.add(self)
|
self._dirty_widgets.add(self)
|
||||||
self._repaint_required = False
|
self._repaint_required = False
|
||||||
|
|
||||||
if self._dirty_widgets and self.is_current:
|
if self._dirty_widgets:
|
||||||
self._compositor.update_widgets(self._dirty_widgets)
|
self._compositor.update_widgets(self._dirty_widgets)
|
||||||
update = self._compositor.render_update(
|
update = self._compositor.render_update(
|
||||||
screen_stack=self.app._background_screens
|
screen_stack=self.app._background_screens
|
||||||
@@ -479,20 +474,12 @@ class Screen(Generic[ScreenResultType], Widget):
|
|||||||
self._dirty_widgets.clear()
|
self._dirty_widgets.clear()
|
||||||
|
|
||||||
if self._callbacks:
|
if self._callbacks:
|
||||||
self.post_message(events.InvokeCallbacks())
|
self.call_next(self._invoke_and_clear_callbacks)
|
||||||
|
|
||||||
async def _on_invoke_callbacks(self, event: events.InvokeCallbacks) -> None:
|
|
||||||
"""Handle PostScreenUpdate events, which are sent after the screen is updated"""
|
|
||||||
await self._invoke_and_clear_callbacks()
|
|
||||||
|
|
||||||
async def _invoke_and_clear_callbacks(self) -> None:
|
async def _invoke_and_clear_callbacks(self) -> None:
|
||||||
"""If there are scheduled callbacks to run, call them and clear
|
"""If there are scheduled callbacks to run, call them and clear
|
||||||
the callback queue."""
|
the callback queue."""
|
||||||
if self._callbacks:
|
if self._callbacks:
|
||||||
display_update = self._compositor.render_update(
|
|
||||||
screen_stack=self.app._background_screens
|
|
||||||
)
|
|
||||||
self.app._display(self, display_update)
|
|
||||||
callbacks = self._callbacks[:]
|
callbacks = self._callbacks[:]
|
||||||
self._callbacks.clear()
|
self._callbacks.clear()
|
||||||
for callback in callbacks:
|
for callback in callbacks:
|
||||||
@@ -757,8 +744,6 @@ class ModalScreen(Screen[ScreenResultType]):
|
|||||||
"""A screen with bindings that take precedence over the App's key bindings.
|
"""A screen with bindings that take precedence over the App's key bindings.
|
||||||
|
|
||||||
The default styling of a modal screen will dim the screen underneath.
|
The default styling of a modal screen will dim the screen underneath.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_CSS = """
|
DEFAULT_CSS = """
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
`ScrollView` is a base class for [line api](/guide/widgets#line-api) widgets.
|
`ScrollView` is a base class for [line api](/guide/widgets#line-api) widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from rich.console import RenderableType
|
from rich.console import RenderableType
|
||||||
|
|
||||||
|
from ._animator import EasingFunction
|
||||||
from .containers import ScrollableContainer
|
from .containers import ScrollableContainer
|
||||||
from .geometry import Size
|
from .geometry import Size
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ class ScrollView(ScrollableContainer):
|
|||||||
"""
|
"""
|
||||||
A base class for a Widget that handles its own scrolling (i.e. doesn't rely
|
A base class for a Widget that handles its own scrolling (i.e. doesn't rely
|
||||||
on the compositor to render children).
|
on the compositor to render children).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_CSS = """
|
DEFAULT_CSS = """
|
||||||
@@ -111,3 +110,37 @@ class ScrollView(ScrollableContainer):
|
|||||||
from rich.panel import Panel
|
from rich.panel import Panel
|
||||||
|
|
||||||
return Panel(f"{self.scroll_offset} {self.show_vertical_scrollbar}")
|
return Panel(f"{self.scroll_offset} {self.show_vertical_scrollbar}")
|
||||||
|
|
||||||
|
# Custom scroll to which doesn't require call_after_refresh
|
||||||
|
def scroll_to(
|
||||||
|
self,
|
||||||
|
x: float | None = None,
|
||||||
|
y: float | None = None,
|
||||||
|
*,
|
||||||
|
animate: bool = True,
|
||||||
|
speed: float | None = None,
|
||||||
|
duration: float | None = None,
|
||||||
|
easing: EasingFunction | str | None = None,
|
||||||
|
force: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""Scroll to a given (absolute) coordinate, optionally animating.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x: X coordinate (column) to scroll to, or `None` for no change.
|
||||||
|
y: Y coordinate (row) to scroll to, or `None` for no change.
|
||||||
|
animate: Animate to new scroll position.
|
||||||
|
speed: Speed of scroll if `animate` is `True`; or `None` to use `duration`.
|
||||||
|
duration: Duration of animation, if `animate` is `True` and `speed` is `None`.
|
||||||
|
easing: An easing method for the scrolling animation.
|
||||||
|
force: Force scrolling even when prohibited by overflow styling.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._scroll_to(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
animate=animate,
|
||||||
|
speed=speed,
|
||||||
|
duration=duration,
|
||||||
|
easing=easing,
|
||||||
|
force=force,
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
Timer objects are created by [set_interval][textual.message_pump.MessagePump.set_interval] or
|
Timer objects are created by [set_interval][textual.message_pump.MessagePump.set_interval] or
|
||||||
[set_timer][textual.message_pump.MessagePump.set_timer].
|
[set_timer][textual.message_pump.MessagePump.set_timer].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -95,7 +94,6 @@ class Timer:
|
|||||||
"""Pause the timer.
|
"""Pause the timer.
|
||||||
|
|
||||||
A paused timer will not send events until it is resumed.
|
A paused timer will not send events until it is resumed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._active.clear()
|
self._active.clear()
|
||||||
|
|
||||||
@@ -131,20 +129,18 @@ class Timer:
|
|||||||
continue
|
continue
|
||||||
now = _time.get_time()
|
now = _time.get_time()
|
||||||
wait_time = max(0, next_timer - now)
|
wait_time = max(0, next_timer - now)
|
||||||
if wait_time > 1 / 1000:
|
await sleep(wait_time)
|
||||||
await sleep(wait_time)
|
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
|
try:
|
||||||
|
await self._tick(next_timer=next_timer, count=count)
|
||||||
|
except EventTargetGone:
|
||||||
|
break
|
||||||
await self._active.wait()
|
await self._active.wait()
|
||||||
if self._reset:
|
if self._reset:
|
||||||
start = _time.get_time()
|
start = _time.get_time()
|
||||||
count = 0
|
count = 0
|
||||||
self._reset = False
|
self._reset = False
|
||||||
continue
|
continue
|
||||||
try:
|
|
||||||
await self._tick(next_timer=next_timer, count=count)
|
|
||||||
except EventTargetGone:
|
|
||||||
break
|
|
||||||
|
|
||||||
async def _tick(self, *, next_timer: float, count: int) -> None:
|
async def _tick(self, *, next_timer: float, count: int) -> None:
|
||||||
"""Triggers the Timer's action: either call its callback, or sends an event to its target"""
|
"""Triggers the Timer's action: either call its callback, or sends an event to its target"""
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ Functions for *walking* the DOM.
|
|||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
For most purposes you would be better off using [query][textual.dom.DOMNode.query], which uses these functions internally.
|
For most purposes you would be better off using [query][textual.dom.DOMNode.query], which uses these functions internally.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -57,7 +56,6 @@ def walk_depth_first(
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An iterable of DOMNodes, or the type specified in ``filter_type``.
|
An iterable of DOMNodes, or the type specified in ``filter_type``.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from textual.dom import DOMNode
|
from textual.dom import DOMNode
|
||||||
|
|
||||||
@@ -118,7 +116,6 @@ def walk_breadth_first(
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An iterable of DOMNodes, or the type specified in ``filter_type``.
|
An iterable of DOMNodes, or the type specified in ``filter_type``.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from textual.dom import DOMNode
|
from textual.dom import DOMNode
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
The base class for widgets.
|
The base class for widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -94,7 +93,6 @@ class AwaitMount:
|
|||||||
```python
|
```python
|
||||||
await self.mount(Static("foo"))
|
await self.mount(Static("foo"))
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent: Widget, widgets: Sequence[Widget]) -> None:
|
def __init__(self, parent: Widget, widgets: Sequence[Widget]) -> None:
|
||||||
@@ -233,7 +231,6 @@ class Widget(DOMNode):
|
|||||||
A Widget is the base class for Textual widgets.
|
A Widget is the base class for Textual widgets.
|
||||||
|
|
||||||
See also [static][textual.widgets._static.Static] for starting point for your own widgets.
|
See also [static][textual.widgets._static.Static] for starting point for your own widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_CSS = """
|
DEFAULT_CSS = """
|
||||||
@@ -409,7 +406,6 @@ class Widget(DOMNode):
|
|||||||
"""Check if vertical scroll is permitted.
|
"""Check if vertical scroll is permitted.
|
||||||
|
|
||||||
May be overridden if you want different logic regarding allowing scrolling.
|
May be overridden if you want different logic regarding allowing scrolling.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.is_scrollable and self.show_vertical_scrollbar
|
return self.is_scrollable and self.show_vertical_scrollbar
|
||||||
|
|
||||||
@@ -418,7 +414,6 @@ class Widget(DOMNode):
|
|||||||
"""Check if horizontal scroll is permitted.
|
"""Check if horizontal scroll is permitted.
|
||||||
|
|
||||||
May be overridden if you want different logic regarding allowing scrolling.
|
May be overridden if you want different logic regarding allowing scrolling.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.is_scrollable and self.show_horizontal_scrollbar
|
return self.is_scrollable and self.show_horizontal_scrollbar
|
||||||
|
|
||||||
@@ -635,7 +630,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
An iterable of Widgets.
|
An iterable of Widgets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._horizontal_scrollbar is not None:
|
if self._horizontal_scrollbar is not None:
|
||||||
yield self._horizontal_scrollbar
|
yield self._horizontal_scrollbar
|
||||||
@@ -874,7 +868,6 @@ class Widget(DOMNode):
|
|||||||
)
|
)
|
||||||
yield Footer()
|
yield Footer()
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
yield from ()
|
yield from ()
|
||||||
|
|
||||||
@@ -1134,7 +1127,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ScrollBarCorner Widget.
|
ScrollBarCorner Widget.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from .scrollbar import ScrollBarCorner
|
from .scrollbar import ScrollBarCorner
|
||||||
|
|
||||||
@@ -1248,7 +1240,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A tuple of (<vertical scrollbar enabled>, <horizontal scrollbar enabled>)
|
A tuple of (<vertical scrollbar enabled>, <horizontal scrollbar enabled>)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self.is_scrollable:
|
if not self.is_scrollable:
|
||||||
return False, False
|
return False, False
|
||||||
@@ -1300,7 +1291,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Additional spacing around content area.
|
Additional spacing around content area.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.styles.gutter + self.scrollbar_gutter
|
return self.styles.gutter + self.scrollbar_gutter
|
||||||
|
|
||||||
@@ -1359,7 +1349,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Offset from widget's origin.
|
Offset from widget's origin.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
x, y = self.gutter.top_left
|
x, y = self.gutter.top_left
|
||||||
return Offset(x, y)
|
return Offset(x, y)
|
||||||
@@ -1370,7 +1359,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Content area size.
|
Content area size.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.region.shrink(self.styles.gutter).size
|
return self.region.shrink(self.styles.gutter).size
|
||||||
|
|
||||||
@@ -1412,7 +1400,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The virtual region.
|
The virtual region.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self.screen.find_widget(self).virtual_region
|
return self.screen.find_widget(self).virtual_region
|
||||||
@@ -1461,7 +1448,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of widgets that can receive focus.
|
List of widgets that can receive focus.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
focusable = [child for child in self._nodes if child.display and child.visible]
|
focusable = [child for child in self._nodes if child.display and child.visible]
|
||||||
return sorted(focusable, key=attrgetter("_focus_sort_key"))
|
return sorted(focusable, key=attrgetter("_focus_sort_key"))
|
||||||
@@ -1493,7 +1479,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A Rich console object.
|
A Rich console object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return active_app.get().console
|
return active_app.get().console
|
||||||
|
|
||||||
@@ -1534,7 +1519,6 @@ class Widget(DOMNode):
|
|||||||
delay: A delay (in seconds) before the animation starts.
|
delay: A delay (in seconds) before the animation starts.
|
||||||
easing: An easing method.
|
easing: An easing method.
|
||||||
on_complete: A callable to invoke when the animation is finished.
|
on_complete: A callable to invoke when the animation is finished.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self._animate is None:
|
if self._animate is None:
|
||||||
self._animate = self.app.animator.bind(self)
|
self._animate = self.app.animator.bind(self)
|
||||||
@@ -1556,7 +1540,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A layout object.
|
A layout object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.styles.layout or self._default_layout
|
return self.styles.layout or self._default_layout
|
||||||
|
|
||||||
@@ -1576,7 +1559,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Name of layer.
|
Name of layer.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.styles.layer or "default"
|
return self.styles.layer or "default"
|
||||||
|
|
||||||
@@ -1600,7 +1582,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Rich style.
|
Rich style.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
styles = self.styles
|
styles = self.styles
|
||||||
_, background = self.background_colors
|
_, background = self.background_colors
|
||||||
@@ -1622,7 +1603,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Rich Style.
|
Rich Style.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
styles = self.styles
|
styles = self.styles
|
||||||
_, background = self.background_colors
|
_, background = self.background_colors
|
||||||
@@ -1646,7 +1626,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*regions: Regions which require a repaint.
|
*regions: Regions which require a repaint.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if regions:
|
if regions:
|
||||||
content_offset = self.content_offset
|
content_offset = self.content_offset
|
||||||
@@ -2559,7 +2538,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuples of scrollbar Widget and region.
|
Tuples of scrollbar Widget and region.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
show_vertical_scrollbar, show_horizontal_scrollbar = self.scrollbars_enabled
|
show_vertical_scrollbar, show_horizontal_scrollbar = self.scrollbars_enabled
|
||||||
|
|
||||||
@@ -2613,7 +2591,6 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Names of the pseudo classes.
|
Names of the pseudo classes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
node: MessagePump | None = self
|
node: MessagePump | None = self
|
||||||
while isinstance(node, Widget):
|
while isinstance(node, Widget):
|
||||||
|
|||||||
@@ -143,7 +143,6 @@ class Button(Static, can_focus=True):
|
|||||||
border-bottom: tall $error-lighten-2;
|
border-bottom: tall $error-lighten-2;
|
||||||
border-top: tall $error-darken-2;
|
border-top: tall $error-darken-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BINDINGS = [Binding("enter", "press", "Press Button", show=False)]
|
BINDINGS = [Binding("enter", "press", "Press Button", show=False)]
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ class MarkdownH1(MarkdownHeader):
|
|||||||
text-style: bold;
|
text-style: bold;
|
||||||
color: $text;
|
color: $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -148,7 +147,6 @@ class MarkdownH2(MarkdownHeader):
|
|||||||
padding: 1;
|
padding: 1;
|
||||||
text-style: bold;
|
text-style: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -378,7 +376,6 @@ class MarkdownTable(MarkdownBlock):
|
|||||||
background: $panel;
|
background: $panel;
|
||||||
border: wide $background;
|
border: wide $background;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
@@ -830,7 +827,6 @@ class MarkdownViewer(VerticalScroll, can_focus=True, can_focus_children=True):
|
|||||||
MarkdownViewer.-show-table-of-contents > MarkdownTableOfContents {
|
MarkdownViewer.-show-table-of-contents > MarkdownTableOfContents {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
show_table_of_contents = reactive(True)
|
show_table_of_contents = reactive(True)
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ class Placeholder(Widget):
|
|||||||
Placeholder.-text {
|
Placeholder.-text {
|
||||||
padding: 1;
|
padding: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Consecutive placeholders get assigned consecutive colors.
|
# Consecutive placeholders get assigned consecutive colors.
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class TabPane(Widget):
|
|||||||
"""A container for switchable content, with additional title.
|
"""A container for switchable content, with additional title.
|
||||||
|
|
||||||
This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent].
|
This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent].
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_CSS = """
|
DEFAULT_CSS = """
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ class Underline(Widget):
|
|||||||
| Class | Description |
|
| Class | Description |
|
||||||
| :- | :- |
|
| :- | :- |
|
||||||
| `underline-bar` | Style of the bar (may be used to change the color). |
|
| `underline-bar` | Style of the bar (may be used to change the color). |
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
highlight_start = reactive(0)
|
highlight_start = reactive(0)
|
||||||
|
|||||||
@@ -418,7 +418,6 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
Tree > .tree--highlight-line {
|
Tree > .tree--highlight-line {
|
||||||
background: $boost;
|
background: $boost;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
show_root = reactive(True)
|
show_root = reactive(True)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ I will face my fear.
|
|||||||
I will permit it to pass over me and through me.
|
I will permit it to pass over me and through me.
|
||||||
And when it has gone past, I will turn the inner eye to see its path.
|
And when it has gone past, I will turn the inner eye to see its path.
|
||||||
Where the fear has gone there will be nothing. Only I will remain."
|
Where the fear has gone there will be nothing. Only I will remain."
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
A class to manage concurrent [work](/guide/workers).
|
A class to manage concurrent [work](/guide/workers).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -204,7 +203,6 @@ class Worker(Generic[ResultType]):
|
|||||||
"""Has the work been cancelled?
|
"""Has the work been cancelled?
|
||||||
|
|
||||||
Note that cancelled work may still be running.
|
Note that cancelled work may still be running.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._cancelled
|
return self._cancelled
|
||||||
|
|
||||||
@@ -237,7 +235,6 @@ class Worker(Generic[ResultType]):
|
|||||||
"""Progress as a percentage.
|
"""Progress as a percentage.
|
||||||
|
|
||||||
If the total steps is None, then this will return 0. The percentage will be clamped between 0 and 100.
|
If the total steps is None, then this will return 0. The percentage will be clamped between 0 and 100.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self._total_steps:
|
if not self._total_steps:
|
||||||
return 0.0
|
return 0.0
|
||||||
@@ -267,7 +264,6 @@ class Worker(Generic[ResultType]):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
steps: Number of steps to advance.
|
steps: Number of steps to advance.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._completed_steps += steps
|
self._completed_steps += steps
|
||||||
|
|
||||||
@@ -278,7 +274,6 @@ class Worker(Generic[ResultType]):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Return value of work.
|
Return value of work.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class ScrollViewTester(App[None]):
|
|||||||
background: $primary-darken-2;
|
background: $primary-darken-2;
|
||||||
border: round red;
|
border: round red;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ class AnimApp(App):
|
|||||||
#foo {
|
#foo {
|
||||||
height: 1;
|
height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
|
|||||||
@@ -39,4 +39,4 @@ async def test_call_after_refresh() -> None:
|
|||||||
app.call_after_refresh(callback)
|
app.call_after_refresh(callback)
|
||||||
await asyncio.wait_for(called_event.wait(), 1)
|
await asyncio.wait_for(called_event.wait(), 1)
|
||||||
app_display_count = app.display_count
|
app_display_count = app.display_count
|
||||||
assert app_display_count > display_count
|
assert app_display_count == display_count
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ re_link_ids = re.compile(r"id=[\d\.\-]*?;.*?\x1b")
|
|||||||
def replace_link_ids(render: str) -> str:
|
def replace_link_ids(render: str) -> str:
|
||||||
"""Link IDs have a random ID and system path which is a problem for
|
"""Link IDs have a random ID and system path which is a problem for
|
||||||
reproducible tests.
|
reproducible tests.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return re_link_ids.sub("id=0;foo\x1b", render)
|
return re_link_ids.sub("id=0;foo\x1b", render)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user