Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a04a687

Browse filesBrowse files
committed
can sync selectors, can remove them from synchronizer too
1 parent bc9af00 commit a04a687
Copy full SHA for a04a687

File tree

Expand file treeCollapse file tree

2 files changed

+84
-1
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+84
-1
lines changed

‎fastplotlib/graphics/features/_base.py

Copy file name to clipboardExpand all lines: fastplotlib/graphics/features/_base.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def remove_event_handler(self, handler: callable):
122122
if handler not in self._event_handlers:
123123
raise KeyError(f"event handler {handler} not registered.")
124124

125-
self._event_handlers.pop(handler)
125+
self._event_handlers.remove(handler)
126126

127127
#TODO: maybe this can be implemented right here in the base class
128128
@abstractmethod
+83Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from typing import *
2+
3+
from . import LinearSelector
4+
5+
6+
class Synchronizer:
7+
def __init__(self, *selectors: LinearSelector, key_bind: str = "Shift"):
8+
"""
9+
Synchronize the movement of `Selectors`. Selectors will move in sync only when the selected `"key_bind"` is
10+
used during the mouse movement event. Valid key binds are: ``"Control"``, ``"Shift"`` and ``"Alt"``.
11+
If ``key_bind`` is ``None`` then the selectors will always be synchronized.
12+
13+
Parameters
14+
----------
15+
selectors
16+
selectors to synchronize
17+
18+
key_bind: str, default ``"Shift"``
19+
one of ``"Control"``, ``"Shift"`` and ``"Alt"``
20+
"""
21+
self._selectors = list()
22+
self.key_bind = key_bind
23+
24+
for s in selectors:
25+
self.add(s)
26+
27+
self.block_event = False
28+
29+
@property
30+
def selectors(self):
31+
"""Selectors managed by the Synchronizer"""
32+
return self._selectors
33+
34+
def add(self, selector):
35+
"""add a selector"""
36+
selector.selection.add_event_handler(self._handle_event)
37+
self._selectors.append(selector)
38+
39+
def remove(self, selector):
40+
"""remove a selector"""
41+
self._selectors.remove(selector)
42+
selector.selection.remove_event_handler(self._handle_event)
43+
44+
def _handle_event(self, ev):
45+
if self.block_event:
46+
# because infinite recursion
47+
return
48+
49+
self.block_event = True
50+
51+
source = ev.pick_info["graphic"]
52+
delta = ev.pick_info["delta"]
53+
pygfx_ev = ev.pick_info["pygfx_event"]
54+
55+
# only moves when modifier is used
56+
if pygfx_ev is None:
57+
self.block_event = False
58+
return
59+
60+
if self.key_bind is not None:
61+
if self.key_bind not in pygfx_ev.modifiers:
62+
self.block_event = False
63+
return
64+
65+
if delta is not None:
66+
self._move_selectors(source, delta)
67+
68+
self.block_event = False
69+
70+
def _move_selectors(self, source, delta):
71+
for s in self.selectors:
72+
# must use == and not is to compare Graphics because they are weakref proxies!
73+
if s == source:
74+
# if it's the source, since it has already movied
75+
continue
76+
77+
s._move_graphic(delta)
78+
79+
def __del__(self):
80+
for s in self.selectors:
81+
self.remove(s)
82+
83+
self.selectors.clear()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.