From 63ef97d6ae41f36c6f27a132320d7e546d8d908f Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 4 Jan 2025 15:15:01 +0000 Subject: [PATCH] allow select --- CHANGELOG.md | 5 +++++ src/textual/app.py | 6 ++++++ src/textual/screen.py | 12 +++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a70f0110..44232e150b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `Widget.scrollable_container` property - Added `Widget.select_all` - Added `Region.bottom_right_inclusive` +- Added double click to select, triple click to select all in container +- Added arbitrary text selection +- Added Widget.ALLOW_SELECT classvar for a per-widget switch to disable text selection +- Added Widget.allow_select method for programmatic control of text selection +- Added App.ALLOW_SELECT for a global switch to disable text selection ### Fixed diff --git a/src/textual/app.py b/src/textual/app.py index b9b9b01e86..e750dc7389 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -396,6 +396,12 @@ class MyApp(App[None]): Setting to `None` or `""` disables auto focus. """ + ALLOW_SELECT: ClassVar[bool] = True + """A switch to toggle arbitrary text selection for the app. + + Note that this doesn't apply to Input and TextArea which have builtin support for selection. + """ + _BASE_PATH: str | None = None CSS_PATH: ClassVar[CSSPathType | None] = None """File paths to load CSS from.""" diff --git a/src/textual/screen.py b/src/textual/screen.py index eb42a5b95d..c9d90c805e 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -511,6 +511,11 @@ def is_active(self) -> bool: except Exception: return False + @property + def allow_select(self) -> bool: + """Check if this widget permits text selection.""" + return self.ALLOW_SELECT + def render(self) -> RenderableType: """Render method inherited from widget, used to render the screen's background. @@ -1520,7 +1525,12 @@ def _forward_event(self, event: events.Event) -> None: select_widget, select_offset = self.get_widget_and_offset_at( event.screen_x, event.screen_y ) - if select_widget is not None and select_widget.allow_select: + if ( + select_widget is not None + and select_widget.allow_select + and self.screen.allow_select + and self.app.ALLOW_SELECT + ): self._selecting = True if select_widget is not None and select_offset is not None: self._select_start = (