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

Skip to content

Move set_cursor from the toolbar to FigureCanvas. #20620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/api/next_api_changes/deprecations/20620-ES.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
``NavigationToolbar2.set_cursor`` and ``backend_tools.SetCursorBase.set_cursor``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead, use the `.FigureCanvasBase.set_cursor` method on the canvas (available
as the ``canvas`` attribute on the toolbar or the Figure.)

``backend_tools.SetCursorBase`` and subclasses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``backend_tools.SetCursorBase`` was subclassed to provide backend-specific
implementations of ``set_cursor``. As that is now deprecated, the subclassing
is no longer necessary. Consequently, the following subclasses are also
deprecated:

- ``matplotlib.backends.backend_gtk3.SetCursorGTK3``
- ``matplotlib.backends.backend_qt5.SetCursorQt``
- ``matplotlib.backends._backend_tk.SetCursorTk``
- ``matplotlib.backends.backend_wx.SetCursorWx``

Instead, use the `.backend_tools.ToolSetCursor` class.
47 changes: 32 additions & 15 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,24 @@ def release_mouse(self, ax):
if self.mouse_grabber is ax:
self.mouse_grabber = None

def set_cursor(self, cursor):
"""
Set the current cursor.

This may have no effect if the backend does not display anything.

If required by the backend, this method should trigger an update in
the backend event loop after the cursor is set, as this method may be
called e.g. before a long-running task during which the GUI is not
updated.

Parameters
----------
cursor : `.Cursors`
The cursor to dispay over the canvas. Note: some backends may
change the cursor for the entire window.
"""

def draw(self, *args, **kwargs):
"""
Render the `.Figure`.
Expand Down Expand Up @@ -2864,9 +2882,6 @@ class NavigationToolbar2:
:meth:`save_figure`
save the current figure

:meth:`set_cursor`
if you want the pointer icon to change

:meth:`draw_rubberband` (optional)
draw the zoom to rect "rubberband" rectangle

Expand Down Expand Up @@ -2914,7 +2929,7 @@ def __init__(self, canvas):
canvas.toolbar = self
self._nav_stack = cbook.Stack()
# This cursor will be set after the initial draw.
self._lastCursor = cursors.POINTER
self._lastCursor = tools.Cursors.POINTER

self._id_press = self.canvas.mpl_connect(
'button_press_event', self._zoom_pan_handler)
Expand Down Expand Up @@ -2983,16 +2998,16 @@ def _update_cursor(self, event):
"""
if self.mode and event.inaxes and event.inaxes.get_navigate():
if (self.mode == _Mode.ZOOM
and self._lastCursor != cursors.SELECT_REGION):
self.set_cursor(cursors.SELECT_REGION)
self._lastCursor = cursors.SELECT_REGION
and self._lastCursor != tools.Cursors.SELECT_REGION):
self.canvas.set_cursor(tools.Cursors.SELECT_REGION)
self._lastCursor = tools.Cursors.SELECT_REGION
elif (self.mode == _Mode.PAN
and self._lastCursor != cursors.MOVE):
self.set_cursor(cursors.MOVE)
self._lastCursor = cursors.MOVE
elif self._lastCursor != cursors.POINTER:
self.set_cursor(cursors.POINTER)
self._lastCursor = cursors.POINTER
and self._lastCursor != tools.Cursors.MOVE):
self.canvas.set_cursor(tools.Cursors.MOVE)
self._lastCursor = tools.Cursors.MOVE
elif self._lastCursor != tools.Cursors.POINTER:
self.canvas.set_cursor(tools.Cursors.POINTER)
self._lastCursor = tools.Cursors.POINTER

@contextmanager
def _wait_cursor_for_draw_cm(self):
Expand All @@ -3009,10 +3024,10 @@ def _wait_cursor_for_draw_cm(self):
time.time(), getattr(self, "_draw_time", -np.inf))
if self._draw_time - last_draw_time > 1:
try:
self.set_cursor(cursors.WAIT)
self.canvas.set_cursor(tools.Cursors.WAIT)
yield
finally:
self.set_cursor(self._lastCursor)
self.canvas.set_cursor(self._lastCursor)
else:
yield

Expand Down Expand Up @@ -3230,6 +3245,7 @@ def save_figure(self, *args):
"""Save the current figure."""
raise NotImplementedError

@_api.deprecated("3.5", alternative="canvas.set_cursor")
def set_cursor(self, cursor):
"""
Set the current cursor to one of the :class:`Cursors` enums values.
Expand All @@ -3239,6 +3255,7 @@ def set_cursor(self, cursor):
called e.g. before a long-running task during which the GUI is not
updated.
"""
self.canvas.set_cursor(cursor)

def update(self):
"""Reset the axes stack."""
Expand Down
10 changes: 10 additions & 0 deletions lib/matplotlib/backend_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,16 @@ def add_tool(self, name, tool, *args, **kwargs):
'exists, not added')
return self._tools[name]

