from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
 
import os
import signal
import sys
 
import matplotlib
 
from matplotlib.cbook import is_string_like
from matplotlib.backend_bases import FigureManagerBase
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.backend_bases import NavigationToolbar2
 
from matplotlib.backend_bases import cursors
from matplotlib.backend_bases import TimerBase
from matplotlib.backend_bases import ShowBase
 
from matplotlib._pylab_helpers import Gcf
from matplotlib.figure import Figure
 
 
from matplotlib.widgets import SubplotTool
try:
    import matplotlib.backends.qt5_editor.figureoptions as figureoptions
except ImportError:
    figureoptions = None
 
from PyQt5 import QtCore, QtGui, QtWidgets
 
_getSaveFileName = QtWidgets.QFileDialog.getSaveFileName
__version__ = QtCore.PYQT_VERSION_STR
backend_version = __version__
 
 
def fn_name():
    return sys._getframe(1).f_code.co_name
 
DEBUG = False
 
cursord = {
    cursors.MOVE: QtCore.Qt.SizeAllCursor,
    cursors.HAND: QtCore.Qt.PointingHandCursor,
    cursors.POINTER: QtCore.Qt.ArrowCursor,
    cursors.SELECT_REGION: QtCore.Qt.CrossCursor
}
 
 
def draw_if_interactive():
    """
    Is called after every pylab drawing command
    """
    if matplotlib.is_interactive():
        figManager = Gcf.get_active()
        if figManager is not None:
            figManager.canvas.draw_idle()
 
 
def _create_qApp():
    """
    Only one qApp can exist at a time, so check before creating one.
    """
    if QtWidgets.QApplication.startingUp():
        if DEBUG:
            print("Starting up QApplication")
        global qApp
        app = QtWidgets.QApplication.instance()
        if app is None:
 
            # check for DISPLAY env variable on X11 build of Qt
            if hasattr(QtWidgets, "QX11Info"):
                display = os.environ.get('DISPLAY')
                if display is None or not re.search(':\d', display):
                    raise RuntimeError('Invalid DISPLAY variable')
 
            qApp = QtWidgets.QApplication([str(" ")])
            qApp.lastWindowClosed.connect(qApp.quit)
        else:
            qApp = app
 
 
class Show(ShowBase):
    def mainloop(self):
        # allow KeyboardInterrupt exceptions to close the plot window.
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        print('mainloop')
        QtWidgets.qApp.exec_()
