2 ## This file is part of the sigrok-meter project.
4 ## Copyright (C) 2015 Jens Steinhauser <jens.steinhauser@gmail.com>
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 QtCore
= qtcompat
.QtCore
24 QtGui
= qtcompat
.QtGui
25 pyqtgraph
= qtcompat
.pyqtgraph
27 # black foreground on white background
28 pyqtgraph
.setConfigOption('background', 'w')
29 pyqtgraph
.setConfigOption('foreground', 'k')
32 '''Helper class to keep all graphics items of a plot together.'''
34 def __init__(self
, view
, xaxis
, yaxis
):
40 class MultiPlotItem(pyqtgraph
.GraphicsWidget
):
42 # Emitted when a plot is shown.
43 plotShown
= QtCore
.Signal()
45 # Emitted when a plot is hidden by the user via the context menu.
46 plotHidden
= QtCore
.Signal(Plot
)
48 def __init__(self
, parent
=None):
49 pyqtgraph
.GraphicsWidget
.__init
__(self
, parent
)
51 self
.setLayout(QtGui
.QGraphicsGridLayout())
52 self
.layout().setContentsMargins(10, 10, 10, 1)
53 self
.layout().setHorizontalSpacing(0)
54 self
.layout().setVerticalSpacing(0)
57 self
.layout().setColumnPreferredWidth(i
, 0)
58 self
.layout().setColumnMinimumWidth(i
, 0)
59 self
.layout().setColumnSpacing(i
, 0)
61 self
.layout().setColumnStretchFactor(0, 0)
62 self
.layout().setColumnStretchFactor(1, 100)
64 # List of 'Plot' objects that are shown.
67 self
._hideActions
= {}
70 '''Adds and returns a new plot.'''
72 row
= self
.layout().rowCount()
74 view
= pyqtgraph
.ViewBox(parent
=self
)
76 # If this is not the first plot, link to the axis of the previous one.
78 view
.setXLink(self
._plots
[-1].view
)
80 yaxis
= pyqtgraph
.AxisItem(parent
=self
, orientation
='left')
81 yaxis
.linkToView(view
)
84 xaxis
= pyqtgraph
.AxisItem(parent
=self
, orientation
='bottom')
85 xaxis
.linkToView(view
)
88 plot
= Plot(view
, xaxis
, yaxis
)
89 self
._plots
.append(plot
)
93 # Create a separate action object for each plots context menu, so that
94 # we can later find out which plot should be hidden by looking at
95 # 'self._hideActions'.
96 hideAction
= QtGui
.QAction('Hide', self
)
97 hideAction
.triggered
.connect(self
._onHideActionTriggered
)
98 self
._hideActions
[id(hideAction
)] = plot
99 view
.menu
.insertAction(view
.menu
.actions()[0], hideAction
)
103 def _rowNumber(self
, plot
):
104 '''Returns the number of the first row a plot occupies.'''
106 # Every plot takes up two rows
107 return 2 * self
._plots
.index(plot
)
110 def _onHideActionTriggered(self
, checked
=False):
111 # The plot that we want to hide.
112 plot
= self
._hideActions
[id(self
.sender())]
115 def hidePlot(self
, plot
):
118 # Only hiding wouldn't give up the space occupied by the items,
119 # we have to remove them from the layout.
120 self
.layout().removeItem(plot
.view
)
121 self
.layout().removeItem(plot
.xaxis
)
122 self
.layout().removeItem(plot
.yaxis
)
128 row
= self
._rowNumber
(plot
)
129 self
.layout().setRowStretchFactor(row
, 0)
130 self
.layout().setRowStretchFactor(row
+ 1, 0)
133 self
.plotHidden
.emit(plot
)
135 def showPlot(self
, plot
):
136 '''Adds the items of the plot to the scene's layout and makes
142 row
= self
._rowNumber
(plot
)
143 self
.layout().addItem(plot
.yaxis
, row
, 0, QtCore
.Qt
.AlignRight
)
144 self
.layout().addItem(plot
.view
, row
, 1)
145 self
.layout().addItem(plot
.xaxis
, row
+ 1, 1)
151 for i
in range(row
, row
+ 2):
152 self
.layout().setRowPreferredHeight(i
, 0)
153 self
.layout().setRowMinimumHeight(i
, 0)
154 self
.layout().setRowSpacing(i
, 0)
156 self
.layout().setRowStretchFactor(row
, 100)
157 self
.layout().setRowStretchFactor(row
+ 1, 0)
160 self
.plotShown
.emit()
162 class MultiPlotWidget(pyqtgraph
.GraphicsView
):
163 '''Widget that aligns multiple plots on top of each other.
165 (The built in classes fail at doing this correctly when the axis grow,
166 just try zooming in the "GraphicsLayout" or the "Linked View" examples.)'''
168 def __init__(self
, parent
=None):
169 pyqtgraph
.GraphicsView
.__init
__(self
, parent
)
171 self
.multiPlotItem
= MultiPlotItem()
172 self
.setCentralItem(self
.multiPlotItem
)
178 setattr(self
, m
, getattr(self
.multiPlotItem
, m
))
180 self
.multiPlotItem
.plotShown
.connect(self
._on
_plotShown
)
182 # Expose the signal of the plot item.
183 self
.plotHidden
= self
.multiPlotItem
.plotHidden
185 def _on_plotShown(self
):
186 # This call is needed if only one plot exists and it was hidden,
187 # without it the layout would start acting weird and not make the
188 # MultiPlotItem fill the view widget after showing the plot again.
189 self
.resizeEvent(None)