|
15 | 15 | from matplotlib._pylab_helpers import Gcf
|
16 | 16 | from matplotlib.backend_bases import (
|
17 | 17 | _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2,
|
18 |
| - TimerBase, cursors) |
| 18 | + TimerBase, cursors, ToolContainerBase, StatusbarBase) |
19 | 19 | import matplotlib.backends.qt_editor.figureoptions as figureoptions
|
20 | 20 | from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
|
21 | 21 | from matplotlib.figure import Figure
|
| 22 | +from matplotlib.backend_managers import ToolManager |
| 23 | +from matplotlib import backend_tools |
22 | 24 |
|
23 | 25 | from .qt_compat import (
|
24 | 26 | QtCore, QtGui, QtWidgets, _getSaveFileName, is_pyqt5, __version__, QT_API)
|
@@ -583,14 +585,23 @@ def __init__(self, canvas, num):
|
583 | 585 |
|
584 | 586 | self.window._destroying = False
|
585 | 587 |
|
586 |
| - # add text label to status bar |
587 |
| - self.statusbar_label = QtWidgets.QLabel() |
588 |
| - self.window.statusBar().addWidget(self.statusbar_label) |
589 |
| - |
| 588 | + self.toolmanager = self._get_toolmanager() |
590 | 589 | self.toolbar = self._get_toolbar(self.canvas, self.window)
|
| 590 | + self.statusbar = None |
| 591 | + |
| 592 | + if self.toolmanager: |
| 593 | + backend_tools.add_tools_to_manager(self.toolmanager) |
| 594 | + if self.toolbar: |
| 595 | + backend_tools.add_tools_to_container(self.toolbar) |
| 596 | + self.statusbar = StatusbarQt(self.window, self.toolmanager) |
| 597 | + |
591 | 598 | if self.toolbar is not None:
|
592 | 599 | self.window.addToolBar(self.toolbar)
|
593 |
| - self.toolbar.message.connect(self.statusbar_label.setText) |
| 600 | + if not self.toolmanager: |
| 601 | + # add text label to status bar |
| 602 | + statusbar_label = QtWidgets.QLabel() |
| 603 | + self.window.statusBar().addWidget(statusbar_label) |
| 604 | + self.toolbar.message.connect(statusbar_label.setText) |
594 | 605 | tbs_height = self.toolbar.sizeHint().height()
|
595 | 606 | else:
|
596 | 607 | tbs_height = 0
|
@@ -639,10 +650,19 @@ def _get_toolbar(self, canvas, parent):
|
639 | 650 | # attrs are set
|
640 | 651 | if matplotlib.rcParams['toolbar'] == 'toolbar2':
|
641 | 652 | toolbar = NavigationToolbar2QT(canvas, parent, False)
|
| 653 | + elif matplotlib.rcParams['toolbar'] == 'toolmanager': |
| 654 | + toolbar = ToolbarQt(self.toolmanager, self.window) |
642 | 655 | else:
|
643 | 656 | toolbar = None
|
644 | 657 | return toolbar
|
645 | 658 |
|
| 659 | + def _get_toolmanager(self): |
| 660 | + if matplotlib.rcParams['toolbar'] == 'toolmanager': |
| 661 | + toolmanager = ToolManager(self.canvas.figure) |
| 662 | + else: |
| 663 | + toolmanager = None |
| 664 | + return toolmanager |
| 665 | + |
646 | 666 | def resize(self, width, height):
|
647 | 667 | 'set the canvas size in pixels'
|
648 | 668 | self.window.resize(width, height + self._status_and_tool_height)
|
@@ -912,6 +932,151 @@ def _reset(self):
|
912 | 932 | self._widgets[attr].setValue(value)
|
913 | 933 |
|
914 | 934 |
|
| 935 | +class ToolbarQt(ToolContainerBase, QtWidgets.QToolBar): |
| 936 | + def __init__(self, toolmanager, parent): |
| 937 | + ToolContainerBase.__init__(self, toolmanager) |
| 938 | + QtWidgets.QToolBar.__init__(self, parent) |
| 939 | + self._toolitems = {} |
| 940 | + self._groups = {} |
| 941 | + self._last = None |
| 942 | + |
| 943 | + @property |
| 944 | + def _icon_extension(self): |
| 945 | + if is_pyqt5(): |
| 946 | + return '_large.png' |
| 947 | + return '.png' |
| 948 | + |
| 949 | + def add_toolitem( |
| 950 | + self, name, group, position, image_file, description, toggle): |
| 951 | + |
| 952 | + button = QtWidgets.QToolButton(self) |
| 953 | + button.setIcon(self._icon(image_file)) |
| 954 | + button.setText(name) |
| 955 | + if description: |
| 956 | + button.setToolTip(description) |
| 957 | + |
| 958 | + def handler(): |
| 959 | + self.trigger_tool(name) |
| 960 | + if toggle: |
| 961 | + button.setCheckable(True) |
| 962 | + button.toggled.connect(handler) |
| 963 | + else: |
| 964 | + button.clicked.connect(handler) |
| 965 | + |
| 966 | + self._last = button |
| 967 | + self._toolitems.setdefault(name, []) |
| 968 | + self._add_to_group(group, name, button, position) |
| 969 | + self._toolitems[name].append((button, handler)) |
| 970 | + |
| 971 | + def _add_to_group(self, group, name, button, position): |
| 972 | + gr = self._groups.get(group, []) |
| 973 | + if not gr: |
| 974 | + sep = self.addSeparator() |
| 975 | + gr.append(sep) |
| 976 | + before = gr[position] |
| 977 | + widget = self.insertWidget(before, button) |
| 978 | + gr.insert(position, widget) |
| 979 | + self._groups[group] = gr |
| 980 | + |
| 981 | + def _icon(self, name): |
| 982 | + pm = QtGui.QPixmap(name) |
| 983 | + if hasattr(pm, 'setDevicePixelRatio'): |
| 984 | + pm.setDevicePixelRatio(self.toolmanager.canvas._dpi_ratio) |
| 985 | + return QtGui.QIcon(pm) |
| 986 | + |
| 987 | + def toggle_toolitem(self, name, toggled): |
| 988 | + if name not in self._toolitems: |
| 989 | + return |
| 990 | + for button, handler in self._toolitems[name]: |
| 991 | + button.toggled.disconnect(handler) |
| 992 | + button.setChecked(toggled) |
| 993 | + button.toggled.connect(handler) |
| 994 | + |
| 995 | + def remove_toolitem(self, name): |
| 996 | + for button, handler in self._toolitems[name]: |
| 997 | + button.setParent(None) |
| 998 | + del self._toolitems[name] |
| 999 | + |
| 1000 | + |
| 1001 | +class StatusbarQt(StatusbarBase, QtWidgets.QLabel): |
| 1002 | + def __init__(self, window, *args, **kwargs): |
| 1003 | + StatusbarBase.__init__(self, *args, **kwargs) |
| 1004 | + QtWidgets.QLabel.__init__(self) |
| 1005 | + window.statusBar().addWidget(self) |
| 1006 | + |
| 1007 | + def set_message(self, s): |
| 1008 | + self.setText(s) |
| 1009 | + |
| 1010 | + |
| 1011 | +class ConfigureSubplotsQt(backend_tools.ConfigureSubplotsBase): |
| 1012 | + def trigger(self, *args): |
| 1013 | + image = os.path.join(matplotlib.rcParams['datapath'], |
| 1014 | + 'images', 'matplotlib.png') |
| 1015 | + parent = self.canvas.manager.window |
| 1016 | + dia = SubplotToolQt(self.figure, parent) |
| 1017 | + dia.setWindowIcon(QtGui.QIcon(image)) |
| 1018 | + dia.exec_() |
| 1019 | + |
| 1020 | + |
| 1021 | +class SaveFigureQt(backend_tools.SaveFigureBase): |
| 1022 | + def trigger(self, *args): |
| 1023 | + filetypes = self.canvas.get_supported_filetypes_grouped() |
| 1024 | + sorted_filetypes = sorted(six.iteritems(filetypes)) |
| 1025 | + default_filetype = self.canvas.get_default_filetype() |
| 1026 | + |
| 1027 | + startpath = os.path.expanduser( |
| 1028 | + matplotlib.rcParams['savefig.directory']) |
| 1029 | + start = os.path.join(startpath, self.canvas.get_default_filename()) |
| 1030 | + filters = [] |
| 1031 | + selectedFilter = None |
| 1032 | + for name, exts in sorted_filetypes: |
| 1033 | + exts_list = " ".join(['*.%s' % ext for ext in exts]) |
| 1034 | + filter = '%s (%s)' % (name, exts_list) |
| 1035 | + if default_filetype in exts: |
| 1036 | + selectedFilter = filter |
| 1037 | + filters.append(filter) |
| 1038 | + filters = ';;'.join(filters) |
| 1039 | + |
| 1040 | + parent = self.canvas.manager.window |
| 1041 | + fname, filter = _getSaveFileName(parent, |
| 1042 | + "Choose a filename to save to", |
| 1043 | + start, filters, selectedFilter) |
| 1044 | + if fname: |
| 1045 | + # Save dir for next time, unless empty str (i.e., use cwd). |
| 1046 | + if startpath != "": |
| 1047 | + matplotlib.rcParams['savefig.directory'] = ( |
| 1048 | + os.path.dirname(six.text_type(fname))) |
| 1049 | + try: |
| 1050 | + self.canvas.figure.savefig(six.text_type(fname)) |
| 1051 | + except Exception as e: |
| 1052 | + QtWidgets.QMessageBox.critical( |
| 1053 | + self, "Error saving file", six.text_type(e), |
| 1054 | + QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton) |
| 1055 | + |
| 1056 | + |
| 1057 | +class SetCursorQt(backend_tools.SetCursorBase): |
| 1058 | + def set_cursor(self, cursor): |
| 1059 | + self.canvas.setCursor(cursord[cursor]) |
| 1060 | + |
| 1061 | + |
| 1062 | +class RubberbandQt(backend_tools.RubberbandBase): |
| 1063 | + def draw_rubberband(self, x0, y0, x1, y1): |
| 1064 | + height = self.canvas.figure.bbox.height |
| 1065 | + y1 = height - y1 |
| 1066 | + y0 = height - y0 |
| 1067 | + rect = [int(val) for val in (x0, y0, x1 - x0, y1 - y0)] |
| 1068 | + self.canvas.drawRectangle(rect) |
| 1069 | + |
| 1070 | + def remove_rubberband(self): |
| 1071 | + self.canvas.drawRectangle(None) |
| 1072 | + |
| 1073 | + |
| 1074 | +backend_tools.ToolSaveFigure = SaveFigureQt |
| 1075 | +backend_tools.ToolConfigureSubplots = ConfigureSubplotsQt |
| 1076 | +backend_tools.ToolSetCursor = SetCursorQt |
| 1077 | +backend_tools.ToolRubberband = RubberbandQt |
| 1078 | + |
| 1079 | + |
915 | 1080 | def error_msg_qt(msg, parent=None):
|
916 | 1081 | if not isinstance(msg, six.string_types):
|
917 | 1082 | msg = ','.join(map(str, msg))
|
|
0 commit comments