예제 #1
0
class Snippets(QDialog):

    def __init__(self, parent=None):
        super(Snippets, self).__init__(parent)
        # Create widgets
        self.setWindowModality(Qt.ApplicationModal)
        self.title = QLabel(self.tr("Snippet Editor"))
        self.saveButton = QPushButton(self.tr("Save"))
        self.closeButton = QPushButton(self.tr("Close"))
        self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey"))
        self.setWindowTitle(self.title.text())
        self.newFolderButton = QPushButton("New Folder")
        self.deleteSnippetButton = QPushButton("Delete")
        self.newSnippetButton = QPushButton("New Snippet")
        self.edit = QPlainTextEdit()
        self.edit.setPlaceholderText("python code")
        self.resetting = False
        self.columns = 3

        self.keySequenceEdit = QKeySequenceEdit(self)
        self.currentHotkey = QKeySequence()
        self.currentHotkeyLabel = QLabel("")
        self.currentFileLabel = QLabel()
        self.currentFile = ""
        self.snippetDescription = QLineEdit()
        self.snippetDescription.setPlaceholderText("optional description")

        #Set Editbox Size
        font = getMonospaceFont(self)
        self.edit.setFont(font)
        font = QFontMetrics(font)
        self.edit.setTabStopWidth(4 * font.width(' ')); #TODO, replace with settings API

        #Files
        self.files = QFileSystemModel()
        self.files.setRootPath(snippetPath)
        self.files.setNameFilters(["*.py"])

        #Tree
        self.tree = QTreeView()
        self.tree.setModel(self.files)
        self.tree.setSortingEnabled(True)
        self.tree.hideColumn(2)
        self.tree.sortByColumn(0, Qt.AscendingOrder)
        self.tree.setRootIndex(self.files.index(snippetPath))
        for x in range(self.columns):
            #self.tree.resizeColumnToContents(x)
            self.tree.header().setSectionResizeMode(x, QHeaderView.ResizeToContents) 
        treeLayout = QVBoxLayout()
        treeLayout.addWidget(self.tree)
        treeButtons = QHBoxLayout()
        treeButtons.addWidget(self.newFolderButton)
        treeButtons.addWidget(self.newSnippetButton)
        treeButtons.addWidget(self.deleteSnippetButton)
        treeLayout.addLayout(treeButtons)
        treeWidget = QWidget()
        treeWidget.setLayout(treeLayout)

        # Create layout and add widgets
        buttons = QHBoxLayout()
        buttons.addWidget(self.clearHotkeyButton)
        buttons.addWidget(self.keySequenceEdit)
        buttons.addWidget(self.currentHotkeyLabel)
        buttons.addWidget(self.closeButton)
        buttons.addWidget(self.saveButton)

        description = QHBoxLayout()
        description.addWidget(QLabel(self.tr("Description: ")))
        description.addWidget(self.snippetDescription)

        vlayoutWidget = QWidget()
        vlayout = QVBoxLayout()
        vlayout.addLayout(description)
        vlayout.addWidget(self.edit)
        vlayout.addLayout(buttons)
        vlayoutWidget.setLayout(vlayout)

        hsplitter = QSplitter()
        hsplitter.addWidget(treeWidget)
        hsplitter.addWidget(vlayoutWidget)

        hlayout = QHBoxLayout()
        hlayout.addWidget(hsplitter)

        self.showNormal() #Fixes bug that maximized windows are "stuck"
        self.settings = QSettings("Vector35", "Snippet Editor")
        if self.settings.contains("ui/snippeteditor/geometry"):
            self.restoreGeometry(self.settings.value("ui/snippeteditor/geometry"))
        else:
            self.edit.setMinimumWidth(80 * font.averageCharWidth())
            self.edit.setMinimumHeight(30 * font.lineSpacing())

        # Set dialog layout
        self.setLayout(hlayout)

        # Add signals
        self.saveButton.clicked.connect(self.save)
        self.closeButton.clicked.connect(self.close)
        self.clearHotkeyButton.clicked.connect(self.clearHotkey)
        self.tree.selectionModel().selectionChanged.connect(self.selectFile)
        self.newSnippetButton.clicked.connect(self.newFileDialog)
        self.deleteSnippetButton.clicked.connect(self.deleteSnippet)
        self.newFolderButton.clicked.connect(self.newFolder)

        if self.settings.contains("ui/snippeteditor/selected"):
            selectedName = self.settings.value("ui/snippeteditor/selected")
            self.tree.selectionModel().select(self.files.index(selectedName), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
            if self.tree.selectionModel().hasSelection():
                self.selectFile(self.tree.selectionModel().selection(), None)
                self.edit.setFocus()
                cursor = self.edit.textCursor()
                cursor.setPosition(self.edit.document().characterCount()-1)
                self.edit.setTextCursor(cursor)
            else:
                self.readOnly(True)
        else:
            self.readOnly(True)


    @staticmethod
    def registerAllSnippets():
        for action in list(filter(lambda x: x.startswith("Snippets\\"), UIAction.getAllRegisteredActions())):
            if action == "Snippets\\Snippet Editor...":
                continue
            UIActionHandler.globalActions().unbindAction(action)
            Menu.mainMenu("Tools").removeAction(action)
            UIAction.unregisterAction(action)

        for snippet in includeWalk(snippetPath, ".py"):
            snippetKeys = None
            (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(snippet)
            if not snippetDescription:
                actionText = "Snippets\\" + os.path.basename(snippet).rstrip(".py")
            else:
                actionText = "Snippets\\" + snippetDescription
            if snippetCode:
                if snippetKeys == None:
                    UIAction.registerAction(actionText)
                else:
                    UIAction.registerAction(actionText, snippetKeys)
                UIActionHandler.globalActions().bindAction(actionText, UIAction(makeSnippetFunction(snippetCode)))
                Menu.mainMenu("Tools").addAction(actionText, actionText)

    def clearSelection(self):
        self.keySequenceEdit.clear()
        self.currentHotkey = QKeySequence()
        self.currentHotkeyLabel.setText("")
        self.currentFileLabel.setText("")
        self.snippetDescription.setText("")
        self.edit.setPlainText("")
        self.currentFile = ""

    def reject(self):
        self.settings.setValue("ui/snippeteditor/geometry", self.saveGeometry())

        if self.snippetChanged():
            question = QMessageBox.question(self, self.tr("Discard"), self.tr("You have unsaved changes, quit anyway?"))
            if question != QMessageBox.StandardButton.Yes:
                return
        self.accept()

    def newFolder(self):
        (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"), self.tr("Folder Name: "))
        if ok and folderName:
            index = self.tree.selectionModel().currentIndex()
            selection = self.files.filePath(index)
            if QFileInfo(selection).isDir():
                QDir(selection).mkdir(folderName)
            else:
                QDir(snippetPath).mkdir(folderName)    

    def selectFile(self, new, old):
        if (self.resetting):
            self.resetting = False
            return
        newSelection = self.files.filePath(new.indexes()[0])
        self.settings.setValue("ui/snippeteditor/selected", newSelection)
        if QFileInfo(newSelection).isDir():
            self.readOnly(True)
            self.tree.clearSelection()
            self.currentFile = ""
            return

        if old and old.length() > 0:
            oldSelection = self.files.filePath(old.indexes()[0])
            if not QFileInfo(oldSelection).isDir() and self.snippetChanged():
                question = QMessageBox.question(self, self.tr("Discard"), self.tr("Snippet changed. Discard changes?"))
                if question != QMessageBox.StandardButton.Yes:
                    self.resetting = True
                    self.tree.selectionModel().select(old, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
                    return False

        self.currentFile = newSelection
        self.loadSnippet()

    def loadSnippet(self):
        self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName())
        (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile)
        self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("")
        self.keySequenceEdit.setKeySequence(snippetKeys) if snippetKeys else self.keySequenceEdit.setKeySequence(QKeySequence(""))
        self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("")
        self.readOnly(False)

    def newFileDialog(self):
        (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: "))
        if ok and snippetName:
            if not snippetName.endswith(".py"):
                snippetName += ".py"
            index = self.tree.selectionModel().currentIndex()
            selection = self.files.filePath(index)
            if QFileInfo(selection).isDir():
                path = os.path.join(selection, snippetName)
            else:
                path = os.path.join(snippetPath, snippetName)
                self.readOnly(False)
            open(path, "w").close()
            self.tree.setCurrentIndex(self.files.index(path))
            log_debug("Snippet %s created." % snippetName)

    def readOnly(self, flag):
        self.keySequenceEdit.setEnabled(not flag)
        self.snippetDescription.setReadOnly(flag)
        self.edit.setReadOnly(flag)
        if flag:
            self.snippetDescription.setDisabled(True)
            self.edit.setDisabled(True)
        else:
            self.snippetDescription.setEnabled(True)
            self.edit.setEnabled(True)

    def deleteSnippet(self):
        selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row
        snippetName = self.files.fileName(selection)
        question = QMessageBox.question(self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName)
        if (question == QMessageBox.StandardButton.Yes):
            log_debug("Deleting snippet %s." % snippetName)
            self.clearSelection()
            self.files.remove(selection)
            self.registerAllSnippets()

    def snippetChanged(self):
        if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()):
            return False
        (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile)
        if snippetKeys == None and not self.keySequenceEdit.keySequence().isEmpty():
            return True
        if snippetKeys != None and snippetKeys != self.keySequenceEdit.keySequence().toString():
            return True
        return self.edit.toPlainText() != snippetCode or \
               self.snippetDescription.text() != snippetDescription

    def save(self):
        log_debug("Saving snippet %s" % self.currentFile)
        outputSnippet = open(self.currentFile, "w")
        outputSnippet.write("#" + self.snippetDescription.text() + "\n")
        outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n")
        outputSnippet.write(self.edit.toPlainText())
        outputSnippet.close()
        self.registerAllSnippets()

    def clearHotkey(self):
        self.keySequenceEdit.clear()
예제 #2
0
class micGui(QWidget):
    app_icon = QIcon()
    app = QApplication([])
    handlers = han.Handlers(50)
    changesAvailable = True
    changed = -1  #0: handle, #1: type, #2: resolution, #3: rate
    handleUpdated = -1
    sliders = []
    comboBoxResol = 0
    comboBoxRate = 0
    resolIndex = -1
    rateIndex = -1
    modeIndex = -1
    filterIndex = -1
    guiSettings = guiSettings(initValues=[0, 2, 3, 0, 50])
    queue = Queue()

    # Initializes graphical setup and updates queue
    def __init__(self, queue, numberOfHandles=10):
        super(micGui, self).__init__()
        self.setupGui(numberOfHandles)
        self.queue = queue

    # Configs graphical elements and their initializations
    def setupGui(self, numberOfHandles):
        self.configWindow()
        self.configureBackground()
        self.resolutionOptions()
        self.samplingRateOptions()
        self.modeOptions()
        self.showSettingsButton()
        for i in range(numberOfHandles):
            self.sliders.append(
                self.createImgSlider("./mic/gui/filter-gui/slider.png", i))
            self.sliders[i].valueChanged[int].connect(
                lambda val, index=i: self.setHandlers(val, index))
            self.handlers.register_callback(self.updateHandlersStatus)

    # Updates handle value when signal is received and sends
    # a signal for filter updater
    def updateHandlersStatus(self, handleNumber):
        self.changesAvailable = True
        self.handleUpdated = handleNumber
        self.changed = 0

    # Sends gui settings
    def setHandlers(self, newVal, handlerID):
        self.guiSettings.updatesAvailable = True
        self.guiSettings.handleSelected = handlerID
        self.guiSettings.handleValue = newVal
        self.queue.put(self.guiSettings)

    # Initializes resolution options and it's changes callback
    def resolutionOptions(self):
        resolutions = ["Ultra High", "High", "Normal", "Low", "Ultra Low"]
        self.comboBoxResol = self.setComboBox(2, 542, 187, "comboBoxResol",
                                              resolutions)
        l = lambda optionSelected, optionIndex=2: self.updateComboBoxStatus(
            optionSelected, optionIndex)
        self.comboBoxResol.currentIndexChanged[int].connect(l)

    # Initializes sampling rate options and it's changes callback
    def samplingRateOptions(self):
        rates = ["48000", "44100", "32000", "22050", "11025", "8000"]
        self.comboBoxRate = self.setComboBox(3, 542, 125, "comboBoxRate",
                                             rates)
        l = lambda optionSelected, optionIndex=3: self.updateComboBoxStatus(
            optionSelected, optionIndex)
        self.comboBoxRate.currentIndexChanged[int].connect(l)

    # Initializes mode options and it's changes callback
    def modeOptions(self):
        modes = ["FIR (slow)", "Butterworth (fast)", "Devil", "Goblin"]
        self.comboBoxMode = self.setComboBox(0, 542, 63, "comboBoxMode", modes)
        l = lambda optionSelected, optionIndex=1: self.updateComboBoxStatus(
            optionSelected, optionIndex)
        self.comboBoxMode.currentIndexChanged[int].connect(l)

    # If any combo box option is changed, this callback is called.
    # Sends update to updates queue.
    @QtCore.Slot(int)
    def updateComboBoxStatus(self, newVal, changeCode):
        self.changesAvailable = True
        self.changed = changeCode
        if (changeCode == 3):
            self.rateIndex = newVal
            self.guiSettings.rateSelected = newVal
        elif (changeCode == 2):
            self.resolIndex = newVal
            self.guiSettings.resolutionSelected = newVal
        elif (changeCode == 1):
            self.filterIndex = newVal
            self.guiSettings.filterSelected = newVal
        self.queue.put(self.guiSettings)

    # Sets background image
    def configureBackground(self):
        image = "mic/gui/filter-gui/UI.png"

        self.text_field = QPlainTextEdit(self)
        self.text_field.setDisabled(True)
        self.text_field.setMinimumSize(720, 301)
        self.text_field.setStyleSheet("background-image: url(" + image +
                                      "); background-attachment: fixed")

    # Initializes combo box
    def setComboBox(self,
                    startingIndex=0,
                    xPos=0,
                    yPos=0,
                    objName="default",
                    items=[]):
        combo = QComboBox(self)
        for item in items:
            combo.addItem(item)
        combo.setObjectName(objName)
        combo.setGeometry(QRect(xPos, yPos, 125, 22))
        combo.setCurrentIndex(startingIndex)
        combo.setStyleSheet(
            "background-color: rgb(47, 47, 47) ; color: rgb(255, 96, 96);")
        return combo

    # Initializes Windows and title bar icons
    def configIcons(self):
        self.app_icon.addFile('mic/gui/filter-gui/icon/icon16.png',
                              QSize(16, 16))
        self.app_icon.addFile('mic/gui/filter-gui/icon/icon24.png',
                              QSize(24, 24))
        self.app_icon.addFile('mic/gui/filter-gui/icon/icon32.png',
                              QSize(32, 32))
        self.app_icon.addFile('mic/gui/filter-gui/icon/icon48.png',
                              QSize(48, 48))
        self.app_icon.addFile('mic/gui/filter-gui/icon/icon256.png',
                              QSize(256, 256))
        self.app.setWindowIcon(self.app_icon)

    # Initializes general window's elements like
    # title Bar and window size
    def configWindow(self):
        self.configIcons()
        self.setWindowTitle('Bokus Multiband Filter')
        self.setWindowFlags(self.windowFlags() | QtCore.Qt.CustomizeWindowHint)
        self.setWindowFlags(self.windowFlags()
                            & ~QtCore.Qt.WindowMaximizeButtonHint)
        self.setFixedSize(720, 301)

    # Creates an slider, with an image as a handle
    def createImgSlider(self, imgPath, index):
        xPosition = 36 + 47 * index
        slider = QSlider(self)
        slider.setObjectName(u"slider" + str(index))
        slider.setGeometry(QRect(xPosition, -1, 51, 300))
        slider.setCursor(QCursor(Qt.OpenHandCursor))
        slider.setMouseTracking(False)
        slider.setFocusPolicy(Qt.StrongFocus)
        slider.setAcceptDrops(False)
        slider.setAutoFillBackground(False)
        slider.setStyleSheet(u"QSlider::handle:vertical {\n"
                             "	image: url(" + imgPath + ");\n"
                             "	width: 90px;\n"
                             "	height: 90px\n"
                             "}\n"
                             "\n"
                             "QSlider::groove:vertical{\n"
                             "	background: rgba(0, 0, 0, 0);\n"
                             "}")
        slider.setValue(50)
        slider.setSliderPosition(50)
        slider.setOrientation(Qt.Vertical)
        slider.setInvertedAppearance(False)
        return slider

    # [DEPRECATED] loads GUI from from.ui (PyQt)
    def load_ui(self):
        loader = QUiLoader()
        path = os.path.join(os.path.dirname(__file__),
                            "./gui/filter-gui/form2.ui")
        ui_file = QFile(path)
        ui_file.open(QFile.ReadOnly)
        loader.load(ui_file, self)
        ui_file.close()

    # [DEPRECATED. Replaced with combo boxes] loads buttons for mode selecting.
    def filterModeButtons(self):
        self.filterTypeButtons = QButtonGroup(self)
        self.configFilterTypeButtons("firButton", True, 560, 49, 0)
        self.configFilterTypeButtons("iirButton", False, 560, 68, 1)
        self.configFilterTypeButtons("devilButton", False, 560, 86, 2)
        self.configFilterTypeButtons("goblinButton", False, 560, 104, 3)

    # [DEPRECATED. Used in filterModeButtons]
    def configFilterTypeButtons(self,
                                name=u"default",
                                checked=False,
                                xPos=0,
                                yPos=0,
                                idButton=0):
        button = QRadioButton(self)
        button.setObjectName(name)
        button.setEnabled(True)
        button.setGeometry(QRect(xPos, yPos, 82, 17))
        button.setCursor(QCursor(Qt.PointingHandCursor))
        button.setChecked(checked)
        lam = lambda id=idButton: self.buttonChecked(id)
        self.connect(button, SIGNAL("clicked()"), lam)
        self.filterTypeButtons.addButton(button, idButton)

    # [DEPRECATED. Used in filterModeButtons]
    def buttonChecked(self, idButton):
        self.filterIndex = idButton
        self.guiSettings.filterSelected = idButton
        self.queue.put(self.guiSettings)

    # Properly closes GUI if flag is received
    def sys_exit(self, exitProgram):
        self.app.exec_()
        exitProgram.value = True
        self.queue.put(None)
        sys.exit()

    # Properly closes settings window
    def closeEvent(self, event):
        self.closeSettings()

    # Properly closes settings window
    def closeSettings(self):
        if hasattr(self, 'sets'):
            self.sets.close()

    # Initializes button for opening settings
    def showSettingsButton(self):
        image = "./mic/gui/filter-gui/settings-button.png"
        imageHover = "./mic/gui/filter-gui/settings-button-hover.png"
        button = QPushButton("", self)
        button.setGeometry(685, 10, 24, 27)
        button.setStyleSheet("border-radius : 50")
        button.setStyleSheet("QPushButton {border-image: url(" + image +
                             "); } QPushButton:hover { border-image: url(" +
                             imageHover + ")}")
        button.clicked.connect(self.openSettings)
        self.settingsButton = button

    # Shows settings
    def openSettings(self):
        self.sets = settingsWindow()
        self.sets.show()