Exemple #1
0
Fichier : scj.py Projet : Ptaah/SCJ
class QtSCJ(QDialog) :
    """
    QtSCJ est une boite de dialogue contenant l'état de la progression de 
    chaque processus
    """

    def __init__(self, parent=None):
        super(QtSCJ, self).__init__(parent)
        self.dir = None
        self.jobs = { }
        self.log = [ ]
        self.mode = "ogg"
        self.filter = "*.mp3 *.ogg *.wav"
        self.modes = [ "ogg", "mp3", "wav" ]

        self.readSettings()

        self.setupUi()
        self.retranslateUi()
        self.fermer.setEnabled(True)
        
        self.connect(self.fermer,SIGNAL("clicked()"),self.close)
        self.connect(self.convertDir,SIGNAL("clicked()"),self.getDir)
        self.connect(self.convertFile,SIGNAL("clicked()"),self.getFiles)
        self.connect(self.startallbtn,SIGNAL("clicked()"),self.startAll)
        self.connect(self.delallbtn,SIGNAL("clicked()"),self.delAll)
        self.connect(self.output,SIGNAL("currentIndexChanged(const QString)"),
                     self.setMode)

    def setMode(self, mode):
        self.mode = mode
        self.writeSettings()

    def writeSettings(self):
        settings = QSettings("scj", "scj")
        settings.setValue("mode", self.mode)

    def readSettings(self):
        settings = QSettings("scj", "scj")
        self.mode = settings.value("mode", "ogg").toString()

    def setupUi(self):
        self.setObjectName("SCJ")
        self.setFixedSize(600,260)
        #self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.verticalLayout = QVBoxLayout(self)
        self.verticalLayout.setObjectName("verticalLayout")
        #self.infoText = QTextEdit(self)
        self.infoText = QLabel(self)
        palette = QPalette()
        brush = QBrush(QColor(245, 245, 245))
        brush.setStyle(Qt.SolidPattern)
        palette.setBrush(QPalette.Normal, QPalette.Background, brush)
        self.infoText.setPalette(palette)
        self.infoText.setAutoFillBackground(True)
        self.infoText.setFixedHeight(200)
        self.infoText.setObjectName("infoText")
        #self.infoText.setReadOnly(True)
        self.infoText.setWordWrap(True)
        self.verticalLayout.addWidget(self.infoText)
        # Manage Actions buttons
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        ## Format de sortie
        self.outlabel = QLabel(self.trUtf8("Choix du format de destination"))
        self.horizontalLayout.addWidget(self.outlabel)
        self.output = QComboBox()
        self.output.addItems(self.modes)
        self.output.setCurrentIndex(self.output.findText(self.mode))
        self.horizontalLayout.addWidget(self.output)
        # Buttons
        self.fermer = QPushButton(self)
        self.fermer.setObjectName("fermer")
        self.horizontalLayout.addWidget(self.fermer)
        self.convertDir = QPushButton(self)
        self.convertDir.setObjectName("convertDir")
        self.horizontalLayout.addWidget(self.convertDir)
        self.convertFile = QPushButton(self)
        self.convertFile.setObjectName("convertFile")
        self.horizontalLayout.addWidget(self.convertFile)
        self.verticalLayout.addLayout(self.horizontalLayout)

        # Layout for allButtons
        self.allLayout = QHBoxLayout()
        # Add startAll bouton
        self.startallbtn = QPushButton(self)
        self.allLayout.addWidget(self.startallbtn)
        self.startallbtn.hide()
        self.verticalLayout.addLayout(self.allLayout)
        # Add delAll bouton
        self.delallbtn = QPushButton(self)
        self.allLayout.addWidget(self.delallbtn)
        self.delallbtn.hide()
        # Mode avec scroll
        self.frame = QFrame()
        self.frame.setMinimumSize(520,250)
        self.frame.setMaximumWidth(520)
        self.scroll = QScrollArea()
        self.scroll.setMinimumHeight(180)
        self.jobsLayout = QVBoxLayout(self.frame)
        self.jobsLayout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        #self.jobsLayout.setSizeConstraint(QLayout.SetMinimumSize)
        #self.jobsLayout.setSizeConstraint(QLayout.SetMaximumSize)
        self.scroll.setWidget(self.frame)
        self.scroll.setWidgetResizable(False)
        self.verticalLayout.addWidget(self.scroll)
        self.scroll.hide()

        # Mode sans scroll
        #self.jobsLayout = QVBoxLayout()
        #self.verticalLayout.addLayout(self.jobsLayout)

        # Add a strech to the bottom of the window
        self.verticalLayout.insertStretch(-1)

    def retranslateUi(self):
        self.setWindowTitle(u"SCJ")
        self.infoText.setToolTip(self.trUtf8("Messages"))
        self.fermer.setToolTip(self.trUtf8("Fermer la fenetre"))
        self.fermer.setText(self.trUtf8("Fermer"))
        self.startallbtn.setToolTip(self.trUtf8("Demarrer toutes les taches"))
        self.startallbtn.setText(self.trUtf8("Tout demarrer"))
        self.delallbtn.setToolTip(self.trUtf8("Supprimmer toutes les taches"))
        self.delallbtn.setText(self.trUtf8("Tout supprimer"))
        self.convertDir.setToolTip(self.trUtf8("Convertir un repertoire"))
        self.convertDir.setText(self.trUtf8("Repertoire"))
        self.convertFile.setToolTip(self.trUtf8("Convertir un fichier"))
        self.convertFile.setText(self.trUtf8("Fichier(s)"))
        self.infoText.setText(u"<h1>%s</h1>\
                                \n%s<br/>\
                                \n%s\
                                \n<ul><li>%s</li>\
                                \n    <li>%s</li>\
                                \n    <li><b>%s</b></li>\
                                \n</ul>" %
                (self.trUtf8("BIENVENUE SUR SCJ"),
                 self.trUtf8("SCJ permet de convertir un ou plusieurs fichiers"+
                              " son vers differents formats."),
                 self.trUtf8("Il gere egalement les repertoires en convertissant"+
                              " l'ensemble des fichiers sons presents vers le"+
                              " format voulu."),
                 self.trUtf8("Choisissez le format de destination"),
                 self.trUtf8("Cliquez sur Fichier(s) ou Repertoire en fonction"+
                             " de ve que vous voulez convertir."),
                 self.trUtf8("Demarrez la conversion !")
                ))

    def addFile(self, file, createDir=False):
        file.makeAbsolute()
        if (file.suffix() != self.mode):
            job = SCJProgress( parent=None,
                                     file=file.filePath(),
                                     format=self.mode,
                                     createDir=createDir)
            if not self.jobs.get(job.output):
                self.jobs[job.output] = job
                self.jobsLayout.addLayout(self.jobs[job.output])
                self.connect(self.jobs[job.output], SIGNAL("void removed(QString)"), self.delFile)
        self.addStartAll()

    def delFile(self, job):
        j = self.jobs.pop(job)
        self.addStartAll()
        self.jobsLayout.removeItem(j)

    def getDir(self):
        self.dir = QFileDialog.getExistingDirectory(
                                parent = self,
                                caption = self.trUtf8("Choix du repertoire"),
					            directory = QDir.homePath(),
		                        options = QFileDialog.ShowDirsOnly |
                                QFileDialog.DontResolveSymlinks)
        if self.dir :
            directory = QDir(self.dir, self.filter)
            for file in directory.entryInfoList():
                self.addFile(file, createDir=True)

    def getFiles(self):
        files = QFileDialog.getOpenFileNames(
                                parent = self,
                                caption = self.trUtf8("Choix des fichiers"),
                                directory = QDir.homePath(),
                                filter = u"%s (%s)" % (self.trUtf8("Sons"),
                                                       self.filter))
        for file in files:
            self.addFile(QFileInfo(file), createDir=False)

    def addStartAll(self):
        if (len(self.jobs) > 0 ):
            self.startallbtn.setVisible(True)
            self.delallbtn.setVisible(True)
            self.scroll.setVisible(True)
            self.setFixedSize(600, 480)
        else:
            self.startallbtn.setVisible(False)
            self.delallbtn.setVisible(False)
            self.scroll.setVisible(False)
            self.setFixedSize(600, 260)
        self.updateGeometry()

    def startAll(self):
        for (key, job) in self.jobs.items():
            job.start()

    def delAll(self):
        for (key, job) in self.jobs.items():
            job.stop()
            self.delFile(key)

    def close(self):
        print u"%s" % self.trUtf8("We are stopping running jobs"),
        for (key, job) in self.jobs.items():
            job.stop()
            print ".",
        print u"%s" % self.trUtf8("Done")
        super(QtSCJ, self).close()
