Source code for schrodinger.ui.qt.smatplotlib
"""
Contains Schrodinger helper widgets for matplotlib display in PyQt
"""
# Copyright Schrodinger, LLC. All rights reserved.
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import navtoolbar
[docs]class SmatplotlibCanvas(FigureCanvasQTAgg):
    """
    Custom subclass of FigureCanvasQTAgg that does the following:
        - Allows for simultaneous definition of the Canvas, Figure and toolbar
            objects, and placing them in a layout
        - Fixes known bugs with the mouse events detecting modifier keys
    """
[docs]    def __init__(self,
                 width=5,
                 height=4,
                 dpi=100,
                 toolbar=True,
                 layout=None,
                 expanding=True,
                 **kwargs):
        """
        :type width: number
        :param width: width of the plot Figure in inches
        :type height: number
        :param height: height of the plot Figure in inches
        :type dpi: int
        :param dpi: resolution of the plot
        :type toolbar: boolean
        :param toolbar: True if the toolbar should be created, but the parent
            parameter must be supplied in this case
        :type layout: QLayout object
        :param layout: If layout is supplied, the toolbar and canvas will be
            placed in it.
        Extra keyword arguments are passed to the toolbar function
        """
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        # self._control_down is used to capture when the control key is down
        self._control_down = False
        FigureCanvasQTAgg.__init__(self, self.fig)
        try:
            # PYTHON-2324
            import pyemf  # noqa: F401
        except ImportError:
            try:
                del self.filetypes['emf']
            except KeyError:
                pass
        if expanding:
            FigureCanvasQTAgg.setSizePolicy(self,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Expanding)
        FigureCanvasQTAgg.updateGeometry(self)
        # Do not allow shrinking below this size (fixes PYAPP-6020):
        self.setMinimumSize(100, 100)
        # Create the toolbar if asked for
        if toolbar:
            self.toolbar = navtoolbar.NavToolbar(self, self, **kwargs)
            self.toolbar.update()
            if layout is not None:
                layout.addWidget(self.toolbar)
        if layout is not None:
            layout.addWidget(self)
        # Custom handling of events
        self.installEventFilter(self) 
[docs]    def eventFilter(self, obj, event):
        """
        The canvas needs to grab keyboard input in order to reliably tell when
        a modifier key (shift or control) is down when a mouse button is
        pressed/released.
        Some environments have trouble with passing the control key in events -
        a control-left-click is often mapped to a right-click.  Therefore we do
        our best to capture on our own when the control key is down.  Note that
        even this breaks for multiple control-clicks on Linux running under
        VMWare Fusion on Macs, because VMWare by default "lifts" the control
        key after the first click.
        :type obj: not used
        :param obj: not used
        :type event: QEvent
        :param event: the event object
        """
        # Grab and release the keyboard when the mouse enters or leaves the
        # canvas
        if event.type() == QtCore.QEvent.Enter:
            self.grabKeyboard()
        elif event.type() == QtCore.QEvent.Leave:
            self.releaseKeyboard()
        # Capture when the control key is pressed or raised.
        elif event.type() == QtCore.QEvent.KeyPress:
            key_event = QtGui.QKeyEvent(event)
            if key_event.key() == QtCore.Qt.Key_Control:
                self._control_down = True
        elif event.type() == QtCore.QEvent.KeyRelease:
            key_event = QtGui.QKeyEvent(event)
            if key_event.key() == QtCore.Qt.Key_Control:
                self._control_down = False
        return False 
[docs]    def mousePressEvent(self, event):
        """
        Add in the control modifier key to the button_press_event
        :type event: QMouseEvent
        :param event: the QMouseEvent that triggered this handler
        self._key is matplotlib's way of storing the modifier keys
        """
        if not self._key and self._control_down:
            self._key = 'control'
        FigureCanvasQTAgg.mousePressEvent(self, event) 
[docs]    def mouseReleaseEvent(self, event):
        """
        Add in the control modifier key to the button_release_event
        :type event: QMouseEvent
        :param event: the QMouseEvent that triggered this handler
        self._key is matplotlib's way of storing the modifier keys
        """
        if not self._key and self._control_down:
            self._key = 'control'
        FigureCanvasQTAgg.mouseReleaseEvent(self, event)