def respondToErrorMessage(self, caller, event):
   errorMessage = self.__logic.GetErrorMessage()
   # inform user only if the message is not empty since vtkErrorMacro invokes this event as well
   if errorMessage != None:
     Helper.Debug('respondToErrorMessage, event = '+str(event)+', message =\n\t'+str(errorMessage))
     errorDialog = qt.QErrorMessage(self.parent)
     errorDialog.showMessage(errorMessage)
Example #2
0
    def setup(self):
        ScriptedLoadableModuleWidget.setup(self)
        # Instantiate and connect widgets ...

        #
        # Parameters Area
        #
        parametersCollapsibleButton = ctk.ctkCollapsibleButton()
        parametersCollapsibleButton.text = "Parameters"
        self.layout.addWidget(parametersCollapsibleButton)

        # Layout within the dummy collapsible button
        parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)

        #
        # Configuration Selection
        #
        self.configPathEdit = ctk.ctkPathLineEdit()
        self.configPathEdit.toolTip = "A json file in the format described in the help tab above."
        parametersFormLayout.addRow('Config File', self.configPathEdit)

        self.targetDirectoryButton = ctk.ctkDirectoryButton()
        self.targetDirectoryButton.directory = slicer.app.temporaryPath
        self.targetDirectoryButton.toolTip = "Where you want the customized Slicer application to be created.  By default it is the current Slicer temporary directory."
        parametersFormLayout.addRow('Target Directory',
                                    self.targetDirectoryButton)

        #
        # Apply Button
        #
        self.applyButton = qt.QPushButton("Generate")
        self.applyButton.toolTip = "Generate the Custom Slicer."
        parametersFormLayout.addRow(self.applyButton)

        # connections
        self.applyButton.connect('clicked(bool)', self.onApplyButton)

        # Possible use for error messages
        self.message = qt.QErrorMessage()
        self.message.setWindowTitle("CustomSlicerGenerator")

        # Add vertical spacer
        self.layout.addStretch(1)
        self.logic = CustomSlicerGeneratorLogic()

        # QPushButton used for signal connection between widget and logic
        self.myQObject = qt.QPushButton()
        self.myQObject.connect('clicked(bool)', self.doneGenerating)
Example #3
0
    def confirmSeedSelection(self):

        labelVolume = self.editUtil.getLabelVolume()
        backgroundVolume = self.editUtil.getBackgroundVolume()

        if (not labelVolume) or (not backgroundVolume):
            self.goToRobustStatisticsSegmenter.enabled = False
            self.smooth_boundary.enabled = False
            self.good_contrast.enabled = False
            self.region_small.enabled = False
            self.region_medium.enabled = False
            self.region_large.enabled = False
            self.apply.enabled = False
            #dialog = qt.QErrorMessage(self.parent)
            #dialog.showMessage("Need a background volume and label volume (seed) to perform segmentation!")
        else:
            labelID = self.editUtil.getLabelID()
            labelNode = slicer.mrmlScene.GetNodeByID(labelID)
            labelImage = labelNode.GetImageData()

            backgroundID = self.editUtil.getBackgroundID()
            backgroundNode = slicer.mrmlScene.GetNodeByID(backgroundID)
            backgroundImage = backgroundNode.GetImageData()

            labelDim = labelImage.GetDimensions()
            backgroundDim = backgroundImage.GetDimensions()

            if labelDim != backgroundDim:
                dialog = qt.QErrorMessage(self.parent)
                dialog.showMessage(
                    "Label Image and Background Image Dimensions don't match!")
            else:
                self.goToRobustStatisticsSegmenter.enabled = True
                self.smooth_boundary.enabled = True
                self.good_contrast.enabled = True
                self.region_small.enabled = True
                self.region_medium.enabled = True
                self.region_large.enabled = True
                self.apply.enabled = True