if name == 'cursor' and tool_cls != tools.SetCursorBase:
_api.warn_deprecated("3.5",
message="Overriding ToolSetCursor with "
f"{tool_cls.__qualname__} was only "
"necessary to provide the .set_cursor() "
"method, which is deprecated since "
"%(since)s and will be removed "
"%(removal)s. Please report this to the "
f"{tool_cls.__module__} author.")

tool_obj = tool_cls(self, name, *args, **kwargs)
self._tools[name] = tool_obj

Expand Down
18 changes: 11 additions & 7 deletions lib/matplotlib/backend_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import matplotlib as mpl
from matplotlib._pylab_helpers import Gcf
from matplotlib import cbook
from matplotlib import _api, cbook


class Cursors(enum.IntEnum): # Must subclass int for the macOS backend.
Expand Down Expand Up @@ -266,24 +266,28 @@ def _add_tool_cbk(self, event):
self._add_tool(event.tool)

def _set_cursor_cbk(self, event):
if not event:
if not event or not self.canvas:
return
if (self._current_tool and getattr(event, "inaxes", None)
and event.inaxes.get_navigate()):
if self._last_cursor != self._current_tool.cursor:
self.set_cursor(self._current_tool.cursor)
self.canvas.set_cursor(self._current_tool.cursor)
self._last_cursor = self._current_tool.cursor
elif self._last_cursor != self._default_cursor:
self.set_cursor(self._default_cursor)
self.canvas.set_cursor(self._default_cursor)
self._last_cursor = self._default_cursor

@_api.deprecated("3.5", alternative="figure.canvas.set_cursor")
def set_cursor(self, cursor):
"""
Set the cursor.

This method has to be implemented per backend.
"""
raise NotImplementedError
self.canvas.set_cursor(cursor)


# This exists solely for deprecation warnings; remove with
# SetCursorBase.set_cursor.
ToolSetCursor = SetCursorBase


class ToolCursorPosition(ToolBase):
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/_backend_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ def remove_rubberband(self):
del self.lastrect


