diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bf7dd9df..a76f222901 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed -- Fixed issue with the "transparent" CSS value not being transparent when set using python +- Fixed issue with the "transparent" CSS value not being transparent when set using python https://github.com/Textualize/textual/pull/5890 +- Fixed issue with pushing screens when Input has mouse captured https://github.com/Textualize/textual/pull/5900 + +## Changed + +- Widget.release_mouse will now only release the mouse, if it was captured by self https://github.com/Textualize/textual/pull/5900 ## [3.5.0] - 2025-06-20 diff --git a/src/textual/app.py b/src/textual/app.py index eecddc1d4d..01996615ff 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -2680,6 +2680,7 @@ async def _replace_screen(self, screen: Screen) -> Screen: if not self.is_screen_installed(screen) and all( screen not in stack for stack in self._screen_stacks.values() ): + self.capture_mouse(None) await screen.remove() self.log.system(f"{screen} REMOVED") return screen @@ -2736,6 +2737,7 @@ def push_screen( else: future = loop.create_future() + self.app.capture_mouse(None) if self._screen_stack: self.screen.post_message(events.ScreenSuspend()) self.screen.refresh() @@ -2804,6 +2806,7 @@ def switch_screen(self, screen: Screen | str) -> AwaitComplete: self.log.system(f"Screen {screen} is already current.") return AwaitComplete.nothing() + self.app.capture_mouse(None) top_screen = self._screen_stack.pop() top_screen._pop_result_callback() diff --git a/src/textual/widget.py b/src/textual/widget.py index 05d99addc3..4b9936c629 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -4341,7 +4341,8 @@ def release_mouse(self) -> None: Mouse events will only be sent when the mouse is over the widget. """ - self.app.capture_mouse(None) + if self.app.mouse_captured is self: + self.app.capture_mouse(None) def text_select_all(self) -> None: """Select the entire widget.""" diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py index 326e535958..715ab0f5f0 100644 --- a/src/textual/widgets/_input.py +++ b/src/textual/widgets/_input.py @@ -769,12 +769,19 @@ async def _on_mouse_down(self, event: events.MouseDown) -> None: self._selecting = True self.capture_mouse() - async def _on_mouse_up(self, event: events.MouseUp) -> None: + def _end_selecting(self) -> None: + """End selecting if it is currently active.""" if self._selecting: self._selecting = False self.release_mouse() self._restart_blink() + async def _on_mouse_release(self, _event: events.MouseRelease) -> None: + self._end_selecting() + + async def _on_mouse_up(self, _event: events.MouseUp) -> None: + self._end_selecting() + async def _on_mouse_move(self, event: events.MouseMove) -> None: if self._selecting: # As we drag the mouse, we update the end position of the selection,