Example #1
0
class FigureBrowser(QWidget):
    """
    Widget to browse the figures that were sent by the kernel to the IPython
    console to be plotted inline.
    """
    sig_option_changed = Signal(str, object)
    sig_collapse = Signal()

    def __init__(self,
                 parent=None,
                 options_button=None,
                 plugin_actions=[],
                 background_color=None):
        super(FigureBrowser, self).__init__(parent)

        self.shellwidget = None
        self.is_visible = True
        self.figviewer = None
        self.setup_in_progress = False
        self.background_color = background_color

        # Options :
        self.mute_inline_plotting = None
        self.show_plot_outline = None
        self.auto_fit_plotting = None

        # Option actions :
        self.mute_inline_action = None
        self.show_plot_outline_action = None
        self.auto_fit_action = None

        self.options_button = options_button
        self.plugin_actions = plugin_actions
        self.shortcuts = self.create_shortcuts()

    def setup(self,
              mute_inline_plotting=None,
              show_plot_outline=None,
              auto_fit_plotting=None):
        """Setup the figure browser with provided settings."""
        assert self.shellwidget is not None

        self.mute_inline_plotting = mute_inline_plotting
        self.show_plot_outline = show_plot_outline
        self.auto_fit_plotting = auto_fit_plotting

        if self.figviewer is not None:
            self.mute_inline_action.setChecked(mute_inline_plotting)
            self.show_plot_outline_action.setChecked(show_plot_outline)
            self.auto_fit_action.setChecked(auto_fit_plotting)
            return

        self.figviewer = FigureViewer(background_color=self.background_color)
        self.figviewer.setStyleSheet("FigureViewer{"
                                     "border: 1px solid lightgrey;"
                                     "border-top-width: 0px;"
                                     "border-bottom-width: 0px;"
                                     "border-left-width: 0px;"
                                     "}")
        self.thumbnails_sb = ThumbnailScrollBar(
            self.figviewer, background_color=self.background_color)

        # Option actions :
        self.setup_option_actions(mute_inline_plotting, show_plot_outline,
                                  auto_fit_plotting)

        # Create the layout :
        main_widget = QSplitter()
        main_widget.addWidget(self.figviewer)
        main_widget.addWidget(self.thumbnails_sb)
        main_widget.setFrameStyle(QScrollArea().frameStyle())

        self.tools_layout = QHBoxLayout()
        toolbar = self.setup_toolbar()
        for widget in toolbar:
            self.tools_layout.addWidget(widget)
        self.tools_layout.addStretch()
        self.setup_options_button()

        layout = create_plugin_layout(self.tools_layout, main_widget)
        self.setLayout(layout)

    def setup_toolbar(self):
        """Setup the toolbar"""
        savefig_btn = create_toolbutton(self,
                                        icon=ima.icon('filesave'),
                                        tip=_("Save Image As..."),
                                        triggered=self.save_figure)

        saveall_btn = create_toolbutton(self,
                                        icon=ima.icon('save_all'),
                                        tip=_("Save All Images..."),
                                        triggered=self.save_all_figures)

        copyfig_btn = create_toolbutton(
            self,
            icon=ima.icon('editcopy'),
            tip=_("Copy plot to clipboard as image (%s)" %
                  get_shortcut('plots', 'copy')),
            triggered=self.copy_figure)

        closefig_btn = create_toolbutton(self,
                                         icon=ima.icon('editclear'),
                                         tip=_("Remove image"),
                                         triggered=self.close_figure)

        closeall_btn = create_toolbutton(
            self,
            icon=ima.icon('filecloseall'),
            tip=_("Remove all images from the explorer"),
            triggered=self.close_all_figures)

        vsep1 = QFrame()
        vsep1.setFrameStyle(53)

        goback_btn = create_toolbutton(self,
                                       icon=ima.icon('ArrowBack'),
                                       tip=_("Previous Figure ({})".format(
                                           get_shortcut(
                                               'plots', 'previous figure'))),
                                       triggered=self.go_previous_thumbnail)

        gonext_btn = create_toolbutton(self,
                                       icon=ima.icon('ArrowForward'),
                                       tip=_("Next Figure ({})".format(
                                           get_shortcut(
                                               'plots', 'next figure'))),
                                       triggered=self.go_next_thumbnail)

        vsep2 = QFrame()
        vsep2.setFrameStyle(53)

        zoom_out_btn = create_toolbutton(
            self,
            icon=ima.icon('zoom_out'),
            tip=_("Zoom out (Ctrl + mouse-wheel-down)"),
            triggered=self.zoom_out)

        zoom_in_btn = create_toolbutton(
            self,
            icon=ima.icon('zoom_in'),
            tip=_("Zoom in (Ctrl + mouse-wheel-up)"),
            triggered=self.zoom_in)

        self.zoom_disp = QSpinBox()
        self.zoom_disp.setAlignment(Qt.AlignCenter)
        self.zoom_disp.setButtonSymbols(QSpinBox.NoButtons)
        self.zoom_disp.setReadOnly(True)
        self.zoom_disp.setSuffix(' %')
        self.zoom_disp.setRange(0, 9999)
        self.zoom_disp.setValue(100)
        self.figviewer.sig_zoom_changed.connect(self.zoom_disp.setValue)

        zoom_pan = QWidget()
        layout = QHBoxLayout(zoom_pan)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(zoom_out_btn)
        layout.addWidget(zoom_in_btn)
        layout.addWidget(self.zoom_disp)

        return [
            savefig_btn, saveall_btn, copyfig_btn, closefig_btn, closeall_btn,
            vsep1, goback_btn, gonext_btn, vsep2, zoom_pan
        ]

    def setup_option_actions(self, mute_inline_plotting, show_plot_outline,
                             auto_fit_plotting):
        """Setup the actions to show in the cog menu."""
        self.setup_in_progress = True
        self.mute_inline_action = create_action(
            self,
            _("Mute inline plotting"),
            tip=_("Mute inline plotting in the ipython console."),
            toggled=lambda state: self.option_changed('mute_inline_plotting',
                                                      state))
        self.mute_inline_action.setChecked(mute_inline_plotting)

        self.show_plot_outline_action = create_action(
            self,
            _("Show plot outline"),
            tip=_("Show the plot outline."),
            toggled=self.show_fig_outline_in_viewer)
        self.show_plot_outline_action.setChecked(show_plot_outline)

        self.auto_fit_action = create_action(
            self,
            _("Fit plots to window"),
            tip=_("Automatically fit plots to Plot pane size."),
            toggled=self.change_auto_fit_plotting)
        self.auto_fit_action.setChecked(auto_fit_plotting)

        self.actions = [
            self.mute_inline_action, self.show_plot_outline_action,
            self.auto_fit_action
        ]

        self.setup_in_progress = False

    def setup_options_button(self):
        """Add the cog menu button to the toolbar."""
        if not self.options_button:
            # When the FigureBowser widget is instatiated outside of the
            # plugin (for testing purpose for instance), we need to create
            # the options_button and set its menu.
            self.options_button = create_toolbutton(
                self, text=_('Options'), icon=ima.icon('tooloptions'))

            actions = self.actions + [MENU_SEPARATOR] + self.plugin_actions
            self.options_menu = QMenu(self)
            add_actions(self.options_menu, actions)
            self.options_button.setMenu(self.options_menu)

        if self.tools_layout.itemAt(self.tools_layout.count() - 1) is None:
            self.tools_layout.insertWidget(self.tools_layout.count() - 1,
                                           self.options_button)
        else:
            self.tools_layout.addWidget(self.options_button)

    def create_shortcuts(self):
        """Create shortcuts for this widget."""
        # Configurable
        copyfig = config_shortcut(self.copy_figure,
                                  context='plots',
                                  name='copy',
                                  parent=self)
        prevfig = config_shortcut(self.go_previous_thumbnail,
                                  context='plots',
                                  name='previous figure',
                                  parent=self)
        nextfig = config_shortcut(self.go_next_thumbnail,
                                  context='plots',
                                  name='next figure',
                                  parent=self)

        return [copyfig, prevfig, nextfig]

    def get_shortcut_data(self):
        """
        Return shortcut data, a list of tuples (shortcut, text, default).

        shortcut (QShortcut or QAction instance)
        text (string): action/shortcut description
        default (string): default key sequence
        """
        return [sc.data for sc in self.shortcuts]

    def option_changed(self, option, value):
        """Handle when the value of an option has changed"""
        setattr(self, to_text_string(option), value)
        self.shellwidget.set_namespace_view_settings()
        if self.setup_in_progress is False:
            self.sig_option_changed.emit(option, value)

    def show_fig_outline_in_viewer(self, state):
        """Draw a frame around the figure viewer if state is True."""
        if state is True:
            self.figviewer.figcanvas.setStyleSheet(
                "FigureCanvas{border: 1px solid lightgrey;}")
        else:
            self.figviewer.figcanvas.setStyleSheet("FigureCanvas{}")
        self.option_changed('show_plot_outline', state)

    def change_auto_fit_plotting(self, state):
        """Change the auto_fit_plotting option and scale images."""
        self.option_changed('auto_fit_plotting', state)
        self.figviewer.auto_fit_plotting = state
        self.figviewer.scale_image()

    def set_shellwidget(self, shellwidget):
        """Bind the shellwidget instance to the figure browser"""
        self.shellwidget = shellwidget
        shellwidget.set_figurebrowser(self)
        shellwidget.sig_new_inline_figure.connect(self._handle_new_figure)

    def get_actions(self):
        """Get the actions of the widget."""
        return self.actions

    def _handle_new_figure(self, fig, fmt):
        """
        Handle when a new figure is sent to the IPython console by the
        kernel.
        """
        self.thumbnails_sb.add_thumbnail(fig, fmt)

    # ---- Toolbar Handlers
    def zoom_in(self):
        """Zoom the figure in by a single step in the figure viewer."""
        self.figviewer.zoom_in()

    def zoom_out(self):
        """Zoom the figure out by a single step in the figure viewer."""
        self.figviewer.zoom_out()

    def go_previous_thumbnail(self):
        """
        Select the thumbnail previous to the currently selected one in the
        thumbnail scrollbar.
        """
        self.thumbnails_sb.go_previous_thumbnail()

    def go_next_thumbnail(self):
        """
        Select the thumbnail next to the currently selected one in the
        thumbnail scrollbar.
        """
        self.thumbnails_sb.go_next_thumbnail()

    def save_figure(self):
        """Save the currently selected figure in the thumbnail scrollbar."""
        self.thumbnails_sb.save_current_figure_as()

    def save_all_figures(self):
        """Save all the figures in a selected directory."""
        return self.thumbnails_sb.save_all_figures_as()

    def close_figure(self):
        """Close the currently selected figure in the thumbnail scrollbar."""
        self.thumbnails_sb.remove_current_thumbnail()

    def close_all_figures(self):
        """Close all the figures in the thumbnail scrollbar."""
        self.thumbnails_sb.remove_all_thumbnails()

    def copy_figure(self):
        """Copy figure from figviewer to clipboard."""
        if self.figviewer and self.figviewer.figcanvas.fig:
            self.figviewer.figcanvas.copy_figure()
