Skip to content

Commit

Permalink
Template Backend plus fix FigManager for non-GUI backends and add gen…
Browse files Browse the repository at this point in the history
…eric focus
  • Loading branch information
OceanWolf committed Jun 29, 2015
1 parent 113d91f commit d3a4c65
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 61 deletions.
3 changes: 3 additions & 0 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1787,6 +1787,9 @@ def __init__(self, figure, manager=None, backend=None, **kwargs):
def backend(self):
return self._backend

def focus(self):
pass

def is_saving(self):
"""
Returns `True` when the renderer is in the process of saving
Expand Down
31 changes: 19 additions & 12 deletions lib/matplotlib/backend_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,19 @@ class FigureManager(cbook.EventEmitter):
"""
def __init__(self, figure, num, **kwargs):
super(FigureManager, self).__init__(**kwargs)
self._backend = get_backend()

self.num = num
self.figure = figure

self._is_gui = hasattr(self._backend, 'Window')
if not self._is_gui:
return

self._backend = get_backend()
self._mainloop = self._backend.MainLoop()
self.window = self._backend.Window('Figure %d' % num)
self.window.mpl_connect('window_destroy_event', self.destroy)

self.figure = figure

w = int(self.figure.bbox.width)
h = int(self.figure.bbox.height)

Expand Down Expand Up @@ -137,7 +141,7 @@ def destroy(self, *args):

# Make sure we run this routine only once for the FigureManager
# This ensures the nasty __del__ fix below works.
if getattr(self, '_destroying', False):
if getattr(self, '_destroying', False) or self._is_gui is False:
return

self._destroying = True
Expand All @@ -157,7 +161,7 @@ def destroy(self, *args):
def show(self):
"""Shows the figure"""
self.window.show()
self.canvas.grab_focus()
self.canvas.focus()

def full_screen_toggle(self):
"""Toggles whether we show fullscreen, alternatively call
Expand Down Expand Up @@ -188,13 +192,16 @@ def backend(self):
return self._backend

def _get_toolbar(self):
# must be inited after the window, drawingArea and figure
# attrs are set
if rcParams['toolbar'] == 'toolmanager':
toolbar = self._backend.Toolbar(self.toolmanager)
else:
toolbar = None
return toolbar
try:
# must be inited after the window, drawingArea and figure
# attrs are set
if rcParams['toolbar'] == 'toolmanager':
toolbar = self._backend.Toolbar(self.toolmanager)
else:
toolbar = None
return toolbar
except:
return None

def show_popup(self, msg):
"""
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def pylab_setup():
backend_mod = get_backend()

# Things we pull in from all backends
new_figure_manager = backend_mod.new_figure_manager
new_figure_manager = getattr(backend_mod, 'new_figure_manager', None)

# image backends like pdf, agg or svg do not need to do anything
# for "show" or "draw_if_interactive", so if they are not defined
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/backends/backend_gtk3.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ def __init__(self, *args, **kwargs):
default_context = GLib.main_context_get_thread_default() or GLib.main_context_default()
self._idle_event_source = default_context.find_source_by_id(self._idle_event_id)

def focus(self):
self.grab_focus()

def destroy(self):
#Gtk.DrawingArea.destroy(self)
self.close_event()
Expand Down
72 changes: 24 additions & 48 deletions lib/matplotlib/backends/backend_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
Copy this to backend_xxx.py and replace all instances of 'template'
with 'xxx'. Then implement the class methods and functions below, and
add 'xxx' to the switchyard in matplotlib/backends/__init__.py and
'xxx' to the backends list in the validate_backend methon in
'xxx' to the backends list in the validate_backend method in
matplotlib/__init__.py and you're off. You can use your backend with::
import matplotlib
Expand All @@ -25,14 +25,14 @@
plot([1,2,3])
show()
matplotlib also supports external backends, so you can place you can
use any module in your PYTHONPATH with the syntax::
matplotlib also supports external backends, by placing
any module in your PYTHONPATH and then using the syntax::
import matplotlib
matplotlib.use('module://my_backend')
where my_backend.py is your module name. This syntax is also
recognized in the rc file and in the -d argument in pylab, e.g.,::
recognized in the rc file and also with the -d argument in pylab, e.g.,::
python simple_plot.py -dmodule://my_backend
Expand All @@ -48,6 +48,7 @@
matplotlib/backends/backend_your_backend.py
matplotlib/backend_bases.py
matplotlib/backend_managers.py
matplotlib/backends/__init__.py
matplotlib/__init__.py
matplotlib/_pylab_helpers.py
Expand All @@ -68,9 +69,9 @@
import six

import matplotlib
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
FigureManagerBase, FigureCanvasBase
WindowBase, FigureCanvasBase, MainLoopBase, ToolbarBase
from matplotlib import backend_tools
from matplotlib.figure import Figure
from matplotlib.transforms import Bbox

Expand Down Expand Up @@ -178,41 +179,6 @@ def draw_if_interactive():
"""
pass

def show():
"""
For image backends - is not required
For GUI backends - show() is usually the last line of a pylab script and
tells the backend that it is time to draw. In interactive mode, this may
be a do nothing func. See the GTK backend for an example of how to handle
interactive versus batch mode
"""
for manager in Gcf.get_all_fig_managers():
# do something to display the GUI
pass


def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
"""
# if a main-level app must be created, this (and
# new_figure_manager_given_figure) is the usual place to
# do it -- see backend_wx, backend_wxagg and backend_tkagg for
# examples. Not all GUIs require explicit instantiation of a
# main-level app (egg backend_gtk, backend_gtkagg) for pylab
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
return new_figure_manager_given_figure(num, thisFig)


def new_figure_manager_given_figure(num, figure):
"""
Create a new figure manager instance for the given figure.
"""
canvas = FigureCanvasTemplate(figure)
manager = FigureManagerTemplate(canvas, num)
return manager


class FigureCanvasTemplate(FigureCanvasBase):
"""
Expand Down Expand Up @@ -256,19 +222,29 @@ def print_foo(self, filename, *args, **kwargs):
def get_default_filetype(self):
return 'foo'

class FigureManagerTemplate(FigureManagerBase):
"""
Wrap everything up into a window for the pylab interface

For non interactive backends, the base class does all the work
"""
class WindowTemplate(WindowBase):
def show(self):
pass


class RubberbandTemplate(backend_tools.RubberbandBase):
pass


class SetCursorTemplate(backend_tools.SetCursorBase):
pass

########################################################################
#
# Now just provide the standard names that backend.__init__ is expecting
# Now just provide the standard names that backend.__init__ expects
#
########################################################################

FigureCanvas = FigureCanvasTemplate
FigureManager = FigureManagerTemplate

# Needed for a GUI
MainLoop = MainLoopBase
Window = WindowTemplate
ToolRubberband = RubberbandTemplate
ToolSetCursor = SetCursorTemplate

0 comments on commit d3a4c65

Please sign in to comment.