mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'main' into datatable-events
This commit is contained in:
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Added Widget._refresh_scroll to avoid expensive layout when scrolling https://github.com/Textualize/textual/pull/1524
|
||||
- `events.Paste` now bubbles https://github.com/Textualize/textual/issues/1434
|
||||
- Clock color in the `Header` widget now matches the header color https://github.com/Textualize/textual/issues/1459
|
||||
- Programmatic calls to scroll now optionally scroll even if overflow styling says otherwise (introduces a new `force` parameter to all the `scroll_*` methods) https://github.com/Textualize/textual/issues/1201
|
||||
- `COMPONENT_CLASSES` are now inherited from base classes https://github.com/Textualize/textual/issues/1399
|
||||
- Watch methods may now take no parameters
|
||||
- Added `compute` parameter to reactive
|
||||
@@ -36,6 +37,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Behavior of widget `Input` when rendering after programmatic value change and related scenarios https://github.com/Textualize/textual/issues/1477 https://github.com/Textualize/textual/issues/1443
|
||||
- `DataTable.show_cursor` now correctly allows cursor toggling https://github.com/Textualize/textual/pull/1547
|
||||
- Fixed cursor not being visible on `DataTable` mount when `fixed_columns` were used https://github.com/Textualize/textual/pull/1547
|
||||
- Fixed TextLog wrapping issue https://github.com/Textualize/textual/issues/1554
|
||||
- Fixed issue with TextLog not writing anything before layout https://github.com/Textualize/textual/issues/1498
|
||||
|
||||
## [0.9.1] - 2022-12-30
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This directory contains example Textual applications.
|
||||
|
||||
To run them, navigate to the examples directory and enter `python` followed buy the name of the Python file.
|
||||
To run them, navigate to the examples directory and enter `python` followed by the name of the Python file.
|
||||
|
||||
```
|
||||
cd textual/examples
|
||||
|
||||
@@ -240,8 +240,20 @@ class App(Generic[ReturnType], DOMNode):
|
||||
SCREENS: dict[str, Screen | Callable[[], Screen]] = {}
|
||||
_BASE_PATH: str | None = None
|
||||
CSS_PATH: CSSPathType = None
|
||||
|
||||
TITLE: str | None = None
|
||||
"""str | None: The default title for the application.
|
||||
|
||||
If set to a string, this sets the default title for the application. See
|
||||
also the `title` attribute.
|
||||
"""
|
||||
|
||||
SUB_TITLE: str | None = None
|
||||
"""str | None: The default sub-title for the application.
|
||||
|
||||
If set to a string, this sets the default sub-title for the application. See
|
||||
also the `sub_title` attribute.
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
Binding("ctrl+c", "quit", "Quit", show=False, priority=True),
|
||||
@@ -303,10 +315,24 @@ class App(Generic[ReturnType], DOMNode):
|
||||
self._animator = Animator(self)
|
||||
self._animate = self._animator.bind(self)
|
||||
self.mouse_position = Offset(0, 0)
|
||||
|
||||
self.title = (
|
||||
self.TITLE if self.TITLE is not None else f"{self.__class__.__name__}"
|
||||
)
|
||||
"""The title for the application.
|
||||
|
||||
The initial value in a running application will be that set in `TITLE`
|
||||
(if one is set). Assign new values to this instance attribute to change
|
||||
the title.
|
||||
"""
|
||||
|
||||
self.sub_title = self.SUB_TITLE if self.SUB_TITLE is not None else ""
|
||||
"""The sub-title for the application.
|
||||
|
||||
The initial value in a running application will be that set in `SUB_TITLE`
|
||||
(if one is set). Assign new values to this instance attribute to change
|
||||
the sub-title.
|
||||
"""
|
||||
|
||||
self._logger = Logger(self._log)
|
||||
|
||||
|
||||
@@ -28,17 +28,17 @@ class Binding:
|
||||
"""The configuration of a key binding."""
|
||||
|
||||
key: str
|
||||
"""str: Key to bind. This can also be a comma-separated list of keys to map multiple keys to a single action."""
|
||||
"""Key to bind. This can also be a comma-separated list of keys to map multiple keys to a single action."""
|
||||
action: str
|
||||
"""str: Action to bind to."""
|
||||
"""Action to bind to."""
|
||||
description: str
|
||||
"""str: Description of action."""
|
||||
"""Description of action."""
|
||||
show: bool = True
|
||||
"""bool: Show the action in Footer, or False to hide."""
|
||||
"""Show the action in Footer, or False to hide."""
|
||||
key_display: str | None = None
|
||||
"""str | None: How the key should be shown in footer."""
|
||||
"""How the key should be shown in footer."""
|
||||
priority: bool = False
|
||||
"""bool: Enable priority binding for this key."""
|
||||
"""Enable priority binding for this key."""
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
|
||||
@@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
def match(selector_sets: Iterable[SelectorSet], node: DOMNode) -> bool:
|
||||
"""Check if a given selector matches any of the given selector sets.
|
||||
"""Check if a given node matches any of the given selector sets.
|
||||
|
||||
Args:
|
||||
selector_sets (Iterable[SelectorSet]): Iterable of selector sets.
|
||||
|
||||
@@ -57,12 +57,14 @@ class Strip:
|
||||
return cls([Segment(" " * cell_length, style)], cell_length)
|
||||
|
||||
@classmethod
|
||||
def from_lines(cls, lines: list[list[Segment]], cell_length: int) -> list[Strip]:
|
||||
def from_lines(
|
||||
cls, lines: list[list[Segment]], cell_length: int | None = None
|
||||
) -> list[Strip]:
|
||||
"""Convert lines (lists of segments) to a list of Strips.
|
||||
|
||||
Args:
|
||||
lines (list[list[Segment]]): List of lines, where a line is a list of segments.
|
||||
cell_length (int): Cell length of lines (must be same).
|
||||
cell_length (int | None): Cell length of lines (must be same) or None if not known. Defaults to None.
|
||||
|
||||
Returns:
|
||||
list[Strip]: List of strips.
|
||||
|
||||
@@ -803,16 +803,14 @@ class Widget(DOMNode):
|
||||
self.highlight_link_id = hover_style.link_id
|
||||
|
||||
def watch_scroll_x(self, old_value: float, new_value: float) -> None:
|
||||
if self.show_horizontal_scrollbar:
|
||||
self.horizontal_scrollbar.position = round(new_value)
|
||||
if round(old_value) != round(new_value):
|
||||
self._refresh_scroll()
|
||||
self.horizontal_scrollbar.position = round(new_value)
|
||||
if round(old_value) != round(new_value):
|
||||
self._refresh_scroll()
|
||||
|
||||
def watch_scroll_y(self, old_value: float, new_value: float) -> None:
|
||||
if self.show_vertical_scrollbar:
|
||||
self.vertical_scrollbar.position = round(new_value)
|
||||
if round(old_value) != round(new_value):
|
||||
self._refresh_scroll()
|
||||
self.vertical_scrollbar.position = round(new_value)
|
||||
if round(old_value) != round(new_value):
|
||||
self._refresh_scroll()
|
||||
|
||||
def validate_scroll_x(self, value: float) -> float:
|
||||
return clamp(value, 0, self.max_scroll_x)
|
||||
@@ -1340,6 +1338,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll to a given (absolute) coordinate, optionally animating.
|
||||
|
||||
@@ -1351,10 +1350,13 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if the scroll position changed, otherwise False.
|
||||
"""
|
||||
maybe_scroll_x = x is not None and (self.allow_horizontal_scroll or force)
|
||||
maybe_scroll_y = y is not None and (self.allow_vertical_scroll or force)
|
||||
scrolled_x = scrolled_y = False
|
||||
if animate:
|
||||
# TODO: configure animation speed
|
||||
@@ -1364,7 +1366,7 @@ class Widget(DOMNode):
|
||||
if easing is None:
|
||||
easing = DEFAULT_SCROLL_EASING
|
||||
|
||||
if x is not None:
|
||||
if maybe_scroll_x:
|
||||
self.scroll_target_x = x
|
||||
if x != self.scroll_x:
|
||||
self.animate(
|
||||
@@ -1375,7 +1377,7 @@ class Widget(DOMNode):
|
||||
easing=easing,
|
||||
)
|
||||
scrolled_x = True
|
||||
if y is not None:
|
||||
if maybe_scroll_y:
|
||||
self.scroll_target_y = y
|
||||
if y != self.scroll_y:
|
||||
self.animate(
|
||||
@@ -1388,11 +1390,11 @@ class Widget(DOMNode):
|
||||
scrolled_y = True
|
||||
|
||||
else:
|
||||
if x is not None:
|
||||
if maybe_scroll_x:
|
||||
scroll_x = self.scroll_x
|
||||
self.scroll_target_x = self.scroll_x = x
|
||||
scrolled_x = scroll_x != self.scroll_x
|
||||
if y is not None:
|
||||
if maybe_scroll_y:
|
||||
scroll_y = self.scroll_y
|
||||
self.scroll_target_y = self.scroll_y = y
|
||||
scrolled_y = scroll_y != self.scroll_y
|
||||
@@ -1408,6 +1410,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll relative to current position.
|
||||
|
||||
@@ -1419,6 +1422,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if the scroll position changed, otherwise False.
|
||||
@@ -1430,6 +1434,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_home(
|
||||
@@ -1439,6 +1444,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll to home position.
|
||||
|
||||
@@ -1448,6 +1454,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1455,7 +1462,13 @@ class Widget(DOMNode):
|
||||
if speed is None and duration is None:
|
||||
duration = 1.0
|
||||
return self.scroll_to(
|
||||
0, 0, animate=animate, speed=speed, duration=duration, easing=easing
|
||||
0,
|
||||
0,
|
||||
animate=animate,
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_end(
|
||||
@@ -1465,6 +1478,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll to the end of the container.
|
||||
|
||||
@@ -1474,6 +1488,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1488,6 +1503,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_left(
|
||||
@@ -1497,6 +1513,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one cell left.
|
||||
|
||||
@@ -1506,6 +1523,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1517,6 +1535,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_right(
|
||||
@@ -1526,6 +1545,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll on cell right.
|
||||
|
||||
@@ -1535,6 +1555,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1546,6 +1567,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_down(
|
||||
@@ -1555,6 +1577,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one line down.
|
||||
|
||||
@@ -1564,6 +1587,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1575,6 +1599,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_up(
|
||||
@@ -1584,6 +1609,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one line up.
|
||||
|
||||
@@ -1593,6 +1619,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1604,6 +1631,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_page_up(
|
||||
@@ -1613,6 +1641,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one page up.
|
||||
|
||||
@@ -1622,6 +1651,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1633,6 +1663,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_page_down(
|
||||
@@ -1642,6 +1673,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one page down.
|
||||
|
||||
@@ -1651,6 +1683,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1662,6 +1695,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_page_left(
|
||||
@@ -1671,6 +1705,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one page left.
|
||||
|
||||
@@ -1680,6 +1715,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1693,6 +1729,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_page_right(
|
||||
@@ -1702,6 +1739,7 @@ class Widget(DOMNode):
|
||||
speed: float | None = None,
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll one page right.
|
||||
|
||||
@@ -1711,6 +1749,7 @@ class Widget(DOMNode):
|
||||
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling was done.
|
||||
@@ -1724,6 +1763,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def scroll_to_widget(
|
||||
@@ -1735,6 +1775,7 @@ class Widget(DOMNode):
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
top: bool = False,
|
||||
force: bool = False,
|
||||
) -> bool:
|
||||
"""Scroll scrolling to bring a widget in to view.
|
||||
|
||||
@@ -1746,6 +1787,7 @@ class Widget(DOMNode):
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
top (bool, optional): Scroll widget to top of container. Defaults to False.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if any scrolling has occurred in any descendant, otherwise False.
|
||||
@@ -1765,6 +1807,7 @@ class Widget(DOMNode):
|
||||
duration=duration,
|
||||
top=top,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
if scroll_offset:
|
||||
scrolled = True
|
||||
@@ -1793,6 +1836,7 @@ class Widget(DOMNode):
|
||||
duration: float | None = None,
|
||||
easing: EasingFunction | str | None = None,
|
||||
top: bool = False,
|
||||
force: bool = False,
|
||||
) -> Offset:
|
||||
"""Scrolls a given region in to view, if required.
|
||||
|
||||
@@ -1808,6 +1852,7 @@ class Widget(DOMNode):
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
top (bool, optional): Scroll region to top of container. Defaults to False.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
|
||||
Returns:
|
||||
Offset: The distance that was scrolled.
|
||||
@@ -1835,6 +1880,7 @@ class Widget(DOMNode):
|
||||
speed=speed,
|
||||
duration=duration,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
return delta
|
||||
|
||||
@@ -1846,6 +1892,7 @@ class Widget(DOMNode):
|
||||
duration: float | None = None,
|
||||
top: bool = False,
|
||||
easing: EasingFunction | str | None = None,
|
||||
force: bool = False,
|
||||
) -> None:
|
||||
"""Scroll the container to make this widget visible.
|
||||
|
||||
@@ -1856,6 +1903,7 @@ class Widget(DOMNode):
|
||||
top (bool, optional): Scroll to top of container. Defaults to False.
|
||||
easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None",
|
||||
which will result in Textual choosing the configured default scrolling easing function.
|
||||
force (bool, optional): Force scrolling even when prohibited by overflow styling. Defaults to `False`.
|
||||
"""
|
||||
parent = self.parent
|
||||
if isinstance(parent, Widget):
|
||||
@@ -1867,6 +1915,7 @@ class Widget(DOMNode):
|
||||
duration=duration,
|
||||
top=top,
|
||||
easing=easing,
|
||||
force=force,
|
||||
)
|
||||
|
||||
def __init_subclass__(
|
||||
|
||||
@@ -195,8 +195,13 @@ class Button(Static, can_focus=True):
|
||||
self.variant = self.validate_variant(variant)
|
||||
|
||||
label: Reactive[RenderableType] = Reactive("")
|
||||
"""The text label that appears within the button."""
|
||||
|
||||
variant = Reactive.init("default")
|
||||
"""The variant name for the button."""
|
||||
|
||||
disabled = Reactive(False)
|
||||
"""The disabled state of the button; `True` if disabled, `False` if not."""
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield from super().__rich_repr__()
|
||||
|
||||
@@ -57,9 +57,6 @@ class Checkbox(Widget, can_focus=True):
|
||||
"checkbox--switch",
|
||||
}
|
||||
|
||||
value = reactive(False, init=False)
|
||||
slider_pos = reactive(0.0)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
value: bool = False,
|
||||
@@ -84,6 +81,12 @@ class Checkbox(Widget, can_focus=True):
|
||||
self._reactive_value = value
|
||||
self._should_animate = animate
|
||||
|
||||
value = reactive(False, init=False)
|
||||
"""The value of the checkbox; `True` for on and `False` for off."""
|
||||
|
||||
slider_pos = reactive(0.0)
|
||||
"""The position of the slider."""
|
||||
|
||||
def watch_value(self, value: bool) -> None:
|
||||
target_slider_pos = 1.0 if value else 0.0
|
||||
if self._should_animate:
|
||||
|
||||
@@ -113,6 +113,17 @@ class Input(Widget, can_focus=True):
|
||||
id: str | None = None,
|
||||
classes: str | None = None,
|
||||
) -> None:
|
||||
"""Initialise the `Input` widget.
|
||||
|
||||
Args:
|
||||
value (str | None, optional): An optional default value for the input.
|
||||
placeholder (str, optional): Optional placeholder text for the input.
|
||||
highlighter (Highlighter | None, optional): An optional highlighter for the input.
|
||||
password (bool, optional): Flag to say if the field should obfuscate its content. Default is `False`.
|
||||
name (str | None, optional): Optional name for the input widget.
|
||||
id (str | None): Optional ID for the widget.
|
||||
classes (str | None): Optional initial classes for the widget.
|
||||
"""
|
||||
super().__init__(name=name, id=id, classes=classes)
|
||||
if value is not None:
|
||||
self.value = value
|
||||
@@ -127,7 +138,7 @@ class Input(Widget, can_focus=True):
|
||||
|
||||
@property
|
||||
def _cursor_offset(self) -> int:
|
||||
"""Get the cell offset of the cursor."""
|
||||
"""The cell offset of the cursor."""
|
||||
offset = self._position_to_cell(self.cursor_position)
|
||||
if self._cursor_at_end:
|
||||
offset += 1
|
||||
@@ -135,7 +146,7 @@ class Input(Widget, can_focus=True):
|
||||
|
||||
@property
|
||||
def _cursor_at_end(self) -> bool:
|
||||
"""Check if the cursor is at the end"""
|
||||
"""Flag to indicate if the cursor is at the end"""
|
||||
return self.cursor_position >= len(self.value)
|
||||
|
||||
def validate_cursor_position(self, cursor_position: int) -> int:
|
||||
@@ -170,7 +181,7 @@ class Input(Widget, can_focus=True):
|
||||
|
||||
@property
|
||||
def cursor_width(self) -> int:
|
||||
"""Get the width of the input (with extra space for cursor at the end)."""
|
||||
"""The width of the input (with extra space for cursor at the end)."""
|
||||
if self.placeholder and not self.value:
|
||||
return cell_len(self.placeholder)
|
||||
return self._position_to_cell(len(self.value)) + 1
|
||||
|
||||
@@ -19,10 +19,10 @@ from ..strip import Strip
|
||||
|
||||
|
||||
class TextLog(ScrollView, can_focus=True):
|
||||
DEFAULT_CSS = """
|
||||
DEFAULT_CSS = """
|
||||
TextLog{
|
||||
background: $surface;
|
||||
color: $text;
|
||||
color: $text;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
"""
|
||||
@@ -103,11 +103,11 @@ class TextLog(ScrollView, can_focus=True):
|
||||
container_width = (
|
||||
self.scrollable_content_region.width if width is None else width
|
||||
)
|
||||
|
||||
if expand and render_width < container_width:
|
||||
render_width = container_width
|
||||
if shrink and render_width > container_width:
|
||||
render_width = container_width
|
||||
if container_width:
|
||||
if expand and render_width < container_width:
|
||||
render_width = container_width
|
||||
if shrink and render_width > container_width:
|
||||
render_width = container_width
|
||||
|
||||
segments = self.app.console.render(
|
||||
renderable, render_options.update_width(render_width)
|
||||
@@ -120,7 +120,9 @@ class TextLog(ScrollView, can_focus=True):
|
||||
self.max_width,
|
||||
max(sum(segment.cell_length for segment in _line) for _line in lines),
|
||||
)
|
||||
strips = Strip.from_lines(lines, render_width)
|
||||
strips = Strip.from_lines(lines)
|
||||
for strip in strips:
|
||||
strip.adjust_cell_length(render_width)
|
||||
self.lines.extend(strips)
|
||||
|
||||
if self.max_lines is not None and len(self.lines) > self.max_lines:
|
||||
|
||||
Reference in New Issue
Block a user