Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion src/textual/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
9 changes: 8 additions & 1 deletion src/textual/widgets/_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading