Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
dcfbbc3
demo updates
willmcgugan Nov 14, 2024
f84b166
copy tweak
willmcgugan Nov 14, 2024
e377822
copy
willmcgugan Nov 14, 2024
ece2e89
more data in data table
willmcgugan Nov 14, 2024
caa7dde
default theme logic
willmcgugan Nov 14, 2024
0a7a292
maximize demo widgets
willmcgugan Nov 14, 2024
adeb306
empty sparklines
willmcgugan Nov 14, 2024
201f106
test fixes
willmcgugan Nov 14, 2024
9f49bc2
add is_scrolling
willmcgugan Nov 14, 2024
6fadab9
remove scroll pause
willmcgugan Nov 14, 2024
7c1ebfc
button tweak
willmcgugan Nov 14, 2024
35d6d6a
restore previous buttons
willmcgugan Nov 14, 2024
6dfe107
Merge branch 'main' into demo-polish
willmcgugan Nov 14, 2024
d31b373
snapshot fixes
willmcgugan Nov 14, 2024
7543303
digit
willmcgugan Nov 14, 2024
a5c3c70
disable button text
willmcgugan Nov 14, 2024
672daf8
Add text area
willmcgugan Nov 15, 2024
df63030
markdowns
willmcgugan Nov 15, 2024
09a4390
catch no screen
willmcgugan Nov 15, 2024
86fc98a
tree demo
willmcgugan Nov 15, 2024
f74e4db
harden lazy reveal
willmcgugan Nov 15, 2024
326e6c4
tabs demo
willmcgugan Nov 15, 2024
a0d4587
test fixes
willmcgugan Nov 15, 2024
12f3cc6
catch bad screen on timer
willmcgugan Nov 15, 2024
07bd5db
timing issue in test
willmcgugan Nov 15, 2024
d795c43
Refine
willmcgugan Nov 16, 2024
57e65d9
more efficient order styles
willmcgugan Nov 16, 2024
3503562
Changelog
willmcgugan Nov 16, 2024
6f79324
changelog
willmcgugan Nov 16, 2024
d8f149d
refine
willmcgugan Nov 16, 2024
91c71e5
changelog
willmcgugan Nov 16, 2024
060ae89
version bump
willmcgugan Nov 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased
## [0.86.0]

### Fixed

Expand All @@ -28,6 +28,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `textual.theme.ThemeProvider`, a command palette provider which returns all registered themes https://github.com/Textualize/textual/pull/5087
- Added several new built-in CSS variables https://github.com/Textualize/textual/pull/5087
- Added support for in-band terminal resize protocol https://github.com/Textualize/textual/pull/5217
- Added TEXTUAL_THEME environment var, which should be a comma separated list of desired themes https://github.com/Textualize/textual/pull/5238
- Added `Widget.is_scrolling` https://github.com/Textualize/textual/pull/5238
- Added `Tree.add_json` https://github.com/Textualize/textual/pull/5238

### Changed

Expand All @@ -36,12 +39,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `can_focus` and `can_focus_children` parameters to scrollable container types. https://github.com/Textualize/textual/pull/5226
- Added `textual.lazy.Reveal` https://github.com/Textualize/textual/pull/5226
- Added `Screen.action_blur` https://github.com/Textualize/textual/pull/5226

### Changed

- `Click` events can now be used with the on decorator to match the originally clicked widget https://github.com/Textualize/textual/pull/5238
- Breaking change: Removed `App.dark` reactive attribute https://github.com/Textualize/textual/pull/5087
- Breaking change: To improve consistency, several changes have been made to default widget CSS and the CSS variables which ship with Textual. On upgrading, your app will likely look different. All of these changes can be overidden with your own CSS. https://github.com/Textualize/textual/pull/5087

### Removed

- Removed `App.HOVER_EFFECTS_SCROLL_PAUSE` https://github.com/Textualize/textual/pull/5238

