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 c740fc8

Browse filesBrowse files
authored
Merge pull request #29066 from anntzer/cbpz
Check pressed mouse buttons in pan/zoom drag handlers.
2 parents 55fa822 + 78bece9 commit c740fc8
Copy full SHA for c740fc8

File tree

Expand file treeCollapse file tree

4 files changed

+42
-15
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+42
-15
lines changed

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+25-7Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,6 +3059,11 @@ def press_pan(self, event):
30593059

30603060
def drag_pan(self, event):
30613061
"""Callback for dragging in pan/zoom mode."""
3062+
if event.buttons != {self._pan_info.button}:
3063+
# Zoom ended while canvas not in focus (it did not receive a
3064+
# button_release_event); cancel it.
3065+
self.release_pan(None) # release_pan doesn't actually use event.
3066+
return
30623067
for ax in self._pan_info.axes:
30633068
# Using the recorded button at the press is safer than the current
30643069
# button, as multiple buttons can get pressed during motion.
@@ -3092,7 +3097,7 @@ def zoom(self, *args):
30923097
for a in self.canvas.figure.get_axes():
30933098
a.set_navigate_mode(self.mode._navigate_mode)
30943099

3095-
_ZoomInfo = namedtuple("_ZoomInfo", "direction start_xy axes cid cbar")
3100+
_ZoomInfo = namedtuple("_ZoomInfo", "button start_xy axes cid cbar")
30963101

30973102
def press_zoom(self, event):
30983103
"""Callback for mouse button press in zoom to rect mode."""
@@ -3117,11 +3122,17 @@ def press_zoom(self, event):
31173122
cbar = None
31183123

31193124
self._zoom_info = self._ZoomInfo(
3120-
direction="in" if event.button == 1 else "out",
3121-
start_xy=(event.x, event.y), axes=axes, cid=id_zoom, cbar=cbar)
3125+
button=event.button, start_xy=(event.x, event.y), axes=axes,
3126+
cid=id_zoom, cbar=cbar)
31223127

31233128
def drag_zoom(self, event):
31243129
"""Callback for dragging in zoom mode."""
3130+
if event.buttons != {self._zoom_info.button}:
3131+
# Zoom ended while canvas not in focus (it did not receive a
3132+
# button_release_event); cancel it.
3133+
self._cleanup_post_zoom()
3134+
return
3135+
31253136
start_xy = self._zoom_info.start_xy
31263137
ax = self._zoom_info.axes[0]
31273138
(x1, y1), (x2, y2) = np.clip(
@@ -3150,6 +3161,7 @@ def release_zoom(self, event):
31503161
self.remove_rubberband()
31513162

31523163
start_x, start_y = self._zoom_info.start_xy
3164+
direction = "in" if self._zoom_info.button == 1 else "out"
31533165
key = event.key
31543166
# Force the key on colorbars to ignore the zoom-cancel on the
31553167
# short-axis side
@@ -3161,8 +3173,7 @@ def release_zoom(self, event):
31613173
# "cancel" a zoom action by zooming by less than 5 pixels.
31623174
if ((abs(event.x - start_x) < 5 and key != "y") or
31633175
(abs(event.y - start_y) < 5 and key != "x")):
3164-
self.canvas.draw_idle()
3165-
self._zoom_info = None
3176+
self._cleanup_post_zoom()
31663177
return
31673178

31683179
for i, ax in enumerate(self._zoom_info.axes):
@@ -3174,11 +3185,18 @@ def release_zoom(self, event):
31743185
for prev in self._zoom_info.axes[:i])
31753186
ax._set_view_from_bbox(
31763187
(start_x, start_y, event.x, event.y),
3177-
self._zoom_info.direction, key, twinx, twiny)
3188+
direction, key, twinx, twiny)
3189+
3190+
self._cleanup_post_zoom()
3191+
self.push_current()
31783192

3193+
def _cleanup_post_zoom(self):
3194+
# We don't check the event button here, so that zooms can be cancelled
3195+
# by (pressing and) releasing another mouse button.
3196+
self.canvas.mpl_disconnect(self._zoom_info.cid)
3197+
self.remove_rubberband()
31793198
self.canvas.draw_idle()
31803199
self._zoom_info = None
3181-
self.push_current()
31823200

31833201
def push_current(self):
31843202
"""Push the current view limits and position onto the stack."""

‎lib/matplotlib/backend_bases.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.pyi
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ class NavigationToolbar2:
429429
def zoom(self, *args) -> None: ...
430430

431431
class _ZoomInfo(NamedTuple):
432-
direction: Literal["in", "out"]
432+
button: MouseButton
433433
start_xy: tuple[float, float]
434434
axes: list[Axes]
435435
cid: int