Example #2
0
class FigureBrowser(QWidget):
    """
    Widget to browse the figures that were sent by the kernel to the IPython
    console to be plotted inline.
    """
    sig_option_changed = Signal(str, object)
    sig_collapse = Signal()

    def __init__(self, parent=None, options_button=None, plugin_actions=[],
                 background_color=None):
        super(FigureBrowser, self).__init__(parent)

        self.shellwidget = None
        self.is_visible = True
        self.figviewer = None
        self.setup_in_progress = False
        self.background_color = background_color

        # Options :
        self.mute_inline_plotting = None
        self.show_plot_outline = None

        # Option actions :
        self.mute_inline_action = None
        self.show_plot_outline_action = None

        self.options_button = options_button
        self.plugin_actions = plugin_actions
        self.shortcuts = self.create_shortcuts()

    def setup(self, mute_inline_plotting=None, show_plot_outline=None):
        """Setup the figure browser with provided settings."""
        assert self.shellwidget is not None

        self.mute_inline_plotting = mute_inline_plotting
        self.show_plot_outline = show_plot_outline

        if self.figviewer is not None:
            self.mute_inline_action.setChecked(mute_inline_plotting)
            self.show_plot_outline_action.setChecked(show_plot_outline)
            return

        self.figviewer = FigureViewer(background_color=self.background_color)
        self.figviewer.setStyleSheet("FigureViewer{"
                                     "border: 1px solid lightgrey;"
                                     "border-top-width: 0px;"
                                     "border-bottom-width: 0px;"
                                     "border-left-width: 0px;"
                                     "}")
        self.thumbnails_sb = ThumbnailScrollBar(
            self.figviewer, background_color=self.background_color)

        # Option actions :
        self.setup_option_actions(mute_inline_plotting, show_plot_outline)

        # Create the layout :
        main_widget = QSplitter()
        main_widget.addWidget(self.figviewer)
        main_widget.addWidget(self.thumbnails_sb)
        main_widget.setFrameStyle(QScrollArea().frameStyle())

        self.tools_layout = QHBoxLayout()
        toolbar = self.setup_toolbar()
        for widget in toolbar:
            self.tools_layout.addWidget(widget)
        self.tools_layout.addStretch()
        self.setup_options_button()

        layout = create_plugin_layout(self.tools_layout, main_widget)
        self.setLayout(layout)

    def setup_toolbar(self):
        """Setup the toolbar"""
        savefig_btn = create_toolbutton(
                self, icon=ima.icon('filesave'),
                tip=_("Save Image As..."),
                triggered=self.save_figure)

        saveall_btn = create_toolbutton(
                self, icon=ima.icon('save_all'),
                tip=_("Save All Images..."),
                triggered=self.save_all_figures)

        copyfig_btn = create_toolbutton(
            self, icon=ima.icon('editcopy'),
            tip=_("Copy plot to clipboard as image (%s)" %
                  get_shortcut('plots', 'copy')),
            triggered=self.copy_figure)

        closefig_btn = create_toolbutton(
                self, icon=ima.icon('editclear'),
                tip=_("Remove image"),
                triggered=self.close_figure)

        closeall_btn = create_toolbutton(
                self, icon=ima.icon('filecloseall'),
                tip=_("Remove all images from the explorer"),
                triggered=self.close_all_figures)

        vsep1 = QFrame()
        vsep1.setFrameStyle(53)

        goback_btn = create_toolbutton(
                self, icon=ima.icon('ArrowBack'),
                tip=_("Previous Figure ({})".format(
                      get_shortcut('plots', 'previous figure'))),
                triggered=self.go_previous_thumbnail)

        gonext_btn = create_toolbutton(
                self, icon=ima.icon('ArrowForward'),
                tip=_("Next Figure ({})".format(
                      get_shortcut('plots', 'next figure'))),
                triggered=self.go_next_thumbnail)

        vsep2 = QFrame()
        vsep2.setFrameStyle(53)

        zoom_out_btn = create_toolbutton(
                self, icon=ima.icon('zoom_out'),
                tip=_("Zoom out (Ctrl + mouse-wheel-down)"),
                triggered=self.zoom_out)

        zoom_in_btn = create_toolbutton(
                self, icon=ima.icon('zoom_in'),
                tip=_("Zoom in (Ctrl + mouse-wheel-up)"),
                triggered=self.zoom_in)

        self.zoom_disp = QSpinBox()
        self.zoom_disp.setAlignment(Qt.AlignCenter)
        self.zoom_disp.setButtonSymbols(QSpinBox.NoButtons)
        self.zoom_disp.setReadOnly(True)
        self.zoom_disp.setSuffix(' %')
        self.zoom_disp.setRange(0, 9999)
        self.zoom_disp.setValue(100)
        self.figviewer.sig_zoom_changed.connect(self.zoom_disp.setValue)

        zoom_pan = QWidget()
        layout = QHBoxLayout(zoom_pan)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(zoom_out_btn)
        layout.addWidget(zoom_in_btn)
        layout.addWidget(self.zoom_disp)

        return [savefig_btn, saveall_btn, copyfig_btn, closefig_btn,
                closeall_btn, vsep1, goback_btn, gonext_btn, vsep2, zoom_pan]

    def setup_option_actions(self, mute_inline_plotting, show_plot_outline):
        """Setup the actions to show in the cog menu."""
        self.setup_in_progress = True
        self.mute_inline_action = create_action(
            self, _("Mute inline plotting"),
            tip=_("Mute inline plotting in the ipython console."),
            toggled=lambda state:
            self.option_changed('mute_inline_plotting', state)
            )
        self.mute_inline_action.setChecked(mute_inline_plotting)

        self.show_plot_outline_action = create_action(
            self, _("Show plot outline"),
            tip=_("Show the plot outline."),
            toggled=self.show_fig_outline_in_viewer
            )
        self.show_plot_outline_action.setChecked(show_plot_outline)

        self.actions = [self.mute_inline_action, self.show_plot_outline_action]
        self.setup_in_progress = False

    def setup_options_button(self):
        """Add the cog menu button to the toolbar."""
        if not self.options_button:
            # When the FigureBowser widget is instatiated outside of the
            # plugin (for testing purpose for instance), we need to create
            # the options_button and set its menu.
            self.options_button = create_toolbutton(
                self, text=_('Options'), icon=ima.icon('tooloptions'))

            actions = self.actions + [MENU_SEPARATOR] + self.plugin_actions
            self.options_menu = QMenu(self)
            add_actions(self.options_menu, actions)
            self.options_button.setMenu(self.options_menu)

        if self.tools_layout.itemAt(self.tools_layout.count() - 1) is None:
            self.tools_layout.insertWidget(
                self.tools_layout.count() - 1, self.options_button)
        else:
            self.tools_layout.addWidget(self.options_button)

    def create_shortcuts(self):
        """Create shortcuts for this widget."""
        # Configurable
        copyfig = config_shortcut(self.copy_figure, context='plots',
                                  name='copy', parent=self)
        prevfig = config_shortcut(self.go_previous_thumbnail, context='plots',
                                  name='previous figure', parent=self)
        nextfig = config_shortcut(self.go_next_thumbnail, context='plots',
                                  name='next figure', parent=self)

        return [copyfig, prevfig, nextfig]

    def get_shortcut_data(self):
        """
        Return shortcut data, a list of tuples (shortcut, text, default).

        shortcut (QShortcut or QAction instance)
        text (string): action/shortcut description
        default (string): default key sequence
        """
        return [sc.data for sc in self.shortcuts]

    def option_changed(self, option, value):
        """Handle when the value of an option has changed"""
        setattr(self, to_text_string(option), value)
        self.shellwidget.set_namespace_view_settings()
        if self.setup_in_progress is False:
            self.sig_option_changed.emit(option, value)

    def show_fig_outline_in_viewer(self, state):
        """Draw a frame around the figure viewer if state is True."""
        if state is True:
            self.figviewer.figcanvas.setStyleSheet(
                    "FigureCanvas{border: 1px solid lightgrey;}")
        else:
            self.figviewer.figcanvas.setStyleSheet("FigureCanvas{}")
        self.option_changed('show_plot_outline', state)

    def set_shellwidget(self, shellwidget):
        """Bind the shellwidget instance to the figure browser"""
        self.shellwidget = shellwidget
        shellwidget.set_figurebrowser(self)
        shellwidget.sig_new_inline_figure.connect(self._handle_new_figure)

    def get_actions(self):
        """Get the actions of the widget."""
        return self.actions

    def _handle_new_figure(self, fig, fmt):
        """
        Handle when a new figure is sent to the IPython console by the
        kernel.
        """
        self.thumbnails_sb.add_thumbnail(fig, fmt)

    # ---- Toolbar Handlers
    def zoom_in(self):
        """Zoom the figure in by a single step in the figure viewer."""
        self.figviewer.zoom_in()

    def zoom_out(self):
        """Zoom the figure out by a single step in the figure viewer."""
        self.figviewer.zoom_out()

    def go_previous_thumbnail(self):
        """
        Select the thumbnail previous to the currently selected one in the
        thumbnail scrollbar.
        """
        self.thumbnails_sb.go_previous_thumbnail()

    def go_next_thumbnail(self):
        """
        Select the thumbnail next to the currently selected one in the
        thumbnail scrollbar.
        """
        self.thumbnails_sb.go_next_thumbnail()

    def save_figure(self):
        """Save the currently selected figure in the thumbnail scrollbar."""
        self.thumbnails_sb.save_current_figure_as()

    def save_all_figures(self):
        """Save all the figures in a selected directory."""
        return self.thumbnails_sb.save_all_figures_as()

    def close_figure(self):
        """Close the currently selected figure in the thumbnail scrollbar."""
        self.thumbnails_sb.remove_current_thumbnail()

    def close_all_figures(self):
        """Close all the figures in the thumbnail scrollbar."""
        self.thumbnails_sb.remove_all_thumbnails()

    def copy_figure(self):
        """Copy figure from figviewer to clipboard."""
        if self.figviewer and self.figviewer.figcanvas.fig:
            self.figviewer.figcanvas.copy_figure()
