parameterTypes.py 23.9 KB
Newer Older
1
2
from ..Qt import QtCore, QtGui
from ..python2_3 import asUnicode
3
4
from .Parameter import Parameter, registerParameterType
from .ParameterItem import ParameterItem
5
6
7
8
9
from ..widgets.SpinBox import SpinBox
from ..widgets.ColorButton import ColorButton
#from ..widgets.GradientWidget import GradientWidget ## creates import loop
from .. import pixmaps as pixmaps
from .. import functions as fn
10
import os
11
from ..pgcollections import OrderedDict
12
13
14
15

class WidgetParameterItem(ParameterItem):
    """
    ParameterTree item with:
Luke Campagnola's avatar
Luke Campagnola committed
16
    
17
18
19
20
    * label in second column for displaying value
    * simple widget for editing value (displayed instead of label when item is selected)
    * button that resets value to default
    
21
22
23
24
25
26
27
28
29
30
    ==========================  =============================================================
    **Registered Types:**
    int                         Displays a :class:`SpinBox <pyqtgraph.SpinBox>` in integer
                                mode.
    float                       Displays a :class:`SpinBox <pyqtgraph.SpinBox>`.
    bool                        Displays a QCheckBox
    str                         Displays a QLineEdit
    color                       Displays a :class:`ColorButton <pyqtgraph.ColorButton>`
    colormap                    Displays a :class:`GradientWidget <pyqtgraph.GradientWidget>`
    ==========================  =============================================================
Luke Campagnola's avatar
Luke Campagnola committed
31
    
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    This class can be subclassed by overriding makeWidget() to provide a custom widget.
    """
    def __init__(self, param, depth):
        ParameterItem.__init__(self, param, depth)
        
        self.hideWidget = True  ## hide edit widget, replace with label when not selected
                                ## set this to False to keep the editor widget always visible
        
        
        ## build widget into column 1 with a display label and default button.
        w = self.makeWidget()  
        self.widget = w
        self.eventProxy = EventProxy(w, self.widgetEventFilter)
        
        opts = self.param.opts
        if 'tip' in opts:
            w.setToolTip(opts['tip'])
        
        self.defaultBtn = QtGui.QPushButton()
        self.defaultBtn.setFixedWidth(20)
        self.defaultBtn.setFixedHeight(20)
        modDir = os.path.dirname(__file__)
54
        self.defaultBtn.setIcon(QtGui.QIcon(pixmaps.getPixmap('default')))
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        self.defaultBtn.clicked.connect(self.defaultClicked)
        
        self.displayLabel = QtGui.QLabel()
        
        layout = QtGui.QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(2)
        layout.addWidget(w)
        layout.addWidget(self.displayLabel)
        layout.addWidget(self.defaultBtn)
        self.layoutWidget = QtGui.QWidget()
        self.layoutWidget.setLayout(layout)
        
        if w.sigChanged is not None:
            w.sigChanged.connect(self.widgetValueChanged)
            
        if hasattr(w, 'sigChanging'):
            w.sigChanging.connect(self.widgetValueChanging)
            
        ## update value shown in widget. 
75
76
77
78
79
        if opts.get('value', None) is not None:
            self.valueChanged(self, opts['value'], force=True)
        else:
            ## no starting value was given; use whatever the widget has
            self.widgetValueChanged()
80
81
82
83
84
85


    def makeWidget(self):
        """
        Return a single widget that should be placed in the second tree column.
        The widget must be given three attributes:
Luke Campagnola's avatar
Luke Campagnola committed
86
87
88
89
90
91
92
        
        ==========  ============================================================
        sigChanged  a signal that is emitted when the widget's value is changed
        value       a function that returns the value
        setValue    a function that sets the value
        ==========  ============================================================
            
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
        This is a good function to override in subclasses.
        """
        opts = self.param.opts
        t = opts['type']
        if t == 'int':
            defs = {
                'value': 0, 'min': None, 'max': None, 'int': True, 
                'step': 1.0, 'minStep': 1.0, 'dec': False, 
                'siPrefix': False, 'suffix': ''
            } 
            defs.update(opts)
            if 'limits' in opts:
                defs['bounds'] = opts['limits']
            w = SpinBox()
            w.setOpts(**defs)
            w.sigChanged = w.sigValueChanged
            w.sigChanging = w.sigValueChanging
        elif t == 'float':
            defs = {
                'value': 0, 'min': None, 'max': None, 
                'step': 1.0, 'dec': False, 
                'siPrefix': False, 'suffix': ''
            }
            defs.update(opts)
            if 'limits' in opts:
                defs['bounds'] = opts['limits']
            w = SpinBox()
            w.setOpts(**defs)
            w.sigChanged = w.sigValueChanged
            w.sigChanging = w.sigValueChanging
        elif t == 'bool':
            w = QtGui.QCheckBox()
            w.sigChanged = w.toggled
            w.value = w.isChecked
            w.setValue = w.setChecked
            self.hideWidget = False
        elif t == 'str':
            w = QtGui.QLineEdit()
            w.sigChanged = w.editingFinished