@_api.deprecated("3.5", alternative="ToolSetCursor")
class SetCursorTk(backend_tools.SetCursorBase):
def set_cursor(self, cursor):
NavigationToolbar2Tk.set_cursor(
Expand Down Expand Up @@ -907,7 +908,6 @@ def trigger(self, *args):

backend_tools.ToolSaveFigure = SaveFigureTk
backend_tools.ToolConfigureSubplots = ConfigureSubplotsTk
backend_tools.ToolSetCursor = SetCursorTk
backend_tools.ToolRubberband = RubberbandTk
backend_tools.ToolHelp = HelpTk
backend_tools.ToolCopyToClipboard = backend_tools.ToolCopyToClipboardBase
Expand Down
21 changes: 11 additions & 10 deletions lib/matplotlib/backends/backend_gtk3.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ def _create_application():

@functools.lru_cache()
def _mpl_to_gtk_cursor(mpl_cursor):
name = {
name = _api.check_getitem({
Cursors.MOVE: "move",
Cursors.HAND: "pointer",
Cursors.POINTER: "default",
Cursors.SELECT_REGION: "crosshair",
Cursors.WAIT: "wait",
Cursors.RESIZE_HORIZONTAL: "ew-resize",
Cursors.RESIZE_VERTICAL: "ns-resize",
}[mpl_cursor]
}, cursor=mpl_cursor)
return Gdk.Cursor.new_from_name(Gdk.Display.get_default(), name)


Expand Down Expand Up @@ -188,6 +188,14 @@ def __init__(self, figure=None):
def destroy(self):
self.close_event()

def set_cursor(self, cursor):
# docstring inherited
window = self.get_property("window")
if window is not None:
window.set_cursor(_mpl_to_gtk_cursor(cursor))
context = GLib.MainContext.default()
context.iteration(True)

def scroll_event(self, widget, event):
x = event.x
# flipy so y=0 is bottom of canvas
Expand Down Expand Up @@ -533,13 +541,6 @@ def set_message(self, s):
escaped = GLib.markup_escape_text(s)
self.message.set_markup(f'<small>{escaped}</small>')

def set_cursor(self, cursor):
window = self.canvas.get_property("window")
if window is not None:
window.set_cursor(_mpl_to_gtk_cursor(cursor))
context = GLib.MainContext.default()
context.iteration(True)

def draw_rubberband(self, event, x0, y0, x1, y1):
height = self.canvas.figure.bbox.height
y1 = height - y1
Expand Down Expand Up @@ -717,6 +718,7 @@ class PseudoToolbar:
return NavigationToolbar2GTK3.save_figure(PseudoToolbar())


@_api.deprecated("3.5", alternative="ToolSetCursor")
class SetCursorGTK3(backend_tools.SetCursorBase):
def set_cursor(self, cursor):
NavigationToolbar2GTK3.set_cursor(
Expand Down Expand Up @@ -850,7 +852,6 @@ def error_msg_gtk(msg, parent=None):

backend_tools.ToolSaveFigure = SaveFigureGTK3
backend_tools.ToolConfigureSubplots = ConfigureSubplotsGTK3
backend_tools.ToolSetCursor = SetCursorGTK3
backend_tools.ToolRubberband = RubberbandGTK3
backend_tools.ToolHelp = HelpGTK3
backend_tools.ToolCopyToClipboard = ToolCopyToClipboardGTK3
Expand Down
7 changes: 4 additions & 3 deletions lib/matplotlib/backends/backend_macosx.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def _set_device_scale(self, value):
self._dpi_ratio, old_value = value, self._dpi_ratio
self.figure.dpi = self.figure.dpi / old_value * self._dpi_ratio

def set_cursor(self, cursor):
# docstring inherited
_macosx.set_cursor(cursor)

def _draw(self):
renderer = self.get_renderer(cleared=self.figure.stale)
if self.figure.stale:
Expand Down Expand Up @@ -108,9 +112,6 @@ def release_zoom(self, event):
super().release_zoom(event)
self.canvas.remove_rubberband()

def set_cursor(self, cursor):
_macosx.set_cursor(cursor)

def save_figure(self, *args):
filename = _macosx.choose_save_file('Save the figure',
self.canvas.get_default_filename())
Expand Down
9 changes: 5 additions & 4 deletions lib/matplotlib/backends/backend_qt5.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ def showEvent(self, event):
window.screenChanged.connect(self._update_screen)
self._update_screen(window.screen())

def set_cursor(self, cursor):
# docstring inherited
self.setCursor(_api.check_getitem(cursord, cursor=cursor))

def enterEvent(self, event):
try:
x, y = self.mouseEventCoords(event.pos())
Expand Down Expand Up @@ -702,9 +706,6 @@ def set_message(self, s):
if self.coordinates:
self.locLabel.setText(s)

def set_cursor(self, cursor):
self.canvas.setCursor(cursord[cursor])

def draw_rubberband(self, event, x0, y0, x1, y1):
height = self.canvas.figure.bbox.height
y1 = height - y1
Expand Down Expand Up @@ -931,6 +932,7 @@ def trigger(self, *args):
self._make_classic_style_pseudo_toolbar())


@_api.deprecated("3.5", alternative="ToolSetCursor")
class SetCursorQt(backend_tools.SetCursorBase):
def set_cursor(self, cursor):
NavigationToolbar2QT.set_cursor(
Expand Down Expand Up @@ -960,7 +962,6 @@ def trigger(self, *args, **kwargs):

backend_tools.ToolSaveFigure = SaveFigureQt
backend_tools.ToolConfigureSubplots = ConfigureSubplotsQt
backend_tools.ToolSetCursor = SetCursorQt
backend_tools.ToolRubberband = RubberbandQt
backend_tools.ToolHelp = HelpQt
backend_tools.ToolCopyToClipboard = ToolCopyToClipboardQT
Expand Down
31 changes: 16 additions & 15 deletions lib/matplotlib/backends/backend_webagg_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,19 @@ def blit(self, bbox=None):
def draw_idle(self):
self.send_event("draw")

def set_cursor(self, cursor):
# docstring inherited
cursor = _api.check_getitem({
backend_tools.Cursors.HAND: 'pointer',
backend_tools.Cursors.POINTER: 'default',
backend_tools.Cursors.SELECT_REGION: 'crosshair',
backend_tools.Cursors.MOVE: 'move',
backend_tools.Cursors.WAIT: 'wait',
backend_tools.Cursors.RESIZE_HORIZONTAL: 'ew-resize',
backend_tools.Cursors.RESIZE_VERTICAL: 'ns-resize',
}, cursor=cursor)
self.send_event('cursor', cursor=cursor)

def set_image_mode(self, mode):
"""
Set the image mode for any subsequent images which will be sent
Expand Down Expand Up @@ -362,30 +375,18 @@ class NavigationToolbar2WebAgg(backend_bases.NavigationToolbar2):
if name_of_method in _ALLOWED_TOOL_ITEMS
]

cursor = _api.deprecate_privatize_attribute("3.5")

def __init__(self, canvas):
self.message = ''
self.cursor = None
self._cursor = None # Remove with deprecation.
super().__init__(canvas)

def set_message(self, message):
if message != self.message:
self.canvas.send_event("message", message=message)
self.message = message

def set_cursor(self, cursor):
if cursor != self.cursor:
cursor = {
backend_tools.Cursors.HAND: 'pointer',
backend_tools.Cursors.POINTER: 'default',
backend_tools.Cursors.SELECT_REGION: 'crosshair',
backend_tools.Cursors.MOVE: 'move',
backend_tools.Cursors.WAIT: 'wait',
backend_tools.Cursors.RESIZE_HORIZONTAL: 'ew-resize',
backend_tools.Cursors.RESIZE_VERTICAL: 'ns-resize',
}[cursor]
self.canvas.send_event("cursor", cursor=cursor)
self.cursor = cursor

def draw_rubberband(self, event, x0, y0, x1, y1):
self.canvas.send_event(
"rubberband", x0=x0, y0=y0, x1=x1, y1=y1)
Expand Down
Loading