show = Show()
 
 
def new_figure_manager(num, *args, **kwargs):
    """
    Create a new figure manager instance
    """
    thisFig = Figure(*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 = FigureCanvasQT(figure)
    manager = FigureManagerQT(canvas, num)
    return manager
 
 
class TimerQT(TimerBase):
    """
    Subclass of :class:`backend_bases.TimerBase` that uses Qt5 timer events.
 
    Attributes:
    * interval: The time between timer events in milliseconds. Default
        is 1000 ms.
    * single_shot: Boolean flag indicating whether this timer should
        operate as single shot (run once and then stop). Defaults to False.
    * callbacks: Stores list of (func, args) tuples that will be called
        upon timer events. This list can be manipulated directly, or the
        functions add_callback and remove_callback can be used.
    """
    def __init__(self, *args, **kwargs):
        super(TimerQT, self).__init__(*args, **kwargs)
 
        # Create a new timer and connect the timeout() signal to the
        # _on_timer method.
        self._timer = QtCore.QTimer()
        self._timer.timeout.connect(self._on_timer)
        self._timer_set_interval()
 
    def __del__(self):
        # Probably not necessary in practice, but is good behavior to
        # disconnect
        try:
            TimerBase.__del__(self)
            self._timer.timeout.disconnect(self._on_timer)
        except RuntimeError:
            # Timer C++ object already deleted
            pass
 
    def _timer_set_single_shot(self):
        self._timer.setSingleShot(self._single)
 
    def _timer_set_interval(self):
        self._timer.setInterval(self._interval)
 
    def _timer_start(self):
        self._timer.start()
 
    def _timer_stop(self):
        self._timer.stop()
 
 
class FigureCanvasQT(QtWidgets.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',
        QtCore.Qt.Key_Right: 'right',
        QtCore.Qt.Key_Down: 'down',
        QtCore.Qt.Key_Escape: 'escape',
        QtCore.Qt.Key_F1: 'f1',
        QtCore.Qt.Key_F2: 'f2',
        QtCore.Qt.Key_F3: 'f3',
        QtCore.Qt.Key_F4: 'f4',
        QtCore.Qt.Key_F5: 'f5',
        QtCore.Qt.Key_F6: 'f6',
        QtCore.Qt.Key_F7: 'f7',
        QtCore.Qt.Key_F8: 'f8',
        QtCore.Qt.Key_F9: 'f9',
        QtCore.Qt.Key_F10: 'f10',
        QtCore.Qt.Key_F11: 'f11',
        QtCore.Qt.Key_F12: 'f12',
        QtCore.Qt.Key_Home: 'home',
        QtCore.Qt.Key_End: 'end',
        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,
               }
 
    def __init__(self, figure):
        if DEBUG:
            print('FigureCanvasQt: ', figure)
        _create_qApp()
 
        super(FigureCanvasQT, self).__init__(figure=figure)
        self.figure = figure
        self.setMouseTracking(True)
        self._idle = True
        w, h = self.get_width_height()
        self.resize(w, h)
 
    def __timerEvent(self, event):
        # hide until we can test and fix
        self.mpl_idle_event(event)
 
    def enterEvent(self, event):
        FigureCanvasBase.enter_notify_event(self, event)
 
    def leaveEvent(self, event):
        QtWidgets.QApplication.restoreOverrideCursor()
        FigureCanvasBase.leave_notify_event(self, event)
 
    def mousePressEvent(self, event):
        x = event.pos().x()
        # flipy so y=0 is bottom of canvas
        y = self.figure.bbox.height - event.pos().y()
        button = self.buttond.get(event.button())
        if button is not None:
            FigureCanvasBase.button_press_event(self, x, y, button)
        if DEBUG:
            print('button pressed:', event.button())
 
    def mouseDoubleClickEvent(self, event):
        x = event.pos().x()
        # flipy so y=0 is bottom of canvas
        y = self.figure.bbox.height - event.pos().y()
        button = self.buttond.get(event.button())
        if button is not None:
            FigureCanvasBase.button_press_event(self, x, y,
                                                button, dblclick=True)
        if DEBUG:
            print ('button doubleclicked:', event.button())
 
    def mouseMoveEvent(self, event):
        x = event.x()
        # flipy so y=0 is bottom of canvas
        y = self.figure.bbox.height - event.y()
        FigureCanvasBase.motion_notify_event(self, x, y)
        #if DEBUG: print('mouse move')
 
    def mouseReleaseEvent(self, event):
        x = event.x()
        # flipy so y=0 is bottom of canvas
        y = self.figure.bbox.height - event.y()
        button = self.buttond.get(event.button())
        if button is not None:
            FigureCanvasBase.button_release_event(self, x, y, button)
        if DEBUG:
            print('button released')
 
    def wheelEvent(self, event):
        x = event.x()
        # flipy so y=0 is bottom of canvas
        y = self.figure.bbox.height - event.y()
        # from QWheelEvent::delta doc
        steps = event.delta()/120
        if (event.orientation() == QtCore.Qt.Vertical):
            FigureCanvasBase.scroll_event(self, x, y, steps)
            if DEBUG:
                print('scroll event: delta = %i, '
                      'steps = %i ' % (event.delta(), steps))
 
    def keyPressEvent(self, event):
        key = self._get_key(event)
        if key is None:
            return
        FigureCanvasBase.key_press_event(self, key)
        if DEBUG:
            print('key press', key)
 
    def keyReleaseEvent(self, event):
        key = self._get_key(event)
        if key is None:
            return
        FigureCanvasBase.key_release_event(self, key)
        if DEBUG:
            print('key release', key)
 
    def resizeEvent(self, event):
        w = event.size().width()
        h = event.size().height()
        if DEBUG:
            print('resize (%d x %d)' % (w, h))
            print("FigureCanvasQt.resizeEvent(%d, %d)" % (w, h))
        dpival = self.figure.dpi
        winch = w/dpival
        hinch = h/dpival
        self.figure.set_size_inches(winch, hinch)
        FigureCanvasBase.resize_event(self)
        self.draw()
        self.update()
        QtWidgets.QWidget.resizeEvent(self, event)
 
    def sizeHint(self):
        w, h = self.get_width_height()
        return QtCore.QSize(w, h)
 
    def minumumSizeHint(self):
        return QtCore.QSize(10, 10)
 
    def _get_key(self, event):
        if event.isAutoRepeat():
            return None
 
        if event.key() < 256:
            key = six.text_type(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 = 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 = '{0}+{1}'.format(prefix, key)
 
        return key
 
    def new_timer(self, *args, **kwargs):
        """
        Creates a new backend-specific subclass of
        :class:`backend_bases.Timer`.  This is useful for getting
        periodic events through the backend's native event
        loop. Implemented only for backends with GUIs.
 
        optional arguments:
 
        *interval*
            Timer interval in milliseconds
 
        *callbacks*
            Sequence of (func, args, kwargs) where func(*args, **kwargs)
            will be executed by the timer every *interval*.
 
    """
        return TimerQT(*args, **kwargs)
 
    def flush_events(self):
        QtWidgets.qApp.processEvents()
 
    def start_event_loop(self, timeout):
        FigureCanvasBase.start_event_loop_default(self, timeout)
 
    start_event_loop.__doc__ = FigureCanvasBase.start_event_loop_default.__doc__
 
    def stop_event_loop(self):
        FigureCanvasBase.stop_event_loop_default(self)
 
    stop_event_loop.__doc__ = FigureCanvasBase.stop_event_loop_default.__doc__
 
    def draw_idle(self):
        'update drawing area only if idle'
        d = self._idle
        self._idle = False
 
        def idle_draw(*args):
            self.draw()
            self._idle = True
        if d:
            QtCore.QTimer.singleShot(0, idle_draw)
 
 
class MainWindow(QtWidgets.QMainWindow):
    closing = QtCore.pyqtSignal()
 
    def closeEvent(self, event):
        self.closing.emit()
        QtWidgets.QMainWindow.closeEvent(self, event)
 
 
class FigureManagerQT(FigureManagerBase):
    """
    Public attributes
 
    canvas      : The FigureCanvas instance
    num         : The Figure number
    toolbar     : The qt.QToolBar
    window      : The qt.QMainWindow
    """
 
    def __init__(self, canvas, num):
        if DEBUG:
            print('FigureManagerQT.%s' % fn_name())
        super(FigureManagerQT, self).__init__(canvas=canvas, num=num)
        self.canvas = canvas
        self.window = MainWindow()
        self.window.closing.connect(canvas.close_event)
        self.window.closing.connect(self._widgetclosed)
 
        self.window.setWindowTitle("Figure %d" % num)
        image = os.path.join(matplotlib.rcParams['datapath'],
                             'images', 'matplotlib.png')
        self.window.setWindowIcon(QtGui.QIcon(image))
 
        # Give the keyboard focus to the figure instead of the
        # manager; StrongFocus accepts both tab and click to focus and
        # will enable the canvas to process event w/o clicking.
        # ClickFocus only takes the focus is the window has been
        # clicked
        # on. http://qt-project.org/doc/qt-4.8/qt.html#FocusPolicy-enum or
        # http://doc.qt.digia.com/qt/qt.html#FocusPolicy-enum
        self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.canvas.setFocus()
 
        self.window._destroying = False
 
        self.toolbar = self._get_toolbar(self.canvas, self.window)
        if self.toolbar is not None:
            self.window.addToolBar(self.toolbar)
            self.toolbar.message.connect(self._show_message)
            tbs_height = self.toolbar.sizeHint().height()
        else:
            tbs_height = 0
 
        # resize the main window so it will display the canvas with the
        # requested size:
        cs = canvas.sizeHint()
        sbs = self.window.statusBar().sizeHint()
        self._status_and_tool_height = tbs_height + sbs.height()
        height = cs.height() + self._status_and_tool_height
        self.window.resize(cs.width(), height)
 
        self.window.setCentralWidget(self.canvas)
 
        if matplotlib.is_interactive():
            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()
        self.canvas.figure.add_axobserver(notify_axes_change)
 
    @QtCore.pyqtSlot()
    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
        try:
            Gcf.destroy(self.num)
        except AttributeError:
            pass
            # It seems that when the python session is killed,
            # 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
        if matplotlib.rcParams['toolbar'] == 'toolbar2':
            toolbar = NavigationToolbar2QT(canvas, parent, False)
        else:
            toolbar = None
        return toolbar
 
    def resize(self, width, height):
        'set the canvas size in pixels'
        self.window.resize(width, height + self._status_and_tool_height)
 
    def show(self):
        self.window.show()
 
    def destroy(self, *args):
        if self.window._destroying:
            return
        self.window._destroying = True
        self.window.destroyed.connect(self._widgetclosed)
 
        if self.toolbar:
                self.toolbar.destroy()
        if DEBUG:
                print("destroy figure manager")
        self.window.close()
 
    def get_window_title(self):
        return str(self.window.windowTitle())
 
    def set_window_title(self, title):
        self.window.setWindowTitle(title)
 
 
class NavigationToolbar2QT(QtWidgets.QToolBar, NavigationToolbar2):
    message = QtCore.pyqtSignal(str)
 
    def __init__(self, canvas, parent, coordinates=True):
        """ coordinates: should we show the coordinates on the right? """
        self.canvas = canvas
        self.coordinates = coordinates
        self._actions = {}
        """A mapping of toolitem method names to their QActions"""
 
        super(NavigationToolbar2QT, self).__init__(canvas=canvas, parent=parent)
 
    def _icon(self, name):
        return QtGui.QIcon(os.path.join(self.basedir, name))
 
    def _init_toolbar(self):
        self.basedir = os.path.join(matplotlib.rcParams['datapath'], 'images')
 
        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))
                self._actions[callback] = a
                if callback in ['zoom', 'pan']:
                    a.setCheckable(True)
                if tooltip_text is not None:
                    a.setToolTip(tooltip_text)
 
        if figureoptions is not None:
            a = self.addAction(self._icon("qt5_editor_options.png"),
                               'Customize', self.edit_parameters)
            a.setToolTip('Edit curves line and axes parameters')
 
        self.buttons = {}
 
        # Add the x,y location widget at the right side of the toolbar
        # The stretch factor is 1 which means any resizing of the toolbar
        # will resize this label instead of the buttons.
        if self.coordinates:
            self.locLabel = QtWidgets.QLabel("", self)
            self.locLabel.setAlignment(
                QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
            self.locLabel.setSizePolicy(
                QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                      QtWidgets.QSizePolicy.Ignored))
            labelAction = self.addWidget(self.locLabel)
            labelAction.setVisible(True)
 
        # reference holder for subplots_adjust window
        self.adj_window = None
 
    if figureoptions is not None:
        def edit_parameters(self):
            allaxes = self.canvas.figure.get_axes()
            if len(allaxes) == 1:
                axes = allaxes[0]
            else:
                titles = []
                for axes in allaxes:
                    title = axes.get_title()
                    ylabel = axes.get_ylabel()
                    if title:
                        fmt = "%(title)s"
                        if ylabel:
                            fmt += ": %(ylabel)s"
                        fmt += " (%(axes_repr)s)"
                    elif ylabel:
                        fmt = "%(axes_repr)s (%(ylabel)s)"
                    else:
                        fmt = "%(axes_repr)s"
                    titles.append(fmt % dict(title=title,
                                             ylabel=ylabel,
                                             axes_repr=repr(axes)))
                item, ok = QtWidgets.QInputDialog.getItem(self, 'Customize',
                                                          'Select axes:',
                                                          titles,
                                                          0, False)
                if ok:
                    axes = allaxes[titles.index(six.text_type(item))]
                else:
                    return
 
            figureoptions.figure_edit(axes, self)
 
    def _update_buttons_checked(self):
        #sync button checkstates to match active mode
        self._actions['pan'].setChecked(self._active == 'PAN')
        self._actions['zoom'].setChecked(self._active == 'ZOOM')
 
    def pan(self, *args):
        super(NavigationToolbar2QT, self).pan(*args)
        self._update_buttons_checked()
 
    def zoom(self, *args):
        super(NavigationToolbar2QT, self).zoom(*args)
        self._update_buttons_checked()
 
    def dynamic_update(self):
        self.canvas.draw()
 
    def set_message(self, s):
        self.message.emit(s)
        if self.coordinates:
            self.locLabel.setText(s.replace(', ', '\n'))
 
    def set_cursor(self, cursor):
        if DEBUG:
            print('Set cursor', cursor)
        self.canvas.setCursor(cursord[cursor])
 
    def draw_rubberband(self, event, x0, y0, x1, y1):
        height = self.canvas.figure.bbox.height
        y1 = height - y1
        y0 = height - y0
 
        w = abs(x1 - x0)
        h = abs(y1 - y0)
 
        rect = [int(val)for val in (min(x0, x1), min(y0, y1), w, h)]
        self.canvas.drawRectangle(rect)
 
    def configure_subplots(self):
        self.adj_window = QtWidgets.QMainWindow()
        win = self.adj_window
 
        win.setWindowTitle("Subplot Configuration Tool")
        image = os.path.join(matplotlib.rcParams['datapath'],
                             'images', 'matplotlib.png')
        win.setWindowIcon(QtGui.QIcon(image))
 
        tool = SubplotToolQt(self.canvas.figure, win)
        win.setCentralWidget(tool)
        win.setSizePolicy(QtWidgets.QSizePolicy.Preferred,
                          QtWidgets.QSizePolicy.Preferred)
 
        win.show()
 
    def _get_canvas(self, fig):
        return FigureCanvasQT(fig)
 
    def save_figure(self, *args):
        filetypes = self.canvas.get_supported_filetypes_grouped()
        sorted_filetypes = list(six.iteritems(filetypes))
        sorted_filetypes.sort()
        default_filetype = self.canvas.get_default_filetype()
 
        startpath = matplotlib.rcParams.get('savefig.directory', '')
        startpath = os.path.expanduser(startpath)
        start = os.path.join(startpath, self.canvas.get_default_filename())
        filters = []
        selectedFilter = None
        for name, exts in sorted_filetypes:
            exts_list = " ".join(['*.%s' % ext for ext in exts])
            filter = '%s (%s)' % (name, exts_list)
            if default_filetype in exts:
                selectedFilter = filter
            filters.append(filter)
        filters = ';;'.join(filters)
        fname = _getSaveFileName(self, "Choose a filename to save to",
                                 start, filters, selectedFilter)
        if fname:
            if startpath == '':
                # explicitly missing key or empty str signals to use cwd
                matplotlib.rcParams['savefig.directory'] = startpath
            else:
                # save dir for next time
                matplotlib.rcParams['savefig.directory'] = os.path.dirname(
                    six.text_type(fname))
            try:
                self.canvas.print_figure(six.text_type(fname))
            except Exception as e:
                QtWidgets.QMessageBox.critical(
                    self, "Error saving file", str(e),
                    QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton)
 
 
