mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Support MouseScrollLeft and MouseScrollRight control sequences.
This commit is contained in:
@@ -100,9 +100,12 @@ class XTermParser(Parser[Message]):
|
||||
event_class: type[events.MouseEvent]
|
||||
|
||||
if buttons & 64:
|
||||
event_class = (
|
||||
events.MouseScrollDown if buttons & 1 else events.MouseScrollUp
|
||||
)
|
||||
event_class = [
|
||||
events.MouseScrollUp,
|
||||
events.MouseScrollDown,
|
||||
events.MouseScrollLeft,
|
||||
events.MouseScrollRight,
|
||||
][buttons & 3]
|
||||
button = 0
|
||||
else:
|
||||
button = (buttons + 1) & 3
|
||||
|
||||
@@ -606,6 +606,24 @@ class MouseScrollUp(MouseEvent, bubble=True, verbose=True):
|
||||
"""
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class MouseScrollRight(MouseEvent, bubble=True, verbose=True):
|
||||
"""Sent when the mouse wheel is scrolled *right*.
|
||||
|
||||
- [X] Bubbles
|
||||
- [X] Verbose
|
||||
"""
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class MouseScrollLeft(MouseEvent, bubble=True, verbose=True):
|
||||
"""Sent when the mouse wheel is scrolled *left*.
|
||||
|
||||
- [X] Bubbles
|
||||
- [X] Verbose
|
||||
"""
|
||||
|
||||
|
||||
class Click(MouseEvent, bubble=True):
|
||||
"""Sent when a widget is clicked.
|
||||
|
||||
|
||||
@@ -113,7 +113,12 @@ _JUSTIFY_MAP: dict[str, JustifyMethod] = {
|
||||
|
||||
|
||||
_MOUSE_EVENTS_DISALLOW_IF_DISABLED = (events.MouseEvent, events.Enter, events.Leave)
|
||||
_MOUSE_EVENTS_ALLOW_IF_DISABLED = (events.MouseScrollDown, events.MouseScrollUp)
|
||||
_MOUSE_EVENTS_ALLOW_IF_DISABLED = (
|
||||
events.MouseScrollDown,
|
||||
events.MouseScrollUp,
|
||||
events.MouseScrollRight,
|
||||
events.MouseScrollLeft,
|
||||
)
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
@@ -4569,6 +4574,18 @@ class Widget(DOMNode):
|
||||
if self._scroll_up_for_pointer(animate=False):
|
||||
event.stop()
|
||||
|
||||
def _on_mouse_scroll_right(self, event: events.MouseScrollRight) -> None:
|
||||
if self.allow_horizontal_scroll:
|
||||
self.release_anchor()
|
||||
if self._scroll_right_for_pointer(animate=False):
|
||||
event.stop()
|
||||
|
||||
def _on_mouse_scroll_left(self, event: events.MouseScrollLeft) -> None:
|
||||
if self.allow_horizontal_scroll:
|
||||
self.release_anchor()
|
||||
if self._scroll_left_for_pointer(animate=False):
|
||||
event.stop()
|
||||
|
||||
def _on_scroll_to(self, message: ScrollTo) -> None:
|
||||
if self._allow_scroll:
|
||||
self.release_anchor()
|
||||
|
||||
@@ -8,6 +8,8 @@ from textual.events import (
|
||||
MouseDown,
|
||||
MouseMove,
|
||||
MouseScrollDown,
|
||||
MouseScrollLeft,
|
||||
MouseScrollRight,
|
||||
MouseScrollUp,
|
||||
MouseUp,
|
||||
Paste,
|
||||
@@ -283,6 +285,56 @@ def test_mouse_scroll_down(parser, sequence, shift, meta):
|
||||
assert event.meta is meta
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, shift, meta",
|
||||
[
|
||||
("\x1b[<66;18;25M", False, False),
|
||||
("\x1b[<70;18;25M", True, False),
|
||||
("\x1b[<74;18;25M", False, True),
|
||||
],
|
||||
)
|
||||
def test_mouse_scroll_left(parser, sequence, shift, meta):
|
||||
"""Scrolling the mouse with and without modifiers held down.
|
||||
We don't currently capture modifier keys in scroll events.
|
||||
"""
|
||||
events = list(parser.feed(sequence))
|
||||
|
||||
assert len(events) == 1
|
||||
|
||||
event = events[0]
|
||||
|
||||
assert isinstance(event, MouseScrollLeft)
|
||||
assert event.x == 17
|
||||
assert event.y == 24
|
||||
assert event.shift is shift
|
||||
assert event.meta is meta
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"sequence, shift, meta",
|
||||
[
|
||||
("\x1b[<67;18;25M", False, False),
|
||||
("\x1b[<71;18;25M", True, False),
|
||||
("\x1b[<75;18;25M", False, True),
|
||||
],
|
||||
)
|
||||
def test_mouse_scroll_right(parser, sequence, shift, meta):
|
||||
"""Scrolling the mouse with and without modifiers held down.
|
||||
We don't currently capture modifier keys in scroll events.
|
||||
"""
|
||||
events = list(parser.feed(sequence))
|
||||
|
||||
assert len(events) == 1
|
||||
|
||||
event = events[0]
|
||||
|
||||
assert isinstance(event, MouseScrollRight)
|
||||
assert event.x == 17
|
||||
assert event.y == 24
|
||||
assert event.shift is shift
|
||||
assert event.meta is meta
|
||||
|
||||
|
||||
def test_mouse_event_detected_but_info_not_parsed(parser):
|
||||
# I don't know if this can actually happen in reality, but
|
||||
# there's a branch in the code that allows for the possibility.
|
||||
|
||||
Reference in New Issue
Block a user