Skip to content

Commit

Permalink
fix axes key events to work w/o motion if the cursor is already over …
Browse files Browse the repository at this point in the history
…the axes when the window is raised
  • Loading branch information
jdh2358 committed Feb 26, 2012
1 parent c2d62b1 commit 91fdb41
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 2 deletions.
11 changes: 10 additions & 1 deletion lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1693,18 +1693,27 @@ def leave_notify_event(self, guiEvent=None):
the native UI event that generated the mpl event
"""

self.callbacks.process('figure_leave_event', LocationEvent.lastevent)
LocationEvent.lastevent = None
self._lastx, self._lasty = None, None

def enter_notify_event(self, guiEvent=None):
def enter_notify_event(self, guiEvent=None, xy=None):
"""
Backend derived classes should call this function when entering
canvas
*guiEvent*
the native UI event that generated the mpl event
*xy*
the coordinate location of the pointer when the canvas is
entered
"""
if xy is not None:
x, y = xy
self._lastx, self._lasty = x, y

event = Event('figure_enter_event', self, guiEvent)
self.callbacks.process('figure_enter_event', event)

Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/backends/backend_gtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ def leave_notify_event(self, widget, event):
FigureCanvasBase.leave_notify_event(self, event)

def enter_notify_event(self, widget, event):
FigureCanvasBase.enter_notify_event(self, event)
x, y, state = event.window.get_pointer()
FigureCanvasBase.enter_notify_event(self, event, xy=(x,y))

def _get_key(self, event):
if event.keyval in self.keyvald:
Expand Down
69 changes: 69 additions & 0 deletions lib/matplotlib/backends/backend_tkagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,75 @@ def resize(self, event):
self.resize_event()
self.show()

# a resizing will in general move the pointer position
# relative to the canvas, so process it as a motion notify
# event. An intended side effect of this call is to allow
# window raises (which trigger a resize) to get the cursor
# position to the mpl event framework so key presses which are
# over the axes will work w/o clicks or explicit motion
self._update_pointer_position(event)

def _update_pointer_position(self, guiEvent=None):
"""
Figure out if we are inside the canvas or not and update the
canvas enter/leave events
"""
# if the pointer if over the canvas, set the lastx and lasty
# attrs of the canvas so it can process event w/o mouse click
# or move

# the window's upper, left coords in screen coords
xw = self._tkcanvas.winfo_rootx()
yw = self._tkcanvas.winfo_rooty()
# the pointer's location in screen coords
xp, yp = self._tkcanvas.winfo_pointerxy()

# not figure out the canvas coordinates of the pointer
xc = xp - xw
yc = yp - yw

# flip top/bottom
yc = self.figure.bbox.height - yc

# JDH: this method was written originally to get the pointer
# location to the backend lastx and lasty attrs so that events
# like KeyEvent can be handled without mouse events. Eg, if
# the cursor is already above the axes, then key presses like
# 'g' should toggle the grid. In order for this to work in
# backend_bases, the canvas needs to know _lastx and _lasty.
# There are three ways to get this info the canvas:
#
# 1) set it explicity
#
# 2) call enter/leave events explicity. The downside of this
# in the impl below is that enter could be repeatedly
# triggered if thes mouse is over the axes and one is
# resizing with the keyboard. This is not entirely bad,
# because the mouse position relative to the canvas is
# changing, but it may be surprising to get repeated entries
# without leaves
#
# 3) process it as a motion notify event. This also has pros
# and cons. The mouse is moving relative to the window, but
# this may surpise an event handler writer who is getting
# motion_notify_events even if the mouse has not moved

# here are the three scenarios
if 1:
# just manually set it
self._lastx, self._lasty = xc, yc
elif 0:
# alternate implementation: process it as a motion
FigureCanvasBase.motion_notify_event(self, xc, yc, guiEvent)
elif 0:
# alternate implementation -- process enter/leave events
# instead of motion/notify
if self.figure.bbox.contains(xc, yc):
self.enter_notify_event(guiEvent, xy=(xc,yc))
else:
self.leave_notify_event(guiEvent)


def draw(self):
FigureCanvasAgg.draw(self)
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)
Expand Down

0 comments on commit 91fdb41

Please sign in to comment.