Example #3
0
class RotateLabelDlg(QDialog):

    rotateSelectedPolygon = QtCore.Signal(bool, int)

    def __init__(self,
                 parent=None,
                 rotation_connection=None,
                 clockwise=True,
                 angle=0):
        super(RotateLabelDlg, self).__init__(parent)
        self.setWindowTitle(self.tr("Rotate the selected polygon"))
        if rotation_connection is not None:
            self.rotateSelectedPolygon.connect(rotation_connection)
        self.clockwise = clockwise
        self.angle = angle
        self.setLayout(self.createLayout())
        self.setFixedSize(400, 80)

    def resetRotateDlg(self, parent_topright):
        self.clockwise = True
        self.angle = 0
        self.radio_clockwise.setChecked(self.clockwise)
        self.angle_editor.setValue(self.angle)
        self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
        size = self.size()
        self.move(parent_topright.x() - size.width(), parent_topright.y())

    def createLayout(self):
        hbox = QHBoxLayout()
        self.radio_clockwise = QRadioButton(self.tr("clockwise"), self)
        self.radio_clockwise.clockwise = True
        self.radio_clockwise.setChecked(self.clockwise)
        self.radio_clockwise.toggled.connect(self.rotationDirectionChanged)

        self.radio_anticlockwise = QRadioButton(self.tr("anticlockwise"), self)
        self.radio_anticlockwise.clockwise = False
        self.radio_anticlockwise.setChecked(not self.clockwise)
        self.radio_anticlockwise.toggled.connect(self.rotationDirectionChanged)

        self.angle_editor = QSpinBox(self)
        self.angle_editor.setButtonSymbols(
            QtWidgets.QAbstractSpinBox.NoButtons)
        self.angle_editor.setRange(0, 360)
        self.angle_editor.setSuffix(" °")
        self.angle_editor.setValue(self.angle)
        self.angle_editor.setToolTip("rotation angle")
        self.angle_editor.setStatusTip(self.toolTip())
        self.angle_editor.setAlignment(QtCore.Qt.AlignCenter)
        self.angle_editor.valueChanged.connect(self.rotationAngleChanged)

        hbox.addWidget(self.radio_anticlockwise)
        hbox.addWidget(self.radio_clockwise)
        hbox.addWidget(self.angle_editor)

        self.rotate_bar = AngleBar(self, self.clockwise, self.angle,
                                   self.angleBarChanged)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.rotate_bar)
        return vbox

    def rotationDirectionChanged(self, value):
        # radio button
        rbtn = self.sender()
        if rbtn.isChecked():
            self.clockwise = rbtn.clockwise
            self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
            self.appleRotateInfo()

    def rotationAngleChanged(self, value):
        # spinbox
        if value != self.angle:
            self.angle = value
            self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
            self.appleRotateInfo()

    def angleBarChanged(self, clockwise, angle):
        if self.clockwise == clockwise and self.angle == angle:
            return
        self.clockwise = clockwise
        self.angle = angle

        self.angle_editor.setValue(self.angle)
        if self.clockwise and not self.radio_clockwise.isChecked():
            self.radio_clockwise.setChecked(True)
        elif not self.clockwise and not self.radio_anticlockwise.isChecked():
            self.radio_anticlockwise.setChecked(True)
        else:
            self.appleRotateInfo()

    def appleRotateInfo(self):
        self.rotateSelectedPolygon.emit(self.clockwise, self.angle)
