Skip to content

Commit 91fdb41

Browse files
committed
fix axes key events to work w/o motion if the cursor is already over the axes when the window is raised
1 parent c2d62b1 commit 91fdb41

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1693,18 +1693,27 @@ def leave_notify_event(self, guiEvent=None):
16931693
the native UI event that generated the mpl event
16941694
16951695
"""
1696+
16961697
self.callbacks.process('figure_leave_event', LocationEvent.lastevent)
16971698
LocationEvent.lastevent = None
1699+
self._lastx, self._lasty = None, None
16981700

1699-
def enter_notify_event(self, guiEvent=None):
1701+
def enter_notify_event(self, guiEvent=None, xy=None):
17001702
"""
17011703
Backend derived classes should call this function when entering
17021704
canvas
17031705
17041706
*guiEvent*
17051707
the native UI event that generated the mpl event
1708+
*xy*
1709+
the coordinate location of the pointer when the canvas is
1710+
entered
17061711
17071712
"""
1713+
if xy is not None:
1714+
x, y = xy
1715+
self._lastx, self._lasty = x, y
1716+
17081717
event = Event('figure_enter_event', self, guiEvent)
17091718
self.callbacks.process('figure_enter_event', event)
17101719

lib/matplotlib/backends/backend_gtk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ def leave_notify_event(self, widget, event):
312312
FigureCanvasBase.leave_notify_event(self, event)
313313

314314
def enter_notify_event(self, widget, event):
315-
FigureCanvasBase.enter_notify_event(self, event)
315+
x, y, state = event.window.get_pointer()
316+
FigureCanvasBase.enter_notify_event(self, event, xy=(x,y))
316317

317318
def _get_key(self, event):
318319
if event.keyval in self.keyvald:

lib/matplotlib/backends/backend_tkagg.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,75 @@ def resize(self, event):
237237
self.resize_event()
238238
self.show()
239239

240+
# a resizing will in general move the pointer position
241+
# relative to the canvas, so process it as a motion notify
242+
# event. An intended side effect of this call is to allow
243+
# window raises (which trigger a resize) to get the cursor
244+
# position to the mpl event framework so key presses which are
245+
# over the axes will work w/o clicks or explicit motion
246+
self._update_pointer_position(event)
247+
248+
def _update_pointer_position(self, guiEvent=None):
249+
"""
250+
Figure out if we are inside the canvas or not and update the
251+
canvas enter/leave events
252+
"""
253+
# if the pointer if over the canvas, set the lastx and lasty
254+
# attrs of the canvas so it can process event w/o mouse click
255+
# or move
256+
257+
# the window's upper, left coords in screen coords
258+
xw = self._tkcanvas.winfo_rootx()
259+
yw = self._tkcanvas.winfo_rooty()
260+
# the pointer's location in screen coords
261+
xp, yp = self._tkcanvas.winfo_pointerxy()
262+
263+
# not figure out the canvas coordinates of the pointer
264+
xc = xp - xw
265+
yc = yp - yw
266+
267+
# flip top/bottom
268+
yc = self.figure.bbox.height - yc
269+
270+
# JDH: this method was written originally to get the pointer
271+
# location to the backend lastx and lasty attrs so that events
272+
# like KeyEvent can be handled without mouse events. Eg, if
273+
# the cursor is already above the axes, then key presses like
274+
# 'g' should toggle the grid. In order for this to work in
275+
# backend_bases, the canvas needs to know _lastx and _lasty.
276+
# There are three ways to get this info the canvas:
277+
#
278+
# 1) set it explicity
279+
#
280+
# 2) call enter/leave events explicity. The downside of this
281+
# in the impl below is that enter could be repeatedly
282+
# triggered if thes mouse is over the axes and one is
283+
# resizing with the keyboard. This is not entirely bad,
284+
# because the mouse position relative to the canvas is
285+
# changing, but it may be surprising to get repeated entries
286+
# without leaves
287+
#
288+
# 3) process it as a motion notify event. This also has pros
289+
# and cons. The mouse is moving relative to the window, but
290+
# this may surpise an event handler writer who is getting
291+
# motion_notify_events even if the mouse has not moved
292+
293+
# here are the three scenarios
294+
if 1:
295+
# just manually set it
296+
self._lastx, self._lasty = xc, yc
297+
elif 0:
298+
# alternate implementation: process it as a motion
299+
FigureCanvasBase.motion_notify_event(self, xc, yc, guiEvent)
300+
elif 0:
301+
# alternate implementation -- process enter/leave events
302+
# instead of motion/notify
303+
if self.figure.bbox.contains(xc, yc):
304+
self.enter_notify_event(guiEvent, xy=(xc,yc))
305+
else:
306+
self.leave_notify_event(guiEvent)
307+
308+
240309
def draw(self):
241310
FigureCanvasAgg.draw(self)
242311
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)

0 commit comments

Comments
 (0)