Example #4
0
 def errorDialog(self, message):
     self.dialog = qt.QErrorMessage()
     self.dialog.setWindowTitle("Editor")
     self.dialog.showMessage(message)
Example #5
0
    def editorGestureCheckPoint(self):
        labelID = self.editUtil.getLabelID()
        labelNode = slicer.mrmlScene.GetNodeByID(labelID)
        labelImage = labelNode.GetImageData()

        backgroundID = self.editUtil.getBackgroundID()
        backgroundNode = slicer.mrmlScene.GetNodeByID(backgroundID)
        backgroundImage = backgroundNode.GetImageData()

        labelDim = labelImage.GetDimensions()
        backgroundDim = backgroundImage.GetDimensions()

        gestureID = None
        print("printting label dimensions ")
        print labelDim
        print("printing background dimensions ")
        print backgroundDim
        #    if labelDim[0] != backgroundDim[0]  | labelDim[1] != backgroundDim[1] | labelDim[2] != backgroundDim[2]:
        if labelDim != backgroundDim:
            dialog = qt.QErrorMessage(self.parent)
            dialog.showMessage(
                "Label Image and Background Image Dimensions don't match. Select another label image. All previous gestures will be lost."
            )
        else:
            # flip label name and gesture name
            labelName = labelNode.GetName()
            gestureName = labelName
            labelName = labelName + '-growcut-input'

            slicer.mrmlScene.GetNodeByID(labelID).SetName(gestureName)

            nodes = slicer.mrmlScene.GetNodesByName(labelName)
            if nodes.GetNumberOfItems() == 0:
                volumesLogic = slicer.modules.volumes.logic()
                gestureNode = volumesLogic.CreateLabelVolume(
                    slicer.mrmlScene, labelNode, labelName)
                gestureID = gestureNode.GetID()
                node = self.editorGetGestureParameterNode(gestureID)
            else:
                nNodes = nodes.GetNumberOfItems()
                foundNode = None
                for n in xrange(nNodes):
                    vol = nodes.GetItemAsObject(n)
                    volID = vol.GetID()
                    volname = vol.GetName()
                    if volname == gestureName:
                        foundNode = volID
                        gestureID = volID
                        break
                if foundNode == None:
                    volumesLogic = slicer.modules.volumes.logic()
                    gestureNode = volumesLogic.CreateLabelVolume(
                        slicer.mrmlScene, labelNode, gestureName)
                    gestureID = gestureNode.GetID()
                    node = self.editorGetGestureParameterNode(gestureID)
                else:
                    node = self.editorGetGestureParameterNode(foundNode)
        numNodes = slicer.mrmlScene.GetNumberOfNodesByClass(
            'vtkMRMLSliceCompositeNode')
        for n in xrange(numNodes):
            cnode = slicer.mrmlScene.GetNthNodeByClass(
                n, 'vtkMRMLSliceCompositeNode')
            cnode.SetReferenceLabelVolumeID(labelNode.GetID())
            cnode.SetLabelOpacity(0.6)
            cnode.SetReferenceForegroundVolumeID(gestureID)
            cnode.SetForegroundOpacity(0.4)
