Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2d41a72

Browse files
committed
Simplify pan/zoom toggling.
- Store current active tool just in the .mode attribute, rather than both in .mode and ._active; use a "StrEnum" (like an IntEnum, but for strs...) for backcompat. - Connect a single handler which will dispatch to the correct sub-handler depending on the active tool, rather than having to disconnect and reconnect handlers every time a tool is changed.
1 parent f6b8891 commit 2d41a72

File tree

4 files changed

+48
-64
lines changed

4 files changed

+48
-64
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"""
3030

3131
from contextlib import contextmanager
32-
from enum import IntEnum
32+
from enum import Enum, IntEnum
3333
import functools
3434
import importlib
3535
import io
@@ -2651,6 +2651,15 @@ def set_window_title(self, title):
26512651
cursors = tools.cursors
26522652

26532653

2654+
class _Mode(str, Enum):
2655+
NONE = ""
2656+
PAN = "pan/zoom"
2657+
ZOOM = "zoom rect"
2658+
2659+
def __str__(self):
2660+
return self.value
2661+
2662+
26542663
class NavigationToolbar2:
26552664
"""
26562665
Base class for the navigation cursor, version 2
@@ -2715,19 +2724,20 @@ def __init__(self, canvas):
27152724
canvas.toolbar = self
27162725
self._nav_stack = cbook.Stack()
27172726
self._xypress = None # location and axis info at the time of the press
2718-
self._idPress = None
2719-
self._idRelease = None
2720-
self._active = None
27212727
# This cursor will be set after the initial draw.
27222728
self._lastCursor = cursors.POINTER
27232729
self._init_toolbar()
2730+
self._id_press = self.canvas.mpl_connect(
2731+
'button_press_event', self._zoom_pan_handler)
2732+
self._id_release = self.canvas.mpl_connect(
2733+
'button_release_event', self._zoom_pan_handler)
27242734
self._id_drag = self.canvas.mpl_connect(
27252735
'motion_notify_event', self.mouse_move)
27262736
self._zoom_info = None
27272737

27282738
self._button_pressed = None # determined by button pressed at start
27292739

2730-
self.mode = '' # a mode string for the status bar
2740+
self.mode = _Mode.NONE # a mode string for the status bar
27312741
self.set_history_buttons()
27322742

