Parametertree updates:
- fixes for saveState / restoreState (better handling of custom parameter classes) - added method GroupParameter.setAddList - ListParameter now remembers its value even if its list is cleared and rebuilt - added ActionParameter (buttons) and TextParameter
This commit is contained in:
parent
32311351f1
commit
79e4775165
@ -3,25 +3,29 @@ import collections, os, weakref, re
|
||||
from .ParameterItem import ParameterItem
|
||||
|
||||
PARAM_TYPES = {}
|
||||
|
||||
PARAM_NAMES = {}
|
||||
|
||||
def registerParameterType(name, cls, override=False):
|
||||
global PARAM_TYPES
|
||||
if name in PARAM_TYPES and not override:
|
||||
raise Exception("Parameter type '%s' already exists (use override=True to replace)" % name)
|
||||
PARAM_TYPES[name] = cls
|
||||
PARAM_NAMES[cls] = name
|
||||
|
||||
|
||||
|
||||
class Parameter(QtCore.QObject):
|
||||
"""
|
||||
Tree of name=value pairs (modifiable or not)
|
||||
- Value may be integer, float, string, bool, color, or list selection
|
||||
- Optionally, a custom widget may be specified for a property
|
||||
- Any number of extra columns may be added for other purposes
|
||||
- Any values may be reset to a default value
|
||||
- Parameters may be grouped / nested
|
||||
- Parameter may be subclassed to provide customized behavior.
|
||||
A Parameter is the basic unit of data in a parameter tree. Each parameter has
|
||||
a name, a type, a value, and several other properties that modify the behavior of the
|
||||
Parameter. Parameters may have parent / child / sibling relationships to construct
|
||||
organized hierarchies. Parameters generally do not have any inherent GUI or visual
|
||||
interpretation; instead they manage ParameterItem instances which take care of
|
||||
display and user interaction.
|
||||
|
||||
Note: It is fairly uncommon to use the Parameter class directly; mostly you
|
||||
will use subclasses which provide specialized type and data handling. The static
|
||||
pethod Parameter.create(...) is an easy way to generate instances of these subclasses.
|
||||
|
||||
For more Parameter types, see ParameterTree.parameterTypes module.
|
||||
|
||||
@ -88,7 +92,11 @@ class Parameter(QtCore.QObject):
|
||||
|
||||
Use registerParameterType() to add new class types.
|
||||
"""
|
||||
cls = PARAM_TYPES[opts['type']]
|
||||
typ = opts.get('type', None)
|
||||
if typ is None:
|
||||
cls = Parameter
|
||||
else:
|
||||
cls = PARAM_TYPES[opts['type']]
|
||||
return cls(**opts)
|
||||
|
||||
def __init__(self, **opts):
|
||||
@ -102,6 +110,7 @@ class Parameter(QtCore.QObject):
|
||||
'renamable': False,
|
||||
'removable': False,
|
||||
'strictNaming': False, # forces name to be usable as a python variable
|
||||
#'limits': None, ## This is a bad plan--each parameter type may have a different data type for limits.
|
||||
}
|
||||
self.opts.update(opts)
|
||||
|
||||
@ -120,9 +129,7 @@ class Parameter(QtCore.QObject):
|
||||
raise Exception("Parameter must have a string name specified in opts.")
|
||||
self.setName(opts['name'])
|
||||
|
||||
for chOpts in self.opts.get('children', []):
|
||||
#print self, "Add child:", type(chOpts), id(chOpts)
|
||||
self.addChild(chOpts)
|
||||
self.addChildren(self.opts.get('children', []))
|
||||
|
||||
if 'value' in self.opts and 'default' not in self.opts:
|
||||
self.opts['default'] = self.opts['value']
|
||||
@ -159,6 +166,22 @@ class Parameter(QtCore.QObject):
|
||||
def type(self):
|
||||
return self.opts['type']
|
||||
|
||||
def isType(self, typ):
|
||||
"""
|
||||
Return True if this parameter type matches the name *typ*.
|
||||
This can occur either of two ways:
|
||||
|
||||
- If self.type() == *typ*
|
||||
- If this parameter's class is registered with the name *typ*
|
||||
"""
|
||||
if self.type() == typ:
|
||||
return True
|
||||
global PARAM_TYPES
|
||||
cls = PARAM_TYPES.get(typ, None)
|
||||
if cls is None:
|
||||
raise Exception("Type name '%s' is not registered." % str(typ))
|
||||
return self.__class__ is cls
|
||||
|
||||
def childPath(self, child):
|
||||
"""
|
||||
Return the path of parameter names from self to child.
|
||||
@ -175,7 +198,6 @@ class Parameter(QtCore.QObject):
|
||||
def setValue(self, value, blockSignal=None):
|
||||
## return the actual value that was set
|
||||
## (this may be different from the value that was requested)
|
||||
#print self, "Set value:", value, self.opts['value'], self.opts['value'] == value
|
||||
try:
|
||||
if blockSignal is not None:
|
||||
self.sigValueChanged.disconnect(blockSignal)
|
||||
@ -205,10 +227,13 @@ class Parameter(QtCore.QObject):
|
||||
The tree state may be restored from this structure using restoreState()
|
||||
"""
|
||||
state = self.opts.copy()
|
||||
state['children'] = [ch.saveState() for ch in self]
|
||||
state['children'] = collections.OrderedDict([(ch.name(), ch.saveState()) for ch in self])
|
||||
if state['type'] is None:
|
||||
global PARAM_NAMES
|
||||
state['type'] = PARAM_NAMES.get(type(self), None)
|
||||
return state
|
||||
|
||||
def restoreState(self, state, recursive=True, addChildren=True, removeChildren=True):
|
||||
def restoreState(self, state, recursive=True, addChildren=True, removeChildren=True, blockSignals=True):
|
||||
"""
|
||||
Restore the state of this parameter and its children from a structure generated using saveState()
|
||||
If recursive is True, then attempt to restore the state of child parameters as well.
|
||||
@ -216,55 +241,70 @@ class Parameter(QtCore.QObject):
|
||||
created if they do not already exist.
|
||||
If removeChildren is True, then any children which are not referenced in the state object will
|
||||
be removed.
|
||||
If blockSignals is True, no signals will be emitted until the tree has been completely restored.
|
||||
This prevents signal handlers from responding to a partially-rebuilt network.
|
||||
"""
|
||||
childState = state.get('children', [])
|
||||
self.setOpts(**state)
|
||||
|
||||
if not recursive:
|
||||
return
|
||||
|
||||
ptr = 0 ## pointer to first child that has not been restored yet
|
||||
foundChilds = set()
|
||||
#print "==============", self.name()
|
||||
for ch in childState:
|
||||
name = ch['name']
|
||||
typ = ch['type']
|
||||
#print('child: %s, %s' % (self.name()+'.'+name, typ))
|
||||
## list of children may be stored either as list or dict.
|
||||
if isinstance(childState, dict):
|
||||
childState = childState.values()
|
||||
|
||||
## First, see if there is already a child with this name and type
|
||||
gotChild = False
|
||||
for i, ch2 in enumerate(self.childs[ptr:]):
|
||||
#print ch2, ch2.name, ch2.type
|
||||
if ch2.name() != name or ch2.type() != typ:
|
||||
continue
|
||||
gotChild = True
|
||||
#print " found it"
|
||||
if i != 0: ## move parameter to next position
|
||||
self.removeChild(ch2)
|
||||
|
||||
if blockSignals:
|
||||
self.blockTreeChangeSignal()
|
||||
|
||||
try:
|
||||
self.setOpts(**state)
|
||||
|
||||
if not recursive:
|
||||
return
|
||||
|
||||
ptr = 0 ## pointer to first child that has not been restored yet
|
||||
foundChilds = set()
|
||||
#print "==============", self.name()
|
||||
|
||||
for ch in childState:
|
||||
name = ch['name']
|
||||
typ = ch['type']
|
||||
#print('child: %s, %s' % (self.name()+'.'+name, typ))
|
||||
|
||||
## First, see if there is already a child with this name and type
|
||||
gotChild = False
|
||||
for i, ch2 in enumerate(self.childs[ptr:]):
|
||||
#print " ", ch2.name(), ch2.type()
|
||||
if ch2.name() != name or not ch2.isType(typ):
|
||||
continue
|
||||
gotChild = True
|
||||
#print " found it"
|
||||
if i != 0: ## move parameter to next position
|
||||
#self.removeChild(ch2)
|
||||
self.insertChild(ptr, ch2)
|
||||
#print " moved to position", ptr
|
||||
ch2.restoreState(ch, recursive=recursive, addChildren=addChildren, removeChildren=removeChildren)
|
||||
foundChilds.add(ch2)
|
||||
|
||||
break
|
||||
|
||||
if not gotChild:
|
||||
if not addChildren:
|
||||
#print " ignored child"
|
||||
continue
|
||||
#print " created new"
|
||||
ch2 = Parameter.create(**ch)
|
||||
self.insertChild(ptr, ch2)
|
||||
#print " moved to position", ptr
|
||||
ch2.restoreState(ch, recursive=recursive, addChildren=addChildren, removeChildren=removeChildren)
|
||||
foundChilds.add(ch2)
|
||||
|
||||
break
|
||||
|
||||
if not gotChild:
|
||||
if not addChildren:
|
||||
#print " ignored child"
|
||||
continue
|
||||
#print " created new"
|
||||
ch2 = Parameter.create(**ch)
|
||||
self.insertChild(ptr, ch2)
|
||||
foundChilds.add(ch2)
|
||||
|
||||
ptr += 1
|
||||
|
||||
if removeChildren:
|
||||
for ch in self:
|
||||
if ch not in foundChilds:
|
||||
#print " remove:", ch
|
||||
self.removeChild(ch)
|
||||
foundChilds.add(ch2)
|
||||
|
||||
ptr += 1
|
||||
|
||||
if removeChildren:
|
||||
for ch in self.childs[:]:
|
||||
if ch not in foundChilds:
|
||||
#print " remove:", ch
|
||||
self.removeChild(ch)
|
||||
finally:
|
||||
if blockSignals:
|
||||
self.unblockTreeChangeSignal()
|
||||
|
||||
|
||||
|
||||
@ -362,6 +402,22 @@ class Parameter(QtCore.QObject):
|
||||
def addChild(self, child):
|
||||
"""Add another parameter to the end of this parameter's child list."""
|
||||
return self.insertChild(len(self.childs), child)
|
||||
|
||||
def addChildren(self, children):
|
||||
## If children was specified as dict, then assume keys are the names.
|
||||
if isinstance(children, dict):
|
||||
ch2 = []
|
||||
for name, opts in children.items():
|
||||
if isinstance(opts, dict) and 'name' not in opts:
|
||||
opts = opts.copy()
|
||||
opts['name'] = name
|
||||
ch2.append(opts)
|
||||
children = ch2
|
||||
|
||||
for chOpts in children:
|
||||
#print self, "Add child:", type(chOpts), id(chOpts)
|
||||
self.addChild(chOpts)
|
||||
|
||||
|
||||
def insertChild(self, pos, child):
|
||||
"""
|
||||
@ -373,7 +429,7 @@ class Parameter(QtCore.QObject):
|
||||
child = Parameter.create(**child)
|
||||
|
||||
name = child.name()
|
||||
if name in self.names:
|
||||
if name in self.names and child is not self.names[name]:
|
||||
if child.opts.get('autoIncrementName', False):
|
||||
name = self.incrementName(name)
|
||||
child.setName(name)
|
||||
@ -382,15 +438,16 @@ class Parameter(QtCore.QObject):
|
||||
if isinstance(pos, Parameter):
|
||||
pos = self.childs.index(pos)
|
||||
|
||||
if child.parent() is not None:
|
||||
child.remove()
|
||||
with self.treeChangeBlocker():
|
||||
if child.parent() is not None:
|
||||
child.remove()
|
||||
|
||||
self.names[name] = child
|
||||
self.childs.insert(pos, child)
|
||||
|
||||
self.names[name] = child
|
||||
self.childs.insert(pos, child)
|
||||
|
||||
child.parentChanged(self)
|
||||
self.sigChildAdded.emit(self, child, pos)
|
||||
child.sigTreeStateChanged.connect(self.treeStateChanged)
|
||||
child.parentChanged(self)
|
||||
self.sigChildAdded.emit(self, child, pos)
|
||||
child.sigTreeStateChanged.connect(self.treeStateChanged)
|
||||
return child
|
||||
|
||||
def removeChild(self, child):
|
||||
@ -398,7 +455,6 @@ class Parameter(QtCore.QObject):
|
||||
name = child.name()
|
||||
if name not in self.names or self.names[name] is not child:
|
||||
raise Exception("Parameter %s is not my child; can't remove." % str(child))
|
||||
|
||||
del self.names[name]
|
||||
self.childs.pop(self.childs.index(child))
|
||||
child.parentChanged(None)
|
||||
@ -414,6 +470,9 @@ class Parameter(QtCore.QObject):
|
||||
"""Return a list of this parameter's children."""
|
||||
## warning -- this overrides QObject.children
|
||||
return self.childs[:]
|
||||
|
||||
def hasChildren(self):
|
||||
return len(self.childs) > 0
|
||||
|
||||
def parentChanged(self, parent):
|
||||
"""This method is called when the parameter's parent has changed.
|
||||
@ -443,7 +502,7 @@ class Parameter(QtCore.QObject):
|
||||
num = int(num)
|
||||
while True:
|
||||
newName = base + ("%%0%dd"%numLen) % num
|
||||
if newName not in self.childs:
|
||||
if newName not in self.names:
|
||||
return newName
|
||||
num += 1
|
||||
|
||||
|
@ -8,17 +8,17 @@ import collections, os, weakref, re
|
||||
class ParameterTree(TreeWidget):
|
||||
"""Widget used to display or control data from a ParameterSet"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent=None, showHeader=True):
|
||||
TreeWidget.__init__(self, parent)
|
||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||
self.setHorizontalScrollMode(self.ScrollPerPixel)
|
||||
self.setAnimated(False)
|
||||
self.setColumnCount(2)
|
||||
self.setHeaderLabels(["Parameter", "Value"])
|
||||
self.setRootIsDecorated(False)
|
||||
self.setAlternatingRowColors(True)
|
||||
self.paramSet = None
|
||||
self.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
|
||||
self.setHeaderHidden(not showHeader)
|
||||
self.itemChanged.connect(self.itemChangedEvent)
|
||||
self.lastSel = None
|
||||
self.setRootIsDecorated(False)
|
||||
|
@ -152,7 +152,6 @@ class WidgetParameterItem(ParameterItem):
|
||||
def valueChanged(self, param, val, force=False):
|
||||
## called when the parameter's value has changed
|
||||
ParameterItem.valueChanged(self, param, val)
|
||||
|
||||
self.widget.sigChanged.disconnect(self.widgetValueChanged)
|
||||
try:
|
||||
if force or val != self.widget.value():
|
||||
@ -273,12 +272,21 @@ class SimpleParameter(Parameter):
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
Parameter.__init__(self, *args, **kargs)
|
||||
|
||||
## override a few methods for color parameters
|
||||
if self.opts['type'] == 'color':
|
||||
self.value = self.colorValue
|
||||
self.saveState = self.saveColorState
|
||||
|
||||
def colorValue(self):
|
||||
return pg.mkColor(Parameter.value(self))
|
||||
|
||||
def saveColorState(self):
|
||||
state = Parameter.saveState(self)
|
||||
state['value'] = pg.colorTuple(self.value())
|
||||
return state
|
||||
|
||||
|
||||
registerParameterType('int', SimpleParameter, override=True)
|
||||
registerParameterType('float', SimpleParameter, override=True)
|
||||
registerParameterType('bool', SimpleParameter, override=True)
|
||||
@ -303,9 +311,8 @@ class GroupParameterItem(ParameterItem):
|
||||
addText = param.opts['addText']
|
||||
if 'addList' in param.opts:
|
||||
self.addWidget = QtGui.QComboBox()
|
||||
self.addWidget.addItem(addText)
|
||||
for t in param.opts['addList']:
|
||||
self.addWidget.addItem(t)
|
||||
self.addWidget.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.updateAddList()
|
||||
self.addWidget.currentIndexChanged.connect(self.addChanged)
|
||||
else:
|
||||
self.addWidget = QtGui.QPushButton(addText)
|
||||
@ -315,7 +322,8 @@ class GroupParameterItem(ParameterItem):
|
||||
l.setContentsMargins(0,0,0,0)
|
||||
w.setLayout(l)
|
||||
l.addWidget(self.addWidget)
|
||||
l.addItem(QtGui.QSpacerItem(200, 10, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
|
||||
l.addStretch()
|
||||
#l.addItem(QtGui.QSpacerItem(200, 10, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
|
||||
self.addWidgetBox = w
|
||||
self.addItem = QtGui.QTreeWidgetItem([])
|
||||
self.addItem.setFlags(QtCore.Qt.ItemIsEnabled)
|
||||
@ -370,17 +378,46 @@ class GroupParameterItem(ParameterItem):
|
||||
ParameterItem.insertChild(self, self.childCount()-1, child)
|
||||
else:
|
||||
ParameterItem.addChild(self, child)
|
||||
|
||||
|
||||
def optsChanged(self, param, changed):
|
||||
if 'addList' in changed:
|
||||
self.updateAddList()
|
||||
|
||||
def updateAddList(self):
|
||||
self.addWidget.blockSignals(True)
|
||||
try:
|
||||
self.addWidget.clear()
|
||||
self.addWidget.addItem(self.param.opts['addText'])
|
||||
for t in self.param.opts['addList']:
|
||||
self.addWidget.addItem(t)
|
||||
finally:
|
||||
self.addWidget.blockSignals(False)
|
||||
|
||||
class GroupParameter(Parameter):
|
||||
"""
|
||||
Group parameters are used mainly as a generic parent item that holds (and groups!) a set
|
||||
of child parameters. It also provides a simple mechanism for displaying a button or combo
|
||||
that can be used to add new parameters to the group.
|
||||
of child parameters.
|
||||
|
||||
It also provides a simple mechanism for displaying a button or combo
|
||||
that can be used to add new parameters to the group. To enable this, the group
|
||||
must be initialized with the 'addText' option (the text will be displayed on
|
||||
a button which, when clicked, will cause addNew() to be called). If the 'addList'
|
||||
option is specified as well, then a dropdown-list of addable items will be displayed
|
||||
instead of a button.
|
||||
"""
|
||||
itemClass = GroupParameterItem
|
||||
|
||||
def addNew(self, typ=None):
|
||||
"""
|
||||
This method is called when the user has requested to add a new item to the group.
|
||||
"""
|
||||
raise Exception("Must override this function in subclass.")
|
||||
|
||||
def setAddList(self, vals):
|
||||
"""Change the list of options available for the user to add to the group."""
|
||||
self.setOpts(addList=vals)
|
||||
|
||||
|
||||
|
||||
registerParameterType('group', GroupParameter, override=True)
|
||||
|
||||
@ -394,8 +431,10 @@ class ListParameterItem(WidgetParameterItem):
|
||||
|
||||
"""
|
||||
def __init__(self, param, depth):
|
||||
self.targetValue = None
|
||||
WidgetParameterItem.__init__(self, param, depth)
|
||||
|
||||
|
||||
def makeWidget(self):
|
||||
opts = self.param.opts
|
||||
t = opts['type']
|
||||
@ -418,7 +457,8 @@ class ListParameterItem(WidgetParameterItem):
|
||||
#else:
|
||||
#return key
|
||||
#print key, self.forward
|
||||
return self.forward[key]
|
||||
|
||||
return self.forward.get(key, None)
|
||||
|
||||
def setValue(self, val):
|
||||
#vals = self.param.opts['limits']
|
||||
@ -431,6 +471,7 @@ class ListParameterItem(WidgetParameterItem):
|
||||
#raise Exception("Value '%s' not allowed." % val)
|
||||
#else:
|
||||
#key = unicode(val)
|
||||
self.targetValue = val
|
||||
if val not in self.reverse:
|
||||
self.widget.setCurrentIndex(0)
|
||||
else:
|
||||
@ -440,27 +481,23 @@ class ListParameterItem(WidgetParameterItem):
|
||||
|
||||
def limitsChanged(self, param, limits):
|
||||
# set up forward / reverse mappings for name:value
|
||||
self.forward = collections.OrderedDict() ## name: value
|
||||
self.reverse = collections.OrderedDict() ## value: name
|
||||
if isinstance(limits, dict):
|
||||
for k, v in limits.items():
|
||||
self.forward[k] = v
|
||||
self.reverse[v] = k
|
||||
else:
|
||||
for v in limits:
|
||||
n = asUnicode(v)
|
||||
self.forward[n] = v
|
||||
self.reverse[v] = n
|
||||
#self.forward = collections.OrderedDict([('', None)]) ## name: value
|
||||
#self.reverse = collections.OrderedDict([(None, '')]) ## value: name
|
||||
|
||||
if len(limits) == 0:
|
||||
limits = [''] ## Can never have an empty list--there is always at least a singhe blank item.
|
||||
|
||||
self.forward, self.reverse = ListParameter.mapping(limits)
|
||||
try:
|
||||
self.widget.blockSignals(True)
|
||||
val = asUnicode(self.widget.currentText())
|
||||
val = self.targetValue #asUnicode(self.widget.currentText())
|
||||
|
||||
self.widget.clear()
|
||||
for k in self.forward:
|
||||
self.widget.addItem(k)
|
||||
if k == val:
|
||||
self.widget.setCurrentIndex(self.widget.count()-1)
|
||||
|
||||
self.updateDisplayLabel()
|
||||
finally:
|
||||
self.widget.blockSignals(False)
|
||||
|
||||
@ -472,29 +509,107 @@ class ListParameter(Parameter):
|
||||
def __init__(self, **opts):
|
||||
self.forward = collections.OrderedDict() ## name: value
|
||||
self.reverse = collections.OrderedDict() ## value: name
|
||||
|
||||
## Parameter uses 'limits' option to define the set of allowed values
|
||||
if 'values' in opts:
|
||||
opts['limits'] = opts['values']
|
||||
if opts.get('limits', None) is None:
|
||||
opts['limits'] = []
|
||||
Parameter.__init__(self, **opts)
|
||||
|
||||
def setLimits(self, limits):
|
||||
self.forward = collections.OrderedDict() ## name: value
|
||||
self.reverse = collections.OrderedDict() ## value: name
|
||||
if isinstance(limits, dict):
|
||||
for k, v in limits.items():
|
||||
self.forward[k] = v
|
||||
self.reverse[v] = k
|
||||
else:
|
||||
for v in limits:
|
||||
n = asUnicode(v)
|
||||
self.forward[n] = v
|
||||
self.reverse[v] = n
|
||||
self.forward, self.reverse = self.mapping(limits)
|
||||
|
||||
Parameter.setLimits(self, limits)
|
||||
#print self.name(), self.value(), limits
|
||||
if self.value() not in self.reverse and len(self.reverse) > 0:
|
||||
self.setValue(list(self.reverse.keys())[0])
|
||||
|
||||
@staticmethod
|
||||
def mapping(limits):
|
||||
## Return forward and reverse mapping dictionaries given a limit specification
|
||||
forward = collections.OrderedDict() ## name: value
|
||||
reverse = collections.OrderedDict() ## value: name
|
||||
if isinstance(limits, dict):
|
||||
for k, v in limits.items():
|
||||
forward[k] = v
|
||||
reverse[v] = k
|
||||
else:
|
||||
for v in limits:
|
||||
n = asUnicode(v)
|
||||
forward[n] = v
|
||||
reverse[v] = n
|
||||
return forward, reverse
|
||||
|
||||
registerParameterType('list', ListParameter, override=True)
|
||||
|
||||
|
||||
|
||||
class ActionParameterItem(ParameterItem):
|
||||
def __init__(self, param, depth):
|
||||
ParameterItem.__init__(self, param, depth)
|
||||
self.layoutWidget = QtGui.QWidget()
|
||||
self.layout = QtGui.QHBoxLayout()
|
||||
self.layoutWidget.setLayout(self.layout)
|
||||
self.button = QtGui.QPushButton(param.name())
|
||||
#self.layout.addSpacing(100)
|
||||
self.layout.addWidget(self.button)
|
||||
self.layout.addStretch()
|
||||
self.button.clicked.connect(self.buttonClicked)
|
||||
param.sigNameChanged.connect(self.paramRenamed)
|
||||
self.setText(0, '')
|
||||
|
||||
def treeWidgetChanged(self):
|
||||
ParameterItem.treeWidgetChanged(self)
|
||||
tree = self.treeWidget()
|
||||
if tree is None:
|
||||
return
|
||||
|
||||
tree.setFirstItemColumnSpanned(self, True)
|
||||
tree.setItemWidget(self, 0, self.layoutWidget)
|
||||
|
||||
def paramRenamed(self, param, name):
|
||||
self.button.setText(name)
|
||||
|
||||
def buttonClicked(self):
|
||||
self.param.activate()
|
||||
|
||||
class ActionParameter(Parameter):
|
||||
"""Used for displaying a button within the tree."""
|
||||
itemClass = ActionParameterItem
|
||||
sigActivated = QtCore.Signal(object)
|
||||
|
||||
def activate(self):
|
||||
self.sigActivated.emit(self)
|
||||
self.emitStateChanged('activated', None)
|
||||
|
||||
registerParameterType('action', ActionParameter, override=True)
|
||||
|
||||
|
||||
|
||||
class TextParameterItem(WidgetParameterItem):
|
||||
def __init__(self, param, depth):
|
||||
WidgetParameterItem.__init__(self, param, depth)
|
||||
self.subItem = QtGui.QTreeWidgetItem()
|
||||
self.addChild(self.subItem)
|
||||
|
||||
def treeWidgetChanged(self):
|
||||
self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
|
||||
self.treeWidget().setItemWidget(self.subItem, 0, self.textBox)
|
||||
self.setExpanded(True)
|
||||
|
||||
def makeWidget(self):
|
||||
self.textBox = QtGui.QTextEdit()
|
||||
self.textBox.setMaximumHeight(100)
|
||||
self.textBox.value = lambda: str(self.textBox.toPlainText())
|
||||
self.textBox.setValue = self.textBox.setPlainText
|
||||
self.textBox.sigChanged = self.textBox.textChanged
|
||||
return self.textBox
|
||||
|
||||
class TextParameter(Parameter):
|
||||
"""Editable string; displayed as large text box in the tree."""
|
||||
itemClass = TextParameterItem
|
||||
|
||||
|
||||
|
||||
registerParameterType('text', TextParameter, override=True)
|
||||
|
Loading…
Reference in New Issue
Block a user