Browse files

Merge pull request #851 from pelson/quitkey

Simple GUI interface enhancements
  • Loading branch information...
2 parents dc19faa + d7a4ae2 commit 5b90a27aeda308a7dcbf70d5cc7a0612b3bb41e5 @efiring efiring committed Jul 1, 2012
View
23 doc/users/navigation_toolbar.rst
@@ -83,23 +83,24 @@ Navigation Keyboard Shortcuts
The following table holds all the default keys, which can be overwritten by use of your matplotlibrc (#keymap.\*).
-================================== ==============================================
+================================== =================================================
Command Keyboard Shortcut(s)
-================================== ==============================================
+================================== =================================================
Home/Reset **h** or **r** or **home**
Back **c** or **left arrow** or **backspace**
Forward **v** or **right arrow**
Pan/Zoom **p**
Zoom-to-rect **o**
-Save **s**
-Toggle fullscreen **f**
-Constrain pan/zoom to x axis hold **x**
-Constrain pan/zoom to y axis hold **y**
-Preserve aspect ratio hold **CONTROL**
-Toggle grid **g**
-Toggle x axis scale (log/linear) **L** or **k**
-Toggle y axis scale (log/linear) **l**
-================================== ==============================================
+Save **ctrl** + **s**
+Toggle fullscreen **ctrl** + **f**
+Close plot **ctrl** + **w**
+Constrain pan/zoom to x axis hold **x** when panning/zooming with mouse
+Constrain pan/zoom to y axis hold **y** when panning/zooming with mouse
+Preserve aspect ratio hold **CONTROL** when panning/zooming with mouse
+Toggle grid **g** when mouse is over an axes
+Toggle x axis scale (log/linear) **L** or **k** when mouse is over an axes
+Toggle y axis scale (log/linear) **l** when mouse is over an axes
+================================== =================================================
If you are using :mod:`matplotlib.pyplot` the toolbar will be created
automatically for every figure. If you are writing your own user
View
165 lib/matplotlib/backend_bases.py
@@ -1190,6 +1190,7 @@ class CloseEvent(Event):
def __init__(self, name, canvas, guiEvent=None):
Event.__init__(self, name, canvas, guiEvent)
+
class LocationEvent(Event):
"""
An event that has a screen location
@@ -1295,9 +1296,6 @@ def _update_enter_leave(self):
LocationEvent.lastevent = self
-
-
-
class MouseEvent(LocationEvent):
"""
A mouse event ('button_press_event', 'button_release_event', 'scroll_event',
@@ -1307,10 +1305,12 @@ class MouseEvent(LocationEvent):
attributes, the following attributes are defined:
*button*
- button pressed None, 1, 2, 3, 'up', 'down' (up and down are used for scroll events)
+ button pressed None, 1, 2, 3, 'up', 'down' (up and down are used
+ for scroll events)
*key*
- the key pressed: None, chr(range(255), 'shift', 'win', or 'control'
+ the key depressed when the mouse event triggered (see
+ :class:`KeyEvent`)
*step*
number of scroll steps (positive for 'up', negative for 'down')
@@ -1319,7 +1319,7 @@ class MouseEvent(LocationEvent):
Example usage::
def on_press(event):
- print 'you pressed', event.button, event.xdata, event.ydata
+ print('you pressed', event.button, event.xdata, event.ydata)
cid = fig.canvas.mpl_connect('button_press_event', on_press)
@@ -1346,8 +1346,10 @@ def __init__(self, name, canvas, x, y, button=None, key=None,
self.dblclick = dblclick
def __str__(self):
- return "MPL MouseEvent: xy=(%d,%d) xydata=(%s,%s) button=%d dblclick=%s inaxes=%s"%\
- (self.x,self.y,str(self.xdata),str(self.ydata),self.button,self.dblclick,self.inaxes)
+ return ("MPL MouseEvent: xy=(%d,%d) xydata=(%s,%s) button=%d " +
+ "dblclick=%s inaxes=%s") % (self.x, self.y, self.xdata,
+ self.ydata, self.button, self.dblclick, self.inaxes)
+
class PickEvent(Event):
"""
@@ -1377,7 +1379,7 @@ def on_pick(event):
thisline = event.artist
xdata, ydata = thisline.get_data()
ind = event.ind
- print 'on pick line:', zip(xdata[ind], ydata[ind])
+ print('on pick line:', zip(xdata[ind], ydata[ind]))
cid = fig.canvas.mpl_connect('pick_event', on_pick)
@@ -1400,16 +1402,23 @@ class KeyEvent(LocationEvent):
attributes, the following attributes are defined:
*key*
- the key pressed: None, chr(range(255), shift, win, or control
-
- This interface may change slightly when better support for
- modifier keys is included.
-
-
+ the key(s) pressed. Could be **None**, a single case sensitive ascii
+ character ("g", "G", "#", etc.), a special key
+ ("control", "shift", "f1", "up", etc.) or a
+ combination of the above (e.g. "ctrl+alt+g", "ctrl+alt+G").
+
+ .. note::
+
+ Modifier keys will be prefixed to the pressed key and will be in the
+ order "ctrl", "alt", "super". The exception to this rule is when the
+ pressed key is itself a modifier key, therefore "ctrl+alt" and
+ "alt+control" can both be valid key values.
+
+
Example usage::
def on_key(event):
- print 'you pressed', event.key, event.xdata, event.ydata
+ print('you pressed', event.key, event.xdata, event.ydata)
cid = fig.canvas.mpl_connect('key_press_event', on_key)
@@ -1419,7 +1428,6 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):
self.key = key
-
class FigureCanvasBase(object):
"""
The canvas the figure renders into.
@@ -1448,7 +1456,6 @@ class FigureCanvasBase(object):
'close_event'
]
-
def __init__(self, figure):
figure.set_canvas(self)
self.figure = figure
@@ -1657,7 +1664,8 @@ def button_press_event(self, x, y, button, dblclick=False, guiEvent=None):
"""
self._button = button
s = 'button_press_event'
- mouseevent = MouseEvent(s, self, x, y, button, self._key, dblclick=dblclick, guiEvent=guiEvent)
+ mouseevent = MouseEvent(s, self, x, y, button, self._key,
+ dblclick=dblclick, guiEvent=guiEvent)
self.callbacks.process(s, mouseevent)
def button_release_event(self, x, y, button, guiEvent=None):
@@ -1743,7 +1751,7 @@ def enter_notify_event(self, guiEvent=None, xy=None):
self.callbacks.process('figure_enter_event', event)
def idle_event(self, guiEvent=None):
- 'call when GUI is idle'
+ """Called when GUI is idle."""
s = 'idle_event'
event = IdleEvent(s, self, guiEvent=guiEvent)
self.callbacks.process(s, event)
@@ -1789,7 +1797,7 @@ def draw_cursor(self, event):
def get_width_height(self):
"""
- return the figure width and height in points or pixels
+ Return the figure width and height in points or pixels
(depending on the backend), truncated to integers
"""
return int(self.figure.bbox.width), int(self.figure.bbox.height)
@@ -1911,7 +1919,6 @@ def get_supported_filetypes_grouped(self):
groupings[name].sort()
return groupings
-
def _get_print_method(self, format):
method_name = 'print_%s' % format
@@ -1936,7 +1943,6 @@ def _print_method(*args, **kwargs):
return getattr(self, method_name)
-
def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
orientation='portrait', format=None, **kwargs):
"""
@@ -2078,9 +2084,6 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
#self.figure.canvas.draw() ## seems superfluous
return result
-
-
-
def get_default_filetype(self):
"""
Get the default savefig file format as specified in rcParam
@@ -2099,7 +2102,7 @@ def set_window_title(self, title):
def switch_backends(self, FigureCanvasClass):
"""
- instantiate an instance of FigureCanvasClass
+ Instantiate an instance of FigureCanvasClass
This is used for backend switching, eg, to instantiate a
FigureCanvasPS from a FigureCanvasGTK. Note, deep copying is
@@ -2148,7 +2151,7 @@ def func(event)
Example usage::
def on_press(event):
- print 'you pressed', event.button, event.xdata, event.ydata
+ print('you pressed', event.button, event.xdata, event.ydata)
cid = canvas.mpl_connect('button_press_event', on_press)
@@ -2158,7 +2161,7 @@ def on_press(event):
def mpl_disconnect(self, cid):
"""
- disconnect callback id cid
+ Disconnect callback id cid
Example usage::
@@ -2274,9 +2277,6 @@ def key_press_handler(event, canvas, toolbar=None):
"""
# these bindings happen whether you are over an axes or not
- #if event.key == 'q':
- # self.destroy() # how cruel to have to destroy oneself!
- # return
if event.key is None:
return
@@ -2289,6 +2289,7 @@ def key_press_handler(event, canvas, toolbar=None):
pan_keys = rcParams['keymap.pan']
zoom_keys = rcParams['keymap.zoom']
save_keys = rcParams['keymap.save']
+ quit_keys = rcParams['keymap.quit']
grid_keys = rcParams['keymap.grid']
toggle_yscale_keys = rcParams['keymap.yscale']
toggle_xscale_keys = rcParams['keymap.xscale']
@@ -2298,6 +2299,10 @@ def key_press_handler(event, canvas, toolbar=None):
if event.key in fullscreen_keys:
canvas.manager.full_screen_toggle()
+ # quit the figure (defaut key 'ctrl+w')
+ if event.key in quit_keys:
+ Gcf.destroy_fig(canvas.figure)
+
if toolbar is not None:
# home or reset mnemonic (default key 'h', 'home' and 'r')
if event.key in home_keys:
@@ -2322,7 +2327,8 @@ def key_press_handler(event, canvas, toolbar=None):
if event.inaxes is None:
return
- # the mouse has to be over an axes to trigger these
+ # these bindings require the mouse to be over an axes to trigger
+
# switching on/off a grid in current axes (default key 'g')
if event.key in grid_keys:
event.inaxes.grid()
@@ -2387,16 +2393,16 @@ def __init__(self, canvas, num):
def destroy(self):
pass
- def full_screen_toggle (self):
+ def full_screen_toggle(self):
pass
def resize(self, w, h):
- 'For gui backends: resize window in pixels'
+ """"For gui backends, resize the window (in pixels)."""
pass
def key_press(self, event):
"""
- implement the default mpl key bindings defined at
+ Implement the default mpl key bindings defined at
:ref:`key-event-handling`
"""
key_press_handler(event, self.canvas, self.canvas.toolbar)
@@ -2414,13 +2420,13 @@ def set_window_title(self, title):
"""
pass
-# cursors
-class Cursors: #namespace
+
+class Cursors:
+ # this class is only used as a simple namespace
HAND, POINTER, SELECT_REGION, MOVE = range(4)
cursors = Cursors()
-
class NavigationToolbar2(object):
"""
Base class for the navigation cursor, version 2
@@ -2464,6 +2470,25 @@ class NavigationToolbar2(object):
That's it, we'll do the rest!
"""
+
+ # list of toolitems to add to the toolbar, format is:
+ # (
+ # text, # the text of the button (often not visible to users)
+ # tooltip_text, # the tooltip shown on hover (where possible)
+ # image_file, # name of the image for the button (without the extension)
+ # name_of_method, # name of the method in NavigationToolbar2 to call
+ # )
+ toolitems = (
+ ('Home', 'Reset original view', 'home', 'home'),
+ ('Back', 'Back to previous view', 'back', 'back'),
+ ('Forward', 'Forward to next view', 'forward', 'forward'),
+ (None, None, None, None),
+ ('Pan', 'Pan axes with left mouse, zoom with right', 'move', 'pan'),
+ ('Zoom', 'Zoom to rectangle', 'zoom_to_rect', 'zoom'),
+ (None, None, None, None),
+ ('Subplots', 'Configure subplots', 'subplots', 'configure_subplots'),
+ ('Save', 'Save the figure', 'filesave', 'save_figure'),
+ )
def __init__(self, canvas):
self.canvas = canvas
@@ -2488,11 +2513,11 @@ def __init__(self, canvas):
self.set_history_buttons()
def set_message(self, s):
- 'display a message on toolbar or in status bar'
+ """Display a message on toolbar or in status bar"""
pass
def back(self, *args):
- 'move back up the view lim stack'
+ """move back up the view lim stack"""
self._views.back()
self._positions.back()
self.set_history_buttons()
@@ -2502,18 +2527,18 @@ def dynamic_update(self):
pass
def draw_rubberband(self, event, x0, y0, x1, y1):
- 'draw a rectangle rubberband to indicate zoom limits'
+ """Draw a rectangle rubberband to indicate zoom limits"""
pass
def forward(self, *args):
- 'move forward in the view lim stack'
+ """Move forward in the view lim stack"""
self._views.forward()
self._positions.forward()
self.set_history_buttons()
self._update_view()
def home(self, *args):
- 'restore the original view'
+ """Restore the original view"""
self._views.home()
self._positions.home()
self.set_history_buttons()
@@ -2542,8 +2567,6 @@ class implementation.
raise NotImplementedError
def mouse_move(self, event):
- #print 'mouse_move', event.button
-
if not event.inaxes or not self._active:
if self._lastCursor != cursors.POINTER:
self.set_cursor(cursors.POINTER)
@@ -2561,9 +2584,10 @@ def mouse_move(self, event):
if event.inaxes and event.inaxes.get_navigate():
- try: s = event.inaxes.format_coord(event.xdata, event.ydata)
- except ValueError: pass
- except OverflowError: pass
+ try:
+ s = event.inaxes.format_coord(event.xdata, event.ydata)
+ except (ValueError, OverflowError):
+ pass
else:
if len(self.mode):
self.set_message('%s, %s' % (self.mode, s))
@@ -2572,7 +2596,7 @@ def mouse_move(self, event):
else: self.set_message(self.mode)
def pan(self,*args):
- 'Activate the pan/zoom tool. pan with left button, zoom with right'
+ """Activate the pan/zoom tool. pan with left button, zoom with right"""
# set the pointer icon and button press funcs to the
# appropriate callbacks
@@ -2604,11 +2628,11 @@ def pan(self,*args):
self.set_message(self.mode)
def press(self, event):
- 'this will be called whenver a mouse button is pressed'
+ """Called whenver a mouse button is pressed."""
pass
def press_pan(self, event):
- 'the press mouse button in pan/zoom mode callback'
+ """the press mouse button in pan/zoom mode callback"""
if event.button == 1:
self._button_pressed=1
@@ -2636,7 +2660,7 @@ def press_pan(self, event):
self.press(event)
def press_zoom(self, event):
- 'the press mouse button in zoom to rect mode callback'
+ """the press mouse button in zoom to rect mode callback"""
if event.button == 1:
self._button_pressed=1
elif event.button == 3:
@@ -2658,17 +2682,14 @@ def press_zoom(self, event):
a.transData.frozen() ))
id1 = self.canvas.mpl_connect('motion_notify_event', self.drag_zoom)
-
id2 = self.canvas.mpl_connect('key_press_event',
self._switch_on_zoom_mode)
id3 = self.canvas.mpl_connect('key_release_event',
self._switch_off_zoom_mode)
self._ids_zoom = id1, id2, id3
-
self._zoom_mode = event.key
-
self.press(event)
def _switch_on_zoom_mode(self, event):
@@ -2680,7 +2701,7 @@ def _switch_off_zoom_mode(self, event):
self.mouse_move(event)
def push_current(self):
- 'push the current view limits and position onto the stack'
+ """push the current view limits and position onto the stack"""
lims = []; pos = []
for a in self.canvas.figure.get_axes():
xmin, xmax = a.get_xlim()
@@ -2695,11 +2716,11 @@ def push_current(self):
self.set_history_buttons()
def release(self, event):
- 'this will be called whenever mouse button is released'
+ """this will be called whenever mouse button is released"""
pass
def release_pan(self, event):
- 'the release mouse button callback in pan/zoom mode'
+ """the release mouse button callback in pan/zoom mode"""
if self._button_pressed is None:
return
@@ -2715,7 +2736,7 @@ def release_pan(self, event):
self.draw()
def drag_pan(self, event):
- 'the drag callback in pan/zoom mode'
+ """the drag callback in pan/zoom mode"""
for a, ind in self._xypress:
#safer to use the recorded button at the press than current button:
@@ -2724,7 +2745,7 @@ def drag_pan(self, event):
self.dynamic_update()
def drag_zoom(self, event):
- 'the drag callback in zoom mode'
+ """the drag callback in zoom mode"""
if self._xypress:
x, y = event.x, event.y
@@ -2744,10 +2765,8 @@ def drag_zoom(self, event):
self.draw_rubberband(event, x, y, lastx, lasty)
-
-
def release_zoom(self, event):
- 'the release mouse button callback in zoom to rect mode'
+ """the release mouse button callback in zoom to rect mode"""
for zoom_id in self._ids_zoom:
self.canvas.mpl_disconnect(zoom_id)
self._ids_zoom = []
@@ -2855,7 +2874,7 @@ def release_zoom(self, event):
self.release(event)
def draw(self):
- 'redraw the canvases, update the locators'
+ """Redraw the canvases, update the locators"""
for a in self.canvas.figure.get_axes():
xaxis = getattr(a, 'xaxis', None)
yaxis = getattr(a, 'yaxis', None)
@@ -2871,12 +2890,10 @@ def draw(self):
loc.refresh()
self.canvas.draw()
-
-
def _update_view(self):
- '''update the viewlim and position from the view and
+ """Update the viewlim and position from the view and
position stack for each axes
- '''
+ """
lims = self._views()
if lims is None: return
@@ -2892,9 +2909,8 @@ def _update_view(self):
self.draw()
-
def save_figure(self, *args):
- 'save the current figure'
+ """Save the current figure"""
raise NotImplementedError
def set_cursor(self, cursor):
@@ -2905,13 +2921,13 @@ def set_cursor(self, cursor):
pass
def update(self):
- 'reset the axes stack'
+ """Reset the axes stack"""
self._views.clear()
self._positions.clear()
self.set_history_buttons()
def zoom(self, *args):
- 'activate zoom to rect mode'
+ """Activate zoom to rect mode"""
if self._active == 'ZOOM':
self._active = None
else:
@@ -2938,7 +2954,6 @@ def zoom(self, *args):
self.set_message(self.mode)
-
def set_history_buttons(self):
- 'enable or disable back/forward button'
+ """Enable or disable back/forward button"""
pass
View
2 lib/matplotlib/backends/backend_fltkagg.py
@@ -136,6 +136,8 @@ def handle(self, event):
self._key=special_key[ikey]
except:
self._key=None
+
+ # TODO: Handle ctrl, alt, super modifiers.
FigureCanvasBase.key_press_event(self._source, self._key)
return 1
elif event == Fltk.FL_KEYUP:
View
35 lib/matplotlib/backends/backend_gtk.py
@@ -189,6 +189,10 @@ class FigureCanvasGTK (gtk.DrawingArea, FigureCanvasBase):
65455 : '/',
65439 : 'dec',
65421 : 'enter',
+ 65511 : 'super',
+ 65512 : 'super',
+ 65406 : 'alt',
+ 65289 : 'tab',
}
# Setting this as a static constant prevents
@@ -322,16 +326,20 @@ def enter_notify_event(self, widget, event):
def _get_key(self, event):
if event.keyval in self.keyvald:
key = self.keyvald[event.keyval]
- elif event.keyval <256:
+ elif event.keyval < 256:
key = chr(event.keyval)
else:
key = None
-
- ctrl = event.state & gdk.CONTROL_MASK
- shift = event.state & gdk.SHIFT_MASK
+
+ for key_mask, prefix in (
+ [gdk.MOD4_MASK, 'super'],
+ [gdk.MOD1_MASK, 'alt'],
+ [gdk.CONTROL_MASK, 'ctrl'],):
+ if event.state & key_mask:
+ key = '{}+{}'.format(prefix, key)
+
return key
-
def configure_event(self, widget, event):
if _debug: print('FigureCanvasGTK.%s' % fn_name())
if widget.window is None:
@@ -592,7 +600,7 @@ def show(self):
# show the figure window
self.window.show()
- def full_screen_toggle (self):
+ def full_screen_toggle(self):
self._full_screen_flag = not self._full_screen_flag
if self._full_screen_flag:
self.window.fullscreen()
@@ -624,19 +632,6 @@ def resize(self, width, height):
class NavigationToolbar2GTK(NavigationToolbar2, gtk.Toolbar):
- # list of toolitems to add to the toolbar, format is:
- # text, tooltip_text, image_file, callback(str)
- toolitems = (
- ('Home', 'Reset original view', 'home.png', 'home'),
- ('Back', 'Back to previous view','back.png', 'back'),
- ('Forward', 'Forward to next view','forward.png', 'forward'),
- ('Pan', 'Pan axes with left mouse, zoom with right', 'move.png','pan'),
- ('Zoom', 'Zoom to rectangle','zoom_to_rect.png', 'zoom'),
- (None, None, None, None),
- ('Subplots', 'Configure subplots','subplots.png', 'configure_subplots'),
- ('Save', 'Save the figure','filesave.png', 'save_figure'),
- )
-
def __init__(self, canvas, window):
self.win = window
gtk.Toolbar.__init__(self)
@@ -704,7 +699,7 @@ def _init_toolbar2_4(self):
if text is None:
self.insert( gtk.SeparatorToolItem(), -1 )
continue
- fname = os.path.join(basedir, image_file)
+ fname = os.path.join(basedir, image_file + '.png')
image = gtk.Image()
image.set_from_file(fname)
tbutton = gtk.ToolButton(image, text)
View
29 lib/matplotlib/backends/backend_gtk3.py
@@ -259,15 +259,21 @@ def enter_notify_event(self, widget, event):
def _get_key(self, event):
if event.keyval in self.keyvald:
key = self.keyvald[event.keyval]
- elif event.keyval <256:
+ elif event.keyval < 256:
key = chr(event.keyval)
else:
key = None
- #ctrl = event.get_state() & Gdk.EventMask.CONTROL
- #shift = event.get_state() & Gdk.EventMask.SHIFT
- return key
+ modifiers = [
+ (Gdk.ModifierType.MOD4_MASK, 'super'),
+ (Gdk.ModifierType.MOD1_MASK, 'alt'),
+ (Gdk.ModifierType.CONTROL_MASK, 'ctrl'),
+ ]
+ for key_mask, prefix in modifiers:
+ if event.state & key_mask:
+ key = '{}+{}'.format(prefix, key)
+ return key
def configure_event(self, widget, event):
if _debug: print 'FigureCanvasGTK3.%s' % fn_name()
@@ -453,19 +459,6 @@ def resize(self, width, height):
class NavigationToolbar2GTK3(NavigationToolbar2, Gtk.Toolbar):
- # list of toolitems to add to the toolbar, format is:
- # text, tooltip_text, image_file, callback(str)
- toolitems = (
- ('Home', 'Reset original view', 'home.png', 'home'),
- ('Back', 'Back to previous view','back.png', 'back'),
- ('Forward', 'Forward to next view','forward.png', 'forward'),
- ('Pan', 'Pan axes with left mouse, zoom with right', 'move.png','pan'),
- ('Zoom', 'Zoom to rectangle','zoom_to_rect.png', 'zoom'),
- (None, None, None, None),
- ('Subplots', 'Configure subplots','subplots.png', 'configure_subplots'),
- ('Save', 'Save the figure','filesave.png', 'save_figure'),
- )
-
def __init__(self, canvas, window):
self.win = window
GObject.GObject.__init__(self)
@@ -516,7 +509,7 @@ def _init_toolbar(self):
if text is None:
self.insert( Gtk.SeparatorToolItem(), -1 )
continue
- fname = os.path.join(basedir, image_file)
+ fname = os.path.join(basedir, image_file + '.png')
image = Gtk.Image()
image.set_from_file(fname)
tbutton = Gtk.ToolButton()
View
12 lib/matplotlib/backends/backend_macosx.py
@@ -20,12 +20,13 @@
import matplotlib
from matplotlib.backends import _macosx
+
class Show(ShowBase):
def mainloop(self):
_macosx.show()
-
show = Show()
+
class RendererMac(RendererBase):
"""
The renderer handles drawing/rendering operations. Most of the renderer's
@@ -136,7 +137,7 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle):
def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
if ismath:
- self._draw_mathtext(gc, x, y, s, prop, angle)
+ self._draw_mathtext(gc, x, y, s, prop, angle)
else:
family = prop.get_family()
weight = prop.get_weight()
@@ -174,6 +175,7 @@ def points_to_pixels(self, points):
def option_image_nocomposite(self):
return True
+
class GraphicsContextMac(_macosx.GraphicsContext, GraphicsContextBase):
"""
The GraphicsContext wraps a Quartz graphics context. All methods
@@ -211,6 +213,7 @@ def set_clip_path(self, path):
path = path.get_fully_transformed_path()
_macosx.GraphicsContext.set_clip_path(self, path)
+
########################################################################
#
# The following functions and classes are for pylab and implement
@@ -245,6 +248,7 @@ def new_figure_manager(num, *args, **kwargs):
manager = FigureManagerMac(canvas, num)
return manager
+
class TimerMac(_macosx.Timer, TimerBase):
'''
Subclass of :class:`backend_bases.TimerBase` that uses CoreFoundation
@@ -262,7 +266,6 @@ class TimerMac(_macosx.Timer, TimerBase):
# completely implemented at the C-level (in _macosx.Timer)
-
class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasBase):
"""
The canvas the figure renders into. Calls the draw and print fig
@@ -346,6 +349,7 @@ def new_timer(self, *args, **kwargs):
"""
return TimerMac(*args, **kwargs)
+
class FigureManagerMac(_macosx.FigureManager, FigureManagerBase):
"""
Wrap everything up into a window for the pylab interface
@@ -377,6 +381,7 @@ def notify_axes_change(fig):
def close(self):
Gcf.destroy(self.num)
+
class NavigationToolbarMac(_macosx.NavigationToolbar):
def __init__(self, canvas):
@@ -444,6 +449,7 @@ def save_figure(self, *args):
return
self.canvas.print_figure(filename)
+
class NavigationToolbar2Mac(_macosx.NavigationToolbar2, NavigationToolbar2):
def __init__(self, canvas):
View
20 lib/matplotlib/backends/backend_qt.py
@@ -181,6 +181,8 @@ def _get_key( self, event ):
else:
key = None
+ # TODO: Handle ctrl, alt, super modifiers. qt4 backend has implemented.
+
return key
def flush_events(self):
@@ -295,20 +297,6 @@ def set_window_title(self, title):
self.window.setCaption(title)
class NavigationToolbar2QT( NavigationToolbar2, qt.QWidget ):
- # list of toolitems to add to the toolbar, format is:
- # text, tooltip_text, image_file, callback(str)
- toolitems = (
- ('Home', 'Reset original view', 'home.ppm', 'home'),
- ('Back', 'Back to previous view','back.ppm', 'back'),
- ('Forward', 'Forward to next view','forward.ppm', 'forward'),
- (None, None, None, None),
- ('Pan', 'Pan axes with left mouse, zoom with right', 'move.ppm', 'pan'),
- ('Zoom', 'Zoom to rectangle','zoom_to_rect.ppm', 'zoom'),
- (None, None, None, None),
- ('Subplots', 'Configure subplots','subplots.png', 'configure_subplots'),
- ('Save', 'Save the figure','filesave.ppm', 'save_figure'),
- )
-
def __init__( self, canvas, parent ):
self.canvas = canvas
self.buttons = {}
@@ -329,8 +317,8 @@ def _init_toolbar( self ):
self.layout.addSpacing( 8 )
continue
- fname = os.path.join( basedir, image_file )
- image = qt.QPixmap()
+ fname = os.path.join(basedir, image_file + '.ppm')
+ image = qt.QPixmap()
image.load( fname )
button = qt.QPushButton( qt.QIconSet( image ), "", self )
View
99 lib/matplotlib/backends/backend_qt4.py
@@ -1,6 +1,7 @@
from __future__ import division, print_function
import math
import os
+import signal
import sys
import matplotlib
@@ -60,8 +61,10 @@ def _create_qApp():
class Show(ShowBase):
def mainloop(self):
- QtGui.qApp.exec_()
+ # allow KeyboardInterrupt exceptions to close the plot window.
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ QtGui.qApp.exec_()
show = Show()
@@ -120,6 +123,7 @@ class FigureCanvasQT( QtGui.QWidget, FigureCanvasBase ):
keyvald = { QtCore.Qt.Key_Control : 'control',
QtCore.Qt.Key_Shift : 'shift',
QtCore.Qt.Key_Alt : 'alt',
+ QtCore.Qt.Key_Meta : 'super',
QtCore.Qt.Key_Return : 'enter',
QtCore.Qt.Key_Left : 'left',
QtCore.Qt.Key_Up : 'up',
@@ -143,13 +147,41 @@ class FigureCanvasQT( QtGui.QWidget, FigureCanvasBase ):
QtCore.Qt.Key_PageUp : 'pageup',
QtCore.Qt.Key_PageDown : 'pagedown',
}
+
+ # define the modifier keys which are to be collected on keyboard events.
+ # format is: [(modifier_flag, modifier_name, equivalent_key)
+ _modifier_keys = [
+ (QtCore.Qt.MetaModifier, 'super', QtCore.Qt.Key_Meta),
+ (QtCore.Qt.AltModifier, 'alt', QtCore.Qt.Key_Alt),
+ (QtCore.Qt.ControlModifier, 'ctrl', QtCore.Qt.Key_Control)
+ ]
+
+ _ctrl_modifier = QtCore.Qt.ControlModifier
+
+ if sys.platform == 'darwin':
+ # in OSX, the control and super (aka cmd/apple) keys are switched, so
+ # switch them back.
+ keyvald.update({
+ QtCore.Qt.Key_Control : 'super', # cmd/apple key
+ QtCore.Qt.Key_Meta : 'control',
+ })
+
+ _modifier_keys = [
+ (QtCore.Qt.ControlModifier, 'super', QtCore.Qt.Key_Control),
+ (QtCore.Qt.AltModifier, 'alt', QtCore.Qt.Key_Alt),
+ (QtCore.Qt.MetaModifier, 'ctrl', QtCore.Qt.Key_Meta),
+ ]
+
+ _ctrl_modifier = QtCore.Qt.MetaModifier
+
# map Qt button codes to MouseEvent's ones:
buttond = {QtCore.Qt.LeftButton : 1,
QtCore.Qt.MidButton : 2,
QtCore.Qt.RightButton : 3,
# QtCore.Qt.XButton1 : None,
# QtCore.Qt.XButton2 : None,
}
+
def __init__( self, figure ):
if DEBUG: print('FigureCanvasQt: ', figure)
_create_qApp()
@@ -268,12 +300,32 @@ def minumumSizeHint( self ):
def _get_key( self, event ):
if event.isAutoRepeat():
return None
+
if event.key() < 256:
- key = str(event.text())
- elif event.key() in self.keyvald:
- key = self.keyvald[ event.key() ]
+ key = unicode(event.text())
+ # if the control key is being pressed, we don't get the correct
+ # characters, so interpret them directly from the event.key().
+ # Unfortunately, this means that we cannot handle key's case
+ # since event.key() is not case sensitive, whereas event.text() is,
+ # Finally, since it is not possible to get the CapsLock state
+ # we cannot accurately compute the case of a pressed key when
+ # ctrl+shift+p is pressed.
+ if int(event.modifiers()) & self._ctrl_modifier:
+ # we always get an uppercase character
+ key = chr(event.key())
+ # if shift is not being pressed, lowercase it (as mentioned,
+ # this does not take into account the CapsLock state)
+ if not int(event.modifiers()) & QtCore.Qt.ShiftModifier:
+ key = key.lower()
+
else:
- key = None
+ key = self.keyvald.get(event.key())
+
+ if key is not None:
+ # prepend the ctrl, alt, super keys if appropriate (sorted in that order)
+ for modifier, prefix, Qt_key in self._modifier_keys:
+ if event.key() != Qt_key and int(event.modifiers()) & modifier == modifier:
+ key = u'{}+{}'.format(prefix, key)
return key
@@ -373,16 +425,22 @@ def __init__( self, canvas, num ):
self.canvas.figure.show = lambda *args: self.window.show()
def notify_axes_change( fig ):
- # This will be called whenever the current axes is changed
- if self.toolbar is not None:
- self.toolbar.update()
+ # This will be called whenever the current axes is changed
+ if self.toolbar is not None:
+ self.toolbar.update()
self.canvas.figure.add_axobserver( notify_axes_change )
@QtCore.Slot()
def _show_message(self,s):
# Fixes a PySide segfault.
self.window.statusBar().showMessage(s)
+ def full_screen_toggle(self):
+ if self.window.isFullScreen():
+ self.window.showNormal()
+ else:
+ self.window.showFullScreen()
+
def _widgetclosed( self ):
if self.window._destroying: return
self.window._destroying = True
@@ -394,7 +452,6 @@ def _widgetclosed( self ):
# Gcf can get destroyed before the Gcf.destroy
# line is run, leading to a useless AttributeError.
-
def _get_toolbar(self, canvas, parent):
# must be inited after the window, drawingArea and figure
# attrs are set
@@ -441,22 +498,14 @@ def _icon(self, name):
def _init_toolbar(self):
self.basedir = os.path.join(matplotlib.rcParams[ 'datapath' ],'images')
- a = self.addAction(self._icon('home.png'), 'Home', self.home)
- a.setToolTip('Reset original view')
- a = self.addAction(self._icon('back.png'), 'Back', self.back)
- a.setToolTip('Back to previous view')
- a = self.addAction(self._icon('forward.png'), 'Forward', self.forward)
- a.setToolTip('Forward to next view')
- self.addSeparator()
- a = self.addAction(self._icon('move.png'), 'Pan', self.pan)
- a.setToolTip('Pan axes with left mouse, zoom with right')
- a = self.addAction(self._icon('zoom_to_rect.png'), 'Zoom', self.zoom)
- a.setToolTip('Zoom to rectangle')
- self.addSeparator()
- a = self.addAction(self._icon('subplots.png'), 'Subplots',
- self.configure_subplots)
- a.setToolTip('Configure subplots')
-
+ for text, tooltip_text, image_file, callback in self.toolitems:
+ if text is None:
+ self.addSeparator()
+ else:
+ a = self.addAction(self._icon(image_file + '.png'), text, getattr(self, callback))
+ if tooltip_text is not None:
+ a.setToolTip(tooltip_text)
+
if figureoptions is not None:
a = self.addAction(self._icon("qt4_editor_options.png"),
'Customize', self.edit_parameters)
View
169 lib/matplotlib/backends/backend_tkagg.py
@@ -127,6 +127,7 @@ class FigureCanvasTkAgg(FigureCanvasAgg):
keyvald = {65507 : 'control',
65505 : 'shift',
65513 : 'alt',
+ 65515 : 'super',
65508 : 'control',
65506 : 'shift',
65514 : 'alt',
@@ -174,6 +175,18 @@ class FigureCanvasTkAgg(FigureCanvasAgg):
65439 : 'dec',
65421 : 'enter',
}
+
+ _keycode_lookup = {
+ 262145: 'control',
+ 524320: 'alt',
+ 524352: 'alt',
+ 1048584: 'super',
+ 1048592: 'super',
+ 131074: 'shift',
+ 131076: 'shift',
+ }
+ """_keycode_lookup is used for badly mapped (i.e. no event.key_sym set)
+ keys on apple keyboards."""
def __init__(self, figure, master=None, resize_callback=None):
FigureCanvasAgg.__init__(self, figure)
@@ -217,7 +230,7 @@ def filter_destroy(evt):
self._master = master
self._tkcanvas.focus_set()
-
+
def resize(self, event):
width, height = event.width, event.height
if self._resize_callback is not None:
@@ -399,13 +412,40 @@ def _get_key(self, event):
val = event.keysym_num
if val in self.keyvald:
key = self.keyvald[val]
- elif val<256:
+ elif val == 0 and sys.platform == 'darwin' and \
+ event.keycode in self._keycode_lookup:
+ key = self._keycode_lookup[event.keycode]
+ elif val < 256:
key = chr(val)
else:
key = None
+
+ # add modifier keys to the key string. Bit details originate from
+ # http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
+ # BIT_SHIFT = 0x001; BIT_CAPSLOCK = 0x002; BIT_CONTROL = 0x004;
+ # BIT_LEFT_ALT = 0x008; BIT_NUMLOCK = 0x010; BIT_RIGHT_ALT = 0x080;
+ # BIT_MB_1 = 0x100; BIT_MB_2 = 0x200; BIT_MB_3 = 0x400;
+ # In general, the modifier key is excluded from the modifier flag,
+ # however this is not the case on "darwin", so double check that
+ # we aren't adding repeat modifier flags to a modifier key.
+ modifiers = [(6, 'super', 'super'),
+ (3, 'alt', 'alt'),
+ (2, 'ctrl', 'control'),
+ ]
+ if sys.platform == 'darwin':
+ modifiers = [(3, 'super', 'super'),
+ (4, 'alt', 'alt'),
+ (2, 'ctrl', 'control'),
+ ]
+
+ if key is not None:
+ # note, shift is not added to the keys as this is already accounted for
+ for bitmask, prefix, key_name in modifiers:
+ if event.state & (1 << bitmask) and key_name not in key:
+ key = '{}+{}'.format(prefix, key)
+
return key
-
def key_press(self, event):
key = self._get_key(event)
FigureCanvasBase.key_press_event(self, key, guiEvent=event)
@@ -457,7 +497,7 @@ def __init__(self, canvas, num, window):
self.window.wm_title("Figure %d" % num)
self.canvas = canvas
self._num = num
- t1,t2,w,h = canvas.figure.bbox.bounds
+ _, _, w, h = canvas.figure.bbox.bounds
w, h = int(w), int(h)
self.window.minsize(int(w*3/4),int(h*3/4))
if matplotlib.rcParams['toolbar']=='classic':
@@ -476,12 +516,9 @@ def notify_axes_change(fig):
if self.toolbar != None: self.toolbar.update()
self.canvas.figure.add_axobserver(notify_axes_change)
-
-
# attach a show method to the figure for pylab ease of use
self.canvas.figure.show = lambda *args: self.show()
-
def resize(self, width, height=None):
# before 09-12-22, the resize method takes a single *event*
# parameter. On the other hand, the resize method of other
@@ -499,7 +536,6 @@ def resize(self, width, height=None):
self.toolbar.configure(width=width)
-
def show(self):
"""
this function doesn't segfault but causes the
@@ -518,7 +554,6 @@ def destroy(*args):
self.canvas.draw_idle()
self._shown = True
-
def destroy(self, *args):
if self.window is not None:
#self.toolbar.destroy()
@@ -533,6 +568,11 @@ def destroy(self, *args):
def set_window_title(self, title):
self.window.wm_title(title)
+ def full_screen_toggle(self):
+ is_fullscreen = bool(self.window.attributes('-fullscreen'))
+ self.window.attributes('-fullscreen', not is_fullscreen)
+
+
class AxisMenu:
def __init__(self, master, naxes):
self._master = master
@@ -595,9 +635,10 @@ def select_all(self):
a.set(1)
self.set_active()
+
class NavigationToolbar(Tk.Frame):
"""
- Public attriubutes
+ Public attributes
canvas - the FigureCanvas (gtk.DrawingArea)
win - the gtk.Window
@@ -625,39 +666,39 @@ def __init__(self, canvas, window):
self.update() # Make axes menu
self.bLeft = self._Button(
- text="Left", file="stock_left.ppm",
+ text="Left", file="stock_left",
command=lambda x=-1: self.panx(x))
self.bRight = self._Button(
- text="Right", file="stock_right.ppm",
+ text="Right", file="stock_right",
command=lambda x=1: self.panx(x))
self.bZoomInX = self._Button(
- text="ZoomInX",file="stock_zoom-in.ppm",
+ text="ZoomInX",file="stock_zoom-in",
command=lambda x=1: self.zoomx(x))
self.bZoomOutX = self._Button(
- text="ZoomOutX", file="stock_zoom-out.ppm",
+ text="ZoomOutX", file="stock_zoom-out",
command=lambda x=-1: self.zoomx(x))
self.bUp = self._Button(
- text="Up", file="stock_up.ppm",
+ text="Up", file="stock_up",
command=lambda y=1: self.pany(y))
self.bDown = self._Button(
- text="Down", file="stock_down.ppm",
+ text="Down", file="stock_down",
command=lambda y=-1: self.pany(y))
self.bZoomInY = self._Button(
- text="ZoomInY", file="stock_zoom-in.ppm",
+ text="ZoomInY", file="stock_zoom-in",
command=lambda y=1: self.zoomy(y))
self.bZoomOutY = self._Button(
- text="ZoomOutY",file="stock_zoom-out.ppm",
+ text="ZoomOutY",file="stock_zoom-out",
command=lambda y=-1: self.zoomy(y))
self.bSave = self._Button(
- text="Save", file="stock_save_as.ppm",
+ text="Save", file="stock_save_as",
command=self.save_figure)
self.pack(side=Tk.BOTTOM, fill=Tk.X)
@@ -722,7 +763,7 @@ def update(self):
class NavigationToolbar2TkAgg(NavigationToolbar2, Tk.Frame):
"""
- Public attriubutes
+ Public attributes
canvas - the FigureCanvas (gtk.DrawingArea)
win - the gtk.Window
@@ -762,9 +803,9 @@ def release(self, event):
def set_cursor(self, cursor):
self.window.configure(cursor=cursord[cursor])
- def _Button(self, text, file, command):
- file = os.path.join(rcParams['datapath'], 'images', file)
- im = Tk.PhotoImage(master=self, file=file)
+ def _Button(self, text, file, command, extension='.ppm'):
+ img_file = os.path.join(rcParams['datapath'], 'images', file + extension)
+ im = Tk.PhotoImage(master=self, file=img_file)
b = Tk.Button(
master=self, text=text, padx=2, pady=2, image=im, command=command)
b._ntimage = im
@@ -780,27 +821,16 @@ def _init_toolbar(self):
self.update() # Make axes menu
- self.bHome = self._Button( text="Home", file="home.ppm",
- command=self.home)
-
- self.bBack = self._Button( text="Back", file="back.ppm",
- command = self.back)
-
- self.bForward = self._Button(text="Forward", file="forward.ppm",
- command = self.forward)
-
- self.bPan = self._Button( text="Pan", file="move.ppm",
- command = self.pan)
-
- self.bZoom = self._Button( text="Zoom",
- file="zoom_to_rect.ppm",
- command = self.zoom)
-
- self.bsubplot = self._Button( text="Configure Subplots", file="subplots.ppm",
- command = self.configure_subplots)
-
- self.bsave = self._Button( text="Save", file="filesave.ppm",
- command = self.save_figure)
+ for text, tooltip_text, image_file, callback in self.toolitems:
+ if text is None:
+ # spacer, unhandled in Tk
+ pass
+ else:
+ button = self._Button(text=text, file=image_file,
+ command=getattr(self, callback))
+ if tooltip_text is not None:
+ ToolTip.createToolTip(button, tooltip_text)
+
self.message = Tk.StringVar(master=self)
self._message_label = Tk.Label(master=self, textvariable=self.message)
self._message_label.pack(side=Tk.RIGHT)
@@ -878,3 +908,54 @@ def dynamic_update(self):
FigureManager = FigureManagerTkAgg
+
+
+class ToolTip(object):
+ """
+ Tooltip recipe from
+ http://www.voidspace.org.uk/python/weblog/arch_d7_2006_07_01.shtml#e387
+ """
+ @staticmethod
+ def createToolTip(widget, text):
+ toolTip = ToolTip(widget)
+ def enter(event):
+ toolTip.showtip(text)
+ def leave(event):
+ toolTip.hidetip()
+ widget.bind('<Enter>', enter)
+ widget.bind('<Leave>', leave)
+
+ def __init__(self, widget):
+ self.widget = widget
+ self.tipwindow = None
+ self.id = None
+ self.x = self.y = 0
+
+ def showtip(self, text):
+ "Display text in tooltip window"
+ self.text = text
+ if self.tipwindow or not self.text:
+ return
+ x, y, _, _ = self.widget.bbox("insert")
+ x = x + self.widget.winfo_rootx() + 27
+ y = y + self.widget.winfo_rooty()
+ self.tipwindow = tw = Tk.Toplevel(self.widget)
+ tw.wm_overrideredirect(1)
+ tw.wm_geometry("+%d+%d" % (x, y))
+ try:
+ # For Mac OS
+ tw.tk.call("::tk::unsupported::MacWindowStyle",
+ "style", tw._w,
+ "help", "noActivates")
+ except Tk.TclError:
+ pass
+ label = Tk.Label(tw, text=self.text, justify=Tk.LEFT,
+ background="#ffffe0", relief=Tk.SOLID, borderwidth=1,
+ )
+ label.pack(ipadx=1)
+
+ def hidetip(self):
+ tw = self.tipwindow
+ self.tipwindow = None
+ if tw:
+ tw.destroy()
View
83 lib/matplotlib/backends/backend_wx.py
@@ -1242,13 +1242,20 @@ def _get_key(self, evt):
keyval = evt.m_keyCode
if keyval in self.keyvald:
key = self.keyvald[keyval]
- elif keyval <256:
+ elif keyval < 256:
key = chr(keyval)
+ # wx always returns an uppercase, so make it lowercase if the shift
+ # key is not depressed (NOTE: this will not handle Caps Lock)
+ if not evt.ShiftDown():
+ key = key.lower()
else:
key = None
- # why is wx upcasing this?
- if key is not None: key = key.lower()
+ for meth, prefix in (
+ [evt.AltDown, 'alt'],
+ [evt.ControlDown, 'ctrl'], ):
+ if meth():
+ key = '{}+{}'.format(prefix, key)
return key
@@ -1476,6 +1483,7 @@ def __init__(self, num, fig):
self.SetStatusBar(statbar)
self.canvas = self.get_canvas(fig)
self.canvas.SetInitialSize(wx.Size(fig.bbox.width, fig.bbox.height))
+ self.canvas.SetFocus()
self.sizer =wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)
# By adding toolbar in sizer, we are able to put it at the bottom
@@ -1742,8 +1750,6 @@ def updateButtonText(self, lst):
self.SetLabel("Axes: %s" % axis_txt[:-1])
-
-
cursord = {
cursors.MOVE : wx.CURSOR_HAND,
cursors.HAND : wx.CURSOR_HAND,
@@ -1787,57 +1793,33 @@ def _init_toolbar(self):
DEBUG_MSG("_init_toolbar", 1, self)
self._parent = self.canvas.GetParent()
- _NTB2_HOME =wx.NewId()
- self._NTB2_BACK =wx.NewId()
- self._NTB2_FORWARD =wx.NewId()
- self._NTB2_PAN =wx.NewId()
- self._NTB2_ZOOM =wx.NewId()
- _NTB2_SAVE = wx.NewId()
- _NTB2_SUBPLOT =wx.NewId()
-
- self.SetToolBitmapSize(wx.Size(24,24))
-
- self.AddSimpleTool(_NTB2_HOME, _load_bitmap('home.png'),
- 'Home', 'Reset original view')
- self.AddSimpleTool(self._NTB2_BACK, _load_bitmap('back.png'),
- 'Back', 'Back navigation view')
- self.AddSimpleTool(self._NTB2_FORWARD, _load_bitmap('forward.png'),
- 'Forward', 'Forward navigation view')
- # todo: get new bitmap
- self.AddCheckTool(self._NTB2_PAN, _load_bitmap('move.png'),
- shortHelp='Pan',
- longHelp='Pan with left, zoom with right')
- self.AddCheckTool(self._NTB2_ZOOM, _load_bitmap('zoom_to_rect.png'),
- shortHelp='Zoom', longHelp='Zoom to rectangle')
- self.AddSeparator()
- self.AddSimpleTool(_NTB2_SUBPLOT, _load_bitmap('subplots.png'),
- 'Configure subplots', 'Configure subplot parameters')
- self.AddSimpleTool(_NTB2_SAVE, _load_bitmap('filesave.png'),
- 'Save', 'Save plot contents to file')
-
- bind(self, wx.EVT_TOOL, self.home, id=_NTB2_HOME)
- bind(self, wx.EVT_TOOL, self.forward, id=self._NTB2_FORWARD)
- bind(self, wx.EVT_TOOL, self.back, id=self._NTB2_BACK)
- bind(self, wx.EVT_TOOL, self.zoom, id=self._NTB2_ZOOM)
- bind(self, wx.EVT_TOOL, self.pan, id=self._NTB2_PAN)
- bind(self, wx.EVT_TOOL, self.configure_subplot, id=_NTB2_SUBPLOT)
- bind(self, wx.EVT_TOOL, self.save, id=_NTB2_SAVE)
+ self.wx_ids = {}
+ for text, tooltip_text, image_file, callback in self.toolitems:
+ if text is None:
+ self.AddSeparator()
+ continue
+ self.wx_ids[text] = wx.NewId()
+ if text in ['Pan', 'Zoom']:
+ self.AddCheckTool(self.wx_ids[text], _load_bitmap(image_file + '.png'),
+ shortHelp=text, longHelp=tooltip_text)
+ else:
+ self.AddSimpleTool(self.wx_ids[text], _load_bitmap(image_file + '.png'),
+ text, tooltip_text)
+ bind(self, wx.EVT_TOOL, getattr(self, callback), id=self.wx_ids[text])
self.Realize()
-
def zoom(self, *args):
- self.ToggleTool(self._NTB2_PAN, False)
+ self.ToggleTool(self.wx_ids['Pan'], False)
NavigationToolbar2.zoom(self, *args)
def pan(self, *args):
- self.ToggleTool(self._NTB2_ZOOM, False)
+ self.ToggleTool(self.wx_ids['Zoom'], False)
NavigationToolbar2.pan(self, *args)
-
- def configure_subplot(self, evt):
+ def configure_subplots(self, evt):
frame = wx.Frame(None, -1, "Configure subplots")
toolfig = Figure((6,3))
@@ -1855,7 +1837,7 @@ def configure_subplot(self, evt):
tool = SubplotTool(self.canvas.figure, toolfig)
frame.Show()
- def save(self, evt):
+ def save_figure(self, *args):
# Fetch the required filename and file type.
filetypes, exts, filter_index = self.canvas._get_imagesave_wildcards()
default_file = "image." + self.canvas.get_default_filetype()
@@ -1881,7 +1863,7 @@ def save(self, evt):
os.path.join(dirname, filename), format=format)
except Exception as e:
error_msg_wx(str(e))
-
+
def set_cursor(self, cursor):
cursor =wx.StockCursor(cursord[cursor])
self.canvas.SetCursor( cursor )
@@ -1948,8 +1930,8 @@ def set_message(self, s):
def set_history_buttons(self):
can_backward = (self._views._pos > 0)
can_forward = (self._views._pos < len(self._views._elements) - 1)
- self.EnableTool(self._NTB2_BACK, can_backward)
- self.EnableTool(self._NTB2_FORWARD, can_forward)
+ self.EnableTool(self.wx_ids['Back'], can_backward)
+ self.EnableTool(self.wx_ids['Forward'], can_forward)
class NavigationToolbarWx(wx.ToolBar):
@@ -2149,13 +2131,12 @@ def _onMouseWheel(self, evt):
direction = -1
self.button_fn(direction)
- _onSave = NavigationToolbar2Wx.save
+ _onSave = NavigationToolbar2Wx.save_figure
def _onClose(self, evt):
self.GetParent().Destroy()
-
class StatusBarWx(wx.StatusBar):
"""
A status bar is added to _FigureFrame to allow measurements and the
View
7 lib/matplotlib/rcsetup.py
@@ -576,14 +576,15 @@ def __call__(self, s):
'agg.path.chunksize' : [0, validate_int], # 0 to disable chunking;
# recommend about 20000 to
# enable. Experimental.
- # key-mappings
- 'keymap.fullscreen' : ['f', validate_stringlist],
+ # key-mappings (multi-character mappings should be a list/tuple)
+ 'keymap.fullscreen' : [('f', 'ctrl+f'), validate_stringlist],
'keymap.home' : [['h', 'r', 'home'], validate_stringlist],
'keymap.back' : [['left', 'c', 'backspace'], validate_stringlist],
'keymap.forward' : [['right', 'v'], validate_stringlist],
'keymap.pan' : ['p', validate_stringlist],
'keymap.zoom' : ['o', validate_stringlist],
- 'keymap.save' : ['s', validate_stringlist],
+ 'keymap.save' : [('s', 'ctrl+s'), validate_stringlist],
+ 'keymap.quit' : [('ctrl+w', ), validate_stringlist],
'keymap.grid' : ['g', validate_stringlist],
'keymap.yscale' : ['l', validate_stringlist],
'keymap.xscale' : [['k', 'L'], validate_stringlist],
View
1 matplotlibrc.template
@@ -412,6 +412,7 @@ text.hinting_factor : 8 # Specifies the amount of softness for hinting in the
#keymap.pan : p # pan mnemonic
#keymap.zoom : o # zoom mnemonic
#keymap.save : s # saving current figure
+#keymap.quit : ctrl+w # close the current figure
#keymap.grid : g # switching on/off a grid in current axes
#keymap.yscale : l # toggle scaling of y-axes ('log'/'linear')
#keymap.xscale : L, k # toggle scaling of x-axes ('log'/'linear')
View
2 src/_macosx.m
@@ -5416,6 +5416,7 @@ - (void)keyDown:(NSEvent*)event
{
PyObject* result;
const char* s = [self convertKeyEvent: event];
+ /* TODO: Handle ctrl, alt, super modifiers. qt4 has implemented these. */
PyGILState_STATE gstate = PyGILState_Ensure();
if (s==NULL)
{
@@ -5437,6 +5438,7 @@ - (void)keyUp:(NSEvent*)event
{
PyObject* result;
const char* s = [self convertKeyEvent: event];
+ /* TODO: Handle ctrl, alt, super modifiers. qt4 has implemented these. */
PyGILState_STATE gstate = PyGILState_Ensure();
if (s==NULL)
{

0 comments on commit 5b90a27

Please sign in to comment.