Skip to content

Commit 4ba8352

Browse files
[wip] Added mouse support. - Not yet finished.
1 parent a835c58 commit 4ba8352

File tree

4 files changed

+55
-8
lines changed

4 files changed

+55
-8
lines changed

examples/full-screen/scrollable-panes/with-completion-menu.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ def exit(event) -> None:
7373
kb.add("s-tab")(focus_previous)
7474

7575
# Create and run application.
76-
application = Application(layout=layout, key_bindings=kb, full_screen=True)
76+
application = Application(
77+
layout=layout, key_bindings=kb, full_screen=True, mouse_support=True
78+
)
7779
application.run()
7880

7981

prompt_toolkit/key_binding/bindings/mouse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def _(event: E) -> None:
9494
return
9595

9696
# Call the mouse handler from the renderer.
97-
handler = event.app.renderer.mouse_handlers.mouse_handlers[x, y]
97+
handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x]
9898
handler(MouseEvent(position=Point(x=x, y=y), event_type=mouse_event_type))
9999

100100
@key_bindings.add(Keys.ScrollUp)

prompt_toolkit/layout/mouse_handlers.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
from prompt_toolkit.mouse_events import MouseEvent
66

77
__all__ = [
8+
"MouseHandler",
89
"MouseHandlers",
910
]
1011

12+
MouseHandler = Callable[[MouseEvent], None]
13+
1114

1215
class MouseHandlers:
1316
"""
@@ -20,10 +23,14 @@ def dummy_callback(mouse_event: MouseEvent) -> None:
2023
:param mouse_event: `MouseEvent` instance.
2124
"""
2225

23-
# Map (x,y) tuples to handlers.
26+
# NOTE: Previously, the data structure was a dictionary mapping (x,y)
27+
# to the handlers. This however would be more inefficient when copying
28+
# over the mouse handlers of the visible region in the scrollable pane.
29+
30+
# Map y (row) to x (column) to handlers.
2431
self.mouse_handlers: DefaultDict[
25-
Tuple[int, int], Callable[[MouseEvent], None]
26-
] = defaultdict(lambda: dummy_callback)
32+
int, DefaultDict[int, MouseHandler]
33+
] = defaultdict(lambda: defaultdict(lambda: dummy_callback))
2734

2835
def set_mouse_handler_for_range(
2936
self,
@@ -36,5 +43,8 @@ def set_mouse_handler_for_range(
3643
"""
3744
Set mouse handler for a region.
3845
"""
39-
for x, y in product(range(x_min, x_max), range(y_min, y_max)):
40-
self.mouse_handlers[x, y] = handler
46+
for y in range(y_min, y_max):
47+
row = self.mouse_handlers[y]
48+
49+
for x in range(x_min, x_max):
50+
row[x] = handler

prompt_toolkit/layout/scrollable_pane.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from prompt_toolkit.data_structures import Point
44
from prompt_toolkit.filters import FilterOrBool, to_filter
55
from prompt_toolkit.key_binding import KeyBindingsBase
6+
from prompt_toolkit.mouse_events import MouseEvent
67

78
from .containers import Container, ScrollOffsets
89
from .dimension import AnyDimension, Dimension, sum_layout_dimensions, to_dimension
9-
from .mouse_handlers import MouseHandlers
10+
from .mouse_handlers import MouseHandler, MouseHandlers
1011
from .screen import Char, Screen, WritePosition
1112

1213
__all__ = ["ScrollablePane"]
@@ -199,10 +200,44 @@ def write_to_screen(
199200
if x in temp_zero_width_escapes:
200201
zero_width_escapes[x + xpos] = temp_zero_width_escapes[x]
201202

203+
# Copy over mouse handlers.
204+
mouse_handlers_dict = mouse_handlers.mouse_handlers
205+
temp_mouse_handlers_dict = temp_mouse_handlers.mouse_handlers
206+
207+
mouse_handler_wrappers: Dict[MouseHandler, MouseHandler] = {}
208+
209+
def wrap_mouse_handler(handler: MouseHandler) -> MouseHandler:
210+
" Wrap mouse handler. Translate coordinates in `MouseEvent`. "
211+
if handler not in mouse_handler_wrappers:
212+
213+
def new_handler(event: MouseEvent) -> None:
214+
new_event = MouseEvent(
215+
position=Point(
216+
x=event.position.x - xpos,
217+
y=event.position.y + self.vertical_scroll - ypos,
218+
),
219+
event_type=event.event_type,
220+
)
221+
handler(new_event)
222+
223+
mouse_handler_wrappers[handler] = new_handler
224+
return mouse_handler_wrappers[handler]
225+
226+
for y in range(
227+
self.vertical_scroll, self.vertical_scroll + write_position.height
228+
):
229+
if y in temp_mouse_handlers_dict:
230+
temp_mouse_row = temp_mouse_handlers_dict[y]
231+
mouse_row = mouse_handlers_dict[y]
232+
for x in range(virtual_width):
233+
if x in temp_mouse_row:
234+
mouse_row[x + xpos] = wrap_mouse_handler(temp_mouse_row[x])
235+
202236
# Set screen.width/height.
203237
screen.width = max(screen.width, xpos + virtual_width)
204238
screen.height = max(screen.height, ypos + write_position.height)
205239

240+
# Copy over window write positions.
206241
for win, write_pos in temp_screen.visible_windows_to_write_positions.items():
207242
screen.visible_windows_to_write_positions[win] = WritePosition(
208243
xpos=write_pos.xpos + xpos,

0 commit comments

Comments
 (0)