27332743
def set_message(self, s):
@@ -2805,17 +2815,17 @@ def _update_cursor(self, event):
28052815
"""
28062816
Update the cursor after a mouse move event or a tool (de)activation.
28072817
"""
2808-
if not event.inaxes or not self._active:
2818+
if not event.inaxes or not self.mode:
28092819
if self._lastCursor != cursors.POINTER:
28102820
self.set_cursor(cursors.POINTER)
28112821
self._lastCursor = cursors.POINTER
28122822
else:
2813-
if (self._active == 'ZOOM'
2823+
if (self.mode == _Mode.ZOOM
28142824
and self._lastCursor != cursors.SELECT_REGION):
28152825
self.set_cursor(cursors.SELECT_REGION)
28162826
self._lastCursor = cursors.SELECT_REGION
2817-
elif (self._active == 'PAN' and
2818-
self._lastCursor != cursors.MOVE):
2827+
elif (self.mode == _Mode.PAN
2828+
and self._lastCursor != cursors.MOVE):
28192829
self.set_cursor(cursors.MOVE)
28202830
self._lastCursor = cursors.MOVE
28212831

@@ -2870,40 +2880,32 @@ def mouse_move(self, event):
28702880
else:
28712881
self.set_message(self.mode)
28722882

2883+
def _zoom_pan_handler(self, event):
2884+
if self.mode == _Mode.PAN:
2885+
if event.name == "button_press_event":
2886+
self.press_pan(event)
2887+
elif event.name == "button_release_event":
2888+
self.release_pan(event)
2889+
if self.mode == _Mode.ZOOM:
2890+
if event.name == "button_press_event":
2891+
self.press_zoom(event)
2892+
elif event.name == "button_release_event":
2893+
self.release_zoom(event)
2894+
28732895
def pan(self, *args):
28742896
"""
2875-
Activate the pan/zoom tool.
2897+
Toggle the pan/zoom tool.
28762898
28772899
Pan with left button, zoom with right.
28782900
"""
2879-
# set the pointer icon and button press funcs to the
2880-
# appropriate callbacks
2881-
2882-
if self._active == 'PAN':
2883-
self._active = None
2901+
if self.mode == _Mode.PAN:
2902+
self.mode = _Mode.NONE
2903+
self.canvas.widgetlock.release(self)
28842904
else:
2885-
self._active = 'PAN'
2886-
if self._idPress is not None:
2887-
self._idPress = self.canvas.mpl_disconnect(self._idPress)
2888-
self.mode = ''
2889-
2890-
if self._idRelease is not None:
2891-
self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
2892-
self.mode = ''
2893-
2894-
if self._active:
2895-
self._idPress = self.canvas.mpl_connect(
2896-
'button_press_event', self.press_pan)
2897-
self._idRelease = self.canvas.mpl_connect(
2898-
'button_release_event', self.release_pan)
2899-
self.mode = 'pan/zoom'
2905+
self.mode = _Mode.PAN
29002906
self.canvas.widgetlock(self)
2901-
else:
2902-
self.canvas.widgetlock.release(self)
2903-
29042907
for a in self.canvas.figure.get_axes():
2905-
a.set_navigate_mode(self._active)
2906-
2908+
a.set_navigate_mode(self.mode)
29072909
self.set_message(self.mode)
29082910

29092911
def press(self, event):
@@ -3101,33 +3103,15 @@ def update(self):
31013103
self.set_history_buttons()
31023104

31033105
def zoom(self, *args):
3104-
"""Activate zoom to rect mode."""
3105-
if self._active == 'ZOOM':
3106-
self._active = None
3106+
"""Toggle zoom to rect mode."""
3107+
if self.mode == _Mode.ZOOM:
3108+
self.mode = _Mode.NONE
3109+
self.canvas.widgetlock.release(self)
31073110
else:
3108-
self._active = 'ZOOM'
3109-
3110-
if self._idPress is not None:
3111-
self._idPress = self.canvas.mpl_disconnect(self._idPress)
3112-
self.mode = ''
3113-
3114-
if self._idRelease is not None:
3115-
self._idRelease = self.canvas.mpl_disconnect(self._idRelease)
3116-
self.mode = ''
3117-
3118-
if self._active:
3119-
self._idPress = self.canvas.mpl_connect('button_press_event',
3120-
self.press_zoom)
3121-
self._idRelease = self.canvas.mpl_connect('button_release_event',
3122-
self.release_zoom)
3123-
self.mode = 'zoom rect'
3111+
self.mode = _Mode.ZOOM
31243112
self.canvas.widgetlock(self)
3125-
else:
3126-
self.canvas.widgetlock.release(self)
3127-
31283113
for a in self.canvas.figure.get_axes():
3129-
a.set_navigate_mode(self._active)
3130-
3114+
a.set_navigate_mode(self.mode)
31313115
self.set_message(self.mode)
31323116

31333117
def set_history_buttons(self):

lib/matplotlib/backends/backend_gtk3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ def _update_buttons_checked(self):
528528
button = self._gtk_ids.get(name)
529529
if button:
530530
with button.handler_block(button._signal_handler):
531-
button.set_active(self._active == active)
531+
button.set_active(self.mode.name == active)
532532

533533
def pan(self, *args):
534534
super().pan(*args)

lib/matplotlib/backends/backend_qt5.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,9 +745,9 @@ def edit_parameters(self):
745745
def _update_buttons_checked(self):
746746
# sync button checkstates to match active mode
747747
if 'pan' in self._actions:
748-
self._actions['pan'].setChecked(self._active == 'PAN')
748+
self._actions['pan'].setChecked(self.mode.name == 'PAN')
749749
if 'zoom' in self._actions:
750-
self._actions['zoom'].setChecked(self._active == 'ZOOM')
750+
self._actions['zoom'].setChecked(self.mode.name == 'ZOOM')
751751

752752
def pan(self, *args):
753753
super().pan(*args)

lib/matplotlib/backends/backend_wx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ def set_cursor(self, cursor):
12091209
self.canvas.Update()
12101210

12111211
def press(self, event):
1212-
if self._active == 'ZOOM':
1212+
if self.mode.name == 'ZOOM':
12131213
if not self.retinaFix:
12141214
self.wxoverlay = wx.Overlay()
12151215
else:
@@ -1221,7 +1221,7 @@ def press(self, event):
12211221
self.zoomAxes = event.inaxes
12221222

12231223
def release(self, event):
1224-
if self._active == 'ZOOM':
1224+
if self.mode.name == 'ZOOM':
12251225
# When the mouse is released we reset the overlay and it
12261226
# restores the former content to the window.
12271227
if not self.retinaFix:

0 commit comments

Comments
 (0)