Example #4
0
class PlotsWidget(PluginMainWidget):
    DEFAULT_OPTIONS = {
        'auto_fit_plotting': True,
        'mute_inline_plotting': True,
        'show_plot_outline': True,
        'save_dir': getcwd_or_home()
    }

    # Signals
    sig_option_changed = Signal(str, object)

    sig_figure_loaded = Signal()
    """This signal is emitted when a figure is loaded succesfully"""

    sig_redirect_stdio_requested = Signal(bool)
    """
    This signal is emitted to request the main application to redirect
    standard output/error when using Open/Save/Browse dialogs within widgets.

    Parameters
    ----------
    redirect: bool
        Start redirect (True) or stop redirect (False).
    """
    def __init__(self,
                 name=None,
                 plugin=None,
                 parent=None,
                 options=DEFAULT_OPTIONS):
        super().__init__(name, plugin, parent, options)

        # Widgets
        self._stack = PlotsStackedWidget(parent=self)
        self._shellwidgets = {}
        self.zoom_disp = QSpinBox(self)
        self._right_clicked_thumbnail = None

        # Widget setup
        self.zoom_disp.setAlignment(Qt.AlignCenter)
        self.zoom_disp.setButtonSymbols(QSpinBox.NoButtons)
        self.zoom_disp.setReadOnly(True)
        self.zoom_disp.setSuffix(' %')
        self.zoom_disp.setRange(0, 9999)
        self.zoom_disp.setValue(100)

        # Layout
        layout = QHBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._stack)
        self.setLayout(layout)

        # Signals
        self._stack.sig_figure_loaded.connect(self.sig_figure_loaded)
        self._stack.sig_figure_menu_requested.connect(self.show_figure_menu)
        self._stack.sig_thumbnail_menu_requested.connect(
            self.show_thumbnail_menu)
        self._stack.sig_zoom_changed.connect(self.zoom_disp.setValue)
        self._stack.sig_figure_loaded.connect(self.update_actions)
        self._stack.sig_save_dir_changed.connect(
            lambda val: self.set_option('save_dir', val))

    # --- PluginMainWidget API
    # ------------------------------------------------------------------------
    def get_title(self):
        return _('Plots')

    def get_focus_widget(self):
        widget = self.current_widget()
        if widget and widget.thumbnails_sb.current_thumbnail is not None:
            if widget.figviewer.figcanvas.fig:
                widget = widget.thumbnails_sb.scrollarea

        return widget

    def setup(self, options):
        # Menu actions
        self.mute_action = self.create_action(
            name=PlotsWidgetActions.ToggleMuteInlinePlotting,
            text=_("Mute inline plotting"),
            tip=_("Mute inline plotting in the ipython console."),
            toggled=lambda val: self.set_option('mute_inline_plotting', val),
            initial=options['mute_inline_plotting'],
        )
        self.outline_action = self.create_action(
            name=PlotsWidgetActions.ToggleShowPlotOutline,
            text=_("Show plot outline"),
            tip=_("Show the plot outline."),
            toggled=lambda val: self.set_option('show_plot_outline', val),
            initial=options['show_plot_outline'],
        )
        self.fit_action = self.create_action(
            name=PlotsWidgetActions.ToggleAutoFitPlotting,
            text=_("Fit plots to window"),
            tip=_("Automatically fit plots to Plot pane size."),
            toggled=lambda val: self.set_option('auto_fit_plotting', val),
            initial=options['auto_fit_plotting'],
        )

        # Toolbar actions
        save_action = self.create_action(
            name=PlotsWidgetActions.Save,
            text=_("Save plot as..."),
            icon=self.create_icon('filesave'),
            triggered=self.save_plot,
            register_shortcut=True,
        )
        save_all_action = self.create_action(
            name=PlotsWidgetActions.SaveAll,
            text=_("Save all plots..."),
            icon=self.create_icon('save_all'),
            triggered=self.save_all_plots,
            register_shortcut=True,
        )
        copy_action = self.create_action(
            name=PlotsWidgetActions.Copy,
            text=_("Copy Image"),
            icon=self.create_icon('editcopy'),
            triggered=self.copy_image,
            register_shortcut=True,
        )
        remove_action = self.create_action(
            name=PlotsWidgetActions.Close,
            text=_("Remove plot"),
            icon=self.create_icon('editclear'),
            triggered=self.remove_plot,
        )
        remove_all_action = self.create_action(
            name=PlotsWidgetActions.CloseAll,
            text=_("Remove all plots"),
            tip=_("Remove all plots"),
            icon=self.create_icon('filecloseall'),
            triggered=self.remove_all_plots,
            register_shortcut=True,
        )
        previous_action = self.create_action(
            name=PlotsWidgetActions.MoveToPreviousFigure,
            text=_("Previous plot"),
            tip=_("Previous plot"),
            icon=self.create_icon('ArrowBack'),
            triggered=self.previous_plot,
            register_shortcut=True,
        )
        next_action = self.create_action(
            name=PlotsWidgetActions.MoveToNextFigure,
            text=_("Next plot"),
            tip=_("Next plot"),
            icon=self.create_icon('ArrowForward'),
            triggered=self.next_plot,
            register_shortcut=True,
        )
        zoom_in_action = self.create_action(
            name=PlotsWidgetActions.ZoomIn,
            text=_("Zoom in"),
            tip=_("Zoom in"),
            icon=self.create_icon('zoom_in'),
            triggered=self.zoom_in,
            register_shortcut=True,
        )
        zoom_out_action = self.create_action(
            name=PlotsWidgetActions.ZoomOut,
            text=_("Zoom out"),
            tip=_("Zoom out"),
            icon=self.create_icon('zoom_out'),
            triggered=self.zoom_out,
            register_shortcut=True,
        )

        # Options menu
        options_menu = self.get_options_menu()
        self.add_item_to_menu(self.mute_action, menu=options_menu)
        self.add_item_to_menu(self.outline_action, menu=options_menu)
        self.add_item_to_menu(self.fit_action, menu=options_menu)

        # Main toolbar
        main_toolbar = self.get_main_toolbar()
        for item in [
                save_action, save_all_action, copy_action, remove_action,
                remove_all_action, previous_action, next_action,
                zoom_in_action, zoom_out_action, self.zoom_disp
        ]:
            self.add_item_to_toolbar(
                item,
                toolbar=main_toolbar,
                section=PlotsWidgetMainToolBarSections.Edit,
            )

        # Context menu
        context_menu = self.create_menu(PluginMainWidgetMenus.Context)
        for item in [save_action, copy_action, remove_action]:
            self.add_item_to_menu(item, menu=context_menu)

    def update_actions(self):
        value = False
        widget = self.current_widget()
        figviewer = None
        if widget:
            figviewer = widget.figviewer
            thumbnails_sb = widget.thumbnails_sb
            value = figviewer.figcanvas.fig is not None

        for __, action in self.get_actions().items():
            if action and action not in [
                    self.mute_action, self.outline_action, self.fit_action
            ]:
                action.setEnabled(value)

                # IMPORTANT: Since we are defining the main actions in here
                # and the context is WidgetWithChildrenShortcut we need to
                # assign the same actions to the children widgets in order
                # for shortcuts to work
                if figviewer:
                    figviewer_actions = figviewer.actions()
                    thumbnails_sb_actions = thumbnails_sb.actions()

                    if action not in figviewer_actions:
                        figviewer.addAction(action)

                    if action not in thumbnails_sb_actions:
                        thumbnails_sb.addAction(action)

        self.zoom_disp.setEnabled(value)

        # Disable zoom buttons if autofit
        if value:
            value = not self.get_option('auto_fit_plotting')
            self.get_action(PlotsWidgetActions.ZoomIn).setEnabled(value)
            self.get_action(PlotsWidgetActions.ZoomOut).setEnabled(value)
            self.zoom_disp.setEnabled(value)

    def on_option_update(self, option, value):
        for index in range(self.count()):
            widget = self._stack.widget(index)
            if widget:
                widget.setup({option: value})
                self.update_actions()

    # --- Public API:
    # ------------------------------------------------------------------------
    def set_current_widget(self, fig_browser):
        """
        Set the current figure browser widget in the stack.

        Parameters
        ----------
        fig_browser: spyder.plugins.plots.widgets.figurebrowser.FigureBrowser
            The widget to set.
        """
        self._stack.setCurrentWidget(fig_browser)

    def current_widget(self):
        """
        Return the current figure browser widget in the stack.

        Returns
        -------
        spyder.plugins.plots.widgets.figurebrowser.FigureBrowser
            The current widget.
        """
        return self._stack.currentWidget()

    def count(self):
        """
        Return the number of widgets in the stack.

        Returns
        -------
        int
            The number of widgets in the stack.
        """
        return self._stack.count()

    def remove_widget(self, fig_browser):
        """
        Remove widget from stack.

        Parameters
        ----------
        fig_browser: spyder.plugins.plots.widgets.figurebrowser.FigureBrowser
            The figure browser widget to remove.
        """
        self._stack.removeWidget(fig_browser)

    def add_widget(self, fig_browser):
        """
        Add widget to stack.

        Parameters
        ----------
        fig_browser: spyder.plugins.plots.widgets.figurebrowser.FigureBrowser
            The figure browser widget to add.
        """
        self._stack.addWidget(fig_browser)

    def add_shellwidget(self, shellwidget):
        """
        Add a new shellwidget registered with the plots plugin.

        This function registers a new FigureBrowser for browsing the figures
        in the shell.

        Parameters
        ----------
        shelwidget: spyder.plugins.ipyconsole.widgets.shell.ShellWidget
            The shell widget.
        """
        shellwidget_id = id(shellwidget)
        if shellwidget_id not in self._shellwidgets:
            fig_browser = FigureBrowser(parent=self._stack,
                                        background_color=MAIN_BG_COLOR)
            fig_browser.set_shellwidget(shellwidget)
            fig_browser.sig_redirect_stdio_requested.connect(
                self.sig_redirect_stdio_requested)
            self.add_widget(fig_browser)
            self._shellwidgets[shellwidget_id] = fig_browser
            self.set_shellwidget(shellwidget)
            return fig_browser

    def remove_shellwidget(self, shellwidget):
        """
        Remove the shellwidget registered with the plots plugin.

        Parameters
        ----------
        shelwidget: spyder.plugins.ipyconsole.widgets.shell.ShellWidget
            The shell widget.
        """
        shellwidget_id = id(shellwidget)
        if shellwidget_id in self._shellwidgets:
            fig_browser = self._shellwidgets.pop(shellwidget_id)
            self.remove_widget(fig_browser)
            fig_browser.close()

    def set_shellwidget(self, shellwidget):
        """
        Update the current shellwidget displayed with the plots plugin.

        Parameters
        ----------
        shelwidget: spyder.plugins.ipyconsole.widgets.shell.ShellWidget
            The shell widget.
        """
        shellwidget_id = id(shellwidget)
        if shellwidget_id in self._shellwidgets:
            fig_browser = self._shellwidgets[shellwidget_id]
            fig_browser.setup(self._options)
            self.set_current_widget(fig_browser)

    def show_figure_menu(self, qpoint):
        """
        Show main figure menu and display on given `qpoint`.

        Parameters
        ----------
        qpoint: QPoint
            The point to display the menu in global coordinated.
        """
        self._right_clicked_thumbnail = None
        widget = self.current_widget()
        if widget:
            self.get_menu(PluginMainWidgetMenus.Context).popup(qpoint)

    def show_thumbnail_menu(self, qpoint, thumbnail):
        """
        Show menu on a given `thumbnail` and display on given `qpoint`.

        Parameters
        ----------
        qpoint: QPoint
            The point to display the menu in global coordinated.
        """
        self._right_clicked_thumbnail = thumbnail
        widget = self.current_widget()
        if widget:
            self.get_menu(PluginMainWidgetMenus.Context).popup(qpoint)

    def save_plot(self):
        """
        Save currently active plot or plot selected to be saved with
        context menu in the thumbnails scrollbar.
        """
        widget = self.current_widget()
        if widget:
            if self._right_clicked_thumbnail is None:
                widget.thumbnails_sb.save_current_figure_as()
            else:
                widget.thumbnails_sb.save_thumbnail_figure_as(
                    self._right_clicked_thumbnail)
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

    def save_all_plots(self):
        """Save all available plots."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.save_all_figures_as()

    def copy_image(self):
        """
        Copy currently active plot or plot selected to be copied with
        context menu in the thumbnails scrollbar into the clipboard.
        """
        widget = self.current_widget()
        if widget and widget.figviewer and widget.figviewer.figcanvas.fig:
            if self._right_clicked_thumbnail is None:
                widget.figviewer.figcanvas.copy_figure()
            else:
                self._right_clicked_thumbnail.canvas.copy_figure()
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

    def remove_plot(self):
        """
        Remove currently active plot or plot selected to be removed with
        context menu in the thumbnails scrollbar.
        """
        widget = self.current_widget()
        if widget:
            if self._right_clicked_thumbnail is None:
                widget.thumbnails_sb.remove_current_thumbnail()
            else:
                widget.thumbnails_sb.remove_thumbnail(
                    self._right_clicked_thumbnail)
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

        self.update_actions()

    def remove_all_plots(self):
        """Remove all available plots.."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.remove_all_thumbnails()

        self.update_actions()

    def previous_plot(self):
        """Select the previous plot in the thumbnails scrollbar."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.go_previous_thumbnail()

    def next_plot(self):
        """Select the next plot in the thumbnails scrollbar."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.go_next_thumbnail()

    def zoom_in(self):
        """Perform a zoom in on the main figure."""
        widget = self.current_widget()
        if widget:
            widget.zoom_in()

    def zoom_out(self):
        """Perform a zoom out on the main figure."""
        widget = self.current_widget()
        if widget:
            widget.zoom_out()