132
133
            w.value = lambda: asUnicode(w.text())
            w.setValue = lambda v: w.setText(asUnicode(v))
134
135
136
137
138
139
140
141
142
            w.sigChanging = w.textChanged
        elif t == 'color':
            w = ColorButton()
            w.sigChanged = w.sigColorChanged
            w.sigChanging = w.sigColorChanging
            w.value = w.color
            w.setValue = w.setColor
            self.hideWidget = False
            w.setFlat(True)
143
        elif t == 'colormap':
144
            from ..widgets.GradientWidget import GradientWidget ## need this here to avoid import loop
145
146
147
148
149
150
            w = GradientWidget(orientation='bottom')
            w.sigChanged = w.sigGradientChangeFinished
            w.sigChanging = w.sigGradientChanged
            w.value = w.colorMap
            w.setValue = w.setColorMap
            self.hideWidget = False
151
        else:
152
            raise Exception("Unknown type '%s'" % asUnicode(t))
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
        return w
        
    def widgetEventFilter(self, obj, ev):
        ## filter widget's events
        ## catch TAB to change focus
        ## catch focusOut to hide editor
        if ev.type() == ev.KeyPress:
            if ev.key() == QtCore.Qt.Key_Tab:
                self.focusNext(forward=True)
                return True ## don't let anyone else see this event
            elif ev.key() == QtCore.Qt.Key_Backtab:
                self.focusNext(forward=False)
                return True ## don't let anyone else see this event
            
        #elif ev.type() == ev.FocusOut:
            #self.hideEditor()
        return False
        
    def setFocus(self):
        self.showEditor()
        
    def isFocusable(self):
        return self.param.writable()        
        
    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():
                self.widget.setValue(val)
            self.updateDisplayLabel(val)  ## always make sure label is updated, even if values match!
        finally:
            self.widget.sigChanged.connect(self.widgetValueChanged)
        self.updateDefaultBtn()
        
    def updateDefaultBtn(self):
        ## enable/disable default btn 
        self.defaultBtn.setEnabled(not self.param.valueIsDefault() and self.param.writable())        

    def updateDisplayLabel(self, value=None):
        """Update the display label to reflect the value of the parameter."""
        if value is None:
            value = self.param.value()
        opts = self.param.opts
        if isinstance(self.widget, QtGui.QAbstractSpinBox):
199
            text = asUnicode(self.widget.lineEdit().text())
200
201
202
        elif isinstance(self.widget, QtGui.QComboBox):
            text = self.widget.currentText()
        else:
203
            text = asUnicode(value)
204
205
206
207
208
209
210
        self.displayLabel.setText(text)

    def widgetValueChanged(self):
        ## called when the widget's value has been changed by the user
        val = self.widget.value()
        newVal = self.param.setValue(val)

211
    def widgetValueChanging(self, *args):
212
213
214
215
        """
        Called when the widget's value is changing, but not finalized.
        For example: editing text before pressing enter or changing focus.
        """
