Example #1
0
    def init(self, volumina):
        self.editor = volumina

        self.hudsShown = [True] * 3

        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.layout.setSpacing(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(v)
            #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.quadview.installEventFilter(self)
        self.quadViewStatusBar = QuadStatusBar()
        self.quadViewStatusBar.createQuadViewStatusBar(QColor("#dc143c"),
                                                       QColor("white"),
                                                       QColor("green"),
                                                       QColor("white"),
                                                       QColor("blue"),
                                                       QColor("white"))
        self.quadview.addStatusBar(self.quadViewStatusBar)
        self.layout.addWidget(self.quadview)

        ## Why do we have to prevent TimerEvents reaching the SpinBoxes?
        #
        # Sometimes clicking a SpinBox once caused the value to increase by
        # two. This is why:
        #
        # When a MouseClicked event is received by the SpinBox it fires a timerevent to control
        # the repeated increase of the value as long as the mouse button is pressed. The timer
        # is killed when it receives a MouseRelease event. If a slot connected to the valueChanged
        # signal of the SpinBox takes to long to process the signal the mouse release
        # and timer events get queued up and sometimes the timer event reaches the widget before
        # the mouse release event. That's why it increases the value by another step. To prevent
        # this we are blocking the timer events at the cost of no autorepeat anymore.
        #
        # See also:
        # http://lists.trolltech.com/qt-interest/2002-04/thread00137-0.html
        # http://www.qtcentre.org/threads/43078-QSpinBox-Timer-Issue
        # http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/widgets/qabstractspinbox.cpp#line1195
        self.quadview.statusBar.timeSpinBox.installEventFilter(_timerEater)

        def setTime(t):
            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)

        def onShapeChanged():
            singletonDims = filter(
                lambda (i, dim): dim == 1,
                enumerate(self.editor.posModel.shape5D[1:4]))
            if len(singletonDims) == 1:
                # Maximize the slicing view for this axis
                axis = singletonDims[0][0]
                self.quadview.ensureMaximized(axis)
                self.hudsShown[axis] = self.editor.imageViews[axis].hudVisible(
                )
                self.editor.imageViews[axis].setHudVisible(False)
                self.quadViewStatusBar.showXYCoordinates()

                self.quadview.statusBar.positionCheckBox.setVisible(False)
            else:
                self.quadViewStatusBar.showXYZCoordinates()
                for i in range(3):
                    self.editor.imageViews[i].setHudVisible(self.hudsShown[i])
                self.quadview.statusBar.positionCheckBox.setVisible(True)

            self._setupVolumeExtent()

        self.editor.shapeChanged.connect(onShapeChanged)

        self.updateGeometry()
        self.update()
        self.quadview.update()

        # shortcuts
        self._initShortcuts()
