class VolumeEditorWidget(QWidget): def __init__( self, volumeeditor, parent=None ): super(VolumeEditorWidget, self).__init__(parent=parent) self._ve = volumeeditor self.setFocusPolicy(Qt.StrongFocus) # setup quadview self.quadview = QuadView(self) self.quadview.addWidget(0, self._ve.imageViews[2]) self.quadview.addWidget(1, self._ve.imageViews[0]) self.quadview.addWidget(2, self._ve.imageViews[1]) #3d overview #self.overview = OverviewScene(self, self._ve._shape[1:4]) #self.quadview.addWidget(3, self.overview) self.quadview.addWidget(3, QWidget(self)) #FIXME: resurrect #self.overview.changedSlice.connect(self.changeSlice) #self._ve.changedSlice.connect(self.overview.ChangeSlice) # layout viewingLayout = QVBoxLayout() viewingLayout.setContentsMargins(10,2,0,2) viewingLayout.setSpacing(0) viewingLayout.addWidget(self.quadview) self.quadview.setContentsMargins(0,0,10,0) # Label below views labelLayout = QHBoxLayout() labelLayout.setMargin(0) labelLayout.setSpacing(5) labelLayout.setContentsMargins(0,0,0,0) self.posLabel = QLabel() self.pixelValuesLabel = QLabel() labelLayout.addWidget(self.posLabel) labelLayout.addWidget(self.pixelValuesLabel) labelLayout.addStretch() viewingLayout.addLayout(labelLayout) # Right side toolbox self._toolBox = QWidget() self._toolBox.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._toolBoxLayout = QVBoxLayout() self._toolBoxLayout.setMargin(5) self._toolBox.setLayout(self._toolBoxLayout) self._toolBoxLayout.addStretch() # Toggle slice intersection marks self.indicateSliceIntersectionButton = QToolButton() self.indicateSliceIntersectionButton.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.indicateSliceIntersectionButton.setText("Indicate Current Position") self.indicateSliceIntersectionButton.setCheckable(True) self.indicateSliceIntersectionButton.setChecked(True) self._toolBoxLayout.addWidget(self.indicateSliceIntersectionButton) # Channel Selector QComboBox in right side tool box self._channelSpin = QSpinBox() self._channelSpin.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._channelSpin.setEnabled(True) channelLayout = QHBoxLayout() channelLayout.addWidget(self._channelSpin) self._channelSpinLabel = QLabel("Channel:") self._toolBoxLayout.addWidget(self._channelSpinLabel) self._toolBoxLayout.addLayout(channelLayout) #time selector self._timeSpin = QSpinBox() self._timeSpin.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._timeSpin.setEnabled(True) timeLayout = QHBoxLayout() timeLayout.addWidget(self._timeSpin) self._timeSpinLabel = QLabel("Time:") self._toolBoxLayout.addWidget(self._timeSpinLabel) self._toolBoxLayout.addLayout(timeLayout) self._toolBoxLayout.setAlignment(Qt.AlignTop) self._channelSpin.setRange(0,self._ve._shape[-1] - 1) self._timeSpin.setRange(0,self._ve._shape[0] - 1) def setChannel(c): print "set channel = %d, posModel has channel = %d" % (c, self._ve.posModel.channel) if c == self._ve.posModel.channel: return self._ve.posModel.channel = c self._channelSpin.valueChanged.connect(setChannel) def getChannel(newC): self._channelSpin.setValue(newC) self._ve.posModel.channelChanged.connect(getChannel) def setTime(t): print "set channel = %d, posModel has time = %d" % (t, self._ve.posModel.time) if t == self._ve.posModel.time: return self._ve.posModel.time = t self._timeSpin.valueChanged.connect(setTime) def getTime(newT): self._timeSpin.setValue(newT) self._ve.posModel.timeChanged.connect(getTime) # setup the layout for display self.splitter = QSplitter() self.splitter.setContentsMargins(0,0,0,0) tempWidget = QWidget() tempWidget.setLayout(viewingLayout) self.splitter.addWidget(tempWidget) self.splitter.addWidget(self._toolBox) splitterLayout = QVBoxLayout() splitterLayout.setMargin(0) splitterLayout.setSpacing(0) splitterLayout.addWidget(self.splitter) self.setLayout(splitterLayout) # drawing axisLabels = ["X:", "Y:", "Z:"] for i, v in enumerate(self._ve.imageViews): v.hud = SliceSelectorHud() #connect interpreter v.hud.sliceSelector.valueChanged.connect(partial(self._ve.navInterpret.changeSliceAbsolute, axis=i)) #hud v.hud.bgColor = self._ve.navCtrl.axisColors[i] #FIXME v.hud.label = axisLabels[i] v.hud.minimum = 0 v.hud.maximum = self._ve.posModel.volumeExtent(i) def toggleSliceIntersection(state): self._ve.navCtrl.indicateSliceIntersection = state self.indicateSliceIntersectionButton.toggled.connect(toggleSliceIntersection) #Enabling this makes cursor movement too slow... #self._ve.posModel.cursorPositionChanged.connect(self._updateInfoLabels) # shortcuts self._initShortcuts() self.updateGeometry() self.update() self.quadview.update() def _shortcutHelper(self, keySequence, group, description, parent, function, context = None, enabled = None): shortcut = QShortcut(QKeySequence(keySequence), parent, member=function, ambiguousMember=function) if context != None: shortcut.setContext(context) if enabled != None: shortcut.setEnabled(True) return shortcut, group, description def _initShortcuts(self): self.shortcuts = [] self.shortcuts.append(self._shortcutHelper("Ctrl+Z", "Labeling", "History undo", self, self._ve.historyUndo, Qt.ApplicationShortcut, True)) self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Z", "Labeling", "History redo", self, self._ve.historyRedo, Qt.ApplicationShortcut, True)) self.shortcuts.append(self._shortcutHelper("Ctrl+Y", "Labeling", "History redo", self, self._ve.historyRedo, Qt.ApplicationShortcut, True)) self.shortcuts.append(self._shortcutHelper("l", "Labeling", "Go to next label (cyclic, forward)", self, self._ve.nextLabel)) self.shortcuts.append(self._shortcutHelper("k", "Labeling", "Go to previous label (cyclic, backwards)", self, self._ve.prevLabel)) def fullscreenView(axis): m = not self.quadview.maximized print "maximize axis=%d = %r" % (axis, m) self.quadview.setMaximized(m, axis) maximizeShortcuts = ['x', 'y', 'z'] maximizeViews = [1, 2, 0] for i, v in enumerate(self._ve.imageViews): self.shortcuts.append(self._shortcutHelper(maximizeShortcuts[i], "Navigation", \ "Enlarge slice view %s to full size" % maximizeShortcuts[i], \ self, partial(fullscreenView, maximizeViews[i]), Qt.WidgetShortcut)) #self.shortcuts.append(self._shortcutHelper("n", "Labeling", "Increase brush size", v,self._ve._drawManager.brushSmaller, Qt.WidgetShortcut)) #self.shortcuts.append(self._shortcutHelper("m", "Labeling", "Decrease brush size", v, self._ve._drawManager.brushBigger, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("+", "Navigation", "Zoom in", v, v.zoomIn, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("-", "Navigation", "Zoom out", v, v.zoomOut, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("q", "Navigation", "Switch to next channel", v, self._ve.nextChannel, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("a", "Navigation", "Switch to previous channel", v, self._ve.previousChannel, Qt.WidgetShortcut)) def sliceDelta(axis, delta): newPos = copy.copy(self._ve.posModel.slicingPos) newPos[axis] += delta self._ve.posModel.slicingPos = newPos self.shortcuts.append(self._shortcutHelper("p", "Navigation", "Slice up", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("o", "Navigation", "Slice down", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Up", "Navigation", "Slice up", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Down", "Navigation", "Slice down", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Up", "Navigation", "10 slices up", v, partial(sliceDelta, i, 10), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Down", "Navigation", "10 slices down", v, partial(sliceDelta, i, -10), Qt.WidgetShortcut)) def _updateInfoLabels(self, pos): if any((pos[i] < 0 or pos[i] >= self._ve.posModel.shape[i] for i in xrange(3))): self._ve.posLabel.setText("") return self.posLabel.setText("<b>x:</b> %03i <b>y:</b> %03i <b>z:</b> %03i" % (pos[0], pos[1], pos[2]))
class VolumeEditorWidget(QWidget): def __init__( self, parent=None, editor=None ): super(VolumeEditorWidget, self).__init__(parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setFocusPolicy(Qt.StrongFocus) self.editor = None if editor!=None: self.init(editor) self.allZoomToFit = QAction(QIcon(":/icons/icons/view-fullscreen.png"), "Zoom to &Fit", self) self.allZoomToFit.triggered.connect(self._fitToScreen) self.allToggleHUD = QAction(QIcon(), "Show &HUDs", self) self.allToggleHUD.setCheckable(True) self.allToggleHUD.setChecked(True) self.allToggleHUD.toggled.connect(self._toggleHUDs) self.allCenter = QAction(QIcon(), "&Center views", self) self.allCenter.triggered.connect(self._centerAllImages) self.selectedCenter = QAction(QIcon(), "C&enter view", self) self.selectedCenter.triggered.connect(self._centerImage) self.selectedZoomToFit = QAction(QIcon(":/icons/icons/view-fullscreen.png"), "Zoom to Fit", self) self.selectedZoomToFit.triggered.connect(self._fitImage) self.selectedZoomToOriginal = QAction(QIcon(), "Reset Zoom", self) self.selectedZoomToOriginal.triggered.connect(self._restoreImageToOriginalSize) self.rubberBandZoom = QAction(QIcon(), "Rubberband Zoom", self) self.rubberBandZoom.triggered.connect(self._rubberBandZoom) self.toggleSelectedHUD = QAction(QIcon(), "Show HUD", self) self.toggleSelectedHUD.setCheckable(True) self.toggleSelectedHUD.setChecked(True) self.toggleSelectedHUD.toggled.connect(self._toggleSelectedHud) def _setupVolumeExtent( self ): '''Setup min/max values of position/coordinate control elements. Position/coordinate information is read from the volumeEditor's positionModel. ''' self.quadview.statusBar.channelSpinBox.setRange(0,self.editor.posModel.shape5D[-1] - 1) self.quadview.statusBar.timeSpinBox.setRange(0,self.editor.posModel.shape5D[0] - 1) for i in range(3): self.editor.imageViews[i].hud.setMaximum(self.editor.posModel.volumeExtent(i)-1) def init(self, volumina): self.editor = volumina def onViewFocused(): axis = self.editor._lastImageViewFocus; self.toggleSelectedHUD.setChecked( self.editor.imageViews[axis]._hud.isVisible() ) self.editor.newImageView2DFocus.connect(onViewFocused) self.layout = QHBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) # setup quadview axisLabels = ["X", "Y", "Z"] axisColors = [QColor("#dc143c"), QColor("green"), QColor("blue")] for i, v in enumerate(self.editor.imageViews): v.hud = ImageView2DHud() #connect interpreter v.hud.createImageView2DHud(axisLabels[i], 0, axisColors[i], QColor("white")) v.hud.sliceSelector.valueChanged.connect(partial(self.editor.navCtrl.changeSliceAbsolute, axis=i)) self.quadview = QuadView(self, self.editor.imageViews[2], self.editor.imageViews[0], self.editor.imageViews[1], self.editor.view3d) self.quadViewStatusBar = QuadStatusBar() self.quadViewStatusBar.createQuadViewStatusBar(QColor("#dc143c"), QColor("white"), QColor("green"), QColor("white"), QColor("blue"), QColor("white"), QColor("gray"), QColor("white")) self.quadview.addStatusBar(self.quadViewStatusBar) self.layout.addWidget(self.quadview) def setChannel(c): print "set channel = %d, posModel has channel = %d" % (c, self.editor.posModel.channel) if c == self.editor.posModel.channel: return self.editor.posModel.channel = c self.quadview.statusBar.channelSpinBox.valueChanged.connect(setChannel) def getChannel(newC): self.quadview.statusBar.channelSpinBox.setValue(newC) self.editor.posModel.channelChanged.connect(getChannel) def setTime(t): print "set channel = %d, posModel has time = %d" % (t, self.editor.posModel.time) if t == self.editor.posModel.time: return self.editor.posModel.time = t self.quadview.statusBar.timeSpinBox.valueChanged.connect(setTime) def getTime(newT): self.quadview.statusBar.timeSpinBox.setValue(newT) self.editor.posModel.timeChanged.connect(getTime) def toggleSliceIntersection(state): self.editor.navCtrl.indicateSliceIntersection = (state == Qt.Checked) self.quadview.statusBar.positionCheckBox.stateChanged.connect(toggleSliceIntersection) self.editor.posModel.cursorPositionChanged.connect(self._updateInfoLabels) # shortcuts self._initShortcuts() def onShapeChanged(): self._setupVolumeExtent() self.editor.shapeChanged.connect(onShapeChanged) self.updateGeometry() self.update() self.quadview.update() def _toggleDebugPatches(self,show): self.editor.showDebugPatches = show def _fitToScreen(self): shape = self.editor.posModel.shape for i, v in enumerate(self.editor.imageViews): s = list(copy.copy(shape)) del s[i] v.changeViewPort(v.scene().data2scene.mapRect(QRectF(0,0,*s))) def _fitImage(self): if self.editor._lastImageViewFocus is not None: self.editor.imageViews[self.editor._lastImageViewFocus].fitImage() def _restoreImageToOriginalSize(self): if self.editor._lastImageViewFocus is not None: self.editor.imageViews[self.editor._lastImageViewFocus].doScaleTo() def _rubberBandZoom(self): if self.editor._lastImageViewFocus is not None: if not self.editor.imageViews[self.editor._lastImageViewFocus]._isRubberBandZoom: self.editor.imageViews[self.editor._lastImageViewFocus]._isRubberBandZoom = True self.editor.imageViews[self.editor._lastImageViewFocus]._cursorBackup = self.editor.imageViews[self.editor._lastImageViewFocus].cursor() self.editor.imageViews[self.editor._lastImageViewFocus].setCursor(Qt.CrossCursor) else: self.editor.imageViews[self.editor._lastImageViewFocus]._isRubberBandZoom = False self.editor.imageViews[self.editor._lastImageViewFocus].setCursor(self.editor.imageViews[self.editor._lastImageViewFocus]._cursorBackup) def _toggleHUDs(self, checked): for i, v in enumerate(self.editor.imageViews): v.setHudVisible(checked) def _toggleSelectedHud(self, checked): if self.editor._lastImageViewFocus is not None: self.editor.imageViews[self.editor._lastImageViewFocus].setHudVisible(checked) def _centerAllImages(self): for i, v in enumerate(self.editor.imageViews): v.centerImage() def _centerImage(self): if self.editor._lastImageViewFocus is not None: self.editor.imageViews[self.editor._lastImageViewFocus].centerImage() def _shortcutHelper(self, keySequence, group, description, parent, function, context = None, enabled = None): shortcut = QShortcut(QKeySequence(keySequence), parent, member=function, ambiguousMember=function) if context != None: shortcut.setContext(context) if enabled != None: shortcut.setEnabled(True) return shortcut, group, description def _initShortcuts(self): self.shortcuts = [] #self.shortcuts.append(self._shortcutHelper("Ctrl+Z", "Labeling", "History undo", self, self.editor.historyUndo, Qt.ApplicationShortcut, True)) #self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Z", "Labeling", "History redo", self, self.editor.historyRedo, Qt.ApplicationShortcut, True)) #self.shortcuts.append(self._shortcutHelper("Ctrl+Y", "Labeling", "History redo", self, self.editor.historyRedo, Qt.ApplicationShortcut, True)) def fullscreenView(axis): m = not self.quadview.maximized print "maximize axis=%d = %r" % (axis, m) self.quadview.setMaximized(m, axis) maximizeShortcuts = ['x', 'y', 'z'] maximizeViews = [1, 2, 0] for i, v in enumerate(self.editor.imageViews): self.shortcuts.append(self._shortcutHelper(maximizeShortcuts[i], "Navigation", \ "Enlarge slice view %s to full size" % maximizeShortcuts[i], \ self, partial(fullscreenView, maximizeViews[i]), Qt.WidgetShortcut)) #self.shortcuts.append(self._shortcutHelper("n", "Labeling", "Increase brush size", v,self.editor._drawManager.brushSmaller, Qt.WidgetShortcut)) #self.shortcuts.append(self._shortcutHelper("m", "Labeling", "Decrease brush size", v, self.editor._drawManager.brushBigger, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("+", "Navigation", "Zoom in", v, v.zoomIn, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("-", "Navigation", "Zoom out", v, v.zoomOut, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("c", "Navigation", "Center image", v, v.centerImage, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("h", "Navigation", "Toggle hud", v, v.toggleHud, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("q", "Navigation", "Switch to next channel", v, self.editor.nextChannel, Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("a", "Navigation", "Switch to previous channel", v, self.editor.previousChannel, Qt.WidgetShortcut)) def sliceDelta(axis, delta): newPos = copy.copy(self.editor.posModel.slicingPos) newPos[axis] += delta self.editor.posModel.slicingPos = newPos self.shortcuts.append(self._shortcutHelper("p", "Navigation", "Slice up", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("o", "Navigation", "Slice down", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Up", "Navigation", "Slice up", v, partial(sliceDelta, i, 1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Down", "Navigation", "Slice down", v, partial(sliceDelta, i, -1), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Up", "Navigation", "10 slices up", v, partial(sliceDelta, i, 10), Qt.WidgetShortcut)) self.shortcuts.append(self._shortcutHelper("Ctrl+Shift+Down", "Navigation", "10 slices down", v, partial(sliceDelta, i, -10), Qt.WidgetShortcut)) def _updateInfoLabels(self, pos): self.quadViewStatusBar.setMouseCoords(*pos)