216
217
218
        # This is a bit sketchy: assume the last argument of each signal is
        # the value..
        self.param.sigValueChanging.emit(self.param, args[-1])
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
        
    def selected(self, sel):
        """Called when this item has been selected (sel=True) OR deselected (sel=False)"""
        ParameterItem.selected(self, sel)
        
        if self.widget is None:
            return
        if sel and self.param.writable():
            self.showEditor()
        elif self.hideWidget:
            self.hideEditor()

    def showEditor(self):
        self.widget.show()
        self.displayLabel.hide()
        self.widget.setFocus(QtCore.Qt.OtherFocusReason)

    def hideEditor(self):
        self.widget.hide()
        self.displayLabel.show()

    def limitsChanged(self, param, limits):
        """Called when the parameter's limits have changed"""
        ParameterItem.limitsChanged(self, param, limits)
        
        t = self.param.opts['type']
        if t == 'int' or t == 'float':
            self.widget.setOpts(bounds=limits)
        else:
            return  ## don't know what to do with any other types..

    def defaultChanged(self, param, value):
        self.updateDefaultBtn()

    def treeWidgetChanged(self):
        """Called when this item is added or removed from a tree."""
        ParameterItem.treeWidgetChanged(self)
        
        ## add all widgets for this item into the tree
        if self.widget is not None:
            tree = self.treeWidget()
            if tree is None:
                return
            tree.setItemWidget(self, 1, self.layoutWidget)
            self.displayLabel.hide()
            self.selected(False)            

    def defaultClicked(self):
        self.param.setToDefault()

    def optsChanged(self, param, opts):
        """Called when any options are changed that are not
        name, value, default, or limits"""
        #print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)
        
        if 'readonly' in opts:
            self.updateDefaultBtn()
        
        ## If widget is a SpinBox, pass options straight through
        if isinstance(self.widget, SpinBox):
            if 'units' in opts and 'suffix' not in opts:
                opts['suffix'] = opts['units']
            self.widget.setOpts(**opts)
            self.updateDisplayLabel()
            
class EventProxy(QtCore.QObject):
    def __init__(self, qobj, callback):
        QtCore.QObject.__init__(self)
        self.callback = callback
        qobj.installEventFilter(self)
        
    def eventFilter(self, obj, ev):
        return self.callback(obj, ev)

        


class SimpleParameter(Parameter):
    itemClass = WidgetParameterItem
    
300
301
    def __init__(self, *args, **kargs):
        Parameter.__init__(self, *args, **kargs)
Luke Campagnola's avatar
Luke Campagnola committed
302
303
        
        ## override a few methods for color parameters
304
305
        if self.opts['type'] == 'color':
            self.value = self.colorValue
Luke Campagnola's avatar
Luke Campagnola committed
306
            self.saveState = self.saveColorState
307
308
    
    def colorValue(self):
309
        return fn.mkColor(Parameter.value(self))
310
    
Luke Campagnola's avatar
Luke Campagnola committed
311
312
    def saveColorState(self):
        state = Parameter.saveState(self)
313
        state['value'] = fn.colorTuple(self.value())
Luke Campagnola's avatar
Luke Campagnola committed
314
315
316
        return state
        
    
317
318
319
320
321
registerParameterType('int', SimpleParameter, override=True)
registerParameterType('float', SimpleParameter, override=True)
registerParameterType('bool', SimpleParameter, override=True)
registerParameterType('str', SimpleParameter, override=True)
registerParameterType('color', SimpleParameter, override=True)
322
registerParameterType('colormap', SimpleParameter, override=True)
323
324
325
326
327
328
329
330
331
332
333
334




class GroupParameterItem(ParameterItem):
    """
    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.
    """
    def __init__(self, param, depth):
        ParameterItem.__init__(self, param, depth)
Luke Campagnola's avatar
Luke Campagnola committed
335
        self.updateDepth(depth) 
336
337
338
339
340
341
                
        self.addItem = None
        if 'addText' in param.opts:
            addText = param.opts['addText']
            if 'addList' in param.opts:
                self.addWidget = QtGui.QComboBox()
Luke Campagnola's avatar
Luke Campagnola committed
342
343
                self.addWidget.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
                self.updateAddList()
344
345
346
347
348
349
350
351
352
                self.addWidget.currentIndexChanged.connect(self.addChanged)
            else:
                self.addWidget = QtGui.QPushButton(addText)
                self.addWidget.clicked.connect(self.addClicked)
            w = QtGui.QWidget()
            l = QtGui.QHBoxLayout()
            l.setContentsMargins(0,0,0,0)
            w.setLayout(l)
            l.addWidget(self.addWidget)
Luke Campagnola's avatar
Luke Campagnola committed
353
354
            l.addStretch()
            #l.addItem(QtGui.QSpacerItem(200, 10, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
355
356
357
358
359
            self.addWidgetBox = w
            self.addItem = QtGui.QTreeWidgetItem([])
            self.addItem.setFlags(QtCore.Qt.ItemIsEnabled)
            ParameterItem.addChild(self, self.addItem)
            
