pyqtgraph/flowchart/library/common.py

185 lines
5.7 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2013-12-23 15:01:20 +00:00
from ...Qt import QtCore, QtGui
from ...widgets.SpinBox import SpinBox
#from ...SignalProxy import SignalProxy
from ...WidgetGroup import WidgetGroup
#from ColorMapper import ColorMapper
from ..Node import Node
import numpy as np
2013-12-23 15:01:20 +00:00
from ...widgets.ColorButton import ColorButton
try:
import metaarray
HAVE_METAARRAY = True
except:
HAVE_METAARRAY = False
def generateUi(opts):
"""Convenience function for generating common UI types"""
widget = QtGui.QWidget()
l = QtGui.QFormLayout()
l.setSpacing(0)
widget.setLayout(l)
ctrls = {}
row = 0
for opt in opts:
if len(opt) == 2:
k, t = opt
o = {}
elif len(opt) == 3:
k, t, o = opt
else:
raise Exception("Widget specification must be (name, type) or (name, type, {opts})")
if t == 'intSpin':
w = QtGui.QSpinBox()
if 'max' in o:
w.setMaximum(o['max'])
if 'min' in o:
w.setMinimum(o['min'])
if 'value' in o:
w.setValue(o['value'])
elif t == 'doubleSpin':
w = QtGui.QDoubleSpinBox()
if 'max' in o:
w.setMaximum(o['max'])
if 'min' in o:
w.setMinimum(o['min'])
if 'value' in o:
w.setValue(o['value'])
elif t == 'spin':
w = SpinBox()
w.setOpts(**o)
elif t == 'check':
w = QtGui.QCheckBox()
if 'checked' in o:
w.setChecked(o['checked'])
elif t == 'combo':
w = QtGui.QComboBox()
for i in o['values']:
w.addItem(i)
#elif t == 'colormap':
#w = ColorMapper()
elif t == 'color':
w = ColorButton()
else:
raise Exception("Unknown widget type '%s'" % str(t))
if 'tip' in o:
w.setToolTip(o['tip'])
w.setObjectName(k)
l.addRow(k, w)
if o.get('hidden', False):
w.hide()
label = l.labelForField(w)
label.hide()
ctrls[k] = w
w.rowNum = row
row += 1
group = WidgetGroup(widget)
return widget, group, ctrls
class CtrlNode(Node):
"""Abstract class for nodes with auto-generated control UI"""
sigStateChanged = QtCore.Signal(object)
def __init__(self, name, ui=None, terminals=None):
if ui is None:
if hasattr(self, 'uiTemplate'):
ui = self.uiTemplate
else:
ui = []
if terminals is None:
terminals = {'In': {'io': 'in'}, 'Out': {'io': 'out', 'bypass': 'In'}}
Node.__init__(self, name=name, terminals=terminals)
self.ui, self.stateGroup, self.ctrls = generateUi(ui)
self.stateGroup.sigChanged.connect(self.changed)
def ctrlWidget(self):
return self.ui
def changed(self):
self.update()
self.sigStateChanged.emit(self)
def process(self, In, display=True):
out = self.processData(In)
return {'Out': out}
def saveState(self):
state = Node.saveState(self)
state['ctrl'] = self.stateGroup.state()
return state
def restoreState(self, state):
Node.restoreState(self, state)
if self.stateGroup is not None:
self.stateGroup.setState(state.get('ctrl', {}))
def hideRow(self, name):
w = self.ctrls[name]
l = self.ui.layout().labelForField(w)
w.hide()
l.hide()
def showRow(self, name):
w = self.ctrls[name]
l = self.ui.layout().labelForField(w)
w.show()
l.show()
class PlottingCtrlNode(CtrlNode):
"""Abstract class for CtrlNodes that can connect to plots."""
def __init__(self, name, ui=None, terminals=None):
#print "PlottingCtrlNode.__init__ called."
CtrlNode.__init__(self, name, ui=ui, terminals=terminals)
self.plotTerminal = self.addOutput('plot', optional=True)
def connected(self, term, remote):
CtrlNode.connected(self, term, remote)
if term is not self.plotTerminal:
return
node = remote.node()
node.sigPlotChanged.connect(self.connectToPlot)
self.connectToPlot(node)
def disconnected(self, term, remote):
CtrlNode.disconnected(self, term, remote)
if term is not self.plotTerminal:
return
remote.node().sigPlotChanged.disconnect(self.connectToPlot)
self.disconnectFromPlot(remote.node().getPlot())
def connectToPlot(self, node):
"""Define what happens when the node is connected to a plot"""
raise Exception("Must be re-implemented in subclass")
def disconnectFromPlot(self, plot):
"""Define what happens when the node is disconnected from a plot"""
raise Exception("Must be re-implemented in subclass")
def process(self, In, display=True):
out = CtrlNode.process(self, In, display)
out['plot'] = None
return out
def metaArrayWrapper(fn):
def newFn(self, data, *args, **kargs):
if HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')):
d1 = fn(self, data.view(np.ndarray), *args, **kargs)
info = data.infoCopy()
if d1.shape != data.shape:
for i in range(data.ndim):
if 'values' in info[i]:
info[i]['values'] = info[i]['values'][:d1.shape[i]]
return metaarray.MetaArray(d1, info=info)
else:
return fn(self, data, *args, **kargs)
return newFn