Skip to content

Commit 85a5a35

Browse files
committed
Makes messaging and clipboard logic into its own mixin
1 parent df81064 commit 85a5a35

3 files changed

Lines changed: 50 additions & 36 deletions

File tree

plottr/plot/base.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import numpy as np
1515

16-
from .. import Signal, Flowchart, QtWidgets
16+
from .. import Signal, Flowchart, QtCore, QtWidgets
1717
from ..data.datadict import DataDictBase, DataDict, MeshgridDataDict
1818
from ..node import Node, linearFlowchart
1919
from ..utils import LabeledOptions
@@ -22,6 +22,37 @@
2222
__license__ = 'MIT'
2323

2424

25+
class ClipboardMessageMixin:
26+
"""
27+
Mixin for widgets that show a transient clipboard-feedback message
28+
and revert to a hint message after a short timeout.
29+
30+
Subclasses must inherit from a ``QObject``, implement ``_displayMessage``
31+
to render the text, and call ``_initClipboardMessage`` once in ``__init__``.
32+
"""
33+
34+
CLIPBOARD_MESSAGE_DURATION_MS = 1500
35+
CLIPBOARD_HINT_MESSAGE = "Click on plot to copy coordinates"
36+
37+
def _initClipboardMessage(self) -> None:
38+
self.clipboardMessageActive = False
39+
self.clipboardResetTimer = QtCore.QTimer(self)
40+
self.clipboardResetTimer.setSingleShot(True)
41+
self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage)
42+
43+
def _displayMessage(self, message: str) -> None:
44+
raise NotImplementedError
45+
46+
def showClipboardMessage(self, message: str) -> None:
47+
self.clipboardMessageActive = True
48+
self._displayMessage(message)
49+
self.clipboardResetTimer.start(self.CLIPBOARD_MESSAGE_DURATION_MS)
50+
51+
def clearClipboardMessage(self) -> None:
52+
self.clipboardMessageActive = False
53+
self._displayMessage(self.CLIPBOARD_HINT_MESSAGE)
54+
55+
2556
class PlotNode(Node):
2657
"""
2758
Basic Plot Node, derived from :class:`plottr.node.node.Node`.

plottr/plot/mpl/widgets.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from matplotlib import rcParams
99
from matplotlib.axes import Axes
1010
from matplotlib.figure import Figure
11-
from matplotlib.backend_bases import LocationEvent, Event
11+
from matplotlib.backend_bases import LocationEvent, MouseButton, Event
1212
from matplotlib.backends.backend_qt5agg import (
1313
FigureCanvasQTAgg as FCanvas,
1414
NavigationToolbar2QT as NavBar,
@@ -18,37 +18,27 @@
1818
from plottr import QtWidgets, QtGui, QtCore, Signal, config as plottrconfig
1919
from plottr.data.datadict import DataDictBase
2020
from plottr.gui.tools import widgetDialog, dpiScalingFactor
21-
from ..base import PlotWidget, PlotWidgetContainer
21+
from ..base import PlotWidget, PlotWidgetContainer, ClipboardMessageMixin
2222

2323

24-
class MPLNavBar(NavBar):
24+
class MPLNavBar(ClipboardMessageMixin, NavBar):
2525
"""
2626
Toolbar subclass that shows a hint when the mouse is outside the axes
2727
and can pin a clipboard confirmation message, so hovering won't overwrite it
2828
for a few seconds to make the message visible.
2929
"""
3030

3131
def __init__(self, canvas: FCanvas, parent: QtWidgets.QWidget):
32-
self.clipboardMessageActive = False
33-
self.hintMessage = "Click on plot to copy coordinates"
3432
super().__init__(canvas, parent)
35-
self.clipboardResetTimer = QtCore.QTimer(self)
36-
self.clipboardResetTimer.setSingleShot(True)
37-
self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage)
33+
self._initClipboardMessage()
3834

3935
def set_message(self, s: str) -> None:
4036
if self.clipboardMessageActive:
4137
return
42-
super().set_message(s if s else self.hintMessage)
38+
NavBar.set_message(self, s if s else self.CLIPBOARD_HINT_MESSAGE)
4339

44-
def showClipboardMessage(self, message: str) -> None:
45-
self.clipboardMessageActive = True
46-
super().set_message(message)
47-
self.clipboardResetTimer.start(1500)
48-
49-
def clearClipboardMessage(self) -> None:
50-
self.clipboardMessageActive = False
51-
super().set_message(self.hintMessage)
40+
def _displayMessage(self, message: str) -> None:
41+
NavBar.set_message(self, message)
5242

5343

5444
class MPLPlot(FCanvas):
@@ -161,6 +151,8 @@ def metaToClipboard(self) -> None:
161151

162152
def coordinateToClipboard(self, event: Event) -> None:
163153
if isinstance(event, LocationEvent):
154+
if getattr(event, 'button', None) != MouseButton.LEFT:
155+
return
164156
clipboard = QtWidgets.QApplication.clipboard()
165157
if event.xdata is not None and event.ydata is not None:
166158
coord_info_string = '({:.8g}, {:.8g})'.format(event.xdata, event.ydata)
@@ -255,4 +247,4 @@ def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]:
255247
:return: The figure object of the plot, and the dialog window object.
256248
"""
257249
widget = MPLPlotWidget()
258-
return widget.plot.fig, widgetDialog(widget)
250+
return widget.plot.fig, widgetDialog(widget)