Example #6
0
class EditBox(object):
    def __init__(self,
                 parent=0,
                 optionsFrame=None,
                 embedded=False,
                 suppliedEffects=[]):
        self.effects = []
        self.effectButtons = {}
        self.effectMapper = qt.QSignalMapper()
        self.effectMapper.connect('mapped(const QString&)', self.selectEffect)
        self.editUtil = EditUtil.EditUtil()

        # check for extensions - if none have been registered, just create the empty dictionary
        try:
            slicer.modules.editorExtensions
        except AttributeError:
            slicer.modules.editorExtensions = {}

        # embedded boolean specifies whether or not this edit box is to be embedded
        # into another moduleWidget
        # - if it is, all effect buttons will be displayed in a single row
        self.embedded = embedded

        # save the list of supplied effects that the caller wants to use
        # (should be a subset of EditBox.availableMouseTools + EditBox.availableOperations)
        self.suppliedEffects = suppliedEffects

        if parent == 0:
            self.parent = qt.QFrame()
            self.parent.setLayout(qt.QVBoxLayout())
            self.create()
            self.parent.show()
        else:
            self.parent = parent
            self.create()

        # frame that holds widgets specific for each effect
        if not optionsFrame:
            self.optionsFrame = qt.QFrame(self.parent)
        else:
            self.optionsFrame = optionsFrame

        # state variables for selected effect in the box
        # - currentOption is an instance of an option GUI
        # - currentTools is a list of EffectTool instances
        self.currentOption = None
        self.currentTools = []

    #
    # Public lists of the available effects provided by the editor
    #

    # effects that change the mouse cursor
    availableMouseTools = (
        "ChangeIsland",
        "ChooseColor",
        "ImplicitCube",
        "ImplicitEllipse",
        "ImplicitRectangle",
        "Draw",
        "RemoveIslands",
        "ConnectedComponents",
        "ThresholdBucket",
        "ThresholdPaintLabel",
        "SaveIsland",
        "SlurpColor",
        "Paint",
        "DefaultTool",
        "LevelTracing",
        "MakeModel",
        "Wand",
        "GrowCutSegment",
    )

    # effects that operate from the menu
    availableOperations = (
        "ErodeLabel",
        "DilateLabel",
        "DeleteFiducials",
        "LabelOpacity",
        "ChangeLabel",
        "FiducialVisibilityOff",
        "FiducialVisibilityOn",
        "GoToEditorModule",
        "IdentifyIslands",
        "LabelVisibilityOff",
        "LabelVisibilityOn",
        "NextFiducial",
        "SnapToGridOff",
        "SnapToGridOn",
        "EraseLabel",
        "Threshold",
        "PinOpen",
        "PreviousFiducial",
        "InterpolateLabels",
        "LabelOpacity",
        "ToggleLabelOutline",
        "Watershed",
        "PreviousCheckPoint",
        "NextCheckPoint",
    )

    # these buttons do not switch you out of the current tool
    availableNonmodal = ("FiducialVisibilityOn", "LabelVisibilityOff",
                         "LabelVisibilityOn", "NextFiducial",
                         "PreviousFiducial", "DeleteFiducials", "SnapToGridOn",
                         "SnapToGridOff", "EraseLabel", "PreviousCheckPoint",
                         "NextCheckPoint", "ToggleLabelOutline",
                         "SnapToGridOff", "SnapToGridOn", "LabelOpacity")

    # these buttons start disabled (check points will re-enable when circumstances are right)
    availableDisabled = (
        "ChooseColor",
        "ImplicitCube",
        "ImplicitEllipse",
        "ConnectedComponents",
        "SlurpColor",
        "ThresholdPaintLabel",
        "ThresholdBucket",
        "DeleteFiducials",
        "LabelOpacity",
        "FiducialVisibilityOff",
        "FiducialVisibilityOn",
        "LabelVisibilityOff",
        "LabelVisibilityOn",
        "SnapToGridOff",
        "SnapToGridOn",
        "InterpolateLabels",
        "LabelOpacity",
        "ToggleLabelOutline",
        "Watershed",
        "Wand",
    )

    # allow overriding the developers name of the tool for a more user-friendly label name
    displayNames = {}
    displayNames["PreviousCheckPoint"] = "Undo"
    displayNames["NextCheckPoint"] = "Redo"

    # calculates the intersection of two flat lists
    @classmethod
    def listIntersection(cls, inList1, inList2):
        outList = [val for val in inList1 if val in inList2]
        return outList

    # fill the _effects array bases on what you find in the interpreter
    # if a list of effects was supplied, then use that list instead of all of the effects
    def findEffects(self, path=""):

        # for now, the built in effects are hard-coded to facilitate
        # the icons and layout

        self.effects = []

        # if a list of effects was supplied, then use that list instead of all of the effects
        # don't forget to check that the supplied effects are valid: ensure they exist in the lists of available effects

        if (self.suppliedEffects):
            self.mouseTools = tuple(
                self.listIntersection(self.suppliedEffects,
                                      EditBox.availableMouseTools))
            self.operations = tuple(
                self.listIntersection(self.suppliedEffects,
                                      EditBox.availableOperations))
            self.nonmodal = tuple(
                self.listIntersection(self.suppliedEffects,
                                      EditBox.availableNonmodal))
            self.disabled = tuple(
                self.listIntersection(self.suppliedEffects,
                                      EditBox.availableDisabled))
        # if a list of effects is not supplied, then provide all effects
        else:
            self.mouseTools = EditBox.availableMouseTools
            self.operations = EditBox.availableOperations
            self.nonmodal = EditBox.availableNonmodal
            self.disabled = EditBox.availableDisabled
        '''
    for key in slicer.modules.editorExtensions.keys():
      e = slicer.modules.editorExtensions[key]()
      if 'MouseTool' in e.attributes:
        self.mouseTools.append(key)
      if 'Nonmodal' in e.attributes:
        self.operations.append(key)
      if 'Disabled' in e.attributes:
        self.disabled.append(key)
    '''

        # combined list of all effects
        self.effects = self.mouseTools + self.operations

        # add any extensions that have been registered
        self.effects = self.effects + tuple(
            slicer.modules.editorExtensions.keys())

        # for each effect
        # - look for implementation class of pattern *Effect
        # - get an icon name for the pushbutton
        iconDir = os.environ['SLICER_HOME'] + '/' + os.environ[
            'SLICER_SHARE_DIR'] + '/Tcl/ImageData/'

        self.effectClasses = {}
        self.effectIconFiles = {}
        self.effectModes = {}
        self.icons = {}
        for effect in self.effects:
            tclclass = tcl('info command %sEffect' % effect)
            if tclclass != '':
                self.effectClasses[effect] = tclclass
            else:
                self.effectClasses[effect] = "EffectSWidget"

            for iconType in ("", "Selected", "Disabled"):
                self.effectIconFiles[
                    effect, iconType] = iconDir + effect + iconType + '.png'
                iconMode = ""
                if self.disabled.__contains__(effect):
                    # - don't use the disabled icon for now - Qt's setEnabled method works fine
                    #iconMode = "Disabled"
                    pass

                self.effectModes[effect] = iconMode

    #
    # create a row of the edit box given a list of
    # effect names (items in _effects(list)
    #
    def createButtonRow(self, effects, rowLabel=""):

        f = qt.QFrame(self.parent)
        self.parent.layout().addWidget(f)
        self.rowFrames.append(f)
        hbox = qt.QHBoxLayout()
        f.setLayout(hbox)

        if rowLabel:
            label = qt.QLabel(rowLabel)
            hbox.addWidget(label)

        for effect in effects:
            # check that the effect belongs in our list of effects before including
            # (handles non-embedded widgets where the caller has supplied a custom list of effects)
            if (effect in self.effects):
                i = self.icons[effect] = qt.QIcon(
                    self.effectIconFiles[effect, self.effectModes[effect]])
                a = self.actions[effect] = qt.QAction(i, '', f)
                self.effectButtons[effect] = b = self.buttons[
                    effect] = qt.QToolButton()
                b.setDefaultAction(a)
                b.setToolTip(effect)
                if EditBox.displayNames.has_key(effect):
                    b.setToolTip(EditBox.displayNames[effect])
                hbox.addWidget(b)
                if self.disabled.__contains__(effect):
                    b.setDisabled(1)

                # Setup the mapping between button and its associated effect name
                self.effectMapper.setMapping(self.buttons[effect], effect)
                # Connect button with signal mapper
                self.buttons[effect].connect('clicked()', self.effectMapper,
                                             'map()')

        hbox.addStretch(1)

    # create the edit box
    def create(self):

        self.findEffects()

        #
        # the buttons
        #
        self.rowFrames = []
        self.actions = {}
        self.buttons = {}
        self.icons = {}
        self.callbacks = {}

        # if not using embedded format: create all of the buttons
        # createButtonRow() ensures that only effects in self.effects are exposed,
        # so if the user supplied a list of effects only those in that list will be exposed
        if (not self.embedded):
            self.createButtonRow(
                ("DefaultTool", "EraseLabel", "Paint", "Draw", "LevelTracing",
                 "ImplicitRectangle", "IdentifyIslands", "ChangeIsland",
                 "RemoveIslands", "SaveIsland"))
            self.createButtonRow(
                ("ErodeLabel", "DilateLabel", "Threshold", "ChangeLabel",
                 "MakeModel", "GrowCutSegment"))
            extensions = []
            for k in slicer.modules.editorExtensions:
                extensions.append(k)
            self.createButtonRow(extensions)
            # TODO: add back prev/next fiducial
            #self.createButtonRow( ("PreviousFiducial", "NextFiducial") )
            self.createButtonRow(("PreviousCheckPoint", "NextCheckPoint"),
                                 rowLabel="Undo/Redo: ")
        # if using embedded format: create all of the buttons in the effects list in a single row
        else:
            self.createButtonRow(self.effects)

        #
        # the labels (not shown in embedded format)
        #
        self.toolsActiveToolFrame = qt.QFrame(self.parent)
        self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout())
        self.parent.layout().addWidget(self.toolsActiveToolFrame)
        self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame)
        self.toolsActiveTool.setText('Active Tool:')
        self.toolsActiveTool.setStyleSheet(
            "background-color: rgb(232,230,235)")
        self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool)
        self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame)
        self.toolsActiveToolName.setText('')
        self.toolsActiveToolName.setStyleSheet(
            "background-color: rgb(232,230,235)")
        self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName)

        self.updateCheckPointButtons()

    def setActiveToolLabel(self, name):
        if EditBox.displayNames.has_key(name):
            name = EditBox.displayNames[name]
        self.toolsActiveToolName.setText(name)


