forked from Slicer/SlicerGitSVNArchive
/
EditOptions.py
196 lines (171 loc) · 5.99 KB
/
EditOptions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
import slicer
from __main__ import qt
from __main__ import ctk
from __main__ import vtk
from __main__ import getNodes
from EditUtil import EditUtil
#########################################################
#
#
comment = """
In this file:
Helpers - small widget-like helper classes
EditOptions - EffectOptions superclass
Each effect interface is created when the corresponding
editor effect is active on the slice views. The main
(only) responsibility of these GUIs is to set parameters
on the mrml node that influence the behavior of the
editor effects.
"""
#
#########################################################
#########################################################
# Helpers
#########################################################
class HelpButton(object):
"""
Puts a button on the interface that pops up a message
dialog for help when pressed
"""
def __init__(self, parent, helpString = ""):
self.helpString = helpString
self.message = qt.QMessageBox()
self.message.objectName = 'EditorHelpMessageBox'
self.message.setWindowTitle("Editor Help")
self.button = qt.QPushButton("?", parent)
self.button.objectName = 'EditorHelpButton'
self.button.setMaximumWidth(15)
self.button.setToolTip("Bring up a help window")
parent.layout().addWidget(self.button)
self.button.connect('clicked()', self.showHelp)
def showHelp(self):
self.message.setText(self.helpString)
self.message.open()
#########################################################
# Options
#########################################################
class EditOptions(object):
""" This EditOptions is a parent class for all the GUI options
for editor effects. These are small custom interfaces
that it in the toolOptionsFrame of the Editor interface.
TODO: no support yet for scope options
"""
def __init__(self, parent=None):
self.parent = parent
self.updatingGUI = False
self.observerTags = []
self.widgets = []
self.parameterNode = None
self.parameterNodeTag = None
self.editUtil = EditUtil() # Kept for backward compatibility
self.tools = []
# connections is a list of widget/signal/slot tripples
# for the options gui that can be connected/disconnected
# as needed to prevent triggering mrml updates while
# updating the state of the gui
# - each level of the inheritance tree can add entries
# to this list for use by the connectWidgets
# and disconnectWidgets methods
self.connections = []
self.connectionsConnected = False
# 1) find the parameter node in the scene and observe it
# 2) set the defaults (will only set them if they are not
# already set)
self.updateParameterNode(self.parameterNode, vtk.vtkCommand.ModifiedEvent)
# TODO: change this to look for specfic events (added, removed...)
# but this requires being able to access events by number from wrapped code
tag = slicer.mrmlScene.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateParameterNode)
self.observerTags.append( (slicer.mrmlScene, tag) )
def __del__(self):
self.destroy()
if self.parameterNode:
self.parameterNode.RemoveObserver(self.parameterNodeTag)
for tagpair in self.observerTags:
tagpair[0].RemoveObserver(tagpair[1])
def connectWidgets(self):
if self.connectionsConnected: return
for widget,signal,slot in self.connections:
success = widget.connect(signal,slot)
if not success:
print("Could not connect {signal} to {slot} for {widget}".format(
signal = signal, slot = slot, widget = widget))
self.connectionsConnected = True
def disconnectWidgets(self):
if not self.connectionsConnected: return
for widget,signal,slot in self.connections:
success = widget.disconnect(signal,slot)
if not success:
print("Could not disconnect {signal} to {slot} for {widget}".format(
signal = signal, slot = slot, widget = widget))
self.connectionsConnected = False
def create(self):
if not self.parent:
self.parent = slicer.qMRMLWidget()
self.parent.setLayout(qt.QVBoxLayout())
self.parent.setMRMLScene(slicer.mrmlScene)
self.parent.show()
self.frame = qt.QFrame(self.parent)
self.frame.objectName = 'EditOptionsFrame'
self.frame.setLayout(qt.QVBoxLayout())
self.parent.layout().addWidget(self.frame)
self.widgets.append(self.frame)
def destroy(self):
for w in self.widgets:
self.parent.layout().removeWidget(w)
w.deleteLater()
w.setParent(None)
self.widgets = []
#
# update the GUI for the given label
# - to be overriden by the subclass
#
def updateMRMLFromGUI(self):
pass
#
# update the GUI from MRML
# - to be overriden by the subclass
#
def updateGUIFromMRML(self,caller,event):
pass
#
# update the GUI from MRML
# - to be overriden by the subclass
#
def updateGUI(self):
self.updateGUIFromMRML(self.parameterNode, vtk.vtkCommand.ModifiedEvent)
#
# set the default option values
# - to be overriden by the subclass
#
def setMRMLDefaults(self):
pass
def getBackgroundScalarRange(self):
success = False
lo = -1
hi = -1
backgroundVolume = EditUtil.getBackgroundVolume()
if backgroundVolume:
backgroundImage = backgroundVolume.GetImageData()
if backgroundImage:
lo, hi = backgroundImage.GetScalarRange()
success = True
return success, lo, hi
def setRangeWidgetToBackgroundRange(self, rangeWidget):
"""Set the range widget based on current backgroun
volume - note that hi+1 is used since the range widget
will round floating numbers to 2 significant digits"""
if not rangeWidget:
return
success, lo, hi = self.getBackgroundScalarRange()
if success:
rangeWidget.minimum, rangeWidget.maximum = lo, hi+1
def statusText(self,text):
slicer.util.showStatusMessage(text)
def debug(self,text):
import inspect
print('*'*80)
print(text)
print(self)
stack = inspect.stack()
for frame in stack:
print(frame)