1from __future__ import annotations
2
3from collections import defaultdict
4from collections.abc import Callable
5from typing import TYPE_CHECKING
6
7from prompt_toolkit.mouse_events import MouseEvent
8
9if TYPE_CHECKING:
10 from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone
11
12__all__ = [
13 "MouseHandler",
14 "MouseHandlers",
15]
16
17
18MouseHandler = Callable[[MouseEvent], "NotImplementedOrNone"]
19
20
21class MouseHandlers:
22 """
23 Two dimensional raster of callbacks for mouse events.
24 """
25
26 def __init__(self) -> None:
27 def dummy_callback(mouse_event: MouseEvent) -> NotImplementedOrNone:
28 """
29 :param mouse_event: `MouseEvent` instance.
30 """
31 return NotImplemented
32
33 # NOTE: Previously, the data structure was a dictionary mapping (x,y)
34 # to the handlers. This however would be more inefficient when copying
35 # over the mouse handlers of the visible region in the scrollable pane.
36
37 # Map y (row) to x (column) to handlers.
38 self.mouse_handlers: defaultdict[int, defaultdict[int, MouseHandler]] = (
39 defaultdict(lambda: defaultdict(lambda: dummy_callback))
40 )
41
42 def set_mouse_handler_for_range(
43 self,
44 x_min: int,
45 x_max: int,
46 y_min: int,
47 y_max: int,
48 handler: Callable[[MouseEvent], NotImplementedOrNone],
49 ) -> None:
50 """
51 Set mouse handler for a region.
52 """
53 for y in range(y_min, y_max):
54 row = self.mouse_handlers[y]
55
56 for x in range(x_min, x_max):
57 row[x] = handler