# needs to be a valid effect name and state of "", Disabled, or Selected

    TODO = """
itcl::body EditBox::setButtonState {effect state} {
  $::slicer3::ApplicationGUI SetIconImage \
      $_effects($effect,icon) $_effects($effect,imageData$state)
  $o($effect,button) SetImageToIcon $_effects($effect,icon)
  switch $state {
    Selected -
    "" {
      $o($effect,button) SetState 1
    }
    "Disabled" {
      $o($effect,button) SetState 0
    }
  }
}
"""

    #
    # Pause running the current effect, reverting to the default tool
    #
    def pauseEffect(self):
        self.selectEffect("DefaultTool")

    #
    # Resume running the effect that was being used before a pause (TODO)
    #
    def resumeEffect(self):
        pass

    #
    # manage the editor effects
    #
    def selectEffect(self, effect):
        from slicer import app

        #
        # if a modal effect was selected, build an options GUI
        # - check to see if it is an extension effect,
        # if not, try to create it, else ignore it
        # For extensions, look for 'effect'Options and 'effect'Tool
        # in the editorExtensions map and use those to create the
        # effect
        #
        if not self.nonmodal.__contains__(effect):
            if self.currentOption:
                self.currentOption.__del__()
                self.currentOption = None
                for tool in self.currentTools:
                    tool.cleanup()
                self.currentTools = []
            if effect in slicer.modules.editorExtensions.keys():
                extensionEffect = slicer.modules.editorExtensions[effect]()
                self.currentOption = extensionEffect.options(self.optionsFrame)
                layoutManager = slicer.app.layoutManager()
                sliceNodeCount = slicer.mrmlScene.GetNumberOfNodesByClass(
                    'vtkMRMLSliceNode')
                for nodeIndex in xrange(sliceNodeCount):
                    # find the widget for each node in scene
                    sliceNode = slicer.mrmlScene.GetNthNodeByClass(
                        nodeIndex, 'vtkMRMLSliceNode')
                    sliceWidget = layoutManager.sliceWidget(
                        sliceNode.GetLayoutName())
                    if sliceWidget:
                        tool = extensionEffect.tool(sliceWidget)
                        self.currentTools.append(tool)
            else:
                try:
                    options = eval("%sOptions" % effect)
                    self.currentOption = options(self.optionsFrame)
                except NameError, AttributeError:
                    # No options for this effect, skip it
                    pass

        #
        # If there is no background volume or label map, do nothing
        #
        # TODO should do this regardless of whether or not there is an option
        if not self.editUtil.getBackgroundVolume():
            return
        if not self.editUtil.getLabelVolume():
            return

        app.restoreOverrideCursor()
        self.setActiveToolLabel(effect)
        if not self.nonmodal.__contains__(effect):
            tcl('EffectSWidget::RemoveAll')
            tcl('EditorSetActiveToolLabel %s' % effect)

        # mouse tool changes cursor, and dismisses popup/menu
        mouseTool = False
        if self.mouseTools.__contains__(effect):
            mouseTool = True

        if effect == "DefaultTool":
            # do nothing - this will reset cursor mode
            tcl('EditorSetActiveToolLabel DefaultTool')
        elif effect == "GoToEditorModule":
            tcl('EditorSelectModule')
            tcl('EditorSetActiveToolLabel DefaultTool')
        elif effect == "LabelCheckPoint":
            # save a copy of the current label layer into the scene
            tcl('EditorLabelCheckPoint')
            tcl('EditorSetActiveToolLabel DefaultTool')
        elif effect == "PreviousFiducial":
            tcl('::FiducialsSWidget::JumpAllToNextFiducial -1')
            tcl('EditorSetActiveToolLabel DefaultTool')
        elif effect == "NextFiducial":
            tcl('::FiducialsSWidget::JumpAllToNextFiducial 1')
            tcl('EditorSetActiveToolLabel DefaultTool')
        elif effect == "EraseLabel":
            tcl('EditorToggleErasePaintLabel')
        elif effect == "PreviousCheckPoint":
            tcl('EditorPerformPreviousCheckPoint')
        elif effect == "NextCheckPoint":
            tcl('EditorPerformNextCheckPoint')
        else:
            if effect == "GrowCutSegment":
                self.editorGestureCheckPoint()
                #volumesLogic = slicer.modules.volumes.logic()
                #print ("VolumesLogic is %s " % volumesLogic)
                #tcl('EditorGestureCheckPoint $%s' % volumesLogic)
            if mouseTool:
                # TODO: make some nice custom cursor shapes
                # - for now use the built in override cursor
                #pix = qt.QPixmap()
                #pix.load(self.effectIconFiles[effect,""])
                #cursor = qt.QCursor(pix)
                #app.setOverrideCursor(cursor, 0, 0)
                cursor = qt.QCursor(1)
                app.setOverrideCursor(cursor)
            else:
                app.restoreOverrideCursor()

            #
            # create an instance of the effect for each of the active sliceGUIs
            # - have the effect reset the tool label when completed
            #

            ret = tcl('catch "EffectSWidget::Add %s" res' %
                      self.effectClasses[effect])
            if ret != '0':
                dialog = qt.QErrorMessage(self.parent)
                dialog.showMessage(
                    "Could not select effect.\n\nError was:\n%s" %
                    tcl('set res'))
            else:
                tcl('EffectSWidget::ConfigureAll %s -exitCommand "EditorSetActiveToolLabel DefaultTool"'
                    % self.effectClasses[effect])