plottr/plot/pyqtgraph/autoplot.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from .plots import Plot, PlotWithColorbar, PlotBase
2424
from ..base import AutoFigureMaker as BaseFM, PlotDataType, \
2525
PlotItem, ComplexRepresentation, determinePlotDataType, \
26-
PlotWidgetContainer, PlotWidget
26+
PlotWidgetContainer, PlotWidget, ClipboardMessageMixin
2727

2828
logger = logging.getLogger(__name__)
2929

@@ -249,7 +249,7 @@ def _scatterPlot2d(self, plotItem: PlotItem) -> None:
249249
subPlot.setScatter2d(*plotItem.data)
250250

251251

252-
class AutoPlot(PlotWidget):
252+
class AutoPlot(ClipboardMessageMixin, PlotWidget):
253253
"""Widget for automatic plotting with pyqtgraph.
254254
255255
Uses :class:`.FigureMaker` to produce subplots.
@@ -271,16 +271,11 @@ def __init__(self, parent: Optional[PlotWidgetContainer]) -> None:
271271
layout.setContentsMargins(0, 0, 0, 0)
272272
layout.setSpacing(0)
273273

274-
self.statusLabel = QtWidgets.QLabel("Click on plot to copy coordinates")
274+
self._initClipboardMessage()
275+
self.statusLabel = QtWidgets.QLabel(self.CLIPBOARD_HINT_MESSAGE)
275276
self.statusLabel.setAlignment(QtCore.Qt.AlignCenter)
276277
self.statusLabel.setStyleSheet("color: gray;")
277278

278-
self.clipboardMessageActive = False
279-
self.hintMessage = "Click on plot to copy coordinates"
280-
self.clipboardResetTimer = QtCore.QTimer(self)
281-
self.clipboardResetTimer.setSingleShot(True)
282-
self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage)
283-
284279
self.setLayout(layout)
285280
self.setMinimumSize(*getcfg('main', 'pyqtgraph', 'minimum_plot_size',
286281
default=(400, 400)))
@@ -371,18 +366,12 @@ def _plotData(self, **kwargs: Any) -> None:
371366
def _refreshPlot(self) -> None:
372367
self._plotData()
373368

374-
def showClipboardMessage(self, message: str) -> None:
375-
self.clipboardMessageActive = True
369+
def _displayMessage(self, message: str) -> None:
376370
self.statusLabel.setText(message)
377-
self.clipboardResetTimer.start(1500)
378-
379-
def clearClipboardMessage(self) -> None:
380-
self.clipboardMessageActive = False
381-
self.statusLabel.setText(self.hintMessage)
382371

383372
def setStatusMessage(self, message: str) -> None:
384373
if not self.clipboardMessageActive:
385-
self.statusLabel.setText(message if message else self.hintMessage)
374+
self.statusLabel.setText(message if message else self.CLIPBOARD_HINT_MESSAGE)
386375

387376
def _connectPlotEvents(self, subplot: PlotBase) -> None:
388377
subplot.plot.scene().sigMouseMoved.connect(
@@ -402,6 +391,8 @@ def _onMouseMoved(self, subplot: PlotBase, pos: Any) -> None:
402391
self.setStatusMessage('')
403392

404393
def _onPlotClicked(self, subplot: PlotBase, event: Any) -> None:
394+
if event.button() != QtCore.Qt.LeftButton:
395+
return
405396
vb = subplot.plot.getViewBox()
406397
local = vb.mapFromScene(event.scenePos())
407398
if vb.boundingRect().contains(local):

0 commit comments

Comments
 (0)