Exemple #2
0
    def __init__(self, w=550, h=480, titre=u"Configuration de Ekd", parent=None):
        super(EkdConfigBox, self).__init__(parent)
        self.resize(w,h)
        self.w = w
        self.h = h
        self.setWindowTitle(titre)

        self.layout = QVBoxLayout(self)
        ## Menu contient l'ensemble des sections à paramétrer
        self.menu = QListWidget(self)
        self.layout.addWidget(self.menu)
        ## Pour chaque section à paramétrer, on utilise un Stack d'objets
        self.leftpart = QStackedLayout()
        self.leftpart.setSizeConstraint(QLayout.SetNoConstraint)
        self.layout.addLayout(self.leftpart)

        ## propWidget contient l'ensemble des objets propriété de toutes les section
        ## (il est nécessaire de les stocker pour être capable de les faire interagir)
        self.propWidget=[]
        wid = 0

        ## On crée les différentes parties de configuration qui ne sont pas inclues dans le tableau SECTION_MASK de EkdConfig
        for section in EkdConfig.SECTIONS :
            if not section in EkdConfig.SECTION_MASK :
                self.menu.addItem(EkdConfig.SECTIONS[section])
                allprops = EkdConfig.getAllProperties(EkdConfig.getConfigSection(section))
                scroll = QScrollArea()
                frame = QFrame()
                frame.setMinimumSize(self.w-50, self.h/2) # Ajouté le 10/12/2009 Pour que la partie réglage prenne toute la place dispo.
                frame.setMaximumSize(self.w, self.h)
                linelayout = QGridLayout(frame)

                linelayout.setSizeConstraint(QLayout.SetMinAndMaxSize)
                row = 0
                ## Insertion des propriété de la section en fonction de son type
                allkeys = allprops.keys()
                found = False
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.PATH_PROPERTIES :
                            self.propWidget.append( EkdPathPropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], section=section) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.STYLE_PROPERTIES :
                            self.propWidget.append( EkdStylePropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], EkdConfig.STYLE_PROPERTIES[prop], section=section ) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.CODEC_PROPERTIES :
                            self.propWidget.append( EkdCodecPropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], EkdConfig.CODEC_PROPERTIES[prop], section=section ) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.BOOLEAN_PROPERTIES :
                            self.propWidget.append( EkdBoolPropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], section=section) )
                            linelayout.addWidget(self.propWidget[wid].widget, row, 0, 1, 2)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.NUM_PROPERTIES :
                            self.propWidget.append( EkdNumPropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], section=section) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.TIME_PROPERTIES :
                            self.propWidget.append( EkdTimePropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], section=section) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        row += 1
                for prop in allkeys :
                    if not prop in EkdConfig.PROPERTIES_MASK :
                        if prop in EkdConfig.COLOR_PROPERTIES :
                            self.propWidget.append( EkdColorPropertie(prop, EkdConfig.PROPERTIES[prop], allprops[prop], section=section) )
                            linelayout.addWidget(self.propWidget[wid].label, row, 0)
                            linelayout.addWidget(self.propWidget[wid].widget, row, 1)
                            wid += 1
                            found = True
                        elif not found:
                            line = QLineEdit(allprops[prop])
                            linelayout.addWidget(QLabel(prop), row, 0)
                            linelayout.addWidget(line, row, 1)
                        row += 1

                frame.setLineWidth(0)
                scroll.setWidget(frame)
                self.leftpart.addWidget(scroll)

        self.menu.setAlternatingRowColors(True)
        # Define the size of the list depending of its content
        self.menu.setFixedHeight(( self.menu.sizeHintForRow(0) + self.menu.verticalStepsPerItem() + 1)* self.menu.count())
        self.menu.updateGeometries()

        ## Boutton pour  fermer la boite de dialogue
        self.fermer = QPushButton(_(u"Fermer"))
        self.layout.addWidget(self.fermer)

        ## Lorsqu'on clique sur fermer, la fenêtre se ferme
        self.connect(self.fermer, SIGNAL("clicked()"), self.close)

        ## Lorsqu'on selectionne un élément du menu, on met à jour la partie droite du menu
        self.connect(self.menu, SIGNAL("currentItemChanged(QListWidgetItem *,QListWidgetItem *)"), self.updateMenu)