Example #5
0
class PlotsWidget(ShellConnectMainWidget):
    sig_figure_loaded = Signal()
    """This signal is emitted when a figure is loaded succesfully"""

    sig_redirect_stdio_requested = Signal(bool)
    """
    This signal is emitted to request the main application to redirect
    standard output/error when using Open/Save/Browse dialogs within widgets.

    Parameters
    ----------
    redirect: bool
        Start redirect (True) or stop redirect (False).
    """
    def __init__(self, name=None, plugin=None, parent=None):
        super().__init__(name, plugin, parent)

        # Widgets
        self.zoom_disp = QSpinBox(self)
        self.zoom_disp.ID = PlotsWidgetToolbarItems.ZoomSpinBox
        self._right_clicked_thumbnail = None

        # Widget setup
        self.zoom_disp.setAlignment(Qt.AlignCenter)
        self.zoom_disp.setButtonSymbols(QSpinBox.NoButtons)
        self.zoom_disp.setReadOnly(True)
        self.zoom_disp.setSuffix(' %')
        self.zoom_disp.setRange(0, 9999)
        self.zoom_disp.setValue(100)

        # Resize to a huge width to get the right size of the thumbnail
        # scrollbar at startup.
        self.resize(50000, self.height())

    # ---- PluginMainWidget API
    # ------------------------------------------------------------------------
    def get_title(self):
        return _('Plots')

    def get_focus_widget(self):
        widget = self.current_widget()
        if widget and widget.thumbnails_sb.current_thumbnail is not None:
            if widget.figviewer.figcanvas.fig:
                widget = widget.thumbnails_sb.scrollarea

        return widget

    def setup(self):
        # Menu actions
        self.mute_action = self.create_action(
            name=PlotsWidgetActions.ToggleMuteInlinePlotting,
            text=_("Mute inline plotting"),
            tip=_("Mute inline plotting in the ipython console."),
            toggled=True,
            initial=self.get_conf('mute_inline_plotting'),
            option='mute_inline_plotting')
        self.outline_action = self.create_action(
            name=PlotsWidgetActions.ToggleShowPlotOutline,
            text=_("Show plot outline"),
            tip=_("Show the plot outline."),
            toggled=True,
            initial=self.get_conf('show_plot_outline'),
            option='show_plot_outline')
        self.fit_action = self.create_action(
            name=PlotsWidgetActions.ToggleAutoFitPlotting,
            text=_("Fit plots to window"),
            tip=_("Automatically fit plots to Plot pane size."),
            toggled=True,
            initial=self.get_conf('auto_fit_plotting'),
            option='auto_fit_plotting')

        # Toolbar actions
        save_action = self.create_action(
            name=PlotsWidgetActions.Save,
            text=_("Save plot as..."),
            tip=_("Save plot as..."),
            icon=self.create_icon('filesave'),
            triggered=self.save_plot,
            register_shortcut=True,
        )
        save_all_action = self.create_action(
            name=PlotsWidgetActions.SaveAll,
            text=_("Save all plots..."),
            tip=_("Save all plots..."),
            icon=self.create_icon('save_all'),
            triggered=self.save_all_plots,
            register_shortcut=True,
        )
        copy_action = self.create_action(
            name=PlotsWidgetActions.Copy,
            text=_("Copy image"),
            tip=_("Copy plot to clipboard as image"),
            icon=self.create_icon('editcopy'),
            triggered=self.copy_image,
            register_shortcut=True,
        )
        remove_action = self.create_action(
            name=PlotsWidgetActions.Close,
            text=_("Remove plot"),
            icon=self.create_icon('editclear'),
            triggered=self.remove_plot,
            register_shortcut=True,
        )
        remove_all_action = self.create_action(
            name=PlotsWidgetActions.CloseAll,
            text=_("Remove all plots"),
            tip=_("Remove all plots"),
            icon=self.create_icon('filecloseall'),
            triggered=self.remove_all_plots,
            register_shortcut=True,
        )
        previous_action = self.create_action(
            name=PlotsWidgetActions.MoveToPreviousFigure,
            text=_("Previous plot"),
            tip=_("Previous plot"),
            icon=self.create_icon('previous'),
            triggered=self.previous_plot,
            register_shortcut=True,
        )
        next_action = self.create_action(
            name=PlotsWidgetActions.MoveToNextFigure,
            text=_("Next plot"),
            tip=_("Next plot"),
            icon=self.create_icon('next'),
            triggered=self.next_plot,
            register_shortcut=True,
        )
        zoom_in_action = self.create_action(
            name=PlotsWidgetActions.ZoomIn,
            text=_("Zoom in"),
            tip=_("Zoom in"),
            icon=self.create_icon('zoom_in'),
            triggered=self.zoom_in,
            register_shortcut=True,
        )
        zoom_out_action = self.create_action(
            name=PlotsWidgetActions.ZoomOut,
            text=_("Zoom out"),
            tip=_("Zoom out"),
            icon=self.create_icon('zoom_out'),
            triggered=self.zoom_out,
            register_shortcut=True,
        )

        # Options menu
        options_menu = self.get_options_menu()
        self.add_item_to_menu(self.mute_action, menu=options_menu)
        self.add_item_to_menu(self.outline_action, menu=options_menu)
        self.add_item_to_menu(self.fit_action, menu=options_menu)

        # Main toolbar
        main_toolbar = self.get_main_toolbar()
        for item in [
                save_action, save_all_action, copy_action, remove_action,
                remove_all_action, previous_action, next_action,
                zoom_in_action, zoom_out_action, self.zoom_disp
        ]:
            self.add_item_to_toolbar(
                item,
                toolbar=main_toolbar,
                section=PlotsWidgetMainToolbarSections.Edit,
            )

        # Context menu
        context_menu = self.create_menu(PluginMainWidgetMenus.Context)
        for item in [save_action, copy_action, remove_action]:
            self.add_item_to_menu(item, menu=context_menu)

    def update_actions(self):
        value = False
        widget = self.current_widget()
        figviewer = None
        if widget:
            figviewer = widget.figviewer
            thumbnails_sb = widget.thumbnails_sb
            value = figviewer.figcanvas.fig is not None

        for __, action in self.get_actions().items():
            if action and action not in [
                    self.mute_action, self.outline_action, self.fit_action,
                    self.undock_action, self.close_action, self.dock_action,
                    self.toggle_view_action
            ]:
                action.setEnabled(value)

                # IMPORTANT: Since we are defining the main actions in here
                # and the context is WidgetWithChildrenShortcut we need to
                # assign the same actions to the children widgets in order
                # for shortcuts to work
                if figviewer:
                    figviewer_actions = figviewer.actions()
                    thumbnails_sb_actions = thumbnails_sb.actions()

                    if action not in figviewer_actions:
                        figviewer.addAction(action)

                    if action not in thumbnails_sb_actions:
                        thumbnails_sb.addAction(action)

        self.zoom_disp.setEnabled(value)

        # Disable zoom buttons if autofit
        if value:
            value = not self.get_conf('auto_fit_plotting')
            self.get_action(PlotsWidgetActions.ZoomIn).setEnabled(value)
            self.get_action(PlotsWidgetActions.ZoomOut).setEnabled(value)
            self.zoom_disp.setEnabled(value)

    @on_conf_change(option=[
        'auto_fit_plotting', 'mute_inline_plotting', 'show_plot_outline',
        'save_dir'
    ])
    def on_section_conf_change(self, option, value):
        for index in range(self.count()):
            widget = self._stack.widget(index)
            if widget:
                widget.setup({option: value})
                self.update_actions()

    # ---- Public API:
    # ------------------------------------------------------------------------

    def create_new_widget(self, shellwidget):
        fig_browser = FigureBrowser(parent=self,
                                    background_color=MAIN_BG_COLOR)
        fig_browser.update_splitter_widths(self.width())
        fig_browser.set_shellwidget(shellwidget)
        fig_browser.sig_redirect_stdio_requested.connect(
            self.sig_redirect_stdio_requested)

        fig_browser.sig_figure_menu_requested.connect(self.show_figure_menu)
        fig_browser.sig_thumbnail_menu_requested.connect(
            self.show_thumbnail_menu)
        fig_browser.sig_figure_loaded.connect(self.update_actions)
        fig_browser.sig_save_dir_changed.connect(
            lambda val: self.set_conf('save_dir', val))
        fig_browser.sig_zoom_changed.connect(self.zoom_disp.setValue)
        return fig_browser

    def close_widget(self, fig_browser):
        fig_browser.close()

    def switch_widget(self, fig_browser, old_fig_browser):
        option_keys = [('auto_fit_plotting', True),
                       ('mute_inline_plotting', True),
                       ('show_plot_outline', True),
                       ('save_dir', getcwd_or_home())]

        conf_values = {k: self.get_conf(k, d) for k, d in option_keys}
        fig_browser.setup(conf_values)

    def show_figure_menu(self, qpoint):
        """
        Show main figure menu and display on given `qpoint`.

        Parameters
        ----------
        qpoint: QPoint
            The point to display the menu in global coordinated.
        """
        self._right_clicked_thumbnail = None
        widget = self.current_widget()
        if widget:
            self.get_menu(PluginMainWidgetMenus.Context).popup(qpoint)

    def show_thumbnail_menu(self, qpoint, thumbnail):
        """
        Show menu on a given `thumbnail` and display on given `qpoint`.

        Parameters
        ----------
        qpoint: QPoint
            The point to display the menu in global coordinated.
        """
        self._right_clicked_thumbnail = thumbnail
        widget = self.current_widget()
        if widget:
            self.get_menu(PluginMainWidgetMenus.Context).popup(qpoint)

    def save_plot(self):
        """
        Save currently active plot or plot selected to be saved with
        context menu in the thumbnails scrollbar.
        """
        widget = self.current_widget()
        if widget:
            if self._right_clicked_thumbnail is None:
                widget.thumbnails_sb.save_current_figure_as()
            else:
                widget.thumbnails_sb.save_thumbnail_figure_as(
                    self._right_clicked_thumbnail)
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

    def save_all_plots(self):
        """Save all available plots."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.save_all_figures_as()

    def copy_image(self):
        """
        Copy currently active plot or plot selected to be copied with
        context menu in the thumbnails scrollbar into the clipboard.
        """
        widget = self.current_widget()
        if widget and widget.figviewer and widget.figviewer.figcanvas.fig:
            if self._right_clicked_thumbnail is None:
                widget.figviewer.figcanvas.copy_figure()
            else:
                self._right_clicked_thumbnail.canvas.copy_figure()
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

    def remove_plot(self):
        """
        Remove currently active plot or plot selected to be removed with
        context menu in the thumbnails scrollbar.
        """
        widget = self.current_widget()
        if widget:
            if self._right_clicked_thumbnail is None:
                widget.thumbnails_sb.remove_current_thumbnail()
            else:
                widget.thumbnails_sb.remove_thumbnail(
                    self._right_clicked_thumbnail)
                # Reset the toolbar buttons to use the figviewer and not the thumbnail
                # selection
                self._right_clicked_thumbnail = None

        self.update_actions()

    def remove_all_plots(self):
        """Remove all available plots.."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.remove_all_thumbnails()

        self.update_actions()

    def previous_plot(self):
        """Select the previous plot in the thumbnails scrollbar."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.go_previous_thumbnail()

    def next_plot(self):
        """Select the next plot in the thumbnails scrollbar."""
        widget = self.current_widget()
        if widget:
            widget.thumbnails_sb.go_next_thumbnail()

    def zoom_in(self):
        """Perform a zoom in on the main figure."""
        widget = self.current_widget()
        if widget:
            widget.zoom_in()

    def zoom_out(self):
        """Perform a zoom out on the main figure."""
        widget = self.current_widget()
        if widget:
            widget.zoom_out()