753ac9b4c4
commit ca3fbe2ff9
Author: Luke Campagnola <luke.campagnola@gmail.com>
Date: Thu Aug 7 08:41:30 2014 -0400
Merged numerous updates from acq4:
* Added HDF5 exporter
* CSV exporter gets (x,y,y,y) export mode
* Updates to SVG, Matplotlib exporter
* Console can filter exceptions by string
* Added tick context menu to GradientEditorItem
* Added export feature to imageview
* Parameter trees:
- Option to save only user-editable values
- Option to set visible title of parameters separately from name
- Added experimental ParameterSystem for handling large systems of
interdependent parameters
- Auto-select editable portion of spinbox when editing
* Added Vector.__abs__
* Added replacement garbage collector for avoiding crashes on multithreaded Qt
* Fixed "illegal instruction" caused by closing file handle 7 on OSX
* configfile now reloads QtCore objects, Point, ColorMap, numpy arrays
* Avoid triggering recursion issues in exception handler
* Various bugfies and performance enhancements
172 lines
6.4 KiB
Python
172 lines
6.4 KiB
Python
from ..Qt import QtGui, QtCore
|
|
from ..python2_3 import asUnicode
|
|
import os, weakref, re
|
|
|
|
class ParameterItem(QtGui.QTreeWidgetItem):
|
|
"""
|
|
Abstract ParameterTree item.
|
|
Used to represent the state of a Parameter from within a ParameterTree.
|
|
|
|
- Sets first column of item to name
|
|
- generates context menu if item is renamable or removable
|
|
- handles child added / removed events
|
|
- provides virtual functions for handling changes from parameter
|
|
|
|
For more ParameterItem types, see ParameterTree.parameterTypes module.
|
|
"""
|
|
|
|
def __init__(self, param, depth=0):
|
|
title = param.opts.get('title', None)
|
|
if title is None:
|
|
title = param.name()
|
|
QtGui.QTreeWidgetItem.__init__(self, [title, ''])
|
|
|
|
self.param = param
|
|
self.param.registerItem(self) ## let parameter know this item is connected to it (for debugging)
|
|
self.depth = depth
|
|
|
|
param.sigValueChanged.connect(self.valueChanged)
|
|
param.sigChildAdded.connect(self.childAdded)
|
|
param.sigChildRemoved.connect(self.childRemoved)
|
|
param.sigNameChanged.connect(self.nameChanged)
|
|
param.sigLimitsChanged.connect(self.limitsChanged)
|
|
param.sigDefaultChanged.connect(self.defaultChanged)
|
|
param.sigOptionsChanged.connect(self.optsChanged)
|
|
param.sigParentChanged.connect(self.parentChanged)
|
|
|
|
opts = param.opts
|
|
|
|
## Generate context menu for renaming/removing parameter
|
|
self.contextMenu = QtGui.QMenu()
|
|
self.contextMenu.addSeparator()
|
|
flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
|
|
if opts.get('renamable', False):
|
|
if param.opts.get('title', None) is not None:
|
|
raise Exception("Cannot make parameter with both title != None and renamable == True.")
|
|
flags |= QtCore.Qt.ItemIsEditable
|
|
self.contextMenu.addAction('Rename').triggered.connect(self.editName)
|
|
if opts.get('removable', False):
|
|
self.contextMenu.addAction("Remove").triggered.connect(self.requestRemove)
|
|
|
|
## handle movable / dropEnabled options
|
|
if opts.get('movable', False):
|
|
flags |= QtCore.Qt.ItemIsDragEnabled
|
|
if opts.get('dropEnabled', False):
|
|
flags |= QtCore.Qt.ItemIsDropEnabled
|
|
self.setFlags(flags)
|
|
|
|
## flag used internally during name editing
|
|
self.ignoreNameColumnChange = False
|
|
|
|
|
|
def valueChanged(self, param, val):
|
|
## called when the parameter's value has changed
|
|
pass
|
|
|
|
def isFocusable(self):
|
|
"""Return True if this item should be included in the tab-focus order"""
|
|
return False
|
|
|
|
def setFocus(self):
|
|
"""Give input focus to this item.
|
|
Can be reimplemented to display editor widgets, etc.
|
|
"""
|
|
pass
|
|
|
|
def focusNext(self, forward=True):
|
|
"""Give focus to the next (or previous) focusable item in the parameter tree"""
|
|
self.treeWidget().focusNext(self, forward=forward)
|
|
|
|
|
|
def treeWidgetChanged(self):
|
|
"""Called when this item is added or removed from a tree.
|
|
Expansion, visibility, and column widgets must all be configured AFTER
|
|
the item is added to a tree, not during __init__.
|
|
"""
|
|
self.setHidden(not self.param.opts.get('visible', True))
|
|
self.setExpanded(self.param.opts.get('expanded', True))
|
|
|
|
def childAdded(self, param, child, pos):
|
|
item = child.makeTreeItem(depth=self.depth+1)
|
|
self.insertChild(pos, item)
|
|
item.treeWidgetChanged()
|
|
|
|
for i, ch in enumerate(child):
|
|
item.childAdded(child, ch, i)
|
|
|
|
def childRemoved(self, param, child):
|
|
for i in range(self.childCount()):
|
|
item = self.child(i)
|
|
if item.param is child:
|
|
self.takeChild(i)
|
|
break
|
|
|
|
def parentChanged(self, param, parent):
|
|
## called when the parameter's parent has changed.
|
|
pass
|
|
|
|
def contextMenuEvent(self, ev):
|
|
if not self.param.opts.get('removable', False) and not self.param.opts.get('renamable', False):
|
|
return
|
|
|
|
self.contextMenu.popup(ev.globalPos())
|
|
|
|
def columnChangedEvent(self, col):
|
|
"""Called when the text in a column has been edited (or otherwise changed).
|
|
By default, we only use changes to column 0 to rename the parameter.
|
|
"""
|
|
if col == 0 and (self.param.opts.get('title', None) is None):
|
|
if self.ignoreNameColumnChange:
|
|
return
|
|
try:
|
|
newName = self.param.setName(asUnicode(self.text(col)))
|
|
except Exception:
|
|
self.setText(0, self.param.name())
|
|
raise
|
|
|
|
try:
|
|
self.ignoreNameColumnChange = True
|
|
self.nameChanged(self, newName) ## If the parameter rejects the name change, we need to set it back.
|
|
finally:
|
|
self.ignoreNameColumnChange = False
|
|
|
|
def nameChanged(self, param, name):
|
|
## called when the parameter's name has changed.
|
|
if self.param.opts.get('title', None) is None:
|
|
self.setText(0, name)
|
|
|
|
def limitsChanged(self, param, limits):
|
|
"""Called when the parameter's limits have changed"""
|
|
pass
|
|
|
|
def defaultChanged(self, param, default):
|
|
"""Called when the parameter's default value has changed"""
|
|
pass
|
|
|
|
def optsChanged(self, param, opts):
|
|
"""Called when any options are changed that are not
|
|
name, value, default, or limits"""
|
|
#print opts
|
|
if 'visible' in opts:
|
|
self.setHidden(not opts['visible'])
|
|
|
|
def editName(self):
|
|
self.treeWidget().editItem(self, 0)
|
|
|
|
def selected(self, sel):
|
|
"""Called when this item has been selected (sel=True) OR deselected (sel=False)"""
|
|
pass
|
|
|
|
def requestRemove(self):
|
|
## called when remove is selected from the context menu.
|
|
## we need to delay removal until the action is complete
|
|
## since destroying the menu in mid-action will cause a crash.
|
|
QtCore.QTimer.singleShot(0, self.param.remove)
|
|
|
|
## for python 3 support, we need to redefine hash and eq methods.
|
|
def __hash__(self):
|
|
return id(self)
|
|
|
|
def __eq__(self, x):
|
|
return x is self
|