Example #2
0
    def init(self, volumina):
        self.editor = volumina

        self.hudsShown = [True] * 3

        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.layout.setSpacing(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(v)
            #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.quadview.installEventFilter(self)
        self.quadViewStatusBar = QuadStatusBar()
        self.quadViewStatusBar.createQuadViewStatusBar(QColor("#dc143c"),
                                                       QColor("white"),
                                                       QColor("green"),
                                                       QColor("white"),
                                                       QColor("blue"),
                                                       QColor("white"))
        self.quadview.addStatusBar(self.quadViewStatusBar)
        self.layout.addWidget(self.quadview)

        # Here we subscribe to the dirtyChanged() signal from all slicing views,
        #  and show the status bar "busy indicator" if any view is dirty.
        # Caveat: To avoid a flickering indicator for quick updates, we use a
        #         timer that prevents the indicator from showing for a bit.
        def updateDirtyStatus(fromTimer=False):
            # We only care about views that are both VISIBLE and DIRTY.
            dirties = map(lambda v: v.scene().dirty, self.editor.imageViews)
            visibilities = map(lambda v: v.isVisible(), self.editor.imageViews)
            visible_dirtiness = numpy.logical_and(visibilities, dirties)

            if not any(visible_dirtiness):
                # Not dirty: Hide immediately
                self.quadViewStatusBar.busyIndicator.setVisible(False)
            else:
                if fromTimer:
                    # The timer finished and we're still dirty:
                    # Time to show the busy indicator.
                    self.quadViewStatusBar.busyIndicator.setVisible(True)
                elif not self.quadViewStatusBar.busyIndicator.isVisible(
                ) and not self._dirtyTimer.isActive():
                    # We're dirty, but delay for a bit before showing the busy indicator.
                    self._dirtyTimer.start(750)

        self._dirtyTimer = QTimer()
        self._dirtyTimer.setSingleShot(True)
        self._dirtyTimer.timeout.connect(
            partial(updateDirtyStatus, fromTimer=True))
        for i, view in enumerate(self.editor.imageViews):
            view.scene().dirtyChanged.connect(updateDirtyStatus)

        # If the user changes the position in the quad-view status bar (at the bottom),
        # Update the position of the whole editor.
        def setPositionFromQuadBar(x, y, z):
            self.editor.posModel.slicingPos = (x, y, z)
            self.editor.posModel.cursorPos = (x, y, z)
            self.editor.navCtrl.panSlicingViews((x, y, z), [0, 1, 2])

        self.quadViewStatusBar.positionChanged.connect(setPositionFromQuadBar)

        ## Why do we have to prevent TimerEvents reaching the SpinBoxes?
        #
        # Sometimes clicking a SpinBox once caused the value to increase by
        # two. This is why:
        #
        # When a MouseClicked event is received by the SpinBox it fires a timerevent to control
        # the repeated increase of the value as long as the mouse button is pressed. The timer
        # is killed when it receives a MouseRelease event. If a slot connected to the valueChanged
        # signal of the SpinBox takes to long to process the signal the mouse release
        # and timer events get queued up and sometimes the timer event reaches the widget before
        # the mouse release event. That's why it increases the value by another step. To prevent
        # this we are blocking the timer events at the cost of no autorepeat anymore.
        #
        # See also:
        # http://lists.trolltech.com/qt-interest/2002-04/thread00137-0.html
        # http://www.qtcentre.org/threads/43078-QSpinBox-Timer-Issue
        # http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/widgets/qabstractspinbox.cpp#line1195
        self.quadview.statusBar.timeSpinBox.installEventFilter(_timerEater)

        def setTime(t):
            if t == self.editor.posModel.time:
                return
            self.editor.posModel.time = t

        self.quadview.statusBar.timeSpinBox.delayedValueChanged.connect(
            setTime)

        def setTimeSpinBox(newT):
            self.quadview.statusBar.timeSpinBox.setValue(newT)

        self.editor.posModel.timeChanged.connect(setTimeSpinBox)

        def toggleSliceIntersection(state):
            self.editor.navCtrl.indicateSliceIntersection = (
                state == Qt.Checked)

        self.quadview.statusBar.positionCheckBox.stateChanged.connect(
            toggleSliceIntersection)
        toggleSliceIntersection(
            self.quadview.statusBar.positionCheckBox.checkState())

        self.editor.posModel.cursorPositionChanged.connect(
            self._updateInfoLabels)

        def onShapeChanged():
            # By default, 3D HUD buttons are visible,
            #  but we'll turn them off below if the dataset is 2D.
            for axis in [0, 1, 2]:
                self.editor.imageViews[axis].hud.set3DButtonsVisible(True)

            singletonDims = filter(
                lambda (i, dim): dim == 1,
                enumerate(self.editor.posModel.shape5D[1:4]))
            if len(singletonDims) == 1:
                # Maximize the slicing view for this axis
                axis = singletonDims[0][0]
                self.quadview.ensureMaximized(axis)
                self.hudsShown[axis] = self.editor.imageViews[axis].hudVisible(
                )
                self.editor.imageViews[axis].hud.set3DButtonsVisible(False)
                self.quadViewStatusBar.showXYCoordinates()

                self.quadview.statusBar.positionCheckBox.setVisible(False)
            else:
                self.quadViewStatusBar.showXYZCoordinates()
                for i in range(3):
                    self.editor.imageViews[i].setHudVisible(self.hudsShown[i])
                self.quadview.statusBar.positionCheckBox.setVisible(True)

            if self.editor.cropModel._crop_extents[0][
                    0] == None or self.editor.cropModel.cropZero():
                self.quadViewStatusBar.updateShape5D(
                    self.editor.posModel.shape5D)
            else:
                cropMin = (self.editor.posModel.time,
                           self.editor.cropModel._crop_extents[0][0],
                           self.editor.cropModel._crop_extents[1][0],
                           self.editor.cropModel._crop_extents[2][0], 0)
                self.quadViewStatusBar.updateShape5Dcropped(
                    cropMin, self.editor.posModel.shape5D)

            self._setupVolumeExtent()

        self.editor.shapeChanged.connect(onShapeChanged)

        self.updateGeometry()
        self.update()
        self.quadview.update()
        if hasattr(self.editor.view3d, 'bUndock'):
            self.editor.view3d.bUndock.clicked.connect(
                partial(self.quadview.on_dock,
                        self.quadview.dock2_ofSplitHorizontal2))

        # shortcuts
        self._initShortcuts()