Luke Campagnola's avatar
Luke Campagnola committed
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    def updateDepth(self, depth):
        ## Change item's appearance based on its depth in the tree
        ## This allows highest-level groups to be displayed more prominently.
        if depth == 0:
            for c in [0,1]:
                self.setBackground(c, QtGui.QBrush(QtGui.QColor(100,100,100)))
                self.setForeground(c, QtGui.QBrush(QtGui.QColor(220,220,255)))
                font = self.font(c)
                font.setBold(True)
                font.setPointSize(font.pointSize()+1)
                self.setFont(c, font)
                self.setSizeHint(0, QtCore.QSize(0, 25))
        else:
            for c in [0,1]:
                self.setBackground(c, QtGui.QBrush(QtGui.QColor(220,220,220)))
                font = self.font(c)
                font.setBold(True)
                #font.setPointSize(font.pointSize()+1)
                self.setFont(c, font)
                self.setSizeHint(0, QtCore.QSize(0, 20))
    
381
382
383
384
385
386
387
388
389
390
391
392
    def addClicked(self):
        """Called when "add new" button is clicked
        The parameter MUST have an 'addNew' method defined.
        """
        self.param.addNew()

    def addChanged(self):
        """Called when "add new" combo is changed
        The parameter MUST have an 'addNew' method defined.
        """
        if self.addWidget.currentIndex() == 0:
            return
393
        typ = asUnicode(self.addWidget.currentText())
394
395
396
397
398
        self.param.addNew(typ)
        self.addWidget.setCurrentIndex(0)

    def treeWidgetChanged(self):
        ParameterItem.treeWidgetChanged(self)
399
        self.treeWidget().setFirstItemColumnSpanned(self, True)
400
401
402
403
404
405
406
407
408
        if self.addItem is not None:
            self.treeWidget().setItemWidget(self.addItem, 0, self.addWidgetBox)
            self.treeWidget().setFirstItemColumnSpanned(self.addItem, True)
        
    def addChild(self, child):  ## make sure added childs are actually inserted before add btn
        if self.addItem is not None:
            ParameterItem.insertChild(self, self.childCount()-1, child)
        else:
            ParameterItem.addChild(self, child)
Luke Campagnola's avatar
Luke Campagnola committed
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
            
    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)
            
424
425
426
class GroupParameter(Parameter):
    """
    Group parameters are used mainly as a generic parent item that holds (and groups!) a set
Luke Campagnola's avatar
Luke Campagnola committed
427
428
429
430
431
432
433
434
    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.
435
436
437
438
    """
    itemClass = GroupParameterItem

    def addNew(self, typ=None):
Luke Campagnola's avatar
Luke Campagnola committed
439
440
441
        """
        This method is called when the user has requested to add a new item to the group.
        """
442
        raise Exception("Must override this function in subclass.")
Luke Campagnola's avatar
Luke Campagnola committed
443
444
445
446
447
448
    
    def setAddList(self, vals):
        """Change the list of options available for the user to add to the group."""
        self.setOpts(addList=vals)

    
449
450
451
452
453
454
455
456
457
458
459
460
461

registerParameterType('group', GroupParameter, override=True)





class ListParameterItem(WidgetParameterItem):
    """
    WidgetParameterItem subclass providing comboBox that lets the user select from a list of options.
    
    """
    def __init__(self, param, depth):
Luke Campagnola's avatar
Luke Campagnola committed
462
        self.targetValue = None
463
464
        WidgetParameterItem.__init__(self, param, depth)
        
Luke Campagnola's avatar
Luke Campagnola committed
465
        
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
    def makeWidget(self):
        opts = self.param.opts
        t = opts['type']
        w = QtGui.QComboBox()
        w.setMaximumHeight(20)  ## set to match height of spin box and line edit
        w.sigChanged = w.currentIndexChanged
        w.value = self.value
        w.setValue = self.setValue
        self.widget = w  ## needs to be set before limits are changed
        self.limitsChanged(self.param, self.param.opts['limits'])
        if len(self.forward) > 0:
            self.setValue(self.param.value())
        return w
        
    def value(self):
481
        key = asUnicode(self.widget.currentText())
Luke Campagnola's avatar
Luke Campagnola committed
482
483
        
        return self.forward.get(key, None)
484
485
            
    def setValue(self, val):
Luke Campagnola's avatar
Luke Campagnola committed
486
        self.targetValue = val
487
        if val not in self.reverse[0]:
488
489
            self.widget.setCurrentIndex(0)
        else:
490
            key = self.reverse[1][self.reverse[0].index(val)]
491
492
493
494
495
496
            ind = self.widget.findText(key)
            self.widget.setCurrentIndex(ind)

    def limitsChanged(self, param, limits):
        # set up forward / reverse mappings for name:value
        