class SubplotToolQt(QtWidgets.QWidget, SubplotTool):
    def __init__(self, targetfig, parent):
        QtWidgets.QWidget.__init__(self, parent)
 
        self.targetfig = targetfig
        self.parent = parent
 
        self.sliderleft = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.sliderbottom = QtWidgets.QSlider(QtCore.Qt.Vertical)
        self.sliderright = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slidertop = QtWidgets.QSlider(QtCore.Qt.Vertical)
        self.sliderwspace = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.sliderhspace = QtWidgets.QSlider(QtCore.Qt.Vertical)
 
        # constraints
        self.sliderleft.valueChanged.connect(self.sliderright.setMinimum)
        self.sliderright.valueChanged.connect(self.sliderleft.setMaximum)
        self.sliderbottom.valueChanged.connect(self.slidertop.setMinimum)
        self.slidertop.valueChanged.connect(self.sliderbottom.setMaximum)
 
        sliders = (self.sliderleft, self.sliderbottom, self.sliderright,
                   self.slidertop, self.sliderwspace, self.sliderhspace,)
        adjustments = ('left:', 'bottom:', 'right:',
                       'top:', 'wspace:', 'hspace:')
 
        for slider, adjustment in zip(sliders, adjustments):
            slider.setMinimum(0)
            slider.setMaximum(1000)
            slider.setSingleStep(5)
 
        layout = QtWidgets.QGridLayout()
 
        leftlabel = QtWidgets.QLabel('left')
        layout.addWidget(leftlabel, 2, 0)
        layout.addWidget(self.sliderleft, 2, 1)
 
        toplabel = QtWidgets.QLabel('top')
        layout.addWidget(toplabel, 0, 2)
        layout.addWidget(self.slidertop, 1, 2)
        layout.setAlignment(self.slidertop, QtCore.Qt.AlignHCenter)
 
        bottomlabel = QtWidgets.QLabel('bottom')  # this might not ever be used
        layout.addWidget(bottomlabel, 4, 2)
        layout.addWidget(self.sliderbottom, 3, 2)
        layout.setAlignment(self.sliderbottom, QtCore.Qt.AlignHCenter)
 
        rightlabel = QtWidgets.QLabel('right')
        layout.addWidget(rightlabel, 2, 4)
        layout.addWidget(self.sliderright, 2, 3)
 
        hspacelabel = QtWidgets.QLabel('hspace')
        layout.addWidget(hspacelabel, 0, 6)
        layout.setAlignment(hspacelabel, QtCore.Qt.AlignHCenter)
        layout.addWidget(self.sliderhspace, 1, 6)
        layout.setAlignment(self.sliderhspace, QtCore.Qt.AlignHCenter)
 
        wspacelabel = QtWidgets.QLabel('wspace')
        layout.addWidget(wspacelabel, 4, 6)
        layout.setAlignment(wspacelabel, QtCore.Qt.AlignHCenter)
        layout.addWidget(self.sliderwspace, 3, 6)
        layout.setAlignment(self.sliderwspace, QtCore.Qt.AlignBottom)
 
        layout.setRowStretch(1, 1)
        layout.setRowStretch(3, 1)
        layout.setColumnStretch(1, 1)
        layout.setColumnStretch(3, 1)
        layout.setColumnStretch(6, 1)
 
        self.setLayout(layout)
 
        self.sliderleft.setSliderPosition(int(targetfig.subplotpars.left*1000))
        self.sliderbottom.setSliderPosition(
            int(targetfig.subplotpars.bottom*1000))
        self.sliderright.setSliderPosition(
            int(targetfig.subplotpars.right*1000))
        self.slidertop.setSliderPosition(int(targetfig.subplotpars.top*1000))
        self.sliderwspace.setSliderPosition(
            int(targetfig.subplotpars.wspace*1000))
        self.sliderhspace.setSliderPosition(
            int(targetfig.subplotpars.hspace*1000))
 
        self.sliderleft.valueChanged.connect(self.funcleft)
        self.sliderbottom.valueChanged.connect(self.funcbottom)
        self.sliderright.valueChanged.connect(self.funcright)
        self.slidertop.valueChanged.connect(self.functop)
        self.sliderwspace.valueChanged.connect(self.funcwspace)
        self.sliderhspace.valueChanged.connect(self.funchspace)
 
    def funcleft(self, val):
        if val == self.sliderright.value():
            val -= 1
        self.targetfig.subplots_adjust(left=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
    def funcright(self, val):
        if val == self.sliderleft.value():
            val += 1
        self.targetfig.subplots_adjust(right=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
    def funcbottom(self, val):
        if val == self.slidertop.value():
            val -= 1
        self.targetfig.subplots_adjust(bottom=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
    def functop(self, val):
        if val == self.sliderbottom.value():
            val += 1
        self.targetfig.subplots_adjust(top=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
    def funcwspace(self, val):
        self.targetfig.subplots_adjust(wspace=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
    def funchspace(self, val):
        self.targetfig.subplots_adjust(hspace=val/1000.)
        if self.drawon:
            self.targetfig.canvas.draw()
 
 
def error_msg_qt(msg, parent=None):
    if not is_string_like(msg):
        msg = ','.join(map(str, msg))
 
    QtWidgets.QMessageBox.warning(None, "Matplotlib", msg,
                                  QtWidgets.QMessageBox.Ok)
 
 
def exception_handler(type, value, tb):
    """Handle uncaught exceptions
    It does not catch SystemExit
    """
    msg = ''
    # get the filename attribute if available (for IOError)
    if hasattr(value, 'filename') and value.filename is not None:
        msg = value.filename + ': '
    if hasattr(value, 'strerror') and value.strerror is not None:
        msg += value.strerror
    else:
        msg += str(value)
 
    if len(msg):
        error_msg_qt(msg)
 
 
FigureManager = FigureManagerQT