class ManualRegistrationWidget(QWidget):
    '''ManualRegistrationWidget
    A tool for interactive image registration
    '''

    DEFAULT_FONT = QFont('Inconsolata', 12)
    STATUS_FONT = QFont('Inconsolata', 10)

    def __init__(self, parent=None):
        super(ManualRegistrationWidget, self).__init__(parent)
        self.setupUi()
        self.setupConnection()
        self.imFixed = None
        self.imMoving = None
        self.statsFixed = None
        self.statsMoving = None
        self.minFixed = 0
        self.maxFixed = 255
        self.minMoving = 0
        self.maxMoving = 255
        self.transformMatrix = np.array((
            (0.0, 0.0, -1.0, 0.0),
            (0.0, 1.0, 0.0, 0.0),
            (1.0, 0.0, 0.0, 0.0),
            (0.0, 0.0, 0.0, 1.0)
        ))
        self.updateMatrixText()

    def setupConnection(self):
        self.buttonLoadFixed.clicked.connect(self.onLoadFixed)
        self.buttonLoadMoving.clicked.connect(self.onLoadMoving)
        self.comboAxes.currentIndexChanged.connect(self.directionChange)
        self.buttonClear.clicked.connect(self.onClear)
        self.buttonApply.clicked.connect(self.onApply)
        self.buttonMinMaxFixed.clicked.connect(self.onMinMaxFixed)
        self.buttonMinMaxMoving.clicked.connect(self.onMinMaxMoving)
        self.buttonLoadMatrix.clicked.connect(self.onLoadMatrix)
        self.buttonSaveMatrix.clicked.connect(self.onSaveMatrix)

    def setupUi(self):
        '''Setup GUI components'''
        # set font
        self.setFont(self.DEFAULT_FONT)
        self.setupControls()
        self.overlayDisplay = OverlayDisplayWidget(parent=self)
        self.overlayDisplay.setMinimumSize(500, 500)
        self.overlayDisplay.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Expanding)
        self.multiplyDisplay = MultiplyDisplayWidget(parent=self)
        self.multiplyDisplay.setMinimumSize(500, 500)
        self.multiplyDisplay.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Expanding)
        self.displayTab = QTabWidget(self)
        self.displayTab.addTab(self.overlayDisplay, 'Overlay Display')
        self.displayTab.addTab(self.multiplyDisplay, 'Multiply Display')
        # layout
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.controlPanel)
        hlayout.addWidget(self.displayTab)
        self.setLayout(hlayout)

    def setupControls(self):
        self.controlPanel = QFrame()
        self.controlPanel.setMinimumSize(400, 500)
        #
        # create controls
        # first row: buttons and axes selection
        self.buttonLoadFixed = QPushButton('Load Fixed')
        self.buttonLoadMoving = QPushButton('Load Moving')
        self.comboAxes = QComboBox()
        self.comboAxes.addItems(['X-Y', 'X-Z', 'Y-Z'])
        self.buttonMinMaxFixed = QPushButton(r'B&&C Fixed')
        self.buttonMinMaxMoving = QPushButton(r'B&&C Moving')
        self.buttonMinMaxFixed.setEnabled(False)
        self.buttonMinMaxMoving.setEnabled(False)
        # second row: Transformation box
        groupTransform = QGroupBox('Transformation')
        label1 = QLabel('X Angle')
        label2 = QLabel('Y Angle')
        label3 = QLabel('Z Angle')
        self.spinXAngle = QDoubleSpinBox()
        self.spinXAngle.setRange(-90.0, 90.0)
        self.spinYAngle = QDoubleSpinBox()
        self.spinYAngle.setRange(-90.0, 90.0)
        self.spinZAngle = QDoubleSpinBox()
        self.spinZAngle.setRange(-90.0, 90.0)
        label4 = QLabel('X Offset')
        label5 = QLabel('Y Offset')
        label6 = QLabel('Z Offset')
        self.spinXOffset = QDoubleSpinBox()
        self.spinXOffset.setRange(-1000.0, 1000.0)
        self.spinYOffset = QDoubleSpinBox()
        self.spinYOffset.setRange(-1000.0, 1000.0)
        self.spinZOffset = QDoubleSpinBox()
        self.spinZOffset.setRange(-1000.0, 1000.0)
        self.buttonClear = QPushButton('Clear')
        self.buttonApply = QPushButton('Apply')
        # third row: Output matrix
        labelMatrix = QLabel('Transformation matrix')
        self.editMatrix = QTextEdit()
        self.editMatrix.setReadOnly(True)
        self.buttonLoadMatrix = QPushButton('Load Matrix')
        self.buttonSaveMatrix = QPushButton('Save Matrix')
        #
        # layout controls
        # 1st row
        hlayoutButtons1 = QHBoxLayout()
        hlayoutButtons1.addWidget(self.buttonLoadFixed)
        hlayoutButtons1.addWidget(self.buttonLoadMoving)
        hlayoutButtons1.addWidget(self.comboAxes)
        hlayoutButtons2 = QHBoxLayout()
        hlayoutButtons2.addWidget(self.buttonMinMaxFixed)
        hlayoutButtons2.addWidget(self.buttonMinMaxMoving)
        # 2nd row
        hlayoutTransform1 = QHBoxLayout()
        hlayoutTransform1.addWidget(label1)
        hlayoutTransform1.addWidget(self.spinXAngle)
        hlayoutTransform1.addWidget(label4)
        hlayoutTransform1.addWidget(self.spinXOffset)
        hlayoutTransform2 = QHBoxLayout()
        hlayoutTransform2.addWidget(label2)
        hlayoutTransform2.addWidget(self.spinYAngle)
        hlayoutTransform2.addWidget(label5)
        hlayoutTransform2.addWidget(self.spinYOffset)
        hlayoutTransform3 = QHBoxLayout()
        hlayoutTransform3.addWidget(label3)
        hlayoutTransform3.addWidget(self.spinZAngle)
        hlayoutTransform3.addWidget(label6)
        hlayoutTransform3.addWidget(self.spinZOffset)
        hlayoutTransform4 = QHBoxLayout()
        hlayoutTransform4.addStretch()
        hlayoutTransform4.addWidget(self.buttonClear)
        hlayoutTransform4.addWidget(self.buttonApply)
        vlayoutTransform = QVBoxLayout()
        vlayoutTransform.addLayout(hlayoutTransform1)
        vlayoutTransform.addLayout(hlayoutTransform2)
        vlayoutTransform.addLayout(hlayoutTransform3)
        vlayoutTransform.addLayout(hlayoutTransform4)
        groupTransform.setLayout(vlayoutTransform)
        # 3rd row
        hlayout1 = QHBoxLayout()
        hlayout1.addStretch()
        hlayout1.addWidget(self.buttonLoadMatrix)
        hlayout1.addWidget(self.buttonSaveMatrix)
        # final layout
        vlayout = QVBoxLayout()
        vlayout.addLayout(hlayoutButtons1)
        vlayout.addLayout(hlayoutButtons2)
        vlayout.addWidget(groupTransform)
        vlayout.addWidget(labelMatrix)
        vlayout.addWidget(self.editMatrix)
        vlayout.addLayout(hlayout1)
        self.controlPanel.setLayout(vlayout)
        self.controlPanel.setSizePolicy(QSizePolicy.Fixed,
                                        QSizePolicy.Expanding)

    def initializeInteractor(self):
        self.overlayDisplay.initialize()
        self.multiplyDisplay.initialize()

    @pyqtSlot(int)
    def directionChange(self, direction):
        self.overlayDisplay.setDirection(direction)
        self.overlayDisplay.render()
        self.overlayDisplay.update()

    @pyqtSlot()
    def onLoadFixed(self):
        fname = QFileDialog.getOpenFileName(self, 'Load fixed image',
                                            DATA_FOLDER,
                                            filter='TIFF Images (*.tiff *.tif)')
        fname = str(fname)
        if not fname:
            return
        self.imFixed = self.normalizeImage(self.load3DTIFFImage(fname))
        self.statsFixed = ImageStat(self.imFixed)
        self.minFixed, self.maxFixed = self.statsFixed.extrema
        self.overlayDisplay.setVolumeBg(self.imFixed,
                                        self.minFixed, self.maxFixed)
        self.overlayDisplay.render()
        self.buttonMinMaxFixed.setEnabled(True)
        self.multiplyDisplay.setVolumeBg(self.imFixed)
        self.multiplyDisplay.render()

    @pyqtSlot()
    def onLoadMoving(self):
        fname = QFileDialog.getOpenFileName(self, 'Load fixed image',
                                            DATA_FOLDER,
                                            filter='TIFF Images (*.tiff *.tif)')
        fname = str(fname)
        if not fname:
            return
        self.imMoving = self.normalizeImage(self.load3DTIFFImage(fname))
        self.statsMoving = ImageStat(self.imMoving)
        self.minMoving, self.maxMoving = self.statsMoving.extrema
        self.overlayDisplay.setVolumeFg(self.imMoving,
                                        self.minMoving, self.maxMoving)
        self.overlayDisplay.setMatrix(self.transformMatrix)
        self.overlayDisplay.render()
        self.buttonMinMaxMoving.setEnabled(True)
        self.multiplyDisplay.setVolumeFg(self.imMoving)
        self.multiplyDisplay.render()

    @pyqtSlot()
    def onClear(self):
        self.spinXAngle.setValue(0.0)
        self.spinXOffset.setValue(0.0)
        self.spinYAngle.setValue(0.0)
        self.spinYOffset.setValue(0.0)
        self.spinZAngle.setValue(0.0)
        self.spinZOffset.setValue(0.0)

    @pyqtSlot()
    def onApply(self):
        xAngle = self.spinXAngle.value() / 180.0 * np.pi
        xOffset = self.spinXOffset.value()
        yAngle = self.spinYAngle.value() / 180.0 * np.pi
        yOffset = self.spinYOffset.value()
        zAngle = self.spinZAngle.value() / 180.0 * np.pi
        zOffset = self.spinZOffset.value()
        # form rotation matrices
        Rx = np.eye(4)
        Rx[1, 1] = np.cos(xAngle)
        Rx[2, 2] = np.cos(xAngle)
        Rx[1, 2] = -np.sin(xAngle)
        Rx[2, 1] = np.sin(xAngle)
        Ry = np.eye(4)
        Ry[0, 0] = np.cos(yAngle)
        Ry[2, 2] = np.cos(yAngle)
        Ry[0, 2] = np.sin(yAngle)
        Ry[2, 0] = -np.sin(yAngle)
        Rz = np.eye(4)
        Rz[0, 0] = np.cos(zAngle)
        Rz[1, 1] = np.cos(zAngle)
        Rz[0, 1] = -np.sin(zAngle)
        Rz[1, 0] = np.sin(zAngle)
        # final transform
        T = np.dot(Rz, np.dot(Ry, Rx))
        T[0, 3] = xOffset
        T[1, 3] = yOffset
        T[2, 3] = zOffset
        self.transformMatrix = np.dot(T, self.transformMatrix)
        self.updateMatrixText()
        self.overlayDisplay.setMatrix(self.transformMatrix)
        self.onClear()

    @pyqtSlot()
    def onMinMaxFixed(self):
        self.mmDialogFixed = MinMaxDialog(self.minFixed, self.maxFixed,
                                          self.statsFixed, self)
        self.connect(self.mmDialogFixed, SIGNAL('minMaxChanged()'),
                     self.minMaxChangedFixed)
        self.mmDialogFixed.exec_()
        self.disconnect(self.mmDialogFixed, SIGNAL('minMaxChanged()'),
                        self.minMaxChangedFixed)
        del self.mmDialogFixed
        self.mmDialogFixed = None

    @pyqtSlot()
    def onMinMaxMoving(self):
        self.mmDialogMoving = MinMaxDialog(self.minMoving, self.maxMoving,
                                           self.statsMoving, self)
        self.connect(self.mmDialogMoving, SIGNAL('minMaxChanged()'),
                     self.minMaxChangedMoving)
        self.mmDialogMoving.exec_()
        self.disconnect(self.mmDialogMoving, SIGNAL('minMaxChanged()'),
                        self.minMaxChangedMoving)
        del self.mmDialogMoving
        self.mmDialogMoving = None

    @pyqtSlot()
    def onSaveMatrix(self):
        fname = QFileDialog.getSaveFileName(self, 'Save matrix to npy file',
                                            './transform_matrix.npy',
                                            filter='Numpy Array Files (*.npy)')
        fname = str(fname)
        if fname:
            np.save(fname, self.transformMatrix)

    @pyqtSlot()
    def onLoadMatrix(self):
        fname = QFileDialog.getOpenFileName(self, 'Open matrix from npy file',
                                            './transform_matrix.npy',
                                            filter='Numpy Array Files (*.npy)')
        fname = str(fname)
        if fname:
            self.transformMatrix = np.load(fname)
        self.updateMatrixText()
        self.overlayDisplay.setMatrix(self.transformMatrix)
        self.multiplyDisplay.setMatrix(self.transformMatrix)

    @pyqtSlot()
    def minMaxChangedFixed(self):
        self.minFixed, self.maxFixed = self.mmDialogFixed.results
        self.overlayDisplay.setBgMinMax(self.minFixed, self.maxFixed)
        self.overlayDisplay.update()

    @pyqtSlot()
    def minMaxChangedMoving(self):
        self.minMoving, self.maxMoving = self.mmDialogMoving.results
        self.overlayDisplay.setFgMinMax(self.minMoving, self.maxMoving)
        self.overlayDisplay.update()

    def updateMatrixText(self):
        msg = np.array_str(self.transformMatrix,
                           precision=2, suppress_small=True)
        self.editMatrix.setText(msg)

    @staticmethod
    def normalizeImage(im):
        scaledImage = (im - np.amin(im)) / (np.amax(im) - np.amin(im))
        return (scaledImage*255.0).astype(np.uint8)

    @staticmethod
    def load3DTIFFImage(fname):
        imList = fi.read_multipage(fname)
        if not imList:
            return None
        nx, ny = imList[0].shape
        nz = len(imList)
        im = np.zeros((nx, ny, nz))
        for idx in xrange(nz):
            im[:, :, idx] = imList[idx]
        return im.astype(np.float)