‎lib/matplotlib/tests/test_backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_backend_bases.py
+12-5Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,21 @@ def test_interactive_colorbar(plot_func, orientation, tool, button, expected):
260260
# Set up the mouse movements
261261
start_event = MouseEvent(
262262
"button_press_event", fig.canvas, *s0, button)
263+
drag_event = MouseEvent(
264+
"motion_notify_event", fig.canvas, *s1, button, buttons={button})
263265
stop_event = MouseEvent(
264266
"button_release_event", fig.canvas, *s1, button)
265267

266268
tb = NavigationToolbar2(fig.canvas)
267269
if tool == "zoom":
268270
tb.zoom()
269271
tb.press_zoom(start_event)
270-
tb.drag_zoom(stop_event)
272+
tb.drag_zoom(drag_event)
271273
tb.release_zoom(stop_event)
272274
else:
273275
tb.pan()
274276
tb.press_pan(start_event)
275-
tb.drag_pan(stop_event)
277+
tb.drag_pan(drag_event)
276278
tb.release_pan(stop_event)
277279

278280
# Should be close, but won't be exact due to screen integer resolution
@@ -395,14 +397,17 @@ def test_interactive_pan(key, mouseend, expectedxlim, expectedylim):
395397
start_event = MouseEvent(
396398
"button_press_event", fig.canvas, *sstart, button=MouseButton.LEFT,
397399
key=key)
400+
drag_event = MouseEvent(
401+
"motion_notify_event", fig.canvas, *send, button=MouseButton.LEFT,
402+
buttons={MouseButton.LEFT}, key=key)
398403
stop_event = MouseEvent(
399404
"button_release_event", fig.canvas, *send, button=MouseButton.LEFT,
400405
key=key)
401406

402407
tb = NavigationToolbar2(fig.canvas)
403408
tb.pan()
404409
tb.press_pan(start_event)
405-
tb.drag_pan(stop_event)
410+
tb.drag_pan(drag_event)
406411
tb.release_pan(stop_event)
407412
# Should be close, but won't be exact due to screen integer resolution
408413
assert tuple(ax.get_xlim()) == pytest.approx(expectedxlim, abs=0.02)
@@ -510,6 +515,8 @@ def test_interactive_pan_zoom_events(tool, button, patch_vis, forward_nav, t_s):
510515

511516
# Set up the mouse movements
512517
start_event = MouseEvent("button_press_event", fig.canvas, *s0, button)
518+
drag_event = MouseEvent(
519+
"motion_notify_event", fig.canvas, *s1, button, buttons={button})
513520
stop_event = MouseEvent("button_release_event", fig.canvas, *s1, button)
514521

515522
tb = NavigationToolbar2(fig.canvas)
@@ -534,7 +541,7 @@ def test_interactive_pan_zoom_events(tool, button, patch_vis, forward_nav, t_s):
534541

535542
tb.zoom()
536543
tb.press_zoom(start_event)
537-
tb.drag_zoom(stop_event)
544+
tb.drag_zoom(drag_event)
538545
tb.release_zoom(stop_event)
539546

540547
assert ax_t.get_xlim() == pytest.approx(xlim_t, abs=0.15)
@@ -570,7 +577,7 @@ def test_interactive_pan_zoom_events(tool, button, patch_vis, forward_nav, t_s):
570577

571578
tb.pan()
572579
tb.press_pan(start_event)
573-
tb.drag_pan(stop_event)
580+
tb.drag_pan(drag_event)
574581
tb.release_pan(stop_event)
575582

576583
assert ax_t.get_xlim() == pytest.approx(xlim_t, abs=0.15)

‎lib/mpl_toolkits/mplot3d/tests/test_axes3d.py

Copy file name to clipboardExpand all lines: lib/mpl_toolkits/mplot3d/tests/test_axes3d.py
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,19 +2130,21 @@ def test_toolbar_zoom_pan(tool, button, key, expected):
21302130
# Set up the mouse movements
21312131
start_event = MouseEvent(
21322132
"button_press_event", fig.canvas, *s0, button, key=key)
2133+
drag_event = MouseEvent(
2134+
"motion_notify_event", fig.canvas, *s1, button, key=key, buttons={button})
21332135
stop_event = MouseEvent(
21342136
"button_release_event", fig.canvas, *s1, button, key=key)
21352137

21362138
tb = NavigationToolbar2(fig.canvas)
21372139
if tool == "zoom":
21382140
tb.zoom()
21392141
tb.press_zoom(start_event)
2140-
tb.drag_zoom(stop_event)
2142+
tb.drag_zoom(drag_event)
21412143
tb.release_zoom(stop_event)
21422144
else:
21432145
tb.pan()
21442146
tb.press_pan(start_event)
2145-
tb.drag_pan(stop_event)
2147+
tb.drag_pan(drag_event)
21462148
tb.release_pan(stop_event)
21472149

21482150
# Should be close, but won't be exact due to screen integer resolution

0 commit comments

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