Merge branch 'main' into sleep-tweak

This commit is contained in:
Will McGugan
2023-01-05 03:56:19 -08:00
committed by GitHub
5 changed files with 53 additions and 47 deletions

View File

@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.10.0] - Unreleased
### Changed
- `MouseScrollUp` and `MouseScrollDown` now inherit from `MouseEvent` and have attached modifier keys. https://github.com/Textualize/textual/pull/1458
## [0.9.1] - 2022-12-30 ## [0.9.1] - 2022-12-30
### Added ### Added

View File

@@ -365,7 +365,7 @@ The first argument to `reactive` may be a default value or a callable that retur
The `time` attribute has a simple float as the default value, so `self.time` will be `0` on start. The `time` attribute has a simple float as the default value, so `self.time` will be `0` on start.
The `on_mount` method is an event handler called then the widget is first added to the application (or _mounted_). In this method we call [set_interval()][textual.message_pump.MessagePump.set_interval] to create a timer which calls `self.update_time` sixty times a second. This `update_time` method calculates the time elapsed since the widget started and assigns it to `self.time`. Which brings us to one of Reactive's super-powers. The `on_mount` method is an event handler called when the widget is first added to the application (or _mounted_). In this method we call [set_interval()][textual.message_pump.MessagePump.set_interval] to create a timer which calls `self.update_time` sixty times a second. This `update_time` method calculates the time elapsed since the widget started and assigns it to `self.time`. Which brings us to one of Reactive's super-powers.
If you implement a method that begins with `watch_` followed by the name of a reactive attribute (making it a _watch method_), that method will be called when the attribute is modified. If you implement a method that begins with `watch_` followed by the name of a reactive attribute (making it a _watch method_), that method will be called when the attribute is modified.

View File

@@ -54,36 +54,40 @@ class XTermParser(Parser[events.Event]):
if sgr_match: if sgr_match:
_buttons, _x, _y, state = sgr_match.groups() _buttons, _x, _y, state = sgr_match.groups()
buttons = int(_buttons) buttons = int(_buttons)
button = (buttons + 1) & 3
x = int(_x) - 1 x = int(_x) - 1
y = int(_y) - 1 y = int(_y) - 1
delta_x = x - self.last_x delta_x = x - self.last_x
delta_y = y - self.last_y delta_y = y - self.last_y
self.last_x = x self.last_x = x
self.last_y = y self.last_y = y
event: events.Event event_class: type[events.MouseEvent]
if buttons & 64: if buttons & 64:
event = ( event_class = (
events.MouseScrollUp if button == 1 else events.MouseScrollDown events.MouseScrollDown if buttons & 1 else events.MouseScrollUp
)(sender, x, y)
else:
event = (
events.MouseMove
if buttons & 32
else (events.MouseDown if state == "M" else events.MouseUp)
)(
sender,
x,
y,
delta_x,
delta_y,
button,
bool(buttons & 4),
bool(buttons & 8),
bool(buttons & 16),
screen_x=x,
screen_y=y,
) )
button = 0
else:
if buttons & 32:
event_class = events.MouseMove
else:
event_class = events.MouseDown if state == "M" else events.MouseUp
button = (buttons + 1) & 3
event = event_class(
sender,
x,
y,
delta_x,
delta_y,
button,
bool(buttons & 4),
bool(buttons & 8),
bool(buttons & 16),
screen_x=x,
screen_y=y,
)
return event return event
return None return None

View File

@@ -419,22 +419,14 @@ class MouseUp(MouseEvent, bubble=True, verbose=True):
pass pass
class MouseScrollDown(InputEvent, bubble=True, verbose=True): @rich.repr.auto
__slots__ = ["x", "y"] class MouseScrollDown(MouseEvent, bubble=True):
pass
def __init__(self, sender: MessageTarget, x: int, y: int) -> None:
super().__init__(sender)
self.x = x
self.y = y
class MouseScrollUp(InputEvent, bubble=True, verbose=True): @rich.repr.auto
__slots__ = ["x", "y"] class MouseScrollUp(MouseEvent, bubble=True):
pass
def __init__(self, sender: MessageTarget, x: int, y: int) -> None:
super().__init__(sender)
self.x = x
self.y = y
class Click(MouseEvent, bubble=True): class Click(MouseEvent, bubble=True):

View File

@@ -236,14 +236,14 @@ def test_mouse_move(parser, sequence, shift, meta, button):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"sequence", "sequence, shift, meta",
[ [
"\x1b[<64;18;25M", ("\x1b[<64;18;25M", False, False),
"\x1b[<68;18;25M", ("\x1b[<68;18;25M", True, False),
"\x1b[<72;18;25M", ("\x1b[<72;18;25M", False, True),
], ],
) )
def test_mouse_scroll_up(parser, sequence): def test_mouse_scroll_up(parser, sequence, shift, meta):
"""Scrolling the mouse with and without modifiers held down. """Scrolling the mouse with and without modifiers held down.
We don't currently capture modifier keys in scroll events. We don't currently capture modifier keys in scroll events.
""" """
@@ -256,17 +256,19 @@ def test_mouse_scroll_up(parser, sequence):
assert isinstance(event, MouseScrollUp) assert isinstance(event, MouseScrollUp)
assert event.x == 17 assert event.x == 17
assert event.y == 24 assert event.y == 24
assert event.shift is shift
assert event.meta is meta
@pytest.mark.parametrize( @pytest.mark.parametrize(
"sequence", "sequence, shift, meta",
[ [
"\x1b[<65;18;25M", ("\x1b[<65;18;25M", False, False),
"\x1b[<69;18;25M", ("\x1b[<69;18;25M", True, False),
"\x1b[<73;18;25M", ("\x1b[<73;18;25M", False, True),
], ],
) )
def test_mouse_scroll_down(parser, sequence): def test_mouse_scroll_down(parser, sequence, shift, meta):
events = list(parser.feed(sequence)) events = list(parser.feed(sequence))
assert len(events) == 1 assert len(events) == 1
@@ -276,6 +278,8 @@ def test_mouse_scroll_down(parser, sequence):
assert isinstance(event, MouseScrollDown) assert isinstance(event, MouseScrollDown)
assert event.x == 17 assert event.x == 17
assert event.y == 24 assert event.y == 24
assert event.shift is shift
assert event.meta is meta
def test_mouse_event_detected_but_info_not_parsed(parser): def test_mouse_event_detected_but_info_not_parsed(parser):