## [0.85.2] - 2024-11-02

- Fixed broken focus-within https://github.com/Textualize/textual/pull/5190
Expand Down Expand Up @@ -2530,6 +2535,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040
- New handler system for messages that doesn't require inheritance
- Improved traceback handling

[0.86.0]: https://github.com/Textualize/textual/compare/v0.85.2...v0.86.0
[0.85.2]: https://github.com/Textualize/textual/compare/v0.85.1...v0.85.2
[0.85.1]: https://github.com/Textualize/textual/compare/v0.85.0...v0.85.1
[0.85.0]: https://github.com/Textualize/textual/compare/v0.84.0...v0.85.0
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "textual"
version = "0.85.2"
version = "0.86.0"
homepage = "https://github.com/Textualize/textual"
repository = "https://github.com/Textualize/textual"
documentation = "https://textual.textualize.io/"
Expand Down
1 change: 1 addition & 0 deletions src/textual/_xterm_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def parse_mouse_code(self, code: str) -> Message | None:
event_class = events.MouseDown if state == "M" else events.MouseUp

event = event_class(
None,
x,
y,
delta_x,
Expand Down
54 changes: 13 additions & 41 deletions src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,6 @@ class MyApp(App[None]):
SUSPENDED_SCREEN_CLASS: ClassVar[str] = ""
"""Class to apply to suspended screens, or empty string for no class."""

HOVER_EFFECTS_SCROLL_PAUSE: ClassVar[float] = 0.2
"""Seconds to pause hover effects for when scrolling."""

_PSEUDO_CLASSES: ClassVar[dict[str, Callable[[App[Any]], bool]]] = {
"focus": lambda app: app.app_focus,
"blur": lambda app: not app.app_focus,
Expand All @@ -487,7 +484,7 @@ class MyApp(App[None]):
get focus when the terminal widget has focus.
"""

theme: Reactive[str] = Reactive("textual-dark")
theme: Reactive[str] = Reactive(constants.DEFAULT_THEME)
"""The name of the currently active theme."""

ansi_theme_dark = Reactive(MONOKAI, init=False)
Expand Down Expand Up @@ -757,9 +754,6 @@ def __init__(
self._previous_inline_height: int | None = None
"""Size of previous inline update."""

self._paused_hover_effects: bool = False
"""Have the hover effects been paused?"""

self._hover_effects_timer: Timer | None = None

self._resize_event: events.Resize | None = None
Expand Down Expand Up @@ -1192,12 +1186,17 @@ def get_theme(self, theme_name: str) -> Theme | None:
"""Get a theme by name.

Args:
theme_name: The name of the theme to get.
theme_name: The name of the theme to get. May also be a comma
separated list of names, to pick the first available theme.

Returns:
A Theme instance and None if the theme doesn't exist.
"""
return self.available_themes[theme_name]
theme_names = [token.strip() for token in theme_name.split(",")]
for theme_name in theme_names:
if theme_name in self.available_themes:
return self.available_themes[theme_name]
return None

def register_theme(self, theme: Theme) -> None:
"""Register a theme with the app.
Expand Down Expand Up @@ -1233,6 +1232,8 @@ def available_themes(self) -> dict[str, Theme]:
@property
def current_theme(self) -> Theme:
theme = self.get_theme(self.theme)
if theme is None:
theme = self.get_theme("textual-dark")
assert theme is not None # validated by _validate_theme
return theme

Expand Down Expand Up @@ -2814,43 +2815,12 @@ def set_focus(self, widget: Widget | None, scroll_visible: bool = True) -> None:
"""
self.screen.set_focus(widget, scroll_visible)

def _pause_hover_effects(self):
"""Pause any hover effects based on Enter and Leave events for 200ms."""
if not self.HOVER_EFFECTS_SCROLL_PAUSE or self.is_headless:
return
self._paused_hover_effects = True
if self._hover_effects_timer is None:
self._hover_effects_timer = self.set_interval(
self.HOVER_EFFECTS_SCROLL_PAUSE, self._resume_hover_effects
)
else:
self._hover_effects_timer.reset()
self._hover_effects_timer.resume()

def _resume_hover_effects(self):
"""Resume sending Enter and Leave for hover effects."""
if not self.HOVER_EFFECTS_SCROLL_PAUSE or self.is_headless:
return
if self._paused_hover_effects:
self._paused_hover_effects = False
if self._hover_effects_timer is not None:
self._hover_effects_timer.pause()
try:
widget, _ = self.screen.get_widget_at(*self.mouse_position)
except NoWidget:
pass
else:
if widget is not self.mouse_over:
self._set_mouse_over(widget)

def _set_mouse_over(self, widget: Widget | None) -> None:
"""Called when the mouse is over another widget.

Args:
widget: Widget under mouse, or None for no widgets.
"""
if self._paused_hover_effects:
return
if widget is None:
if self.mouse_over is not None:
try:
Expand Down Expand Up @@ -3709,7 +3679,9 @@ async def on_event(self, event: events.Event) -> None:
self.get_widget_at(event.x, event.y)[0]
is self._mouse_down_widget
):
click_event = events.Click.from_event(event)
click_event = events.Click.from_event(
self._mouse_down_widget, event
)
self.screen._forward_event(click_event)
except NoWidget:
pass
Expand Down
3 changes: 2 additions & 1 deletion src/textual/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ class CommandPalette(SystemModalScreen[None]):
CommandPalette > .command-palette--help-text {
color: $text-muted;
background: transparent;
text-style: not bold dim;
text-style: not bold;
}

CommandPalette > .command-palette--highlight {
Expand All @@ -571,6 +571,7 @@ class CommandPalette(SystemModalScreen[None]):
height: 100%;
visibility: hidden;
background: $surface;
&:dark { background: $panel-darken-1; }
}

CommandPalette #--input {
Expand Down
5 changes: 5 additions & 0 deletions src/textual/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,8 @@ def _get_textual_animations() -> AnimationLevel:
"""The time threshold (in milliseconds) after which a warning is logged
if message processing exceeds this duration.
"""

DEFAULT_THEME: Final[str] = get_environ("TEXTUAL_THEME", "textual-dark")
"""Textual theme to make default. More than one theme may be specified in a comma separated list.
Textual will use the first theme that exists.
"""
9 changes: 9 additions & 0 deletions src/textual/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def __init__(
disabled: bool = False,
can_focus: bool | None = None,
can_focus_children: bool | None = None,
can_maximize: bool | None = None,
) -> None:
"""

Expand All @@ -93,6 +94,7 @@ def __init__(
disabled: Whether the widget is disabled or not.
can_focus: Can this container be focused?
can_focus_children: Can this container's children be focused?
can_maximized: Allow this container to maximize? `None` to use default logic.,
"""

super().__init__(
Expand All @@ -106,6 +108,13 @@ def __init__(
self.can_focus = can_focus
if can_focus_children is not None:
self.can_focus_children = can_focus_children
self.can_maximize = can_maximize

@property
def allow_maximize(self) -> bool:
if self.can_maximize is None:
return super().allow_maximize
return self.can_maximize


class Vertical(Widget, inherit_bindings=False):
Expand Down
5 changes: 4 additions & 1 deletion src/textual/css/stylesheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,10 @@ def apply(
node._has_hover_style = "hover" in all_pseudo_classes
node._has_focus_within = "focus-within" in all_pseudo_classes
node._has_order_style = not all_pseudo_classes.isdisjoint(
{"first-of-type", "last-of-type", "odd", "even"}
{"first-of-type", "last-of-type"}
)
node._has_odd_or_even = (
"odd" in all_pseudo_classes or "even" in all_pseudo_classes
)

cache_key: tuple | None = None
Expand Down
Loading
Loading