Luke Campagnola's avatar
Luke Campagnola committed
497
498
499
500
        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)
501
502
        try:
            self.widget.blockSignals(True)
Luke Campagnola's avatar
Luke Campagnola committed
503
504
            val = self.targetValue  #asUnicode(self.widget.currentText())
            
505
506
507
508
509
            self.widget.clear()
            for k in self.forward:
                self.widget.addItem(k)
                if k == val:
                    self.widget.setCurrentIndex(self.widget.count()-1)
Luke Campagnola's avatar
Luke Campagnola committed
510
                    self.updateDisplayLabel()
511
512
513
514
515
516
517
518
519
        finally:
            self.widget.blockSignals(False)
            


class ListParameter(Parameter):
    itemClass = ListParameterItem

    def __init__(self, **opts):
520
521
        self.forward = OrderedDict()  ## {name: value, ...}
        self.reverse = ([], [])       ## ([value, ...], [name, ...])
Luke Campagnola's avatar
Luke Campagnola committed
522
523
        
        ## Parameter uses 'limits' option to define the set of allowed values
524
525
        if 'values' in opts:
            opts['limits'] = opts['values']
Luke Campagnola's avatar
Luke Campagnola committed
526
527
        if opts.get('limits', None) is None:
            opts['limits'] = []
528
        Parameter.__init__(self, **opts)
Luke Campagnola's avatar
Luke Campagnola committed
529
        self.setLimits(opts['limits'])
530
531
        
    def setLimits(self, limits):
Luke Campagnola's avatar
Luke Campagnola committed
532
        self.forward, self.reverse = self.mapping(limits)
533
534
535
        
        Parameter.setLimits(self, limits)
        #print self.name(), self.value(), limits
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
        if len(self.reverse) > 0 and self.value() not in self.reverse[0]:
            self.setValue(self.reverse[0][0])
            
    #def addItem(self, name, value=None):
        #if name in self.forward:
            #raise Exception("Name '%s' is already in use for this parameter" % name)
        #limits = self.opts['limits']
        #if isinstance(limits, dict):
            #limits = limits.copy()
            #limits[name] = value
            #self.setLimits(limits)
        #else:
            #if value is not None:
                #raise Exception  ## raise exception or convert to dict?
            #limits = limits[:]
            #limits.append(name)
        ## what if limits == None?
553
            
Luke Campagnola's avatar
Luke Campagnola committed
554
555
    @staticmethod
    def mapping(limits):
556
557
558
        ## Return forward and reverse mapping objects given a limit specification
        forward = OrderedDict()  ## {name: value, ...}
        reverse = ([], [])       ## ([value, ...], [name, ...])
Luke Campagnola's avatar
Luke Campagnola committed
559
560
561
        if isinstance(limits, dict):
            for k, v in limits.items():
                forward[k] = v
562
563
                reverse[0].append(v)
                reverse[1].append(k)
Luke Campagnola's avatar
Luke Campagnola committed
564
565
566
567
        else:
            for v in limits:
                n = asUnicode(v)
                forward[n] = v
568
569
                reverse[0].append(v)
                reverse[1].append(n)
Luke Campagnola's avatar
Luke Campagnola committed
570
        return forward, reverse
571
572
573
574

registerParameterType('list', ListParameter, override=True)


Luke Campagnola's avatar
Luke Campagnola committed
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620

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)
621
        self.hideWidget = False
Luke Campagnola's avatar
Luke Campagnola committed
622
623
624
625
        self.subItem = QtGui.QTreeWidgetItem()
        self.addChild(self.subItem)

    def treeWidgetChanged(self):
Luke Campagnola's avatar
Luke Campagnola committed
626
627
628
        ## TODO: fix so that superclass method can be called
        ## (WidgetParameter should just natively support this style)
        #WidgetParameterItem.treeWidgetChanged(self)
Luke Campagnola's avatar
Luke Campagnola committed
629
630
        self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
        self.treeWidget().setItemWidget(self.subItem, 0, self.textBox)
Luke Campagnola's avatar
Luke Campagnola committed
631
632
633
634
        
        # for now, these are copied from ParameterItem.treeWidgetChanged
        self.setHidden(not self.param.opts.get('visible', True))
        self.setExpanded(self.param.opts.get('expanded', True))
Luke Campagnola's avatar
Luke Campagnola committed
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
        
    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)