def init_splitter(self): self.frame = QFrame() self.frame.setFrameShape(QFrame.StyledPanel) hbox = QHBoxLayout() # here should be no 'self' argument self.browser_widget = bv.BrowserWidget(self) self.top_splitter = QSplitter(Qt.Horizontal) frame = QFrame() layout = QVBoxLayout() for addon in self.addon_list: layout.addWidget(addon) addon.hide() frame.setLayout(layout) self.top_splitter.addWidget(frame) self.current_addon = self.addon_list[0] self.current_addon.show_itself() self.top_splitter.addWidget(self.browser_widget) self.top_splitter.setSizes([100, 200]) handle_width = 6 # https://stackoverflow.com/questions/2545577/qsplitter-becoming-undistinguishable-between-qwidget-and-qtabwidget self.top_splitter.setOpaqueResize(False) self.top_splitter.setChildrenCollapsible(False) self.top_splitter.setHandleWidth(handle_width) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(self.top_splitter) splitter2.addWidget(self.jupyter_widget) splitter2.setOpaqueResize(False) splitter2.setChildrenCollapsible(False) splitter2.setHandleWidth(handle_width) hbox.addWidget(splitter2) self.frame.setLayout(hbox)
def decorate(splitter: QSplitter, index: int = 1): gripLength = 35 gripWidth = 1 # may need to be 1 or 2 depending on theme gripSpacing = 0 grips = 3 splitter.setOpaqueResize(False) splitter.setChildrenCollapsible(False) splitter.setHandleWidth(7) handle = splitter.handle(index) orientation = splitter.orientation() layout = QHBoxLayout(handle) layout.setSpacing(gripSpacing) layout.setContentsMargins(0, 0, 0, 0) if orientation == Qt.Horizontal: for i in range(grips): line = QFrame(handle) line.setMinimumSize(gripWidth, gripLength) line.setMaximumSize(gripWidth, gripLength) line.setLineWidth(gripWidth) line.setFrameShape(line.StyledPanel) line.setStyleSheet("border: 1px solid lightgray;") layout.addWidget(line) else: # center the vertical grip by adding spacers before and after layout.addStretch() vBox = QVBoxLayout() for i in range(grips): line = QFrame(handle) line.setMinimumSize(gripLength, gripWidth) line.setMaximumSize(gripLength, gripWidth) line.setFrameShape(line.StyledPanel) line.setStyleSheet("border: 1px solid lightgray;") vBox.addWidget(line) layout.addLayout(vBox) layout.addStretch()
class HelpDialog(QObject, LogMixin): """Class implementing qthelp viewer dialog""" def __init__(self, qthelp_file, parent = None): """ Constructor of HelpDialog :param qthelp_file: full path to qthelp helpfile """ super(HelpDialog,self).__init__(parent) # instantiate help engine helpEngine = QHelpEngine(qthelp_file) helpEngine.setupData() self._helpEngine = helpEngine # base dialog widget self.ui = QDialog(None, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowMinMaxButtonsHint | QtCore.Qt.WindowCloseButtonHint ) self.ui.setWindowTitle("HelpViewer") self.ui.setWindowIcon(QIcon(":/images/prog_icons/help/help.ico")) # Create webview for help information # and assign a custom URL scheme handler for scheme "qthelp) self._wv = QWebEngineView(self.ui) self._urlschemehandler = HelpSchemeHandler(self._helpEngine, self._wv.page().profile()) self._wv.page().profile().installUrlSchemeHandler(b'qthelp', self._urlschemehandler) # get help content overview widget self._helpContent = self._helpEngine.contentWidget() self._helpIndex = self._helpEngine.indexWidget() self._helpSearchQuery = self._helpEngine.searchEngine().queryWidget() self._helpSearchResult = self._helpEngine.searchEngine().resultWidget() self._se = self._helpEngine.searchEngine() self._se.reindexDocumentation() self._helpSearchQuery.search.connect(self.search) # create QSplitter self._splitterMain = QSplitter(QtCore.Qt.Vertical) self._splitterMain.setOpaqueResize(False) self._splitterSearch = QSplitter(QtCore.Qt.Horizontal) self._splitterSearch.setOpaqueResize(False) self._splitterUpper = QSplitter(QtCore.Qt.Horizontal) self._splitterUpper.setOpaqueResize(False) self._splitterLower = QSplitter(QtCore.Qt.Horizontal) self._splitterLower.setOpaqueResize(False) # create horzLayout self._horzLayoutSearch = QHBoxLayout() self._horzLayoutUpper = QHBoxLayout() self._horzLayoutLower = QHBoxLayout() # create vertLayout self._vertLayout = QVBoxLayout() # main widgets self._upperWidget = QWidget() self._lowerWidget = QWidget() self._btnReset = QPushButton() self._btnReset.setMaximumHeight(23) self._btnReset.setMaximumWidth(100) # build search structure self._splitterSearch.insertWidget(0, self._helpSearchQuery) self._splitterSearch.insertWidget(1, self._btnReset) # build upper inner structure self._splitterUpper.insertWidget(0, self._helpContent) self._splitterUpper.insertWidget(1, self._wv) self._horzLayoutUpper.addWidget(self._splitterUpper) self._upperWidget.setLayout(self._horzLayoutUpper) # build lower inner structure self._splitterLower.insertWidget(0, self._helpIndex) self._splitterLower.insertWidget(1, self._helpSearchResult) self._horzLayoutLower.addWidget(self._splitterLower) self._lowerWidget.setLayout(self._horzLayoutLower) # build outer structure self._splitterMain.insertWidget(0, self._splitterSearch) self._splitterMain.insertWidget(1, self._upperWidget) self._splitterMain.insertWidget(2, self._lowerWidget) self._helpSearchResult.hide() self._btnReset.hide() self._vertLayout.addWidget(self._splitterMain) self.ui.setLayout(self._vertLayout) # set splitter width w = self._splitterUpper.geometry().width() self._splitterUpper.setSizes([w*(1/4), w*(3/4)]) w = self._splitterLower.geometry().width() self._splitterLower.setSizes([w*(1/5), w*(4/5)]) h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)]) self._helpContent.linkActivated.connect(self._wv.setUrl) self._helpIndex.linkActivated.connect(self._wv.setUrl) self._helpSearchResult.requestShowLink.connect(self._wv.setUrl) self._se.searchingFinished.connect(self.showResults) self._btnReset.clicked.connect(self.resetResult) self.retranslateMsg() def retranslateMsg(self): self.logger.debug("Retranslating further messages...") self._btnReset.setText(translate("HelpViewer", "Reset")) self._btnReset.setText(translate("HelpViewer", "Search")) def search(self): """Initiate qthelp search""" self._se.search(self._helpSearchQuery.query()) def showResults(self): """Show search results, if any""" if self._se.hitCount() > 0: self._helpIndex.hide() h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/3), h*(1/3), h*(1/3)]) self._helpSearchResult.show() self._btnReset.show() def resetResult(self): """Reset search result widget""" self._helpSearchResult.hide() self._btnReset.hide() self._helpIndex.show() h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)])
class GuiMain(QMainWindow): def __init__(self): QMainWindow.__init__(self) logger.info("Starting %s" % nw.__package__) logger.debug("Initialising GUI ...") self.mainConf = nw.CONFIG self.theTheme = GuiTheme(self) self.theProject = NWProject(self) self.theIndex = NWIndex(self.theProject, self) self.hasProject = False self.isZenMode = False logger.info("OS: %s" % ( self.mainConf.osType) ) logger.info("Qt5 Version: %s (%d)" % ( self.mainConf.verQtString, self.mainConf.verQtValue) ) logger.info("PyQt5 Version: %s (%d)" % ( self.mainConf.verPyQtString, self.mainConf.verPyQtValue) ) logger.info("Python Version: %s (0x%x)" % ( self.mainConf.verPyString, self.mainConf.verPyHexVal) ) self.resize(*self.mainConf.winGeometry) self._setWindowTitle() self.setWindowIcon(QIcon(path.join(self.mainConf.appIcon))) # Main GUI Elements self.statusBar = GuiMainStatus(self) self.noticeBar = GuiNoticeBar(self) self.docEditor = GuiDocEditor(self, self.theProject) self.docViewer = GuiDocViewer(self, self.theProject) self.viewMeta = GuiDocViewDetails(self, self.theProject) self.searchBar = GuiSearchBar(self) self.treeMeta = GuiDocDetails(self, self.theProject) self.treeView = GuiDocTree(self, self.theProject) self.mainMenu = GuiMainMenu(self, self.theProject) # Minor Gui Elements self.statusIcons = [] self.importIcons = [] # Assemble Main Window self.treePane = QFrame() self.treeBox = QVBoxLayout() self.treeBox.setContentsMargins(0,0,0,0) self.treeBox.addWidget(self.treeView) self.treeBox.addWidget(self.treeMeta) self.treePane.setLayout(self.treeBox) self.editPane = QFrame() self.docEdit = QVBoxLayout() self.docEdit.setContentsMargins(0,0,0,0) self.docEdit.addWidget(self.searchBar) self.docEdit.addWidget(self.noticeBar) self.docEdit.addWidget(self.docEditor) self.editPane.setLayout(self.docEdit) self.viewPane = QFrame() self.docView = QVBoxLayout() self.docView.setContentsMargins(0,0,0,0) self.docView.addWidget(self.docViewer) self.docView.addWidget(self.viewMeta) self.docView.setStretch(0, 1) self.viewPane.setLayout(self.docView) self.splitView = QSplitter(Qt.Horizontal) self.splitView.setOpaqueResize(False) self.splitView.addWidget(self.editPane) self.splitView.addWidget(self.viewPane) self.splitMain = QSplitter(Qt.Horizontal) self.splitMain.setContentsMargins(4,4,4,4) self.splitMain.setOpaqueResize(False) self.splitMain.addWidget(self.treePane) self.splitMain.addWidget(self.splitView) self.splitMain.setSizes(self.mainConf.mainPanePos) self.setCentralWidget(self.splitMain) self.idxTree = self.splitMain.indexOf(self.treePane) self.idxMain = self.splitMain.indexOf(self.splitView) self.idxEditor = self.splitView.indexOf(self.editPane) self.idxViewer = self.splitView.indexOf(self.viewPane) self.splitMain.setCollapsible(self.idxTree, False) self.splitMain.setCollapsible(self.idxMain, False) self.splitView.setCollapsible(self.idxEditor, False) self.splitView.setCollapsible(self.idxViewer, True) self.viewPane.setVisible(False) self.searchBar.setVisible(False) # Build The Tree View self.treeView.itemSelectionChanged.connect(self._treeSingleClick) self.treeView.itemDoubleClicked.connect(self._treeDoubleClick) self.rebuildTree() # Set Main Window Elements self.setMenuBar(self.mainMenu) self.setStatusBar(self.statusBar) self.statusBar.setStatus("Ready") # Set Up Autosaving Project Timer self.asProjTimer = QTimer() self.asProjTimer.timeout.connect(self._autoSaveProject) # Set Up Autosaving Document Timer self.asDocTimer = QTimer() self.asDocTimer.timeout.connect(self._autoSaveDocument) # Shortcuts and Actions self._connectMenuActions() keyReturn = QShortcut(self.treeView) keyReturn.setKey(QKeySequence(Qt.Key_Return)) keyReturn.activated.connect(self._treeKeyPressReturn) keyEscape = QShortcut(self) keyEscape.setKey(QKeySequence(Qt.Key_Escape)) keyEscape.activated.connect(self._keyPressEscape) # Forward Functions self.setStatus = self.statusBar.setStatus self.setProjectStatus = self.statusBar.setProjectStatus if self.mainConf.showGUI: self.show() self.initMain() self.asProjTimer.start() self.asDocTimer.start() self.statusBar.clearStatus() self.showNormal() if self.mainConf.isFullScreen: self.toggleFullScreenMode() logger.debug("GUI initialisation complete") if self.mainConf.cmdOpen is not None: logger.debug("Opening project from additional command line option") self.openProject(self.mainConf.cmdOpen) return def clearGUI(self): """Wrapper function to clear all sub-elements of the main GUI. """ self.treeView.clearTree() self.docEditor.clearEditor() self.closeDocViewer() self.statusBar.clearStatus() return True def initMain(self): self.asProjTimer.setInterval(int(self.mainConf.autoSaveProj*1000)) self.asDocTimer.setInterval(int(self.mainConf.autoSaveDoc*1000)) return True ## # Project Actions ## def newProject(self, projPath=None, forceNew=False): if self.hasProject: msgBox = QMessageBox() msgRes = msgBox.warning( self, "New Project", "Please close the current project<br>before making a new one." ) return False if projPath is None: projPath = self.newProjectDialog() if projPath is None: return False if path.isfile(path.join(projPath,self.theProject.projFile)) and not forceNew: msgBox = QMessageBox() msgRes = msgBox.critical( self, "New Project", "A project already exists in that location.<br>Please choose another folder." ) return False logger.info("Creating new project") self.theProject.newProject() self.theProject.setProjectPath(projPath) self.rebuildTree() self.saveProject() self.hasProject = True self.statusBar.setRefTime(self.theProject.projOpened) return True def closeProject(self, isYes=False): """Closes the project if one is open. isYes is passed on from the close application event so the user doesn't get prompted twice. """ if not self.hasProject: # There is no project loaded, everything OK return True if self.mainConf.showGUI and not isYes: msgBox = QMessageBox() msgRes = msgBox.question( self, "Close Project", "Save changes and close current project?" ) if msgRes != QMessageBox.Yes: return False if self.docEditor.docChanged: self.saveDocument() if self.theProject.projAltered: saveOK = self.saveProject() doBackup = False if self.theProject.doBackup and self.mainConf.backupOnClose: doBackup = True if self.mainConf.showGUI and self.mainConf.askBeforeBackup: msgBox = QMessageBox() msgRes = msgBox.question( self, "Backup Project", "Backup current project?" ) if msgRes != QMessageBox.Yes: doBackup = False if doBackup: self.backupProject() else: saveOK = True if saveOK: self.closeDocument() self.theProject.closeProject() self.theIndex.clearIndex() self.clearGUI() self.hasProject = False return saveOK def openProject(self, projFile=None): """Open a project. The parameter projFile is passed from the open recent projects menu, so it can be set. If not, we pop the dialog. """ if projFile is None: projFile = self.openProjectDialog() if projFile is None: return False # Make sure any open project is cleared out first before we load # another one if not self.closeProject(): return False # Try to open the project if not self.theProject.openProject(projFile): return False # project is loaded self.hasProject = True # Load the tag index self.theIndex.loadIndex() # Update GUI self._setWindowTitle(self.theProject.projName) self.rebuildTree() self.docEditor.setDictionaries() self.docEditor.setSpellCheck(self.theProject.spellCheck) self.statusBar.setRefTime(self.theProject.projOpened) self.mainMenu.updateMenu() # Restore previously open documents, if any if self.theProject.lastEdited is not None: self.openDocument(self.theProject.lastEdited) if self.theProject.lastViewed is not None: self.viewDocument(self.theProject.lastViewed) # Check if we need to rebuild the index if self.theIndex.indexBroken: self.rebuildIndex() return True def saveProject(self): """Save the current project. """ if not self.hasProject: return False # If the project is new, it may not have a path, so we need one if self.theProject.projPath is None: projPath = self.saveProjectDialog() self.theProject.setProjectPath(projPath) if self.theProject.projPath is None: return False self.treeView.saveTreeOrder() self.theProject.saveProject() self.theIndex.saveIndex() self.mainMenu.updateRecentProjects() return True def backupProject(self): theBackup = NWBackup(self, self.theProject) theBackup.zipIt() return True ## # Document Actions ## def closeDocument(self): if self.hasProject: if self.docEditor.docChanged: self.saveDocument() self.docEditor.clearEditor() return True def openDocument(self, tHandle): if self.hasProject: self.closeDocument() if self.docEditor.loadText(tHandle): self.docEditor.setFocus() self.theProject.setLastEdited(tHandle) else: return False return True def saveDocument(self): if self.hasProject: self.docEditor.saveText() return True def viewDocument(self, tHandle=None): if tHandle is None: tHandle = self.treeView.getSelectedHandle() if tHandle is None: logger.debug("No document selected, trying editor document") tHandle = self.docEditor.theHandle if tHandle is None: logger.debug("No document selected, trying last viewed") tHandle = self.theProject.lastViewed if tHandle is None: logger.debug("No document selected, giving up") return False if self.docViewer.loadText(tHandle) and not self.viewPane.isVisible(): bPos = self.splitMain.sizes() self.viewPane.setVisible(True) vPos = [0,0] vPos[0] = int(bPos[1]/2) vPos[1] = bPos[1]-vPos[0] self.splitView.setSizes(vPos) return True def importDocument(self): lastPath = self.mainConf.lastPath extFilter = [ "Text files (*.txt)", "Markdown files (*.md)", "All files (*.*)", ] dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.DontUseNativeDialog inPath = QFileDialog.getOpenFileName( self,"Import File",lastPath,options=dlgOpt,filter=";;".join(extFilter) ) if inPath: loadFile = inPath[0] else: return False if loadFile.strip() == "": return False theText = None try: with open(loadFile,mode="rt",encoding="utf8") as inFile: theText = inFile.read() self.mainConf.setLastPath(loadFile) except Exception as e: self.makeAlert( ["Could not read file. The file must be an existing text file.",str(e)], nwAlert.ERROR ) return False if self.docEditor.theHandle is None: self.makeAlert( ["Please open a document to import the text file into."], nwAlert.ERROR ) return False if not self.docEditor.isEmpty(): if self.mainConf.showGUI: msgBox = QMessageBox() msgRes = msgBox.question(self, "Import Document",( "Importing the file will overwrite the current content of the document. " "Do you want to proceed?" )) if msgRes != QMessageBox.Yes: return False else: return False self.docEditor.replaceText(theText) return True def mergeDocuments(self): """Merge multiple documents to one single new document. """ if self.mainConf.showGUI: dlgMerge = GuiDocMerge(self, self.theProject) dlgMerge.exec_() return True def splitDocument(self): """Split a single document into multiple documents. """ if self.mainConf.showGUI: dlgSplit = GuiDocSplit(self, self.theProject) dlgSplit.exec_() return True def passDocumentAction(self, theAction): """Pass on document action theAction to whatever document has the focus. If no document has focus, the action is discarded. """ if self.docEditor.hasFocus(): self.docEditor.docAction(theAction) elif self.docViewer.hasFocus(): self.docViewer.docAction(theAction) else: logger.debug("Document action requested, but no document has focus") return True ## # Tree Item Actions ## def openSelectedItem(self): tHandle = self.treeView.getSelectedHandle() if tHandle is None: logger.warning("No item selected") return False logger.verbose("Opening item %s" % tHandle) nwItem = self.theProject.getItem(tHandle) if nwItem.itemType == nwItemType.FILE: logger.verbose("Requested item %s is a file" % tHandle) self.openDocument(tHandle) else: logger.verbose("Requested item %s is not a file" % tHandle) return True def editItem(self): tHandle = self.treeView.getSelectedHandle() if tHandle is None: logger.warning("No item selected") return logger.verbose("Requesting change to item %s" % tHandle) if self.mainConf.showGUI: dlgProj = GuiItemEditor(self, self.theProject, tHandle) if dlgProj.exec_(): self.treeView.setTreeItemValues(tHandle) return def rebuildTree(self): self._makeStatusIcons() self._makeImportIcons() self.treeView.clearTree() self.treeView.buildTree() return def rebuildIndex(self): if not self.hasProject: return False logger.debug("Rebuilding indices ...") self.treeView.saveTreeOrder() self.theIndex.clearIndex() nItems = len(self.theProject.treeOrder) dlgProg = QProgressDialog("Scanning files ...", "Cancel", 0, nItems, self) dlgProg.setWindowModality(Qt.WindowModal) dlgProg.setMinimumDuration(0) dlgProg.setFixedWidth(480) dlgProg.setLabelText("Starting file scan ...") dlgProg.setValue(0) dlgProg.show() time.sleep(0.5) nDone = 0 for tHandle in self.theProject.treeOrder: tItem = self.theProject.getItem(tHandle) dlgProg.setValue(nDone) dlgProg.setLabelText("Scanning: %s" % tItem.itemName) logger.verbose("Scanning: %s" % tItem.itemName) if tItem is not None and tItem.itemType == nwItemType.FILE: theDoc = NWDoc(self.theProject, self) theText = theDoc.openDocument(tHandle, False) # Run Word Count cC, wC, pC = countWords(theText) tItem.setCharCount(cC) tItem.setWordCount(wC) tItem.setParaCount(pC) self.treeView.propagateCount(tHandle, wC) self.treeView.projectWordCount() # Build tag index self.theIndex.scanText(tHandle, theText) nDone += 1 if dlgProg.wasCanceled(): break dlgProg.setValue(nItems) return True ## # Main Dialogs ## def openProjectDialog(self): dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.DontUseNativeDialog projFile, _ = QFileDialog.getOpenFileName( self, "Open novelWriter Project", "", "novelWriter Project File (%s);;All Files (*)" % nwFiles.PROJ_FILE, options=dlgOpt ) if projFile: return projFile return None def saveProjectDialog(self): dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog projPath = QFileDialog.getExistingDirectory( self, "Save novelWriter Project", "", options=dlgOpt ) if projPath: return projPath return None def newProjectDialog(self): dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog projPath = QFileDialog.getExistingDirectory( self, "Select Location for New novelWriter Project", "", options=dlgOpt ) if projPath: return projPath return None def editConfigDialog(self): dlgConf = GuiConfigEditor(self, self.theProject) if dlgConf.exec_() == QDialog.Accepted: logger.debug("Applying new preferences") self.initMain() self.theTheme.updateTheme() self.saveDocument() self.docEditor.initEditor() self.docViewer.initViewer() return True def editProjectDialog(self): if self.hasProject: dlgProj = GuiProjectEditor(self, self.theProject) dlgProj.exec_() self._setWindowTitle(self.theProject.projName) return True def exportProjectDialog(self): if self.hasProject: dlgExport = GuiExport(self, self.theProject) dlgExport.exec_() return True def showTimeLineDialog(self): if self.hasProject: dlgTLine = GuiTimeLineView(self, self.theProject, self.theIndex) dlgTLine.exec_() return True def showSessionLogDialog(self): if self.hasProject: dlgTLine = GuiSessionLogView(self, self.theProject) dlgTLine.exec_() return True def makeAlert(self, theMessage, theLevel=nwAlert.INFO): """Alert both the user and the logger at the same time. Message can be either a string or an array of strings. Severity level is 0 = info, 1 = warning, and 2 = error. """ if isinstance(theMessage, list): popMsg = " ".join(theMessage) logMsg = theMessage else: popMsg = theMessage logMsg = [theMessage] msgBox = QMessageBox() if theLevel == nwAlert.INFO: for msgLine in logMsg: logger.info(msgLine) msgBox.information(self, "Information", popMsg) elif theLevel == nwAlert.WARN: for msgLine in logMsg: logger.warning(msgLine) msgBox.warning(self, "Warning", popMsg) elif theLevel == nwAlert.ERROR: for msgLine in logMsg: logger.error(msgLine) msgBox.critical(self, "Error", popMsg) elif theLevel == nwAlert.BUG: for msgLine in logMsg: logger.error(msgLine) popMsg += "<br>This is a bug!" msgBox.critical(self, "Internal Error", popMsg) return ## # Main Window Actions ## def closeMain(self): if self.mainConf.showGUI and self.hasProject: msgBox = QMessageBox() msgRes = msgBox.question( self, "Exit", "Do you want to save changes and exit?" ) if msgRes != QMessageBox.Yes: return False logger.info("Exiting %s" % nw.__package__) self.closeProject(True) self.mainConf.setTreeColWidths(self.treeView.getColumnSizes()) if not self.mainConf.isFullScreen: self.mainConf.setWinSize(self.width(), self.height()) if not self.isZenMode: self.mainConf.setMainPanePos(self.splitMain.sizes()) self.mainConf.setDocPanePos(self.splitView.sizes()) self.mainConf.saveConfig() qApp.quit() return True def setFocus(self, paneNo): if paneNo == 1: self.treeView.setFocus() elif paneNo == 2: self.docEditor.setFocus() elif paneNo == 3: self.docViewer.setFocus() return def closeDocEditor(self): self.closeDocument() self.theProject.setLastEdited(None) return def closeDocViewer(self): self.docViewer.clearViewer() self.theProject.setLastViewed(None) bPos = self.splitMain.sizes() self.viewPane.setVisible(False) vPos = [bPos[1],0] self.splitView.setSizes(vPos) return not self.viewPane.isVisible() def toggleZenMode(self): """Main GUI Zen Mode hides tree, view pane and optionally also statusbar and menu. """ if self.docEditor.theHandle is None: logger.error("No document open, so not activating Zen Mode") return False self.isZenMode = not self.isZenMode if self.isZenMode: logger.debug("Activating Zen mode") else: logger.debug("Deactivating Zen mode") isVisible = not self.isZenMode self.treePane.setVisible(isVisible) self.statusBar.setVisible(isVisible) self.mainMenu.setVisible(isVisible) if self.viewPane.isVisible(): self.viewPane.setVisible(False) elif self.docViewer.theHandle is not None: self.viewPane.setVisible(True) return True def toggleFullScreenMode(self): """Main GUI full screen mode. The mode is tracked by the flag in config. This only tracks whether the window has been maximised using the internal commands, and may not be correct if the user uses the system window manager. Currently, Qt doesn't have access to the exact state of the window. """ self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) winState = self.windowState() & Qt.WindowFullScreen == Qt.WindowFullScreen if winState: logger.debug("Activated full screen mode") else: logger.debug("Deactivated full screen mode") self.mainConf.isFullScreen = winState return ## # Internal Functions ## def _connectMenuActions(self): """Connect to the main window all menu actions that need to be available also when the main menu is hidden. """ self.addAction(self.mainMenu.aSaveProject) self.addAction(self.mainMenu.aExitNW) self.addAction(self.mainMenu.aSaveDoc) self.addAction(self.mainMenu.aFileDetails) self.addAction(self.mainMenu.aZenMode) self.addAction(self.mainMenu.aFullScreen) self.addAction(self.mainMenu.aViewTimeLine) self.addAction(self.mainMenu.aEditUndo) self.addAction(self.mainMenu.aEditRedo) self.addAction(self.mainMenu.aEditCut) self.addAction(self.mainMenu.aEditCopy) self.addAction(self.mainMenu.aEditPaste) self.addAction(self.mainMenu.aSelectAll) self.addAction(self.mainMenu.aSelectPar) self.addAction(self.mainMenu.aFmtBold) self.addAction(self.mainMenu.aFmtItalic) self.addAction(self.mainMenu.aFmtULine) self.addAction(self.mainMenu.aFmtDQuote) self.addAction(self.mainMenu.aFmtSQuote) self.addAction(self.mainMenu.aFmtHead1) self.addAction(self.mainMenu.aFmtHead2) self.addAction(self.mainMenu.aFmtHead3) self.addAction(self.mainMenu.aFmtHead4) self.addAction(self.mainMenu.aFmtComment) self.addAction(self.mainMenu.aFmtNoFormat) self.addAction(self.mainMenu.aSpellCheck) self.addAction(self.mainMenu.aReRunSpell) self.addAction(self.mainMenu.aPreferences) self.addAction(self.mainMenu.aHelp) return True def _setWindowTitle(self, projName=None): winTitle = "%s" % nw.__package__ if projName is not None: winTitle += " - %s" % projName self.setWindowTitle(winTitle) return True def _autoSaveProject(self): if (self.hasProject and self.theProject.projChanged and self.theProject.projPath is not None): logger.debug("Autosaving project") self.saveProject() return def _autoSaveDocument(self): if self.hasProject and self.docEditor.docChanged: logger.debug("Autosaving document") self.saveDocument() return def _makeStatusIcons(self): self.statusIcons = {} for sLabel, sCol, _ in self.theProject.statusItems: theIcon = QPixmap(32,32) theIcon.fill(QColor(*sCol)) self.statusIcons[sLabel] = QIcon(theIcon) return def _makeImportIcons(self): self.importIcons = {} for sLabel, sCol, _ in self.theProject.importItems: theIcon = QPixmap(32,32) theIcon.fill(QColor(*sCol)) self.importIcons[sLabel] = QIcon(theIcon) return ## # Events ## def closeEvent(self, theEvent): if self.closeMain(): theEvent.accept() else: theEvent.ignore() return ## # Signal Handlers ## def _treeSingleClick(self): sHandle = self.treeView.getSelectedHandle() if sHandle is not None: self.treeMeta.buildViewBox(sHandle) return def _treeDoubleClick(self, tItem, colNo): tHandle = tItem.text(3) logger.verbose("User double clicked tree item with handle %s" % tHandle) nwItem = self.theProject.getItem(tHandle) if nwItem.itemType == nwItemType.FILE: logger.verbose("Requested item %s is a file" % tHandle) self.openDocument(tHandle) else: logger.verbose("Requested item %s is a folder" % tHandle) return def _treeKeyPressReturn(self): tHandle = self.treeView.getSelectedHandle() logger.verbose("User pressed return on tree item with handle %s" % tHandle) nwItem = self.theProject.getItem(tHandle) if nwItem.itemType == nwItemType.FILE: logger.verbose("Requested item %s is a file" % tHandle) self.openDocument(tHandle) else: logger.verbose("Requested item %s is a folder" % tHandle) return def _keyPressEscape(self): """When the escape key is pressed somewhere in the main window, do the following, in order. """ if self.searchBar.isVisible(): self.searchBar.setVisible(False) return elif self.isZenMode: self.toggleZenMode() return
def __init__(self, parent=None): super(StockDialog, self).__init__(parent) self.setWindowTitle("QT painter") mainSplitter = QSplitter(Qt.Horizontal) mainSplitter.setOpaqueResize(True) frame = QFrame(mainSplitter) mainLayout = QGridLayout(frame) # mainLayout.setMargin(10) mainLayout.setSpacing(6) label1 = QLabel("形状:") label2 = QLabel("画笔线宽:") label3 = QLabel("画笔颜色:") label4 = QLabel("画笔风格:") label5 = QLabel("画笔顶端:") label6 = QLabel("画笔连接点:") label7 = QLabel("画刷风格:") label8 = QLabel("画刷颜色:") self.shapeComboBox = QComboBox() self.shapeComboBox.addItem("Line", "Line") self.shapeComboBox.addItem("Rectangle", "Rectangle") self.shapeComboBox.addItem('Rounded Rectangle', 'Rounded Rectangle') self.shapeComboBox.addItem('Ellipse', 'Ellipse') self.shapeComboBox.addItem('Pie', 'Pie') self.shapeComboBox.addItem('Chord', 'Chord') self.shapeComboBox.addItem('Path', 'Path') self.shapeComboBox.addItem('Polygon', 'Polygon') self.shapeComboBox.addItem('Polyline', 'Polyline') self.shapeComboBox.addItem('Arc', 'Arc') self.shapeComboBox.addItem('Points', 'Points') self.shapeComboBox.addItem('Text', 'Text') self.shapeComboBox.addItem('Pixmap', 'Pixmap') self.widthSpinBox = QSpinBox() self.widthSpinBox.setRange(0, 20) self.penColorFrame = QFrame() self.penColorFrame.setAutoFillBackground(True) self.penColorFrame.setPalette(QPalette(Qt.blue)) self.penColorPushButton = QPushButton("更改") self.penStyleComboBox = QComboBox() self.penStyleComboBox.addItem("Solid", Qt.SolidLine) self.penStyleComboBox.addItem('Dash', Qt.DashLine) self.penStyleComboBox.addItem('Dot', Qt.DotLine) self.penStyleComboBox.addItem('Dash Dot', Qt.DashDotLine) self.penStyleComboBox.addItem('Dash Dot Dot', Qt.DashDotDotLine) self.penStyleComboBox.addItem('None', Qt.NoPen) self.penCapComboBox = QComboBox() self.penCapComboBox.addItem("Flat", Qt.FlatCap) self.penCapComboBox.addItem('Square', Qt.SquareCap) self.penCapComboBox.addItem('Round', Qt.RoundCap) self.penJoinComboBox = QComboBox() self.penJoinComboBox.addItem("Miter", Qt.MiterJoin) self.penJoinComboBox.addItem('Bebel', Qt.BevelJoin) self.penJoinComboBox.addItem('Round', Qt.RoundJoin) self.brushStyleComboBox = QComboBox() self.brushStyleComboBox.addItem("Linear Gradient", Qt.LinearGradientPattern) self.brushStyleComboBox.addItem('Radial Gradient', Qt.RadialGradientPattern) self.brushStyleComboBox.addItem('Conical Gradient', Qt.ConicalGradientPattern) self.brushStyleComboBox.addItem('Texture', Qt.TexturePattern) self.brushStyleComboBox.addItem('Solid', Qt.SolidPattern) self.brushStyleComboBox.addItem('Horizontal', Qt.HorPattern) self.brushStyleComboBox.addItem('Vertical', Qt.VerPattern) self.brushStyleComboBox.addItem('Cross', Qt.CrossPattern) self.brushStyleComboBox.addItem('Backward Diagonal', Qt.BDiagPattern) self.brushStyleComboBox.addItem('Forward Diagonal', Qt.FDiagPattern) self.brushStyleComboBox.addItem('Diagonal Cross', Qt.DiagCrossPattern) self.brushStyleComboBox.addItem('Dense 1', Qt.Dense1Pattern) self.brushStyleComboBox.addItem('Dense 2', Qt.Dense2Pattern) self.brushStyleComboBox.addItem('Dense 3', Qt.Dense3Pattern) self.brushStyleComboBox.addItem('Dense 4', Qt.Dense4Pattern) self.brushStyleComboBox.addItem('Dense 5', Qt.Dense5Pattern) self.brushStyleComboBox.addItem('Dense 6', Qt.Dense6Pattern) self.brushStyleComboBox.addItem('Dense 7', Qt.Dense7Pattern) self.brushStyleComboBox.addItem('None', Qt.NoBrush) self.brushColorFrame = QFrame() self.brushColorFrame.setAutoFillBackground(True) self.brushColorFrame.setPalette(QPalette(Qt.green)) self.brushColorPushButton = QPushButton("更改") labelCol = 0 contentCol = 1 # 建立布局 mainLayout.addWidget(label1, 1, labelCol) mainLayout.addWidget(self.shapeComboBox, 1, contentCol) mainLayout.addWidget(label2, 2, labelCol) mainLayout.addWidget(self.widthSpinBox, 2, contentCol) mainLayout.addWidget(label3, 4, labelCol) mainLayout.addWidget(self.penColorFrame, 4, contentCol) mainLayout.addWidget(self.penColorPushButton, 4, 3) mainLayout.addWidget(label4, 6, labelCol) mainLayout.addWidget(self.penStyleComboBox, 6, contentCol) mainLayout.addWidget(label5, 8, labelCol) mainLayout.addWidget(self.penCapComboBox, 8, contentCol) mainLayout.addWidget(label6, 10, labelCol) mainLayout.addWidget(self.penJoinComboBox, 10, contentCol) mainLayout.addWidget(label7, 12, labelCol) mainLayout.addWidget(self.brushStyleComboBox, 12, contentCol) mainLayout.addWidget(label8, 14, labelCol) mainLayout.addWidget(self.brushColorFrame, 14, contentCol) mainLayout.addWidget(self.brushColorPushButton, 14, 3) mainSplitter1 = QSplitter(Qt.Horizontal) mainSplitter1.setOpaqueResize(True) stack1 = QStackedWidget() stack1.setFrameStyle(QFrame.Panel | QFrame.Raised) self.area = PaintArea() stack1.addWidget(self.area) frame1 = QFrame(mainSplitter1) mainLayout1 = QVBoxLayout(frame1) # mainLayout1.setMargin(10) mainLayout1.setSpacing(6) mainLayout1.addWidget(stack1) layout = QGridLayout(self) layout.addWidget(mainSplitter1, 0, 0) layout.addWidget(mainSplitter, 0, 1) self.setLayout(layout) # 信号和槽函数 self.shapeComboBox.activated.connect(self.slotShape) self.widthSpinBox.valueChanged.connect(self.slotPenWidth) self.penColorPushButton.clicked.connect(self.slotPenColor) self.penStyleComboBox.activated.connect(self.slotPenStyle) self.penCapComboBox.activated.connect(self.slotPenCap) self.penJoinComboBox.activated.connect(self.slotPenJoin) self.brushStyleComboBox.activated.connect(self.slotBrush) self.brushColorPushButton.clicked.connect(self.slotBrushColor) self.slotShape(self.shapeComboBox.currentIndex()) self.slotPenWidth(self.widthSpinBox.value()) self.slotBrush(self.brushStyleComboBox.currentIndex())
class Ui_MainWindow(object): def setupUi(self, main_window): main_window.setObjectName("mainWindow") main_window.resize(1024, 768) main_window.setMinimumSize(QSize(1024, 768)) main_window.setToolButtonStyle(Qt.ToolButtonIconOnly) self.central_widget = QWidget(main_window) self.central_widget.setObjectName("central_widget") self.horizontalLayout = QHBoxLayout(self.central_widget) self.horizontalLayout.setObjectName("horizontalLayout") self.topDownSplitter = QSplitter(self.central_widget) self.topDownSplitter.setOrientation(Qt.Vertical) self.topDownSplitter.setOpaqueResize(True) self.topDownSplitter.setHandleWidth(5) self.topDownSplitter.setObjectName("topDownSplitter") self.leftRightSplitter = QSplitter(self.topDownSplitter) self.leftRightSplitter.setOrientation(Qt.Horizontal) self.leftRightSplitter.setObjectName("leftRightSplitter") self.leftPanel = QFrame(self.leftRightSplitter) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.leftPanel.sizePolicy().hasHeightForWidth()) self.leftPanel.setSizePolicy(sizePolicy) self.leftPanel.setMinimumSize(QSize(245, 550)) self.leftPanel.setMaximumSize(QSize(245, 16777215)) self.leftPanel.setFrameShape(QFrame.StyledPanel) self.leftPanel.setFrameShadow(QFrame.Raised) self.leftPanel.setObjectName("leftPanel") self.leftPanelVLayout = QVBoxLayout(self.leftPanel) self.leftPanelVLayout.setObjectName("leftPanelVLayout") self.colorPickerFrame = QFrame(self.leftPanel) self.colorPickerFrame.setMinimumSize(QSize(0, 0)) self.colorPickerFrame.setMaximumSize(QSize(16777215, 16777215)) self.colorPickerFrame.setFrameShape(QFrame.StyledPanel) self.colorPickerFrame.setFrameShadow(QFrame.Raised) self.colorPickerFrame.setObjectName("colorPickerFrame") self.leftPanelVLayout.addWidget(self.colorPickerFrame) self.leftPanelVLayout.setStretch(0, 5) self.mainPanel = QFrame(self.leftRightSplitter) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.mainPanel.sizePolicy().hasHeightForWidth()) self.mainPanel.setSizePolicy(sizePolicy) self.mainPanel.setMinimumSize(QSize(320, 240)) self.mainPanel.setAutoFillBackground(False) self.mainPanel.setFrameShape(QFrame.StyledPanel) self.mainPanel.setFrameShadow(QFrame.Raised) self.mainPanel.setObjectName("mainPanel") self.verticalLayout = QVBoxLayout(self.mainPanel) self.verticalLayout.setObjectName("verticalLayout") self.canvasFrame = QFrame(self.mainPanel) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.canvasFrame.sizePolicy().hasHeightForWidth()) self.canvasFrame.setSizePolicy(sizePolicy) self.canvasFrame.setMinimumSize(310, 230) self.canvasFrame.setFrameShape(QFrame.StyledPanel) self.canvasFrame.setFrameShadow(QFrame.Raised) self.canvasFrame.setObjectName("canvasFrame") self.verticalLayout.addWidget(self.canvasFrame) self.verticalLayout.setStretch(0, 12) self.rightPanel = QFrame(self.leftRightSplitter) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.rightPanel.sizePolicy().hasHeightForWidth()) self.rightPanel.setSizePolicy(sizePolicy) self.rightPanel.setMinimumSize(QSize(245, 550)) self.rightPanel.setMaximumSize(QSize(340, 16777215)) self.rightPanel.setFrameShape(QFrame.StyledPanel) self.rightPanel.setFrameShadow(QFrame.Raised) self.rightPanel.setObjectName("rightPanel") self.rightPanelLayout = QVBoxLayout(self.rightPanel) self.rightPanelLayout.setObjectName("rightPanelLayout") self.previewFrame = QFrame(self.rightPanel) self.previewFrame.setMaximumSize(320, 500) self.previewFrame.setFrameShape(QFrame.StyledPanel) self.previewFrame.setFrameShadow(QFrame.Raised) self.previewFrame.setObjectName("previewFrame") self.rightPanelLayout.addWidget(self.previewFrame) self.layerListFrame = QFrame(self.rightPanel) self.layerListFrame.setFrameShape(QFrame.StyledPanel) self.layerListFrame.setFrameShadow(QFrame.Raised) self.layerListFrame.setObjectName("layerListFrame") self.rightPanelLayout.addWidget(self.layerListFrame) self.animationBarFrame = QFrame(self.topDownSplitter) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.animationBarFrame.sizePolicy().hasHeightForWidth()) self.animationBarFrame.setSizePolicy(sizePolicy) self.animationBarFrame.setMinimumSize(QSize(600, 100)) self.animationBarFrame.setMaximumSize(QSize(16777215, 100)) self.animationBarFrame.setFrameShape(QFrame.StyledPanel) self.animationBarFrame.setFrameShadow(QFrame.Raised) self.animationBarFrame.setObjectName("animationBarFrame") self.horizontalLayout.addWidget(self.topDownSplitter) main_window.setCentralWidget(self.central_widget) self.toolBar = QToolBar(main_window) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.toolBar.sizePolicy().hasHeightForWidth()) self.toolBar.setSizePolicy(sizePolicy) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.setObjectName("toolBar") main_window.addToolBar(Qt.TopToolBarArea, self.toolBar) self.actionNew = QAction(main_window) self.actionNew.setObjectName("actionNew") self.actionQuit = QAction(main_window) self.actionQuit.setObjectName("actionQuit") self.actionOpen = QAction(main_window) self.actionOpen.setObjectName("actionOpen") self.actionSave = QAction(main_window) self.actionSave.setObjectName("actionSave") self.actionSaveAs = QAction(main_window) self.actionSaveAs.setObjectName("actionSaveAs") self.actionClose = QAction(main_window) self.actionClose.setObjectName("actionClose") self.actionExport = QAction(main_window) self.actionExport.setObjectName("actionExport") self.actionImport = QAction(main_window) self.actionImport.setObjectName("actionImport") self.toolBar.addAction(self.actionNew) self.toolBar.addAction(self.actionOpen) self.toolBar.addAction(self.actionImport) self.toolBar.addAction(self.actionSave) self.toolBar.addAction(self.actionSaveAs) self.toolBar.addAction(self.actionExport) self.toolBar.addAction(self.actionClose) self.toolBar.addAction(self.actionQuit) self.retranslateUi(main_window) QMetaObject.connectSlotsByName(main_window) def retranslateUi(self, main_window): _translate = QCoreApplication.translate main_window.setWindowTitle(_translate("MainWindow", "SpriteMator")) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) self.actionNew.setText(_translate("MainWindow", "New")) self.actionNew.setIconText(_translate("MainWindow", "New")) self.actionNew.setToolTip(_translate("MainWindow", "New Sprite")) self.actionNew.setShortcut(_translate("MainWindow", "Ctrl+N")) self.actionQuit.setText(_translate("MainWindow", "Quit")) self.actionQuit.setToolTip( _translate("MainWindow", "Close Application")) self.actionQuit.setShortcut(_translate("MainWindow", "Esc")) self.actionOpen.setText(_translate("MainWindow", "Open")) self.actionOpen.setToolTip(_translate("MainWindow", "Open Sprite")) self.actionOpen.setShortcut(_translate("MainWindow", "Ctrl+O")) self.actionSave.setText(_translate("MainWindow", "Save")) self.actionSave.setToolTip(_translate("MainWindow", "Save Sprite")) self.actionSave.setShortcut(_translate("MainWindow", "Ctrl+S")) self.actionSaveAs.setText(_translate("MainWindow", "SaveAs")) self.actionSaveAs.setToolTip( _translate("MainWindow", "Save Sprite with another name")) self.actionSaveAs.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) self.actionClose.setText(_translate("MainWindow", "Close")) self.actionClose.setToolTip(_translate("MainWindow", "Close Sprite")) self.actionClose.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.actionExport.setText(_translate("MainWindow", "Export")) self.actionExport.setToolTip( _translate( "MainWindow", "Export Sprite animations : Either as separate images or as a spritesheet" )) self.actionExport.setShortcut(_translate("MainWindow", "Ctrl+E")) self.actionImport.setText(_translate("MainWindow", "Import")) self.actionImport.setToolTip( _translate("MainWindow", "Create a Sprite from one or more images")) self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+I"))
class MainWindow(QFrame): smx_file = core.SmxFile() hotplug = core.HotPlug() devices = [] target = None worker = None def __init__(self): super().__init__() self.setWindowTitle('i.MX Smart-Boot Tool') self.setMinimumSize(600, 400) self.center() # create main box layout = QVBoxLayout() # -------------------------------------------------------------------------------------------------------------- # Device selection drop-box with scan button # -------------------------------------------------------------------------------------------------------------- box = QHBoxLayout() self.deviceBox = QComboBox() box.addWidget(self.deviceBox) self.scanButton = QPushButton(" Scan") self.scanButton.setFixedWidth(80) self.scanButton.setIcon(QIcon.fromTheme("view-refresh")) self.scanButton.clicked.connect(self.on_scan_button_clicked) box.addWidget(self.scanButton) layout.addLayout(box) # -------------------------------------------------------------------------------------------------------------- # SMX File inbox with open button # -------------------------------------------------------------------------------------------------------------- box = QHBoxLayout() self.smxEdit = QLineEdit() self.smxEdit.setReadOnly(True) box.addWidget(self.smxEdit) self.openButton = QPushButton(" Open") self.openButton.setFixedWidth(80) self.openButton.setIcon(QIcon.fromTheme("document-open")) self.openButton.clicked.connect(self.on_open_button_clicked) box.addWidget(self.openButton) layout.addLayout(box) # -------------------------------------------------------------------------------------------------------------- # Body # -------------------------------------------------------------------------------------------------------------- self.splitter = QSplitter() self.splitter.setHandleWidth(5) self.splitter.setMidLineWidth(0) self.splitter.setOrientation(Qt.Vertical) self.splitter.setOpaqueResize(True) self.splitter.setChildrenCollapsible(False) self.scriptsList = QListWidget(self.splitter) self.scriptsList.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContents) self.scriptsList.setMinimumHeight(60) self.textEdit = QTextEdit(self.splitter) self.textEdit.setReadOnly(True) self.textEdit.setMinimumHeight(100) layout.addWidget(self.splitter) # Progress Bar self.pgTask = QProgressBar() self.pgTask.setRange(0, PGRANGE) self.pgTask.setFixedHeight(16) self.pgTask.setTextVisible(False) layout.addWidget(self.pgTask) # -------------------------------------------------------------------------------------------------------------- # Buttons # -------------------------------------------------------------------------------------------------------------- box = QHBoxLayout() box.setContentsMargins(-1, 5, -1, -1) # About Button self.aboutButton = QPushButton(" About") self.aboutButton.setMinimumSize(100, 40) self.aboutButton.setIcon(QIcon.fromTheme("help-contents")) self.aboutButton.clicked.connect(self.on_about_button_clicked) box.addWidget(self.aboutButton) # Device Info Button self.devInfoButton = QPushButton(" DevInfo") self.devInfoButton.setEnabled(False) self.devInfoButton.setMinimumSize(100, 40) self.devInfoButton.setIcon(QIcon.fromTheme("help-about")) self.devInfoButton.clicked.connect(self.on_info_button_clicked) box.addWidget(self.devInfoButton) # Spacer box.addItem( QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) # Start Button self.startButton = QPushButton(" Start") self.startButton.setEnabled(False) self.startButton.setMinimumSize(100, 40) self.startButton.setIcon(QIcon.fromTheme("media-playback-start")) self.startButton.clicked.connect(self.on_start_button_clicked) box.addWidget(self.startButton) # Start Button self.exitButton = QPushButton(" Exit") self.exitButton.setMinimumSize(100, 40) self.exitButton.setIcon(QIcon.fromTheme("application-exit")) self.exitButton.clicked.connect(self.on_exit_button_clicked) box.addWidget(self.exitButton) layout.addLayout(box) self.setLayout(layout) # USB hot-plug (Linux only) # self.hotplug.attach(self.scan_usb) # self.hotplug.start() # TODO: Fix USB hot-plug self.scan_usb() def center(self): # center point of screen cp = QDesktopWidget().availableGeometry().center() # move rectangle's center point to screen's center point qr = self.frameGeometry() qr.moveCenter(cp) # top left of rectangle becomes top left of window centering it self.move(qr.topLeft()) #################################################################################################################### # Helper methods #################################################################################################################### def scan_usb(self, obj=None): self.devices = imx.sdp.scan_usb(self.target) self.deviceBox.clear() if self.devices: for dev in self.devices: self.deviceBox.addItem(dev.usbd.info()) self.deviceBox.setCurrentIndex(0) self.deviceBox.setEnabled(True) self.devInfoButton.setEnabled(True) self.startButton.setEnabled(False if self.target is None else True) else: self.deviceBox.setEnabled(False) self.devInfoButton.setEnabled(False) self.startButton.setEnabled(False) def Logger(self, msg, clear): if clear: self.textEdit.clear() if msg: self.textEdit.append(msg) def ProgressBar(self, value): self.pgTask.setValue(min(value, PGRANGE)) def ShowMesageBox(self, title, message, icon=QMessageBox.Warning): alert = QMessageBox() alert.setWindowTitle(title) alert.setText(message) alert.setIcon(icon) alert.exec_() #################################################################################################################### # Buttons callback methods #################################################################################################################### def on_scan_button_clicked(self): self.scan_usb() def on_open_button_clicked(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName( self, "Choose a SmartBoot script file", BASEDIR, "i.MX SmartBoot Files (*.smx)", options=options) if fileName: self.smxEdit.clear() self.scriptsList.clear() try: self.smx_file.open(fileName, True) except Exception as e: self.ShowMesageBox("SMX File Open Error", str(e), QMessageBox.Warning) self.target = None self.startButton.setEnabled(False) else: self.target = self.smx_file.platform self.smxEdit.setText(fileName) for i, item in enumerate(self.smx_file.scripts): self.scriptsList.addItem("{}. {} ({})".format( i, item.name, item.description)) self.scriptsList.setCurrentRow(0) self.scriptsList.adjustSize() # update usb device list self.scan_usb() def on_about_button_clicked(self): text = "<b>i.MX SmartBoot Tool</b> v {}".format(core.__version__) text += "<p>{}".format(core.DESCRIPTION) text += "<p>Copyright © 2018 Martin Olejar." text += "<p>License: {}".format(core.__license__) text += "<p>Sources: <a href='https://github.com/molejar/imxsb'>https://github.com/molejar/imxsb</a>" QMessageBox.about(self, "About", text) def on_info_button_clicked(self): device = self.devices[self.deviceBox.currentIndex()] device.open() self.textEdit.clear() self.textEdit.append("Device: {} \n".format(device.device_name)) device.close() def on_start_button_clicked(self): if self.startButton.text().endswith("Start"): try: device = self.devices[self.deviceBox.currentIndex()] script = self.smx_file.get_script( self.scriptsList.currentRow()) except Exception as e: self.ShowMesageBox("Script Load Error", str(e), QMessageBox.Warning) else: # Start Worker self.worker = Worker(device, script) self.worker.logger.connect(self.Logger) self.worker.finish.connect(self.on_finish) self.worker.prgbar.connect(self.ProgressBar) self.worker.daemon = True self.worker.start() self.startButton.setText(" Stop") self.startButton.setIcon( QIcon.fromTheme("media-playback-stop")) self.scanButton.setEnabled(False) self.openButton.setEnabled(False) self.deviceBox.setEnabled(False) self.scriptsList.setEnabled(False) self.devInfoButton.setEnabled(False) else: # Stop Worker self.worker.stop() def on_finish(self, msg, done): self.textEdit.append(msg) self.startButton.setText(" Start") self.startButton.setIcon(QIcon.fromTheme("media-playback-start")) self.scanButton.setEnabled(True) self.scriptsList.setEnabled(True) self.openButton.setEnabled(True) if done: self.deviceBox.clear() self.startButton.setEnabled(False) else: self.scan_usb() def on_exit_button_clicked(self): self.close()
class ChartDialog(QDialog): """The chart dialog""" def __init__(self, parent): if Figure is None: raise ModuleNotFoundError super().__init__(parent) self.actions = ChartDialogActions(self) self.chart_templates_toolbar = ChartTemplatesToolBar(self) self.setWindowTitle("Chart dialog") self.setModal(True) self.resize(800, 600) self.parent = parent self.actions = ChartDialogActions(self) self.dialog_ui() def on_template(self): """Event handler for pressing a template toolbar button""" chart_template_name = self.sender().data() chart_template_path = MPL_TEMPLATE_PATH / chart_template_name try: with open(chart_template_path) as template_file: chart_template_code = template_file.read() except OSError: return self.editor.insertPlainText(chart_template_code) def dialog_ui(self): """Sets up dialog UI""" msg = "Enter Python code into the editor to the left. Globals " + \ "such as X, Y, Z, S are available as they are in the grid. " + \ "The last line must result in a matplotlib figure.\n \n" + \ "Pressing Apply displays the figure or an error message in " + \ "the right area." self.message = QTextBrowser(self) self.message.setText(msg) self.editor = SpellTextEdit(self) self.splitter = QSplitter(self) buttonbox = self.create_buttonbox() self.splitter.addWidget(self.editor) self.splitter.addWidget(self.message) self.splitter.setOpaqueResize(False) self.splitter.setSizes([9999, 9999]) # Layout layout = QVBoxLayout(self) layout.addWidget(self.chart_templates_toolbar) layout.addWidget(self.splitter) layout.addWidget(buttonbox) self.setLayout(layout) def apply(self): """Executes the code in the dialog and updates the canvas""" # Get current cell key = self.parent.grid.current code = self.editor.toPlainText() figure = self.parent.grid.model.code_array._eval_cell(key, code) if isinstance(figure, Figure): canvas = FigureCanvasQTAgg(figure) self.splitter.replaceWidget(1, canvas) canvas.draw() else: if isinstance(figure, Exception): self.message.setText("Error:\n{}".format(figure)) else: msg_text = "Error:\n{} has type '{}', " + \ "which is no instance of {}." msg = msg_text.format(figure, type(figure).__name__, Figure) self.message.setText(msg) self.splitter.replaceWidget(1, self.message) def create_buttonbox(self): """Returns a QDialogButtonBox with Ok and Cancel""" button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) button_box.button(QDialogButtonBox.Apply).clicked.connect(self.apply) return button_box
class MainWindow(QMainWindow): frame = None jupyter_widget = None browser_widget = None addon_list = [] current_addon = None # currently shown addon def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowTitle(main_window_title) self.setWindowIcon(QIcon(os.path.join(utils.get_exe_folder(), 'appicon.ico'))) self.init_jupyter_widget() self.init_addon_menu() self.init_splitter() self.init_statusbar() self.init_help_menu() self.setCentralWidget(self.frame) def closeEvent(self, event): # close all the plots # plt.close("all") # nothing to close as # all the plots are in # console pass def init_help_menu(self): menubar = self.menuBar() self.__help_menu = menubar.addMenu('Help') action = QAction('User guide', self) self.__help_menu.addAction(action) action.triggered.connect(self.on_help_user_guide) action = QAction('License', self) self.__help_menu.addAction(action) action.triggered.connect(self.on_help_license) action = QAction('About...', self) self.__help_menu.addAction(action) action.triggered.connect(self.on_help_about) def on_help_license(self, q): self.browser_widget.load_page(license_url) def on_help_user_guide(self, q): self.browser_widget.load_page(user_guide_url) def on_help_about(self, q): # main_window_title, app_name, app_version text = (app_name + ' version ' + app_version + '.\nby ' + author + '.') QMessageBox.about(self, main_window_title, text) def init_statusbar(self): self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) def init_splitter(self): self.frame = QFrame() self.frame.setFrameShape(QFrame.StyledPanel) hbox = QHBoxLayout() # here should be no 'self' argument self.browser_widget = bv.BrowserWidget(self) self.top_splitter = QSplitter(Qt.Horizontal) frame = QFrame() layout = QVBoxLayout() for addon in self.addon_list: layout.addWidget(addon) addon.hide() frame.setLayout(layout) self.top_splitter.addWidget(frame) self.current_addon = self.addon_list[0] self.current_addon.show_itself() self.top_splitter.addWidget(self.browser_widget) self.top_splitter.setSizes([100, 200]) handle_width = 6 # https://stackoverflow.com/questions/2545577/qsplitter-becoming-undistinguishable-between-qwidget-and-qtabwidget self.top_splitter.setOpaqueResize(False) self.top_splitter.setChildrenCollapsible(False) self.top_splitter.setHandleWidth(handle_width) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(self.top_splitter) splitter2.addWidget(self.jupyter_widget) splitter2.setOpaqueResize(False) splitter2.setChildrenCollapsible(False) splitter2.setHandleWidth(handle_width) hbox.addWidget(splitter2) self.frame.setLayout(hbox) def init_jupyter_widget(self): self.jupyter_widget = make_jupyter_widget_with_kernel() def shutdown_kernel(self): print('Shutting down kernel...') self.jupyter_widget.kernel_client.stop_channels() self.jupyter_widget.kernel_manager.shutdown_kernel() def init_addon_menu(self): self.__menubar = self.menuBar() addon_list = addon_data.addon_list self.__addon_menu = self.__menubar.addMenu('Addons') for addon_group in addon_list: group_menu = self.__addon_menu.addMenu(addon_group.menu_name) for addon in addon_group.addons: action = QAction(addon.menu_name, self) group_menu.addAction(action) self.inputs_widget = InputsWidget(self, addon) action.triggered.connect(self.inputs_widget.show_itself) self.addon_list.append(self.inputs_widget)
class View(QMainWindow): def __init__(self, model, controller): super().__init__() self._model = model self._controller = controller self.segmentcursor = False self.togglecolors = {"#1f77b4": "m", "m": "#1f77b4"} ################################################################# # define GUI layout and connect input widgets to external slots # ################################################################# self.setWindowTitle("biopeaks") self.setGeometry(50, 50, 1750, 750) self.setWindowIcon(QIcon(":/python_icon.png")) # figure0 for signal self.figure0 = Figure() self.canvas0 = FigureCanvas(self.figure0) self.ax00 = self.figure0.add_subplot(1, 1, 1) self.ax00.set_frame_on(False) self.figure0.subplots_adjust(left=0.04, right=0.98, bottom=0.25) self.line00 = None self.scat = None self.segmentspan = None # figure1 for marker self.figure1 = Figure() self.canvas1 = FigureCanvas(self.figure1) self.ax10 = self.figure1.add_subplot(1, 1, 1, sharex=self.ax00) self.ax10.get_xaxis().set_visible(False) self.ax10.set_frame_on(False) self.figure1.subplots_adjust(left=0.04, right=0.98) self.line10 = None # figure2 for statistics self.figure2 = Figure() self.canvas2 = FigureCanvas(self.figure2) self.ax20 = self.figure2.add_subplot(3, 1, 1, sharex=self.ax00) self.ax20.get_xaxis().set_visible(False) self.ax20.set_frame_on(False) self.line20 = None self.ax21 = self.figure2.add_subplot(3, 1, 2, sharex=self.ax00) self.ax21.get_xaxis().set_visible(False) self.ax21.set_frame_on(False) self.line21 = None self.ax22 = self.figure2.add_subplot(3, 1, 3, sharex=self.ax00) self.ax22.get_xaxis().set_visible(False) self.ax22.set_frame_on(False) self.line22 = None self.figure2.subplots_adjust(left=0.04, right=0.98) # navigation bar self.navitools = CustomNavigationToolbar(self.canvas0, self) # peak editing self.editcheckbox = QCheckBox("editable", self) self.editcheckbox.stateChanged.connect(self._model.set_peakseditable) # peak saving batch self.savecheckbox = QCheckBox("save during batch processing", self) self.savecheckbox.stateChanged.connect(self._model.set_savebatchpeaks) # peak auto-correction batch self.correctcheckbox = QCheckBox("correct during batch processing", self) self.correctcheckbox.stateChanged.connect( self._model.set_correctbatchpeaks) # selecting stats for saving self.periodcheckbox = QCheckBox("period", self) self.periodcheckbox.stateChanged.connect( lambda: self.select_stats("period")) self.ratecheckbox = QCheckBox("rate", self) self.ratecheckbox.stateChanged.connect( lambda: self.select_stats("rate")) self.tidalampcheckbox = QCheckBox("tidal amplitude", self) self.tidalampcheckbox.stateChanged.connect( lambda: self.select_stats("tidalamp")) # channel selection self.sigchanmenulabel = QLabel("biosignal") self.sigchanmenu = QComboBox(self) self.sigchanmenu.addItem("A1") self.sigchanmenu.addItem("A2") self.sigchanmenu.addItem("A3") self.sigchanmenu.addItem("A4") self.sigchanmenu.addItem("A5") self.sigchanmenu.addItem("A6") self.sigchanmenu.currentTextChanged.connect(self._model.set_signalchan) # initialize with default value self._model.set_signalchan(self.sigchanmenu.currentText()) self.markerchanmenulabel = QLabel("marker") self.markerchanmenu = QComboBox(self) self.markerchanmenu.addItem("none") self.markerchanmenu.addItem("I1") self.markerchanmenu.addItem("I2") self.markerchanmenu.addItem("A1") self.markerchanmenu.addItem("A2") self.markerchanmenu.addItem("A3") self.markerchanmenu.addItem("A4") self.markerchanmenu.addItem("A5") self.markerchanmenu.addItem("A6") self.markerchanmenu.currentTextChanged.connect( self._model.set_markerchan) # initialize with default value self._model.set_markerchan(self.markerchanmenu.currentText()) # processing mode (batch or single file) self.batchmenulabel = QLabel("mode") self.batchmenu = QComboBox(self) self.batchmenu.addItem("single file") self.batchmenu.addItem("multiple files") self.batchmenu.currentTextChanged.connect(self._model.set_batchmode) self.batchmenu.currentTextChanged.connect(self.toggle_options) # initialize with default value self._model.set_batchmode(self.batchmenu.currentText()) self.toggle_options(self.batchmenu.currentText()) # modality selection self.modmenulabel = QLabel("modality") self.modmenu = QComboBox(self) self.modmenu.addItem("ECG") self.modmenu.addItem("PPG") self.modmenu.addItem("RESP") self.modmenu.currentTextChanged.connect(self._model.set_modality) self.modmenu.currentTextChanged.connect(self.toggle_options) # initialize with default value self._model.set_modality(self.modmenu.currentText()) self.toggle_options(self.modmenu.currentText()) # segment selection; this widget can be openend / set visible from # the menu and closed from within itself (see mapping of segmentermap); # it provides utilities to select a segment from the signal self.segmentermap = QSignalMapper(self) self.segmenter = QDockWidget("select a segment", self) # disable closing such that widget can only be closed by confirming # selection or custom button self.segmenter.setFeatures(QDockWidget.NoDockWidgetFeatures) # Limit number of decimals to four. regex = QRegExp("[0-9]*\.?[0-9]{4}") validator = QRegExpValidator(regex) self.startlabel = QLabel("start") self.startedit = QLineEdit() self.startedit.setValidator(validator) self.endlabel = QLabel("end") self.endedit = QLineEdit() self.endedit.setValidator(validator) segmentfromcursor = QAction(QIcon(":/mouse_icon.png"), "select with mouse", self) segmentfromcursor.triggered.connect(self.enable_segmentedit) self.startedit.addAction(segmentfromcursor, 1) self.endedit.addAction(segmentfromcursor, 1) self.previewedit = QPushButton("preview segment") lambdafn = lambda: self._model.set_segment( [self.startedit.text(), self.endedit.text()]) self.previewedit.clicked.connect(lambdafn) self.confirmedit = QPushButton("confirm segment") self.confirmedit.clicked.connect(self._controller.segment_signal) self.confirmedit.clicked.connect(self.segmentermap.map) self.segmentermap.setMapping(self.confirmedit, 0) self.abortedit = QPushButton("abort segmentation") self.abortedit.clicked.connect(self.segmentermap.map) # reset the segment to None self.segmentermap.setMapping(self.abortedit, 2) self.segmenterlayout = QFormLayout() self.segmenterlayout.addRow(self.startlabel, self.startedit) self.segmenterlayout.addRow(self.endlabel, self.endedit) self.segmenterlayout.addRow(self.previewedit) self.segmenterlayout.addRow(self.confirmedit) self.segmenterlayout.addRow(self.abortedit) self.segmenterwidget = QWidget() self.segmenterwidget.setLayout(self.segmenterlayout) self.segmenter.setWidget(self.segmenterwidget) self.segmenter.setVisible(False) self.segmenter.setAllowedAreas(Qt.RightDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, self.segmenter) # set up menubar menubar = self.menuBar() # signal menu signalmenu = menubar.addMenu("biosignal") openSignal = QAction("load", self) openSignal.triggered.connect(self._controller.get_fpaths) signalmenu.addAction(openSignal) segmentSignal = QAction("select segment", self) segmentSignal.triggered.connect(self.segmentermap.map) self.segmentermap.setMapping(segmentSignal, 1) signalmenu.addAction(segmentSignal) self.segmentermap.mapped.connect(self.toggle_segmenter) saveSignal = QAction("save", self) saveSignal.triggered.connect(self._controller.get_wpathsignal) signalmenu.addAction(saveSignal) # peak menu peakmenu = menubar.addMenu("peaks") findPeaks = QAction("find", self) findPeaks.triggered.connect(self._controller.find_peaks) peakmenu.addAction(findPeaks) autocorrectPeaks = QAction("autocorrect", self) autocorrectPeaks.triggered.connect(self._controller.autocorrect_peaks) peakmenu.addAction(autocorrectPeaks) savePeaks = QAction("save", self) savePeaks.triggered.connect(self._controller.get_wpathpeaks) peakmenu.addAction(savePeaks) loadPeaks = QAction("load", self) loadPeaks.triggered.connect(self._controller.get_rpathpeaks) peakmenu.addAction(loadPeaks) # stats menu statsmenu = menubar.addMenu("statistics") calculateStats = QAction("calculate", self) calculateStats.triggered.connect(self._controller.calculate_stats) statsmenu.addAction(calculateStats) saveStats = QAction("save", self) saveStats.triggered.connect(self._controller.get_wpathstats) statsmenu.addAction(saveStats) # set up status bar to display error messages and current file path self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.progressBar = QProgressBar(self) self.progressBar.setRange(0, 1) self.statusBar.addPermanentWidget(self.progressBar) self.currentFile = QLabel() self.statusBar.addPermanentWidget(self.currentFile) # set up the central widget containing the plot and navigationtoolbar self.centwidget = QWidget() self.setCentralWidget(self.centwidget) # connect canvas0 to keyboard and mouse input for peak editing; # only widgets (e.g. canvas) that currently have focus capture # keyboard input: "You must enable keyboard focus for a widget if # it processes keyboard events." self.canvas0.setFocusPolicy(Qt.ClickFocus) self.canvas0.setFocus() self.canvas0.mpl_connect("key_press_event", self._controller.edit_peaks) self.canvas0.mpl_connect("button_press_event", self.get_xcursor) # arrange the three figure canvases in splitter object self.splitter = QSplitter(Qt.Vertical) # setting opaque resizing to false is important, since resizing gets # very slow otherwise once axes are populated self.splitter.setOpaqueResize(False) self.splitter.addWidget(self.canvas0) self.splitter.addWidget(self.canvas1) self.splitter.addWidget(self.canvas2) # define GUI layout self.vlayout0 = QVBoxLayout(self.centwidget) self.vlayout1 = QVBoxLayout() self.vlayoutA = QFormLayout() self.vlayoutB = QFormLayout() self.vlayoutC = QVBoxLayout() self.vlayoutD = QVBoxLayout() self.hlayout0 = QHBoxLayout() self.hlayout1 = QHBoxLayout() self.optionsgroupA = QGroupBox("processing options") self.vlayoutA.addRow(self.modmenulabel, self.modmenu) self.vlayoutA.addRow(self.batchmenulabel, self.batchmenu) self.optionsgroupA.setLayout(self.vlayoutA) self.optionsgroupB = QGroupBox("channels") self.vlayoutB.addRow(self.sigchanmenulabel, self.sigchanmenu) self.vlayoutB.addRow(self.markerchanmenulabel, self.markerchanmenu) self.optionsgroupB.setLayout(self.vlayoutB) self.optionsgroupC = QGroupBox("peak options") self.vlayoutC.addWidget(self.editcheckbox) self.vlayoutC.addWidget(self.savecheckbox) self.vlayoutC.addWidget(self.correctcheckbox) self.optionsgroupC.setLayout(self.vlayoutC) self.optionsgroupD = QGroupBox("select statistics for saving") self.vlayoutD.addWidget(self.periodcheckbox) self.vlayoutD.addWidget(self.ratecheckbox) self.vlayoutD.addWidget(self.tidalampcheckbox) self.optionsgroupD.setLayout(self.vlayoutD) self.vlayout1.addWidget(self.optionsgroupA) self.vlayout1.addWidget(self.optionsgroupB) self.vlayout1.addWidget(self.optionsgroupC) self.vlayout1.addWidget(self.optionsgroupD) self.hlayout0.addLayout(self.vlayout1) self.hlayout0.addWidget(self.splitter) self.hlayout0.setStretch(0, 1) self.hlayout0.setStretch(1, 15) self.vlayout0.addLayout(self.hlayout0) self.hlayout1.addWidget(self.navitools) self.vlayout0.addLayout(self.hlayout1) ############################################## # connect output widgets to external signals # ############################################## self._model.signal_changed.connect(self.plot_signal) self._model.marker_changed.connect(self.plot_marker) self._model.peaks_changed.connect(self.plot_peaks) self._model.period_changed.connect(self.plot_period) self._model.rate_changed.connect(self.plot_rate) self._model.tidalamp_changed.connect(self.plot_tidalamp) self._model.path_changed.connect(self.display_path) self._model.segment_changed.connect(self.plot_segment) self._model.status_changed.connect(self.display_status) self._model.progress_changed.connect(self.display_progress) self._model.model_reset.connect(self.reset_plot) ########### # methods # ########### def plot_signal(self, value): self.ax00.clear() self.ax00.relim() # reset navitools history self.navitools.update() self.line00 = self.ax00.plot(self._model.sec, value, zorder=1) self.ax00.set_xlabel("seconds", fontsize="large", fontweight="heavy") self.canvas0.draw() # print("plot_signal listening") # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_peaks(self, value): # self.scat is listed in ax.collections if self.ax00.collections: self.ax00.collections[0].remove() self.scat = self.ax00.scatter(self._model.sec[value], self._model.signal[value], c="m", zorder=2) self.canvas0.draw() # print("plot_peaks listening") # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_segment(self, value): # If an invalid signal has been selected reset the segmenter interface. if value is None: self.toggle_segmenter(1) return if self.ax00.patches: # self.segementspan is listed in ax.patches self.ax00.patches[0].remove() self.segmentspan = self.ax00.axvspan(value[0], value[1], color="m", alpha=0.25) self.canvas0.draw() self.confirmedit.setEnabled(True) # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_marker(self, value): self.ax10.clear() self.ax10.relim() self.line10 = self.ax10.plot(value[0], value[1]) self.canvas1.draw() # print("plot_marker listening") def plot_period(self, value): self.ax20.clear() self.ax20.relim() self.navitools.home() if self._model.savestats["period"]: self.line20 = self.ax20.plot(self._model.sec, value, c="m") else: self.line20 = self.ax20.plot(self._model.sec, value) self.ax20.set_ylim(bottom=min(value), top=max(value)) self.ax20.set_title("period", pad=0, fontweight="heavy") self.ax20.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_period listening") def plot_rate(self, value): self.ax21.clear() self.ax21.relim() self.navitools.home() if self._model.savestats["rate"]: self.line21 = self.ax21.plot(self._model.sec, value, c="m") else: self.line21 = self.ax21.plot(self._model.sec, value) self.ax21.set_ylim(bottom=min(value), top=max(value)) self.ax21.set_title("rate", pad=0, fontweight="heavy") self.ax21.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_rate listening") def plot_tidalamp(self, value): self.ax22.clear() self.ax22.relim() self.navitools.home() if self._model.savestats["tidalamp"]: self.line22 = self.ax22.plot(self._model.sec, value, c="m") else: self.line22 = self.ax22.plot(self._model.sec, value) self.ax22.set_ylim(bottom=min(value), top=max(value)) self.ax22.set_title("amplitude", pad=0, fontweight="heavy") self.ax22.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_tidalamp listening") def display_path(self, value): self.currentFile.setText(value) def display_status(self, status): # display status until new status is set self.statusBar.showMessage(status) def display_progress(self, value): # if value is 0, the progressbar indicates a busy state self.progressBar.setRange(0, value) def toggle_segmenter(self, value): if self._model.loaded: # Open segmenter when called from signalmenu or clear segmenter # upon selection of invalid segment. if value == 1: self.segmenter.setVisible(True) self.confirmedit.setEnabled(False) self.startedit.clear() self.endedit.clear() if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() # Close segmenter after segment has been confirmed. elif value == 0: self.segmenter.setVisible(False) if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() # Close segmenter after segmentation has been aborted (reset # segment). elif value == 2: self._model.set_segment( [0, 0]) # This will reset the model to None self.segmenter.setVisible(False) if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() def enable_segmentedit(self): # disable peak editing to avoid interference self.editcheckbox.setCheckState(0) if self.startedit.hasFocus(): self.segmentcursor = "start" elif self.endedit.hasFocus(): self.segmentcursor = "end" def get_xcursor(self, event): # event.button 1 corresponds to left mouse button if event.button == 1: # limit number of decimal places to two if self.segmentcursor == "start": self.startedit.selectAll() self.startedit.insert("{:.2f}".format(event.xdata)) elif self.segmentcursor == "end": self.endedit.selectAll() self.endedit.insert("{:.2f}".format(event.xdata)) # disable segment cursor again after value has been set self.segmentcursor = False def select_stats(self, event): """ select or deselect statistics to be saved; toggle boolean with xor operator ^=, toggle color with dictionary """ self._model.savestats[event] ^= True line = None if event == "period": if self.line20: line = self.line20[0] elif event == "rate": if self.line21: line = self.line21[0] elif event == "tidalamp": if self.line22: line = self.line22[0] if line: line.set_color(self.togglecolors[line.get_color()]) self.canvas2.draw() def toggle_options(self, event): if event in ["ECG", "PPG"]: self.tidalampcheckbox.setEnabled(False) self.tidalampcheckbox.setChecked(False) self.ax22.set_visible(False) self.canvas2.draw() elif event == "RESP": self.tidalampcheckbox.setEnabled(True) self.ax22.set_visible(True) self.canvas2.draw() elif event == "multiple files": self.editcheckbox.setEnabled(False) self.editcheckbox.setChecked(False) self.savecheckbox.setEnabled(True) self.correctcheckbox.setEnabled(True) self.markerchanmenu.setEnabled(False) elif event == "single file": self.editcheckbox.setEnabled(True) self.markerchanmenu.setEnabled(True) self.savecheckbox.setEnabled(False) self.savecheckbox.setChecked(False) self.correctcheckbox.setEnabled(False) self.correctcheckbox.setChecked(False) def reset_plot(self): self.ax00.clear() self.ax00.relim() self.line00 = None self.scat = None self.segmentspan = None self.ax10.clear() self.ax10.relim() self.line10 = None self.ax20.clear() self.ax20.relim() self.line20 = None self.ax21.clear() self.ax21.relim() self.line21 = None self.ax22.clear() self.ax22.relim() self.line22 = None self.canvas0.draw() self.canvas1.draw() self.canvas2.draw() self.navitools.update() self.currentFile.clear()
def __init__(self, parent=None): super(StockDialog, self).__init__(parent) self.setWindowTitle(self.tr("渐变效果")) self.startColor = Qt.green self.endColor = Qt.blue self.style = QGradient.LinearGradient self.spread = QGradient.PadSpread mainSplitter = QSplitter(Qt.Horizontal) mainSplitter.setOpaqueResize(True) frame = QFrame(mainSplitter) mainLayout = QGridLayout(frame) # mainLayout.setContentsMargins() # mainLayout.setMargin(10) # mainLayout.setSpacing(6) stack1 = QStackedWidget() stack1.setFrameStyle(QFrame.Panel | QFrame.Raised) mainSplitter1 = QSplitter(Qt.Horizontal) mainSplitter1.setOpaqueResize(True) self.area = PaintArea(self) stack1.addWidget(self.area) frame1 = QFrame(mainSplitter1) mainLayout1 = QVBoxLayout(frame1) # mainLayout1.setMargin(10) # mainLayout1.setSpacing(6) mainLayout1.addWidget(stack1) self.startPushButton = QPushButton(self.tr("start")) self.startPushButton.setAutoFillBackground(True) self.startPushButton.setPalette(QPalette(Qt.green)) self.endPushButton = QPushButton(self.tr("end")) self.endPushButton.setAutoFillBackground(True) self.endPushButton.setPalette(QPalette(Qt.blue)) self.startPushButton.clicked.connect(self.slotStartColor) self.endPushButton.clicked.connect(self.slotEndColor) # self.connect(self.startPushButton, SIGNAL("clicked()"), self.slotStartColor) # self.connect(self.endPushButton, SIGNAL("clicked()"), self.slotEndColor) self.grdientComboBox = QComboBox() self.grdientComboBox.addItem(self.tr("Linear Gradient"), QGradient.LinearGradient) self.grdientComboBox.addItem(self.tr("Radial Gradient"), QGradient.RadialGradient) self.grdientComboBox.addItem(self.tr("Conical Gradient"), QGradient.ConicalGradient) self.grdientComboBox.activated.connect(self.slotSetStyle) # self.connect(self.grdientComboBox, SIGNAL("activated(int)"), self.slotSetStyle) self.spreadComboBox = QComboBox() self.spreadComboBox.addItem(self.tr("PadSpread"), QGradient.PadSpread) self.spreadComboBox.addItem(self.tr("RepeatSpread"), QGradient.RepeatSpread) self.spreadComboBox.addItem(self.tr("ReflctSpread"), QGradient.ReflectSpread) self.spreadComboBox.activated.connect(self.slotSetSpread) # self.connect(self.spreadComboBox, SIGNAL("activated(int)"), self.slotSetSpread) mainLayout.addWidget(self.startPushButton, 1, 0) mainLayout.addWidget(self.endPushButton, 1, 1) mainLayout.addWidget(self.grdientComboBox, 1, 2) mainLayout.addWidget(self.spreadComboBox, 1, 3) layout = QGridLayout(self) layout.addWidget(mainSplitter1, 0, 0) layout.addWidget(mainSplitter, 1, 0) self.setLayout(layout)