From 5027b8df1990d1968cad0a53c6120541fd11f0f4 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 13 Jan 2025 02:21:56 +0100 Subject: [PATCH] Clean up warnings and deprecations in gui components --- novelwriter/common.py | 17 +- novelwriter/gui/doceditor.py | 175 ++++++++++--------- novelwriter/gui/dochighlight.py | 16 +- novelwriter/gui/docviewer.py | 95 +++++------ novelwriter/gui/docviewerpanel.py | 60 ++++--- novelwriter/gui/itemdetails.py | 11 +- novelwriter/gui/mainmenu.py | 272 +++++++++++++++--------------- novelwriter/gui/noveltree.py | 36 ++-- novelwriter/gui/outline.py | 69 ++++---- novelwriter/gui/projtree.py | 116 +++++++------ novelwriter/gui/search.py | 40 ++--- novelwriter/gui/sidebar.py | 4 +- novelwriter/gui/statusbar.py | 10 +- novelwriter/gui/theme.py | 11 +- 14 files changed, 458 insertions(+), 474 deletions(-) diff --git a/novelwriter/common.py b/novelwriter/common.py index 193f7c81..50ae5dfd 100644 --- a/novelwriter/common.py +++ b/novelwriter/common.py @@ -38,7 +38,8 @@ from urllib.parse import urljoin from urllib.request import pathname2url from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl -from PyQt6.QtGui import QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo +from PyQt6.QtGui import QAction, QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo +from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType @@ -461,6 +462,20 @@ def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable: return wrapper +def qtAddAction(parent: QWidget, label: str) -> QAction: + """Helper to add action to widget and always return the action.""" + action = QAction(label, parent) + parent.addAction(action) + return action + + +def qtAddMenu(parent: QMenuBar | QMenu, label: str) -> QMenu: + """Helper to add menu to menu and always return the menu.""" + menu = QMenu(label, parent) + parent.addMenu(menu) + return menu + + def encodeMimeHandles(mimeData: QMimeData, handles: list[str]) -> None: """Encode handles into a mime data object.""" mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles)) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index d67f514c..101859b8 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -52,7 +52,9 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import decodeMimeHandles, fontMatcher, minmax, qtLambda, transferCase +from novelwriter.common import ( + decodeMimeHandles, fontMatcher, minmax, qtAddAction, qtLambda, transferCase +) from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode from novelwriter.core.document import NWDocument from novelwriter.enum import ( @@ -168,7 +170,7 @@ class GuiDocEditor(QPlainTextEdit): self.customContextMenuRequested.connect(self._openContextMenu) # Editor Settings - self.setMinimumWidth(CONFIG.pxInt(300)) + self.setMinimumWidth(300) self.setAutoFillBackground(True) self.setFrameStyle(QFrame.Shape.NoFrame) self.setAcceptDrops(True) @@ -295,10 +297,11 @@ class GuiDocEditor(QPlainTextEdit): palette.setColor(QPalette.ColorRole.Text, syntax.text) self.setPalette(palette) - palette = self.viewport().palette() - palette.setColor(QPalette.ColorRole.Base, syntax.back) - palette.setColor(QPalette.ColorRole.Text, syntax.text) - self.viewport().setPalette(palette) + if viewport := self.viewport(): + palette = viewport.palette() + palette.setColor(QPalette.ColorRole.Base, syntax.back) + palette.setColor(QPalette.ColorRole.Text, syntax.text) + viewport.setPalette(palette) self.docHeader.matchColours() self.docFooter.matchColours() @@ -513,29 +516,27 @@ class GuiDocEditor(QPlainTextEdit): def cursorIsVisible(self) -> bool: """Check if the cursor is visible in the editor.""" - return ( - 0 < self.cursorRect().top() - and self.cursorRect().bottom() < self.viewport().height() - ) + viewport = self.viewport() + height = viewport.height() if viewport else 0 + return 0 < self.cursorRect().top() and self.cursorRect().bottom() < height def ensureCursorVisibleNoCentre(self) -> None: """Ensure cursor is visible, but don't force it to centre.""" - cT = self.cursorRect().top() - cB = self.cursorRect().bottom() - vH = self.viewport().height() - if cT < 0: - count = 0 - vBar = self.verticalScrollBar() - while self.cursorRect().top() < 0 and count < 100000: - vBar.setValue(vBar.value() - 1) - count += 1 - elif cB > vH: - count = 0 - vBar = self.verticalScrollBar() - while self.cursorRect().bottom() > vH and count < 100000: - vBar.setValue(vBar.value() + 1) - count += 1 - QApplication.processEvents() + if (viewport := self.viewport()) and (vBar := self.verticalScrollBar()): + cT = self.cursorRect().top() + cB = self.cursorRect().bottom() + vH = viewport.height() + if cT < 0: + count = 0 + while self.cursorRect().top() < 0 and count < 100000: + vBar.setValue(vBar.value() - 1) + count += 1 + elif cB > vH: + count = 0 + while self.cursorRect().bottom() > vH and count < 100000: + vBar.setValue(vBar.value() + 1) + count += 1 + QApplication.processEvents() return def updateDocMargins(self) -> None: @@ -547,10 +548,10 @@ class GuiDocEditor(QPlainTextEdit): wH = self.height() vBar = self.verticalScrollBar() - sW = vBar.width() if vBar.isVisible() else 0 + sW = vBar.width() if vBar and vBar.isVisible() else 0 hBar = self.horizontalScrollBar() - sH = hBar.height() if hBar.isVisible() else 0 + sH = hBar.height() if hBar and hBar.isVisible() else 0 tM = self._vpMargin if CONFIG.textWidth > 0 or SHARED.focusMode: @@ -959,10 +960,9 @@ class GuiDocEditor(QPlainTextEdit): kMod = event.modifiers() okMod = kMod in (QtModNone, QtModShift) okKey = event.key() not in self.MOVE_KEYS - if nPos != cPos and okMod and okKey: - mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height() - if cPos > mPos: - vBar = self.verticalScrollBar() + if nPos != cPos and okMod and okKey and (viewport := self.viewport()): + mPos = CONFIG.autoScrollPos*0.01 * viewport.height() + if cPos > mPos and (vBar := self.verticalScrollBar()): vBar.setValue(vBar.value() + (1 if nPos > cPos else -1)) else: super().keyPressEvent(event) @@ -971,7 +971,7 @@ class GuiDocEditor(QPlainTextEdit): def dragEnterEvent(self, event: QDragEnterEvent) -> None: """Overload drag enter event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): event.acceptProposedAction() else: super().dragEnterEvent(event) @@ -979,7 +979,7 @@ class GuiDocEditor(QPlainTextEdit): def dragMoveEvent(self, event: QDragMoveEvent) -> None: """Overload drag move event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): event.acceptProposedAction() else: super().dragMoveEvent(event) @@ -987,8 +987,8 @@ class GuiDocEditor(QPlainTextEdit): def dropEvent(self, event: QDropEvent) -> None: """Overload drop event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): - if handles := decodeMimeHandles(event.mimeData()): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): + if handles := decodeMimeHandles(data): if SHARED.project.tree.checkType(handles[0], nwItemType.FILE): self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True) else: @@ -1098,10 +1098,10 @@ class GuiDocEditor(QPlainTextEdit): # at unwanted times when other changes are made to the document cursor = self.textCursor() bPos = cursor.positionInBlock() - if bPos > 0: + if bPos > 0 and (viewport := self.viewport()): show = self._completer.updateText(text, bPos) point = self.cursorRect().bottomRight() - self._completer.move(self.viewport().mapToGlobal(point)) + self._completer.move(viewport.mapToGlobal(point)) self._completer.setVisible(show) else: self._completer.setVisible(False) @@ -1148,46 +1148,46 @@ class GuiDocEditor(QPlainTextEdit): ctxMenu = QMenu(self) ctxMenu.setObjectName("ContextMenu") if pBlock.userState() == BLOCK_TITLE: - action = ctxMenu.addAction(self.tr("Set as Document Name")) + action = qtAddAction(ctxMenu, self.tr("Set as Document Name")) action.triggered.connect(qtLambda(self._emitRenameItem, pBlock)) # URL (mData, mType) = self._qDocument.metaDataAtPos(pCursor.position()) if mData and mType == "url": - action = ctxMenu.addAction(self.tr("Open URL")) + action = qtAddAction(ctxMenu, self.tr("Open URL")) action.triggered.connect(qtLambda(SHARED.openWebsite, mData)) ctxMenu.addSeparator() # Follow status = self._processTag(cursor=pCursor, follow=False) if status == nwTrinary.POSITIVE: - action = ctxMenu.addAction(self.tr("Follow Tag")) + action = qtAddAction(ctxMenu, self.tr("Follow Tag")) action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, follow=True)) ctxMenu.addSeparator() elif status == nwTrinary.NEGATIVE: - action = ctxMenu.addAction(self.tr("Create Note for Tag")) + action = qtAddAction(ctxMenu, self.tr("Create Note for Tag")) action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, create=True)) ctxMenu.addSeparator() # Cut, Copy and Paste if uCursor.hasSelection(): - action = ctxMenu.addAction(self.tr("Cut")) + action = qtAddAction(ctxMenu, self.tr("Cut")) action.triggered.connect(qtLambda(self.docAction, nwDocAction.CUT)) - action = ctxMenu.addAction(self.tr("Copy")) + action = qtAddAction(ctxMenu, self.tr("Copy")) action.triggered.connect(qtLambda(self.docAction, nwDocAction.COPY)) - action = ctxMenu.addAction(self.tr("Paste")) + action = qtAddAction(ctxMenu, self.tr("Paste")) action.triggered.connect(qtLambda(self.docAction, nwDocAction.PASTE)) ctxMenu.addSeparator() # Selections - action = ctxMenu.addAction(self.tr("Select All")) + action = qtAddAction(ctxMenu, self.tr("Select All")) action.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL)) - action = ctxMenu.addAction(self.tr("Select Word")) + action = qtAddAction(ctxMenu, self.tr("Select Word")) action.triggered.connect(qtLambda( self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, pos, )) - action = ctxMenu.addAction(self.tr("Select Paragraph")) + action = qtAddAction(ctxMenu, self.tr("Select Paragraph")) action.triggered.connect(qtLambda( self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, pos )) @@ -1203,23 +1203,24 @@ class GuiDocEditor(QPlainTextEdit): sCursor.movePosition(QtMoveRight, QtKeepAnchor, cLen) if suggest: ctxMenu.addSeparator() - ctxMenu.addAction(self.tr("Spelling Suggestion(s)")) + qtAddAction(ctxMenu, self.tr("Spelling Suggestion(s)")) for option in suggest[:15]: - action = ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {option}") + action = qtAddAction(ctxMenu, f"{nwUnicode.U_ENDASH} {option}") action.triggered.connect(qtLambda(self._correctWord, sCursor, option)) else: trNone = self.tr("No Suggestions") - ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {trNone}") + qtAddAction(ctxMenu, f"{nwUnicode.U_ENDASH} {trNone}") ctxMenu.addSeparator() - action = ctxMenu.addAction(self.tr("Ignore Word")) + action = qtAddAction(ctxMenu, self.tr("Ignore Word")) action.triggered.connect(qtLambda(self._addWord, word, block, False)) - action = ctxMenu.addAction(self.tr("Add Word to Dictionary")) + action = qtAddAction(ctxMenu, self.tr("Add Word to Dictionary")) action.triggered.connect(qtLambda(self._addWord, word, block, True)) # Execute the context menu - ctxMenu.exec(self.viewport().mapToGlobal(pos)) - ctxMenu.deleteLater() + if viewport := self.viewport(): + ctxMenu.exec(viewport.mapToGlobal(pos)) + ctxMenu.deleteLater() return @@ -2007,8 +2008,8 @@ class GuiDocEditor(QPlainTextEdit): sPos = cPos for i in range(cPos - bPos): sPos = cPos - i - 1 - cOne = self._qDocument.characterAt(sPos) - cTwo = self._qDocument.characterAt(sPos - 1) + cOne = str(self._qDocument.characterAt(sPos)) + cTwo = str(self._qDocument.characterAt(sPos - 1)) if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()): sPos += 1 break @@ -2017,8 +2018,8 @@ class GuiDocEditor(QPlainTextEdit): ePos = cPos for i in range(bPos + bLen - cPos): ePos = cPos + i - cOne = self._qDocument.characterAt(ePos) - cTwo = self._qDocument.characterAt(ePos + 1) + cOne = str(self._qDocument.characterAt(ePos)) + cTwo = str(self._qDocument.characterAt(ePos + 1)) if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()): break @@ -2122,7 +2123,7 @@ class MetaCompleter(QMenu): for value in sorted(options): rep = value + suffix - action = self.addAction(value) + action = qtAddAction(self, value) action.triggered.connect(qtLambda(self._emitComplete, offset, length, rep)) return True @@ -2339,7 +2340,6 @@ class GuiDocToolBar(QWidget): logger.debug("Create: GuiDocToolBar") iSz = SHARED.theme.baseIconSize - cM = CONFIG.pxInt(4) self.setContentsMargins(0, 0, 0, 0) # General Buttons @@ -2412,7 +2412,7 @@ class GuiDocToolBar(QWidget): self.outerBox.addWidget(self.tbBoldMD) self.outerBox.addWidget(self.tbItalicMD) self.outerBox.addWidget(self.tbStrikeMD) - self.outerBox.addSpacing(cM) + self.outerBox.addSpacing(4) self.outerBox.addWidget(self.tbBold) self.outerBox.addWidget(self.tbItalic) self.outerBox.addWidget(self.tbStrike) @@ -2420,8 +2420,8 @@ class GuiDocToolBar(QWidget): self.outerBox.addWidget(self.tbMark) self.outerBox.addWidget(self.tbSuperscript) self.outerBox.addWidget(self.tbSubscript) - self.outerBox.setContentsMargins(cM, cM, cM, cM) - self.outerBox.setSpacing(cM) + self.outerBox.setContentsMargins(4, 4, 4, 4) + self.outerBox.setSpacing(4) self.setLayout(self.outerBox) self.updateTheme() @@ -2472,7 +2472,6 @@ class GuiDocEditSearch(QFrame): self.docEditor = docEditor iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(6) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) @@ -2498,7 +2497,7 @@ class GuiDocEditSearch(QFrame): self.searchOpt.setContentsMargins(0, 0, 0, 0) self.searchLabel = QLabel(self.tr("Search"), self) - self.searchLabel.setIndent(CONFIG.pxInt(6)) + self.searchLabel.setIndent(6) self.resultLabel = QLabel("?/?", self) @@ -2575,12 +2574,11 @@ class GuiDocEditSearch(QFrame): self.mainBox.setColumnStretch(3, 0) self.mainBox.setColumnStretch(4, 0) self.mainBox.setColumnStretch(5, 0) - self.mainBox.setSpacing(CONFIG.pxInt(2)) - self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.mainBox.setSpacing(2) + self.mainBox.setContentsMargins(6, 6, 6, 6) - boxWidth = CONFIG.pxInt(200) - self.searchBox.setFixedWidth(boxWidth) - self.replaceBox.setFixedWidth(boxWidth) + self.searchBox.setFixedWidth(200) + self.replaceBox.setFixedWidth(200) self.replaceBox.setVisible(False) self.replaceButton.setVisible(False) self.adjustSize() @@ -2848,7 +2846,6 @@ class GuiDocEditHeader(QWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(4) # Main Widget Settings self.setAutoFillBackground(True) @@ -2895,13 +2892,13 @@ class GuiDocEditHeader(QWidget): self.outerBox.addWidget(self.tbButton, 0) self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.searchButton, 0) - self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(4) self.outerBox.addWidget(self.itemTitle, 1) - self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(4) self.outerBox.addSpacing(iPx) self.outerBox.addWidget(self.minmaxButton, 0) self.outerBox.addWidget(self.closeButton, 0) - self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.outerBox.setContentsMargins(4, 4, 4, 4) self.outerBox.setSpacing(0) self.setLayout(self.outerBox) @@ -2912,7 +2909,7 @@ class GuiDocEditHeader(QWidget): # Fix Margins and Size # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) - self.setMinimumHeight(iPx + 2*mPx) + self.setMinimumHeight(iPx + 8) self.updateFont() self.updateTheme() @@ -2945,7 +2942,7 @@ class GuiDocEditHeader(QWidget): tStart = time() self.outlineMenu.clear() for number, text in data.items(): - action = self.outlineMenu.addAction(text) + action = qtAddAction(self.outlineMenu, text) action.triggered.connect(qtLambda(self._gotoBlock, number)) self._docOutline = data logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart)) @@ -3070,9 +3067,6 @@ class GuiDocEditFooter(QWidget): iPx = round(0.9*SHARED.theme.baseIconHeight) fPx = int(0.9*SHARED.theme.fontPixelSize) - mPx = CONFIG.pxInt(8) - bSp = CONFIG.pxInt(4) - hSp = CONFIG.pxInt(6) # Cached Translations self._trLineCount = self.tr("Line: {0} ({1})") @@ -3127,23 +3121,23 @@ class GuiDocEditFooter(QWidget): # Assemble Layout self.outerBox = QHBoxLayout() - self.outerBox.setSpacing(bSp) + self.outerBox.setSpacing(4) self.outerBox.addWidget(self.statusIcon) self.outerBox.addWidget(self.statusText) self.outerBox.addStretch(1) self.outerBox.addWidget(self.linesIcon) self.outerBox.addWidget(self.linesText) - self.outerBox.addSpacing(hSp) + self.outerBox.addSpacing(6) self.outerBox.addWidget(self.wordsIcon) self.outerBox.addWidget(self.wordsText) - self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.outerBox.setContentsMargins(8, 8, 8, 8) self.setLayout(self.outerBox) # Fix Margins and Size # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) - self.setMinimumHeight(fPx + 2*mPx) + self.setMinimumHeight(fPx + 16) # Fix the Colours self.updateFont() @@ -3226,12 +3220,13 @@ class GuiDocEditFooter(QWidget): def updateLineCount(self, cursor: QTextCursor) -> None: """Update the line and document position counter.""" - cPos = cursor.position() + 1 - cLine = cursor.blockNumber() + 1 - cCount = max(cursor.document().characterCount(), 1) - self.linesText.setText( - self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %") - ) + if document := cursor.document(): + cPos = cursor.position() + 1 + cLine = cursor.blockNumber() + 1 + cCount = max(document.characterCount(), 1) + self.linesText.setText( + self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %") + ) return def updateWordCount(self, wCount: int, selection: bool) -> None: diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index de9d9f27..5ee1ea7e 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -272,14 +272,14 @@ class GuiDocHighlighter(QSyntaxHighlighter): """Loop through all blocks and re-highlight those of a given content type. """ - qDoc = self.document() - nBlocks = qDoc.blockCount() - tStart = time() - for i in range(nBlocks): - block = qDoc.findBlockByNumber(i) - if block.userState() & cType > 0: - self.rehighlightBlock(block) - logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart))) + if document := self.document(): + nBlocks = document.blockCount() + tStart = time() + for i in range(nBlocks): + block = document.findBlockByNumber(i) + if block.userState() & cType > 0: + self.rehighlightBlock(block) + logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart))) return ## diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index e813a5c4..0be61bf4 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -32,8 +32,8 @@ from enum import Enum from PyQt6.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot from PyQt6.QtGui import ( - QAction, QCursor, QDesktopServices, QDragEnterEvent, QDragMoveEvent, - QDropEvent, QMouseEvent, QPalette, QResizeEvent, QTextCursor + QCursor, QDesktopServices, QDragEnterEvent, QDragMoveEvent, QDropEvent, + QMouseEvent, QPalette, QResizeEvent, QTextCursor ) from PyQt6.QtWidgets import ( QApplication, QFrame, QHBoxLayout, QMenu, QTextBrowser, QToolButton, @@ -41,7 +41,7 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import decodeMimeHandles, qtLambda +from novelwriter.common import decodeMimeHandles, qtAddAction, qtLambda from novelwriter.constants import nwConst, nwStyles, nwUnicode from novelwriter.enum import nwChange, nwDocAction, nwDocMode, nwItemType from novelwriter.error import logException @@ -79,7 +79,7 @@ class GuiDocViewer(QTextBrowser): self._docTheme = TextDocumentTheme() # Settings - self.setMinimumWidth(CONFIG.pxInt(300)) + self.setMinimumWidth(300) self.setAutoFillBackground(True) self.setOpenLinks(False) self.setOpenExternalLinks(False) @@ -124,8 +124,7 @@ class GuiDocViewer(QTextBrowser): @property def scrollPosition(self) -> int: """Return the scrollbar position.""" - vBar = self.verticalScrollBar() - if vBar.isVisible(): + if (vBar := self.verticalScrollBar()) and vBar.isVisible(): return vBar.value() return 0 @@ -163,12 +162,13 @@ class GuiDocViewer(QTextBrowser): palette.setColor(QPalette.ColorRole.Text, syntax.text) self.setPalette(palette) - palette = self.viewport().palette() - palette.setColor(QPalette.ColorRole.Base, syntax.back) - palette.setColor(QPalette.ColorRole.Text, syntax.text) - self.viewport().setPalette(palette) - self.docHeader.matchColours() - self.docFooter.matchColours() + if viewport := self.viewport(): + palette = viewport.palette() + palette.setColor(QPalette.ColorRole.Base, syntax.back) + palette.setColor(QPalette.ColorRole.Text, syntax.text) + viewport.setPalette(palette) + self.docHeader.matchColours() + self.docFooter.matchColours() # Update theme colours self._docTheme.text = syntax.text @@ -186,7 +186,8 @@ class GuiDocViewer(QTextBrowser): self._docTheme.altdialog = syntax.dialA # Set default text margins - self.document().setDocumentMargin(0) + if document := self.document(): + document.setDocumentMargin(0) # Scroll bars if CONFIG.hideVScroll: @@ -217,7 +218,9 @@ class GuiDocViewer(QTextBrowser): logger.debug("Generating preview for item '%s'", tHandle) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) - sPos = self.verticalScrollBar().value() + vBar = self.verticalScrollBar() + sPos = vBar.value() if vBar else 0 + qDoc = ToQTextDocument(SHARED.project) qDoc.setJustify(CONFIG.doJustify) qDoc.setDialogHighlight(True) @@ -252,9 +255,9 @@ class GuiDocViewer(QTextBrowser): self.setDocument(qDoc.document) self.setTabStopDistance(CONFIG.tabWidth) - if self._docHandle == tHandle: + if self._docHandle == tHandle and vBar: # This is a refresh, so we set the scrollbar back to where it was - self.verticalScrollBar().setValue(sPos) + vBar.setValue(sPos) self._docHandle = tHandle SHARED.project.data.setLastHandle(tHandle, "viewer") @@ -311,10 +314,10 @@ class GuiDocViewer(QTextBrowser): cM = CONFIG.textMargin vBar = self.verticalScrollBar() - sW = vBar.width() if vBar.isVisible() else 0 + sW = vBar.width() if vBar and vBar.isVisible() else 0 hBar = self.horizontalScrollBar() - sH = hBar.height() if hBar.isVisible() else 0 + sH = hBar.height() if hBar and hBar.isVisible() else 0 tM = cM if CONFIG.textWidth > 0: @@ -339,8 +342,7 @@ class GuiDocViewer(QTextBrowser): def setScrollPosition(self, pos: int) -> None: """Set the scrollbar position.""" - vBar = self.verticalScrollBar() - if vBar.isVisible(): + if (vBar := self.verticalScrollBar()) and vBar.isVisible(): vBar.setValue(pos) return @@ -402,31 +404,27 @@ class GuiDocViewer(QTextBrowser): ctxMenu = QMenu(self) if userSelection: - mnuCopy = QAction(self.tr("Copy"), ctxMenu) - mnuCopy.triggered.connect(qtLambda(self.docAction, nwDocAction.COPY)) - ctxMenu.addAction(mnuCopy) - + action = qtAddAction(ctxMenu, self.tr("Copy")) + action.triggered.connect(qtLambda(self.docAction, nwDocAction.COPY)) ctxMenu.addSeparator() - mnuSelAll = QAction(self.tr("Select All"), ctxMenu) - mnuSelAll.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL)) - ctxMenu.addAction(mnuSelAll) + action = qtAddAction(ctxMenu, self.tr("Select All")) + action.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL)) - mnuSelWord = QAction(self.tr("Select Word"), ctxMenu) - mnuSelWord.triggered.connect(qtLambda( + action = qtAddAction(ctxMenu, self.tr("Select Word")) + action.triggered.connect(qtLambda( self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, point )) - ctxMenu.addAction(mnuSelWord) - mnuSelPara = QAction(self.tr("Select Paragraph"), ctxMenu) - mnuSelPara.triggered.connect(qtLambda( + action = qtAddAction(ctxMenu, self.tr("Select Paragraph")) + action.triggered.connect(qtLambda( self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, point )) - ctxMenu.addAction(mnuSelPara) # Open the context menu - ctxMenu.exec(self.viewport().mapToGlobal(point)) - ctxMenu.deleteLater() + if viewport := self.viewport(): + ctxMenu.exec(viewport.mapToGlobal(point)) + ctxMenu.deleteLater() return @@ -452,7 +450,7 @@ class GuiDocViewer(QTextBrowser): def dragEnterEvent(self, event: QDragEnterEvent) -> None: """Overload drag enter event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): event.acceptProposedAction() else: super().dragEnterEvent(event) @@ -460,7 +458,7 @@ class GuiDocViewer(QTextBrowser): def dragMoveEvent(self, event: QDragMoveEvent) -> None: """Overload drag move event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): event.acceptProposedAction() else: super().dragMoveEvent(event) @@ -468,8 +466,8 @@ class GuiDocViewer(QTextBrowser): def dropEvent(self, event: QDropEvent) -> None: """Overload drop event to handle dragged items.""" - if event.mimeData().hasFormat(nwConst.MIME_HANDLE): - if handles := decodeMimeHandles(event.mimeData()): + if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE): + if handles := decodeMimeHandles(data): if SHARED.project.tree.checkType(handles[0], nwItemType.FILE): self.openDocumentRequest.emit(handles[0], nwDocMode.VIEW, "", True) else: @@ -640,7 +638,6 @@ class GuiDocViewHeader(QWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(4) # Main Widget Settings self.setAutoFillBackground(True) @@ -692,9 +689,9 @@ class GuiDocViewHeader(QWidget): self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.backButton, 0) self.outerBox.addWidget(self.forwardButton, 0) - self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(4) self.outerBox.addWidget(self.itemTitle, 1) - self.outerBox.addSpacing(mPx) + self.outerBox.addSpacing(4) self.outerBox.addWidget(self.editButton, 0) self.outerBox.addWidget(self.refreshButton, 0) self.outerBox.addWidget(self.closeButton, 0) @@ -705,8 +702,8 @@ class GuiDocViewHeader(QWidget): # Fix Margins and Size # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) - self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) - self.setMinimumHeight(iPx + 2*mPx) + self.outerBox.setContentsMargins(4, 4, 4, 4) + self.setMinimumHeight(iPx + 8) self.updateFont() self.updateTheme() @@ -747,7 +744,7 @@ class GuiDocViewHeader(QWidget): minLevel = min(minLevel, level) for title, text, level in entries[:30]: indent = " "*(level - minLevel) - action = self.outlineMenu.addAction(f"{indent}{text}") + action = qtAddAction(self.outlineMenu, f"{indent}{text}") action.triggered.connect( lambda _, title=title: self.docViewer.navigateTo(f"#{tHandle}:{title}") ) @@ -885,8 +882,6 @@ class GuiDocViewFooter(QWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - hSp = CONFIG.pxInt(4) - mPx = CONFIG.pxInt(4) # Main Widget Settings self.setContentsMargins(0, 0, 0, 0) @@ -923,14 +918,14 @@ class GuiDocViewFooter(QWidget): self.outerBox.addStretch(1) self.outerBox.addWidget(self.showComments, 0) self.outerBox.addWidget(self.showSynopsis, 0) - self.outerBox.setSpacing(hSp) + self.outerBox.setSpacing(4) self.setLayout(self.outerBox) # Fix Margins and Size # This is needed for high DPI systems. See issue #499. self.setContentsMargins(0, 0, 0, 0) - self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) - self.setMinimumHeight(iPx + 2*mPx) + self.outerBox.setContentsMargins(4, 4, 4, 4) + self.setMinimumHeight(iPx + 8) self.updateFont() self.updateTheme() diff --git a/novelwriter/gui/docviewerpanel.py b/novelwriter/gui/docviewerpanel.py index 91723b91..54284d10 100644 --- a/novelwriter/gui/docviewerpanel.py +++ b/novelwriter/gui/docviewerpanel.py @@ -33,8 +33,8 @@ from PyQt6.QtWidgets import ( QTreeWidgetItem, QVBoxLayout, QWidget ) -from novelwriter import CONFIG, SHARED -from novelwriter.common import checkInt +from novelwriter import SHARED +from novelwriter.common import checkInt, qtAddAction from novelwriter.constants import nwLabels, nwLists, nwStyles, trConst from novelwriter.core.index import IndexHeading, IndexItem from novelwriter.enum import nwChange, nwDocMode, nwItemClass @@ -63,7 +63,7 @@ class GuiDocViewerPanel(QWidget): self.optsMenu = QMenu(self) - self.aInactive = self.optsMenu.addAction(self.tr("Hide Inactive Tags")) + self.aInactive = qtAddAction(self.optsMenu, self.tr("Hide Inactive Tags")) self.aInactive.setCheckable(True) self.aInactive.toggled.connect(self._toggleHideInactive) @@ -248,7 +248,6 @@ class _ViewPanelBackRefs(QTreeWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - cMg = CONFIG.pxInt(6) self.setHeaderLabels([self.tr("Document"), "", "", self.tr("First Heading")]) self.setIndentation(0) @@ -257,16 +256,16 @@ class _ViewPanelBackRefs(QTreeWidget): self.setFrameStyle(QFrame.Shape.NoFrame) # Set Header Sizes - treeHeader = self.header() - treeHeader.setStretchLastSection(True) - treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627 - treeHeader.setSectionResizeMode(self.C_DOC, QtHeaderToContents) - treeHeader.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) - treeHeader.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) - treeHeader.setSectionResizeMode(self.C_TITLE, QtHeaderToContents) - treeHeader.resizeSection(self.C_EDIT, iPx + cMg) - treeHeader.resizeSection(self.C_VIEW, iPx + cMg) - treeHeader.setSectionsMovable(False) + if header := self.header(): + header.setStretchLastSection(True) + header.setMinimumSectionSize(iPx + 6) # See Issue #1627 + header.setSectionResizeMode(self.C_DOC, QtHeaderToContents) + header.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) + header.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) + header.setSectionResizeMode(self.C_TITLE, QtHeaderToContents) + header.resizeSection(self.C_EDIT, iPx + 6) + header.resizeSection(self.C_VIEW, iPx + 6) + header.setSectionsMovable(False) # Cache Icons Locally self._editIcon = SHARED.theme.getIcon("edit", "green") @@ -385,7 +384,6 @@ class _ViewPanelKeyWords(QTreeWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - cMg = CONFIG.pxInt(6) self.setHeaderLabels([ self.tr("Tag"), "", "", self.tr("Importance"), self.tr("Document"), @@ -401,14 +399,14 @@ class _ViewPanelKeyWords(QTreeWidget): self.sortByColumn(self.C_NAME, Qt.SortOrder.AscendingOrder) # Set Header Sizes - treeHeader = self.header() - treeHeader.setStretchLastSection(True) - treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627 - treeHeader.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) - treeHeader.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) - treeHeader.resizeSection(self.C_EDIT, iPx + cMg) - treeHeader.resizeSection(self.C_VIEW, iPx + cMg) - treeHeader.setSectionsMovable(False) + if header := self.header(): + header.setStretchLastSection(True) + header.setMinimumSectionSize(iPx + 6) # See Issue #1627 + header.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) + header.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) + header.resizeSection(self.C_EDIT, iPx + 6) + header.resizeSection(self.C_VIEW, iPx + 6) + header.setSectionsMovable(False) # Cache Icons Locally self.updateTheme() @@ -482,19 +480,19 @@ class _ViewPanelKeyWords(QTreeWidget): def setColumnWidths(self, widths: list[int]) -> None: """Set the column widths.""" if isinstance(widths, list) and len(widths) >= 4: - self.setColumnWidth(self.C_NAME, CONFIG.pxInt(checkInt(widths[0], 100))) - self.setColumnWidth(self.C_IMPORT, CONFIG.pxInt(checkInt(widths[1], 100))) - self.setColumnWidth(self.C_DOC, CONFIG.pxInt(checkInt(widths[2], 100))) - self.setColumnWidth(self.C_TITLE, CONFIG.pxInt(checkInt(widths[3], 100))) + self.setColumnWidth(self.C_NAME, checkInt(widths[0], 100)) + self.setColumnWidth(self.C_IMPORT, checkInt(widths[1], 100)) + self.setColumnWidth(self.C_DOC, checkInt(widths[2], 100)) + self.setColumnWidth(self.C_TITLE, checkInt(widths[3], 100)) return def getColumnWidths(self) -> list[int]: """Get the widths of the user-adjustable columns.""" return [ - CONFIG.rpxInt(self.columnWidth(self.C_NAME)), - CONFIG.rpxInt(self.columnWidth(self.C_IMPORT)), - CONFIG.rpxInt(self.columnWidth(self.C_DOC)), - CONFIG.rpxInt(self.columnWidth(self.C_TITLE)), + self.columnWidth(self.C_NAME), + self.columnWidth(self.C_IMPORT), + self.columnWidth(self.C_DOC), + self.columnWidth(self.C_TITLE), ] ## diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py index 8cc264b7..bb33b65d 100644 --- a/novelwriter/gui/itemdetails.py +++ b/novelwriter/gui/itemdetails.py @@ -30,7 +30,7 @@ from enum import Enum from PyQt6.QtCore import pyqtSlot from PyQt6.QtWidgets import QGridLayout, QLabel, QWidget -from novelwriter import CONFIG, SHARED +from novelwriter import SHARED from novelwriter.common import elide from novelwriter.constants import nwLabels, nwStats, trConst from novelwriter.enum import nwChange @@ -53,9 +53,6 @@ class GuiItemDetails(QWidget): self._handle = None # Sizes - hSp = CONFIG.pxInt(6) - vSp = CONFIG.pxInt(1) - mPx = CONFIG.pxInt(6) fPt = SHARED.theme.fontPointSize fntLabel = self.font() @@ -176,9 +173,9 @@ class GuiItemDetails(QWidget): self.mainBox.setColumnStretch(3, 0) self.mainBox.setColumnStretch(4, 0) - self.mainBox.setHorizontalSpacing(hSp) - self.mainBox.setVerticalSpacing(vSp) - self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx) + self.mainBox.setHorizontalSpacing(6) + self.mainBox.setVerticalSpacing(1) + self.mainBox.setContentsMargins(6, 6, 6, 6) self.setLayout(self.mainBox) diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py index f477217e..9cca259d 100644 --- a/novelwriter/gui/mainmenu.py +++ b/novelwriter/gui/mainmenu.py @@ -33,7 +33,7 @@ from PyQt6.QtGui import QAction from PyQt6.QtWidgets import QMenuBar from novelwriter import CONFIG, SHARED -from novelwriter.common import openExternalPath, qtLambda +from novelwriter.common import openExternalPath, qtAddAction, qtAddMenu, qtLambda from novelwriter.constants import ( nwConst, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode, trConst @@ -128,21 +128,21 @@ class GuiMainMenu(QMenuBar): def _buildProjectMenu(self) -> None: """Assemble the Project menu.""" # Project - self.projMenu = self.addMenu(self.tr("&Project")) + self.projMenu = qtAddMenu(self, self.tr("&Project")) # Project > Create or Open Project - self.aOpenProject = self.projMenu.addAction(self.tr("Create or Open Project")) + self.aOpenProject = qtAddAction(self.projMenu, self.tr("Create or Open Project")) self.aOpenProject.setShortcut("Ctrl+Shift+O") self.aOpenProject.triggered.connect(self.mainGui.showWelcomeDialog) # Project > Save Project - self.aSaveProject = self.projMenu.addAction(self.tr("Save Project")) + self.aSaveProject = qtAddAction(self.projMenu, self.tr("Save Project")) self.aSaveProject.setShortcut("Ctrl+Shift+S") self.aSaveProject.triggered.connect(qtLambda(self.mainGui.saveProject)) self.mainGui.addAction(self.aSaveProject) # Project > Close Project - self.aCloseProject = self.projMenu.addAction(self.tr("Close Project")) + self.aCloseProject = qtAddAction(self.projMenu, self.tr("Close Project")) self.aCloseProject.setShortcut("Ctrl+Shift+W") self.aCloseProject.triggered.connect(qtLambda(self.mainGui.closeProject, False)) @@ -150,12 +150,12 @@ class GuiMainMenu(QMenuBar): self.projMenu.addSeparator() # Project > Project Settings - self.aProjectSettings = self.projMenu.addAction(self.tr("Project Settings")) + self.aProjectSettings = qtAddAction(self.projMenu, self.tr("Project Settings")) self.aProjectSettings.setShortcut("Ctrl+Shift+,") self.aProjectSettings.triggered.connect(self.mainGui.showProjectSettingsDialog) # Project > Novel Details - self.aNovelDetails = self.projMenu.addAction(self.tr("Novel Details")) + self.aNovelDetails = qtAddAction(self.projMenu, self.tr("Novel Details")) self.aNovelDetails.setShortcut("Shift+F6") self.aNovelDetails.triggered.connect(self.mainGui.showNovelDetailsDialog) @@ -163,16 +163,16 @@ class GuiMainMenu(QMenuBar): self.projMenu.addSeparator() # Project > Edit - self.aRenameItem = self.projMenu.addAction(self.tr("Rename Item")) + self.aRenameItem = qtAddAction(self.projMenu, self.tr("Rename Item")) self.aRenameItem.setShortcut("F2") # Project > Delete - self.aDeleteItem = self.projMenu.addAction(self.tr("Delete Item")) + self.aDeleteItem = qtAddAction(self.projMenu, self.tr("Delete Item")) self.aDeleteItem.setShortcut("Del") self.aDeleteItem.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) # Project > Empty Trash - self.aEmptyTrash = self.projMenu.addAction(self.tr("Empty Trash")) + self.aEmptyTrash = qtAddAction(self.projMenu, self.tr("Empty Trash")) self.mainGui.projView.connectMenuActions( self.aRenameItem, self.aDeleteItem, self.aEmptyTrash @@ -182,7 +182,7 @@ class GuiMainMenu(QMenuBar): self.projMenu.addSeparator() # Project > Exit - self.aExitNW = self.projMenu.addAction(self.tr("Exit")) + self.aExitNW = qtAddAction(self.projMenu, self.tr("Exit")) self.aExitNW.setShortcut("Ctrl+Q") self.aExitNW.setMenuRole(QAction.MenuRole.QuitRole) self.aExitNW.triggered.connect(qtLambda(self.mainGui.closeMain)) @@ -193,21 +193,21 @@ class GuiMainMenu(QMenuBar): def _buildDocumentMenu(self) -> None: """Assemble the Document menu.""" # Document - self.docuMenu = self.addMenu(self.tr("&Document")) + self.docuMenu = qtAddMenu(self, self.tr("&Document")) # Document > Open - self.aOpenDoc = self.docuMenu.addAction(self.tr("Open Document")) + self.aOpenDoc = qtAddAction(self.docuMenu, self.tr("Open Document")) self.aOpenDoc.setShortcut("Ctrl+O") self.aOpenDoc.triggered.connect(self.mainGui.openSelectedItem) # Document > Save - self.aSaveDoc = self.docuMenu.addAction(self.tr("Save Document")) + self.aSaveDoc = qtAddAction(self.docuMenu, self.tr("Save Document")) self.aSaveDoc.setShortcut("Ctrl+S") self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument) self.mainGui.addAction(self.aSaveDoc) # Document > Close - self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document")) + self.aCloseDoc = qtAddAction(self.docuMenu, self.tr("Close Document")) self.aCloseDoc.setShortcut("Ctrl+W") self.aCloseDoc.triggered.connect(self.mainGui.closeDocEditor) self.mainGui.addAction(self.aCloseDoc) @@ -216,12 +216,12 @@ class GuiMainMenu(QMenuBar): self.docuMenu.addSeparator() # Document > Preview - self.aViewDoc = self.docuMenu.addAction(self.tr("View Document")) + self.aViewDoc = qtAddAction(self.docuMenu, self.tr("View Document")) self.aViewDoc.setShortcut("Ctrl+R") self.aViewDoc.triggered.connect(qtLambda(self.mainGui.viewDocument, None)) # Document > Close Preview - self.aCloseView = self.docuMenu.addAction(self.tr("Close Document View")) + self.aCloseView = qtAddAction(self.docuMenu, self.tr("Close Document View")) self.aCloseView.setShortcut("Ctrl+Shift+R") self.aCloseView.triggered.connect(self.mainGui.closeDocViewer) @@ -229,11 +229,11 @@ class GuiMainMenu(QMenuBar): self.docuMenu.addSeparator() # Document > Show File Details - self.aFileDetails = self.docuMenu.addAction(self.tr("Show File Details")) + self.aFileDetails = qtAddAction(self.docuMenu, self.tr("Show File Details")) self.aFileDetails.triggered.connect(qtLambda(self.mainGui.docEditor.revealLocation)) # Document > Import From File - self.aImportFile = self.docuMenu.addAction(self.tr("Import Text from File")) + self.aImportFile = qtAddAction(self.docuMenu, self.tr("Import Text from File")) self.aImportFile.triggered.connect(qtLambda(self.mainGui.importDocument)) return @@ -241,10 +241,10 @@ class GuiMainMenu(QMenuBar): def _buildEditMenu(self) -> None: """Assemble the Edit menu.""" # Edit - self.editMenu = self.addMenu(self.tr("&Edit")) + self.editMenu = qtAddMenu(self, self.tr("&Edit")) # Edit > Undo - self.aEditUndo = self.editMenu.addAction(self.tr("Undo")) + self.aEditUndo = qtAddAction(self.editMenu, self.tr("Undo")) self.aEditUndo.setShortcut("Ctrl+Z") self.aEditUndo.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.UNDO) @@ -252,7 +252,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aEditUndo) # Edit > Redo - self.aEditRedo = self.editMenu.addAction(self.tr("Redo")) + self.aEditRedo = qtAddAction(self.editMenu, self.tr("Redo")) self.aEditRedo.setShortcut("Ctrl+Y") self.aEditRedo.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.REDO) @@ -263,7 +263,7 @@ class GuiMainMenu(QMenuBar): self.editMenu.addSeparator() # Edit > Cut - self.aEditCut = self.editMenu.addAction(self.tr("Cut")) + self.aEditCut = qtAddAction(self.editMenu, self.tr("Cut")) self.aEditCut.setShortcut("Ctrl+X") self.aEditCut.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.CUT) @@ -271,7 +271,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aEditCut) # Edit > Copy - self.aEditCopy = self.editMenu.addAction(self.tr("Copy")) + self.aEditCopy = qtAddAction(self.editMenu, self.tr("Copy")) self.aEditCopy.setShortcut("Ctrl+C") self.aEditCopy.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.COPY) @@ -279,7 +279,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aEditCopy) # Edit > Paste - self.aEditPaste = self.editMenu.addAction(self.tr("Paste")) + self.aEditPaste = qtAddAction(self.editMenu, self.tr("Paste")) self.aEditPaste.setShortcut("Ctrl+V") self.aEditPaste.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.PASTE) @@ -290,7 +290,7 @@ class GuiMainMenu(QMenuBar): self.editMenu.addSeparator() # Edit > Select All - self.aSelectAll = self.editMenu.addAction(self.tr("Select All")) + self.aSelectAll = qtAddAction(self.editMenu, self.tr("Select All")) self.aSelectAll.setShortcut("Ctrl+A") self.aSelectAll.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL) @@ -298,7 +298,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aSelectAll) # Edit > Select Paragraph - self.aSelectPar = self.editMenu.addAction(self.tr("Select Paragraph")) + self.aSelectPar = qtAddAction(self.editMenu, self.tr("Select Paragraph")) self.aSelectPar.setShortcut("Ctrl+Shift+A") self.aSelectPar.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA) @@ -310,24 +310,24 @@ class GuiMainMenu(QMenuBar): def _buildViewMenu(self) -> None: """Assemble the View menu.""" # View - self.viewMenu = self.addMenu(self.tr("&View")) + self.viewMenu = qtAddMenu(self, self.tr("&View")) # View > TreeView - self.aFocusTree = self.viewMenu.addAction(self.tr("Go to Tree View")) + self.aFocusTree = qtAddAction(self.viewMenu, self.tr("Go to Tree View")) self.aFocusTree.setShortcut("Ctrl+T") self.aFocusTree.triggered.connect( lambda: self.requestFocusChange.emit(nwFocus.TREE) ) # View > Document Editor - self.aFocusDocument = self.viewMenu.addAction(self.tr("Go to Document")) + self.aFocusDocument = qtAddAction(self.viewMenu, self.tr("Go to Document")) self.aFocusDocument.setShortcut("Ctrl+E") self.aFocusDocument.triggered.connect( lambda: self.requestFocusChange.emit(nwFocus.DOCUMENT) ) # View > Outline - self.aFocusOutline = self.viewMenu.addAction(self.tr("Go to Outline")) + self.aFocusOutline = qtAddAction(self.viewMenu, self.tr("Go to Outline")) self.aFocusOutline.setShortcut("Ctrl+Shift+T") self.aFocusOutline.triggered.connect( lambda: self.requestFocusChange.emit(nwFocus.OUTLINE) @@ -337,14 +337,14 @@ class GuiMainMenu(QMenuBar): self.viewMenu.addSeparator() # View > Go Backward - self.aViewPrev = self.viewMenu.addAction(self.tr("Navigate Backward")) + self.aViewPrev = qtAddAction(self.viewMenu, self.tr("Navigate Backward")) self.aViewPrev.setShortcut("Alt+Left") self.aViewPrev.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) self.aViewPrev.triggered.connect(self.mainGui.docViewer.navBackward) self.mainGui.docViewer.addAction(self.aViewPrev) # View > Go Forward - self.aViewNext = self.viewMenu.addAction(self.tr("Navigate Forward")) + self.aViewNext = qtAddAction(self.viewMenu, self.tr("Navigate Forward")) self.aViewNext.setShortcut("Alt+Right") self.aViewNext.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) self.aViewNext.triggered.connect(self.mainGui.docViewer.navForward) @@ -354,13 +354,13 @@ class GuiMainMenu(QMenuBar): self.viewMenu.addSeparator() # View > Focus Mode - self.aFocusMode = self.viewMenu.addAction(self.tr("Focus Mode")) + self.aFocusMode = qtAddAction(self.viewMenu, self.tr("Focus Mode")) self.aFocusMode.setShortcut("F8") self.aFocusMode.triggered.connect(self.mainGui.toggleFocusMode) self.mainGui.addAction(self.aFocusMode) # View > Toggle Full Screen - self.aFullScreen = self.viewMenu.addAction(self.tr("Full Screen Mode")) + self.aFullScreen = qtAddAction(self.viewMenu, self.tr("Full Screen Mode")) self.aFullScreen.setShortcut("F11") self.aFullScreen.triggered.connect(self.mainGui.toggleFullScreenMode) self.mainGui.addAction(self.aFullScreen) @@ -370,13 +370,13 @@ class GuiMainMenu(QMenuBar): def _buildInsertMenu(self) -> None: """Assemble the Insert menu.""" # Insert - self.insMenu = self.addMenu(self.tr("&Insert")) + self.insMenu = qtAddMenu(self, self.tr("&Insert")) # Insert > Dashes and Dots - self.mInsDashes = self.insMenu.addMenu(self.tr("Dashes")) + self.mInsDashes = qtAddMenu(self.insMenu, self.tr("Dashes")) # Insert > Short Dash - self.aInsENDash = self.mInsDashes.addAction(self.tr("Short Dash")) + self.aInsENDash = qtAddAction(self.mInsDashes, self.tr("Short Dash")) self.aInsENDash.setShortcut("Ctrl+K, -") self.aInsENDash.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_ENDASH) @@ -384,7 +384,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsENDash) # Insert > Long Dash - self.aInsEMDash = self.mInsDashes.addAction(self.tr("Long Dash")) + self.aInsEMDash = qtAddAction(self.mInsDashes, self.tr("Long Dash")) self.aInsEMDash.setShortcut("Ctrl+K, _") self.aInsEMDash.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_EMDASH) @@ -392,7 +392,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsEMDash) # Insert > Long Dash - self.aInsHorBar = self.mInsDashes.addAction(self.tr("Horizontal Bar")) + self.aInsHorBar = qtAddAction(self.mInsDashes, self.tr("Horizontal Bar")) self.aInsHorBar.setShortcut("Ctrl+K, Ctrl+_") self.aInsHorBar.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_HBAR) @@ -400,7 +400,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsHorBar) # Insert > Figure Dash - self.aInsFigDash = self.mInsDashes.addAction(self.tr("Figure Dash")) + self.aInsFigDash = qtAddAction(self.mInsDashes, self.tr("Figure Dash")) self.aInsFigDash.setShortcut("Ctrl+K, ~") self.aInsFigDash.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_FGDASH) @@ -408,10 +408,10 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsFigDash) # Insert > Quote Marks - self.mInsQuotes = self.insMenu.addMenu(self.tr("Quote Marks")) + self.mInsQuotes = qtAddMenu(self.insMenu, self.tr("Quote Marks")) # Insert > Left Single Quote - self.aInsQuoteLS = self.mInsQuotes.addAction(self.tr("Left Single Quote")) + self.aInsQuoteLS = qtAddAction(self.mInsQuotes, self.tr("Left Single Quote")) self.aInsQuoteLS.setShortcut("Ctrl+K, 1") self.aInsQuoteLS.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LS) @@ -419,7 +419,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsQuoteLS) # Insert > Right Single Quote - self.aInsQuoteRS = self.mInsQuotes.addAction(self.tr("Right Single Quote")) + self.aInsQuoteRS = qtAddAction(self.mInsQuotes, self.tr("Right Single Quote")) self.aInsQuoteRS.setShortcut("Ctrl+K, 2") self.aInsQuoteRS.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RS) @@ -427,7 +427,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsQuoteRS) # Insert > Left Double Quote - self.aInsQuoteLD = self.mInsQuotes.addAction(self.tr("Left Double Quote")) + self.aInsQuoteLD = qtAddAction(self.mInsQuotes, self.tr("Left Double Quote")) self.aInsQuoteLD.setShortcut("Ctrl+K, 3") self.aInsQuoteLD.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LD) @@ -435,7 +435,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsQuoteLD) # Insert > Right Double Quote - self.aInsQuoteRD = self.mInsQuotes.addAction(self.tr("Right Double Quote")) + self.aInsQuoteRD = qtAddAction(self.mInsQuotes, self.tr("Right Double Quote")) self.aInsQuoteRD.setShortcut("Ctrl+K, 4") self.aInsQuoteRD.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RD) @@ -443,7 +443,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsQuoteRD) # Insert > Alternative Apostrophe - self.aInsMSApos = self.mInsQuotes.addAction(self.tr("Alternative Apostrophe")) + self.aInsMSApos = qtAddAction(self.mInsQuotes, self.tr("Alternative Apostrophe")) self.aInsMSApos.setShortcut("Ctrl+K, '") self.aInsMSApos.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_MAPOS) @@ -451,10 +451,10 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsMSApos) # Insert > Symbols - self.mInsPunct = self.insMenu.addMenu(self.tr("General Punctuation")) + self.mInsPunct = qtAddMenu(self.insMenu, self.tr("General Punctuation")) # Insert > Ellipsis - self.aInsEllipsis = self.mInsPunct.addAction(self.tr("Ellipsis")) + self.aInsEllipsis = qtAddAction(self.mInsPunct, self.tr("Ellipsis")) self.aInsEllipsis.setShortcut("Ctrl+K, .") self.aInsEllipsis.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_HELLIP) @@ -462,7 +462,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsEllipsis) # Insert > Prime - self.aInsPrime = self.mInsPunct.addAction(self.tr("Prime")) + self.aInsPrime = qtAddAction(self.mInsPunct, self.tr("Prime")) self.aInsPrime.setShortcut("Ctrl+K, Ctrl+'") self.aInsPrime.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_PRIME) @@ -470,7 +470,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsPrime) # Insert > Double Prime - self.aInsDPrime = self.mInsPunct.addAction(self.tr("Double Prime")) + self.aInsDPrime = qtAddAction(self.mInsPunct, self.tr("Double Prime")) self.aInsDPrime.setShortcut("Ctrl+K, Ctrl+\"") self.aInsDPrime.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_DPRIME) @@ -478,10 +478,10 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsDPrime) # Insert > White Spaces - self.mInsSpace = self.insMenu.addMenu(self.tr("White Spaces")) + self.mInsSpace = qtAddMenu(self.insMenu, self.tr("White Spaces")) # Insert > Non-Breaking Space - self.aInsNBSpace = self.mInsSpace.addAction(self.tr("Non-Breaking Space")) + self.aInsNBSpace = qtAddAction(self.mInsSpace, self.tr("Non-Breaking Space")) self.aInsNBSpace.setShortcut("Ctrl+K, Space") self.aInsNBSpace.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_NBSP) @@ -489,7 +489,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsNBSpace) # Insert > Thin Space - self.aInsThinSpace = self.mInsSpace.addAction(self.tr("Thin Space")) + self.aInsThinSpace = qtAddAction(self.mInsSpace, self.tr("Thin Space")) self.aInsThinSpace.setShortcut("Ctrl+K, Shift+Space") self.aInsThinSpace.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_THSP) @@ -497,7 +497,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsThinSpace) # Insert > Thin Non-Breaking Space - self.aInsThinNBSpace = self.mInsSpace.addAction(self.tr("Thin Non-Breaking Space")) + self.aInsThinNBSpace = qtAddAction(self.mInsSpace, self.tr("Thin Non-Breaking Space")) self.aInsThinNBSpace.setShortcut("Ctrl+K, Ctrl+Space") self.aInsThinNBSpace.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_THNBSP) @@ -505,10 +505,10 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsThinNBSpace) # Insert > Symbols - self.mInsSymbol = self.insMenu.addMenu(self.tr("Other Symbols")) + self.mInsSymbol = qtAddMenu(self.insMenu, self.tr("Other Symbols")) # Insert > List Bullet - self.aInsBullet = self.mInsSymbol.addAction(self.tr("List Bullet")) + self.aInsBullet = qtAddAction(self.mInsSymbol, self.tr("List Bullet")) self.aInsBullet.setShortcut("Ctrl+K, *") self.aInsBullet.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_BULL) @@ -516,7 +516,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsBullet) # Insert > Hyphen Bullet - self.aInsHyBull = self.mInsSymbol.addAction(self.tr("Hyphen Bullet")) + self.aInsHyBull = qtAddAction(self.mInsSymbol, self.tr("Hyphen Bullet")) self.aInsHyBull.setShortcut("Ctrl+K, Ctrl+-") self.aInsHyBull.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_HYBULL) @@ -524,7 +524,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsHyBull) # Insert > Flower Mark - self.aInsFlower = self.mInsSymbol.addAction(self.tr("Flower Mark")) + self.aInsFlower = qtAddAction(self.mInsSymbol, self.tr("Flower Mark")) self.aInsFlower.setShortcut("Ctrl+K, Ctrl+*") self.aInsFlower.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_FLOWER) @@ -532,7 +532,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsFlower) # Insert > Per Mille - self.aInsPerMille = self.mInsSymbol.addAction(self.tr("Per Mille")) + self.aInsPerMille = qtAddAction(self.mInsSymbol, self.tr("Per Mille")) self.aInsPerMille.setShortcut("Ctrl+K, %") self.aInsPerMille.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_PERMIL) @@ -540,7 +540,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsPerMille) # Insert > Degree Symbol - self.aInsDegree = self.mInsSymbol.addAction(self.tr("Degree Symbol")) + self.aInsDegree = qtAddAction(self.mInsSymbol, self.tr("Degree Symbol")) self.aInsDegree.setShortcut("Ctrl+K, Ctrl+O") self.aInsDegree.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_DEGREE) @@ -548,7 +548,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsDegree) # Insert > Minus Sign - self.aInsMinus = self.mInsSymbol.addAction(self.tr("Minus Sign")) + self.aInsMinus = qtAddAction(self.mInsSymbol, self.tr("Minus Sign")) self.aInsMinus.setShortcut("Ctrl+K, Ctrl+M") self.aInsMinus.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_MINUS) @@ -556,7 +556,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsMinus) # Insert > Times Sign - self.aInsTimes = self.mInsSymbol.addAction(self.tr("Times Sign")) + self.aInsTimes = qtAddAction(self.mInsSymbol, self.tr("Times Sign")) self.aInsTimes.setShortcut("Ctrl+K, Ctrl+X") self.aInsTimes.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_TIMES) @@ -564,7 +564,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsTimes) # Insert > Division - self.aInsDivide = self.mInsSymbol.addAction(self.tr("Division Sign")) + self.aInsDivide = qtAddAction(self.mInsSymbol, self.tr("Division Sign")) self.aInsDivide.setShortcut("Ctrl+K, Ctrl+D") self.aInsDivide.triggered.connect( lambda: self.requestDocInsertText.emit(nwUnicode.U_DIVIDE) @@ -572,18 +572,18 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsDivide) # Insert > Tags and References - self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References")) + self.mInsKeywords = qtAddMenu(self.insMenu, self.tr("Tags and References")) for key in nwKeyWords.ALL_KEYS: - action = self.mInsKeywords.addAction(trConst(nwLabels.KEY_NAME[key])) + action = qtAddAction(self.mInsKeywords, trConst(nwLabels.KEY_NAME[key])) action.setShortcut(nwLabels.KEY_SHORTCUT[key]) action.triggered.connect(qtLambda(self.requestDocKeyWordInsert.emit, key)) self.mainGui.addAction(action) # Insert > Special Comments - self.mInsComments = self.insMenu.addMenu(self.tr("Special Comments")) + self.mInsComments = qtAddMenu(self.insMenu, self.tr("Special Comments")) # Insert > Synopsis Comment - self.aInsSynopsis = self.mInsComments.addAction(self.tr("Synopsis Comment")) + self.aInsSynopsis = qtAddAction(self.mInsComments, self.tr("Synopsis Comment")) self.aInsSynopsis.setShortcut("Ctrl+K, S") self.aInsSynopsis.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.SYNOPSIS) @@ -591,7 +591,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsSynopsis) # Insert > Short Description Comment - self.aInsShort = self.mInsComments.addAction(self.tr("Short Description Comment")) + self.aInsShort = qtAddAction(self.mInsComments, self.tr("Short Description Comment")) self.aInsShort.setShortcut("Ctrl+K, H") self.aInsShort.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.SHORT) @@ -599,47 +599,47 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aInsShort) # Insert > Word/Character Count - self.mInsField = self.insMenu.addMenu(self.tr("Word/Character Count")) + self.mInsField = qtAddMenu(self.insMenu, self.tr("Word/Character Count")) for field in nwStats.ALL_FIELDS: value = nwShortcode.FIELD_VALUE.format(field) - action = self.mInsField.addAction(trConst(nwLabels.STATS_NAME[field])) + action = qtAddAction(self.mInsField, trConst(nwLabels.STATS_NAME[field])) action.triggered.connect(qtLambda(self.requestDocInsertText.emit, value)) # Insert > Breaks and Vertical Space - self.mInsBreaks = self.insMenu.addMenu(self.tr("Breaks and Vertical Space")) + self.mInsBreaks = qtAddMenu(self.insMenu, self.tr("Breaks and Vertical Space")) # Insert > New Page - self.aInsNewPage = self.mInsBreaks.addAction(self.tr("Page Break")) + self.aInsNewPage = qtAddAction(self.mInsBreaks, self.tr("Page Break")) self.aInsNewPage.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.NEW_PAGE) ) # Insert > Forced Line Break - self.aInsLineBreak = self.mInsBreaks.addAction(self.tr("Forced Line Break")) + self.aInsLineBreak = qtAddAction(self.mInsBreaks, self.tr("Forced Line Break")) self.aInsLineBreak.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.LINE_BRK) ) # Insert > Vertical Space (Single) - self.aInsVSpaceS = self.mInsBreaks.addAction(self.tr("Vertical Space (Single)")) + self.aInsVSpaceS = qtAddAction(self.mInsBreaks, self.tr("Vertical Space (Single)")) self.aInsVSpaceS.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_S) ) # Insert > Vertical Space (Multi) - self.aInsVSpaceM = self.mInsBreaks.addAction(self.tr("Vertical Space (Multi)")) + self.aInsVSpaceM = qtAddAction(self.mInsBreaks, self.tr("Vertical Space (Multi)")) self.aInsVSpaceM.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_M) ) # Insert > Placeholder Text - self.aLipsumText = self.insMenu.addAction(self.tr("Placeholder Text")) + self.aLipsumText = qtAddAction(self.insMenu, self.tr("Placeholder Text")) self.aLipsumText.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.LIPSUM) ) # Insert > Footnote - self.aFootnote = self.insMenu.addAction(self.tr("Footnote")) + self.aFootnote = qtAddAction(self.insMenu, self.tr("Footnote")) self.aFootnote.triggered.connect( lambda: self.requestDocInsert.emit(nwDocInsert.FOOTNOTE) ) @@ -649,10 +649,10 @@ class GuiMainMenu(QMenuBar): def _buildFormatMenu(self) -> None: """Assemble the Format menu.""" # Format - self.fmtMenu = self.addMenu(self.tr("&Format")) + self.fmtMenu = qtAddMenu(self, self.tr("&Format")) # Format > Bold - self.aFmtBold = self.fmtMenu.addAction(self.tr("Bold")) + self.aFmtBold = qtAddAction(self.fmtMenu, self.tr("Bold")) self.aFmtBold.setShortcut("Ctrl+B") self.aFmtBold.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD) @@ -660,7 +660,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtBold) # Format > Italic - self.aFmtItalic = self.fmtMenu.addAction(self.tr("Italic")) + self.aFmtItalic = qtAddAction(self.fmtMenu, self.tr("Italic")) self.aFmtItalic.setShortcut("Ctrl+I") self.aFmtItalic.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC) @@ -668,7 +668,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtItalic) # Format > Strikethrough - self.aFmtStrike = self.fmtMenu.addAction(self.tr("Strikethrough")) + self.aFmtStrike = qtAddAction(self.fmtMenu, self.tr("Strikethrough")) self.aFmtStrike.setShortcut("Ctrl+D") self.aFmtStrike.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE) @@ -679,7 +679,7 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Double Quotes - self.aFmtDQuote = self.fmtMenu.addAction(self.tr("Wrap Double Quotes")) + self.aFmtDQuote = qtAddAction(self.fmtMenu, self.tr("Wrap Double Quotes")) self.aFmtDQuote.setShortcut("Ctrl+\"") self.aFmtDQuote.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.D_QUOTE) @@ -687,7 +687,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtDQuote) # Format > Single Quotes - self.aFmtSQuote = self.fmtMenu.addAction(self.tr("Wrap Single Quotes")) + self.aFmtSQuote = qtAddAction(self.fmtMenu, self.tr("Wrap Single Quotes")) self.aFmtSQuote.setShortcut("Ctrl+'") self.aFmtSQuote.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.S_QUOTE) @@ -698,46 +698,46 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Shortcodes - self.mShortcodes = self.fmtMenu.addMenu(self.tr("More Formats ...")) + self.mShortcodes = qtAddMenu(self.fmtMenu, self.tr("More Formats ...")) # Shortcode Bold - self.aScBold = self.mShortcodes.addAction(self.tr("Bold (Shortcode)")) + self.aScBold = qtAddAction(self.mShortcodes, self.tr("Bold (Shortcode)")) self.aScBold.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_BOLD) ) # Shortcode Italic - self.aScItalic = self.mShortcodes.addAction(self.tr("Italics (Shortcode)")) + self.aScItalic = qtAddAction(self.mShortcodes, self.tr("Italics (Shortcode)")) self.aScItalic.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC) ) # Shortcode Strikethrough - self.aScStrike = self.mShortcodes.addAction(self.tr("Strikethrough (Shortcode)")) + self.aScStrike = qtAddAction(self.mShortcodes, self.tr("Strikethrough (Shortcode)")) self.aScStrike.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_STRIKE) ) # Shortcode Underline - self.aScULine = self.mShortcodes.addAction(self.tr("Underline")) + self.aScULine = qtAddAction(self.mShortcodes, self.tr("Underline")) self.aScULine.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE) ) # Shortcode Mark - self.aScMark = self.mShortcodes.addAction(self.tr("Highlight")) + self.aScMark = qtAddAction(self.mShortcodes, self.tr("Highlight")) self.aScMark.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_MARK) ) # Shortcode Superscript - self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript")) + self.aScSuper = qtAddAction(self.mShortcodes, self.tr("Superscript")) self.aScSuper.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_SUP) ) # Shortcode Subscript - self.aScSub = self.mShortcodes.addAction(self.tr("Subscript")) + self.aScSub = qtAddAction(self.mShortcodes, self.tr("Subscript")) self.aScSub.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.SC_SUB) ) @@ -746,7 +746,7 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Heading 1 (Partition) - self.aFmtHead1 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H1"])) + self.aFmtHead1 = qtAddAction(self.fmtMenu, trConst(nwStyles.T_LABEL["H1"])) self.aFmtHead1.setShortcut("Ctrl+1") self.aFmtHead1.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1) @@ -754,7 +754,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtHead1) # Format > Heading 2 (Chapter) - self.aFmtHead2 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H2"])) + self.aFmtHead2 = qtAddAction(self.fmtMenu, trConst(nwStyles.T_LABEL["H2"])) self.aFmtHead2.setShortcut("Ctrl+2") self.aFmtHead2.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2) @@ -762,7 +762,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtHead2) # Format > Heading 3 (Scene) - self.aFmtHead3 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H3"])) + self.aFmtHead3 = qtAddAction(self.fmtMenu, trConst(nwStyles.T_LABEL["H3"])) self.aFmtHead3.setShortcut("Ctrl+3") self.aFmtHead3.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3) @@ -770,7 +770,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtHead3) # Format > Heading 4 (Section) - self.aFmtHead4 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H4"])) + self.aFmtHead4 = qtAddAction(self.fmtMenu, trConst(nwStyles.T_LABEL["H4"])) self.aFmtHead4.setShortcut("Ctrl+4") self.aFmtHead4.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4) @@ -781,19 +781,19 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Novel Title - self.aFmtTitle = self.fmtMenu.addAction(self.tr("Novel Title")) + self.aFmtTitle = qtAddAction(self.fmtMenu, self.tr("Novel Title")) self.aFmtTitle.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TTL) ) # Format > Unnumbered Chapter - self.aFmtUnNum = self.fmtMenu.addAction(self.tr("Unnumbered Chapter")) + self.aFmtUnNum = qtAddAction(self.fmtMenu, self.tr("Unnumbered Chapter")) self.aFmtUnNum.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN) ) # Format > Alternative Scene - self.aFmtHardSc = self.fmtMenu.addAction(self.tr("Alternative Scene")) + self.aFmtHardSc = qtAddAction(self.fmtMenu, self.tr("Alternative Scene")) self.aFmtHardSc.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_HSC) ) @@ -802,7 +802,7 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Align Left - self.aFmtAlignLeft = self.fmtMenu.addAction(self.tr("Align Left")) + self.aFmtAlignLeft = qtAddAction(self.fmtMenu, self.tr("Align Left")) self.aFmtAlignLeft.setShortcut("Ctrl+5") self.aFmtAlignLeft.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.ALIGN_L) @@ -810,7 +810,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtAlignLeft) # Format > Align Centre - self.aFmtAlignCentre = self.fmtMenu.addAction(self.tr("Align Centre")) + self.aFmtAlignCentre = qtAddAction(self.fmtMenu, self.tr("Align Centre")) self.aFmtAlignCentre.setShortcut("Ctrl+6") self.aFmtAlignCentre.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.ALIGN_C) @@ -818,7 +818,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtAlignCentre) # Format > Align Right - self.aFmtAlignRight = self.fmtMenu.addAction(self.tr("Align Right")) + self.aFmtAlignRight = qtAddAction(self.fmtMenu, self.tr("Align Right")) self.aFmtAlignRight.setShortcut("Ctrl+7") self.aFmtAlignRight.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.ALIGN_R) @@ -829,7 +829,7 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Indent Left - self.aFmtIndentLeft = self.fmtMenu.addAction(self.tr("Indent Left")) + self.aFmtIndentLeft = qtAddAction(self.fmtMenu, self.tr("Indent Left")) self.aFmtIndentLeft.setShortcut("Ctrl+8") self.aFmtIndentLeft.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.INDENT_L) @@ -837,7 +837,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtIndentLeft) # Format > Indent Right - self.aFmtIndentRight = self.fmtMenu.addAction(self.tr("Indent Right")) + self.aFmtIndentRight = qtAddAction(self.fmtMenu, self.tr("Indent Right")) self.aFmtIndentRight.setShortcut("Ctrl+9") self.aFmtIndentRight.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.INDENT_R) @@ -848,7 +848,7 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Comment - self.aFmtComment = self.fmtMenu.addAction(self.tr("Toggle Comment")) + self.aFmtComment = qtAddAction(self.fmtMenu, self.tr("Toggle Comment")) self.aFmtComment.setShortcut("Ctrl+/") self.aFmtComment.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_COM) @@ -856,14 +856,14 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFmtComment) # Format > Ignore Text - self.aFmtIgnore = self.fmtMenu.addAction(self.tr("Toggle Ignore Text")) + self.aFmtIgnore = qtAddAction(self.fmtMenu, self.tr("Toggle Ignore Text")) self.aFmtIgnore.setShortcut("Ctrl+Shift+D") self.aFmtIgnore.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_IGN) ) # Format > Remove Block Format - self.aFmtNoFormat = self.fmtMenu.addAction(self.tr("Remove Block Format")) + self.aFmtNoFormat = qtAddAction(self.fmtMenu, self.tr("Remove Block Format")) self.aFmtNoFormat.setShortcuts(["Ctrl+0", "Ctrl+Shift+/"]) self.aFmtNoFormat.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TXT) @@ -874,19 +874,19 @@ class GuiMainMenu(QMenuBar): self.fmtMenu.addSeparator() # Format > Replace Straight Single Quotes - self.aFmtReplSng = self.fmtMenu.addAction(self.tr("Replace Straight Single Quotes")) + self.aFmtReplSng = qtAddAction(self.fmtMenu, self.tr("Replace Straight Single Quotes")) self.aFmtReplSng.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.REPL_SNG) ) # Format > Replace Straight Double Quotes - self.aFmtReplDbl = self.fmtMenu.addAction(self.tr("Replace Straight Double Quotes")) + self.aFmtReplDbl = qtAddAction(self.fmtMenu, self.tr("Replace Straight Double Quotes")) self.aFmtReplDbl.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.REPL_DBL) ) # Format > Remove In-Paragraph Breaks - self.aFmtRmBreaks = self.fmtMenu.addAction(self.tr("Remove In-Paragraph Breaks")) + self.aFmtRmBreaks = qtAddAction(self.fmtMenu, self.tr("Remove In-Paragraph Breaks")) self.aFmtRmBreaks.triggered.connect( lambda: self.requestDocAction.emit(nwDocAction.RM_BREAKS) ) @@ -896,28 +896,28 @@ class GuiMainMenu(QMenuBar): def _buildSearchMenu(self) -> None: """Assemble the Search menu.""" # Search - self.srcMenu = self.addMenu(self.tr("&Search")) + self.srcMenu = qtAddMenu(self, self.tr("&Search")) # Search > Find - self.aFind = self.srcMenu.addAction(self.tr("Find")) + self.aFind = qtAddAction(self.srcMenu, self.tr("Find")) self.aFind.setShortcut("Ctrl+F") self.aFind.triggered.connect(qtLambda(self.mainGui.docEditor.beginSearch)) self.mainGui.addAction(self.aFind) # Search > Replace - self.aReplace = self.srcMenu.addAction(self.tr("Replace")) + self.aReplace = qtAddAction(self.srcMenu, self.tr("Replace")) self.aReplace.setShortcut("Ctrl+=" if CONFIG.osDarwin else "Ctrl+H") self.aReplace.triggered.connect(qtLambda(self.mainGui.docEditor.beginReplace)) self.mainGui.addAction(self.aReplace) # Search > Find Next - self.aFindNext = self.srcMenu.addAction(self.tr("Find Next")) + self.aFindNext = qtAddAction(self.srcMenu, self.tr("Find Next")) self.aFindNext.setShortcuts(["Ctrl+G", "F3"] if CONFIG.osDarwin else ["F3", "Ctrl+G"]) self.aFindNext.triggered.connect(qtLambda(self.mainGui.docEditor.findNext)) self.mainGui.addAction(self.aFindNext) # Search > Find Prev - self.aFindPrev = self.srcMenu.addAction(self.tr("Find Previous")) + self.aFindPrev = qtAddAction(self.srcMenu, self.tr("Find Previous")) self.aFindPrev.setShortcuts( ["Ctrl+Shift+G", "Shift+F3"] if CONFIG.osDarwin else ["Shift+F3", "Ctrl+Shift+G"] ) @@ -925,7 +925,7 @@ class GuiMainMenu(QMenuBar): self.mainGui.addAction(self.aFindPrev) # Search > Replace Next - self.aReplaceNext = self.srcMenu.addAction(self.tr("Replace Next")) + self.aReplaceNext = qtAddAction(self.srcMenu, self.tr("Replace Next")) self.aReplaceNext.setShortcut("Ctrl+Shift+1") self.aReplaceNext.triggered.connect(qtLambda(self.mainGui.docEditor.replaceNext)) self.mainGui.addAction(self.aReplaceNext) @@ -934,7 +934,7 @@ class GuiMainMenu(QMenuBar): self.srcMenu.addSeparator() # Search > Find in Project - self.aFindProj = self.srcMenu.addAction(self.tr("Find in Project")) + self.aFindProj = qtAddAction(self.srcMenu, self.tr("Find in Project")) self.aFindProj.setShortcut("Ctrl+Shift+F") self.aFindProj.triggered.connect(lambda: self.requestViewChange.emit(nwView.SEARCH)) @@ -943,17 +943,17 @@ class GuiMainMenu(QMenuBar): def _buildToolsMenu(self) -> None: """Assemble the Tools menu.""" # Tools - self.toolsMenu = self.addMenu(self.tr("&Tools")) + self.toolsMenu = qtAddMenu(self, self.tr("&Tools")) # Tools > Check Spelling - self.aSpellCheck = self.toolsMenu.addAction(self.tr("Check Spelling")) + self.aSpellCheck = qtAddAction(self.toolsMenu, self.tr("Check Spelling")) self.aSpellCheck.setCheckable(True) self.aSpellCheck.setChecked(SHARED.project.data.spellCheck) self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled! self.aSpellCheck.setShortcut("Ctrl+F7") self.mainGui.addAction(self.aSpellCheck) - self.mSelectLanguage = self.toolsMenu.addMenu(self.tr("Spell Check Language")) + self.mSelectLanguage = qtAddMenu(self.toolsMenu, self.tr("Spell Check Language")) languages = SHARED.spelling.listDictionaries() languages.insert(0, ("None", self.tr("Default"))) for n, (tag, language) in enumerate(languages): @@ -963,25 +963,25 @@ class GuiMainMenu(QMenuBar): self.mSelectLanguage.addAction(aSpell) # Tools > Re-Run Spell Check - self.aReRunSpell = self.toolsMenu.addAction(self.tr("Re-Run Spell Check")) + self.aReRunSpell = qtAddAction(self.toolsMenu, self.tr("Re-Run Spell Check")) self.aReRunSpell.setShortcut("F7") self.aReRunSpell.triggered.connect(qtLambda(self.mainGui.docEditor.spellCheckDocument)) self.mainGui.addAction(self.aReRunSpell) # Tools > Project Word List - self.aEditWordList = self.toolsMenu.addAction(self.tr("Project Word List")) + self.aEditWordList = qtAddAction(self.toolsMenu, self.tr("Project Word List")) self.aEditWordList.triggered.connect(self.mainGui.showProjectWordListDialog) # Tools > Add Dictionaries if CONFIG.osWindows or CONFIG.isDebug: - self.aAddDicts = self.toolsMenu.addAction(self.tr("Add Dictionaries")) + self.aAddDicts = qtAddAction(self.toolsMenu, self.tr("Add Dictionaries")) self.aAddDicts.triggered.connect(self.mainGui.showDictionariesDialog) # Tools > Separator self.toolsMenu.addSeparator() # Tools > Rebuild Index - self.aRebuildIndex = self.toolsMenu.addAction(self.tr("Rebuild Index")) + self.aRebuildIndex = qtAddAction(self.toolsMenu, self.tr("Rebuild Index")) self.aRebuildIndex.setShortcut("F9") self.aRebuildIndex.triggered.connect(qtLambda(self.mainGui.rebuildIndex)) @@ -989,21 +989,21 @@ class GuiMainMenu(QMenuBar): self.toolsMenu.addSeparator() # Tools > Backup Project - self.aBackupProject = self.toolsMenu.addAction(self.tr("Backup Project")) + self.aBackupProject = qtAddAction(self.toolsMenu, self.tr("Backup Project")) self.aBackupProject.triggered.connect(qtLambda(SHARED.project.backupProject, True)) # Tools > Build Manuscript - self.aBuildManuscript = self.toolsMenu.addAction(self.tr("Build Manuscript")) + self.aBuildManuscript = qtAddAction(self.toolsMenu, self.tr("Build Manuscript")) self.aBuildManuscript.setShortcut("F5") self.aBuildManuscript.triggered.connect(self.mainGui.showBuildManuscriptDialog) # Tools > Writing Statistics - self.aWritingStats = self.toolsMenu.addAction(self.tr("Writing Statistics")) + self.aWritingStats = qtAddAction(self.toolsMenu, self.tr("Writing Statistics")) self.aWritingStats.setShortcut("F6") self.aWritingStats.triggered.connect(self.mainGui.showWritingStatsDialog) # Tools > Preferences - self.aPreferences = self.toolsMenu.addAction(self.tr("Preferences")) + self.aPreferences = qtAddAction(self.toolsMenu, self.tr("Preferences")) self.aPreferences.setShortcut("Ctrl+,") self.aPreferences.setMenuRole(QAction.MenuRole.PreferencesRole) self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog) @@ -1014,15 +1014,15 @@ class GuiMainMenu(QMenuBar): def _buildHelpMenu(self) -> None: """Assemble the Help menu.""" # Help - self.helpMenu = self.addMenu(self.tr("&Help")) + self.helpMenu = qtAddMenu(self, self.tr("&Help")) # Help > About - self.aAboutNW = self.helpMenu.addAction(self.tr("About novelWriter")) + self.aAboutNW = qtAddAction(self.helpMenu, self.tr("About novelWriter")) self.aAboutNW.setMenuRole(QAction.MenuRole.AboutRole) self.aAboutNW.triggered.connect(self.mainGui.showAboutNWDialog) # Help > About Qt - self.aAboutQt = self.helpMenu.addAction(self.tr("About Qt")) + self.aAboutQt = qtAddAction(self.helpMenu, self.tr("About Qt")) self.aAboutQt.setMenuRole(QAction.MenuRole.AboutQtRole) self.aAboutQt.triggered.connect(self.mainGui.showAboutQtDialog) @@ -1030,14 +1030,14 @@ class GuiMainMenu(QMenuBar): self.helpMenu.addSeparator() # Help > User Manual (Online) - self.aHelpDocs = self.helpMenu.addAction(self.tr("User Manual (Online)")) + self.aHelpDocs = qtAddAction(self.helpMenu, self.tr("User Manual (Online)")) self.aHelpDocs.setShortcut("F1") self.aHelpDocs.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_DOCS)) self.mainGui.addAction(self.aHelpDocs) # Help > User Manual (PDF) if isinstance(CONFIG.pdfDocs, Path): - self.aPdfDocs = self.helpMenu.addAction(self.tr("User Manual (PDF)")) + self.aPdfDocs = qtAddAction(self.helpMenu, self.tr("User Manual (PDF)")) self.aPdfDocs.setShortcut("Shift+F1") self.aPdfDocs.triggered.connect(self._openUserManualFile) self.mainGui.addAction(self.aPdfDocs) @@ -1046,15 +1046,15 @@ class GuiMainMenu(QMenuBar): self.helpMenu.addSeparator() # Document > Report an Issue - self.aIssue = self.helpMenu.addAction(self.tr("Report an Issue (GitHub)")) + self.aIssue = qtAddAction(self.helpMenu, self.tr("Report an Issue (GitHub)")) self.aIssue.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_REPORT)) # Document > Ask a Question - self.aQuestion = self.helpMenu.addAction(self.tr("Ask a Question (GitHub)")) + self.aQuestion = qtAddAction(self.helpMenu, self.tr("Ask a Question (GitHub)")) self.aQuestion.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_HELP)) # Document > Main Website - self.aWebsite = self.helpMenu.addAction(self.tr("The novelWriter Website")) + self.aWebsite = qtAddAction(self.helpMenu, self.tr("The novelWriter Website")) self.aWebsite.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_WEB)) return diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index e2e321c5..619700cb 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -38,7 +38,7 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import minmax, qtLambda +from novelwriter.common import minmax, qtAddAction, qtAddMenu, qtLambda from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst from novelwriter.core.index import IndexHeading from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline @@ -199,7 +199,6 @@ class GuiNovelToolBar(QWidget): self.novelView = novelView iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(2) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) @@ -211,7 +210,7 @@ class GuiNovelToolBar(QWidget): self.novelValue = NovelSelector(self) self.novelValue.setFont(selFont) self.novelValue.setListFormat(self.tr("Outline of {0}")) - self.novelValue.setMinimumWidth(CONFIG.pxInt(150)) + self.novelValue.setMinimumWidth(150) self.novelValue.setSizePolicy(QtSizeExpanding, QtSizeExpanding) self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot) @@ -227,7 +226,7 @@ class GuiNovelToolBar(QWidget): # More Options Menu self.mMore = QMenu(self) - self.mLastCol = self.mMore.addMenu(self.tr("Last Column")) + self.mLastCol = qtAddMenu(self.mMore, self.tr("Last Column")) self.gLastCol = QActionGroup(self.mMore) self.aLastCol = {} self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden")) @@ -236,7 +235,7 @@ class GuiNovelToolBar(QWidget): self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot")) self.mLastCol.addSeparator() - self.aLastColSize = self.mLastCol.addAction(self.tr("Column Size")) + self.aLastColSize = qtAddAction(self.mLastCol, self.tr("Column Size")) self.aLastColSize.triggered.connect(self._selectLastColumnSize) self.tbMore = NIconToolButton(self, iSz) @@ -249,7 +248,7 @@ class GuiNovelToolBar(QWidget): self.outerBox.addWidget(self.tbNovel) self.outerBox.addWidget(self.tbRefresh) self.outerBox.addWidget(self.tbMore) - self.outerBox.setContentsMargins(mPx, mPx, 0, mPx) + self.outerBox.setContentsMargins(2, 2, 0, 2) self.outerBox.setSpacing(0) self.setLayout(self.outerBox) @@ -343,7 +342,7 @@ class GuiNovelToolBar(QWidget): def _addLastColAction(self, colType: NovelTreeColumn, actionLabel: str) -> None: """Add a column selection entry to the last column menu.""" - aLast = self.mLastCol.addAction(actionLabel) + aLast = qtAddAction(self.mLastCol, actionLabel) aLast.setCheckable(True) aLast.setActionGroup(self.gLastCol) aLast.triggered.connect(qtLambda(self.setLastColType, colType)) @@ -388,7 +387,6 @@ class GuiNovelTree(QTreeWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - cMg = CONFIG.pxInt(6) self.setIconSize(iSz) self.setFrameStyle(QFrame.Shape.NoFrame) @@ -403,13 +401,13 @@ class GuiNovelTree(QTreeWidget): self.setDragEnabled(False) # Lock the column sizes - treeHeader = self.header() - treeHeader.setStretchLastSection(False) - treeHeader.setMinimumSectionSize(iPx + cMg) - treeHeader.setSectionResizeMode(self.C_TITLE, QtHeaderStretch) - treeHeader.setSectionResizeMode(self.C_WORDS, QtHeaderToContents) - treeHeader.setSectionResizeMode(self.C_EXTRA, QtHeaderToContents) - treeHeader.setSectionResizeMode(self.C_MORE, QtHeaderToContents) + if header := self.header(): + header.setStretchLastSection(False) + header.setMinimumSectionSize(iPx + 6) + header.setSectionResizeMode(self.C_TITLE, QtHeaderStretch) + header.setSectionResizeMode(self.C_WORDS, QtHeaderToContents) + header.setSectionResizeMode(self.C_EXTRA, QtHeaderToContents) + header.setSectionResizeMode(self.C_MORE, QtHeaderToContents) # Pre-Generate Tree Formatting fH1 = self.font() @@ -678,8 +676,9 @@ class GuiNovelTree(QTreeWidget): return - def _updateTreeItemValues(self, trItem: QTreeWidgetItem, idxItem: IndexHeading, - tHandle: str, sTitle: str) -> None: + def _updateTreeItemValues( + self, trItem: QTreeWidgetItem, idxItem: IndexHeading, tHandle: str, sTitle: str + ) -> None: """Set the tree item values from the index entry.""" iLevel = nwStyles.H_LEVEL.get(idxItem.level, 0) hDec = SHARED.theme.getHeaderDecoration(iLevel) @@ -691,7 +690,8 @@ class GuiNovelTree(QTreeWidget): trItem.setData(self.C_MORE, QtDecoration, self._pMore) # Custom column - mW = int(self._lastColSize * self.viewport().width()) + viewport = self.viewport() + mW = int(self._lastColSize * (viewport.width() if viewport else 100)) lastText, toolTip = self._getLastColumnText(tHandle, sTitle) elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW) trItem.setText(self.C_EXTRA, elideText) diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py index a237e5fd..8b1e9a0d 100644 --- a/novelwriter/gui/outline.py +++ b/novelwriter/gui/outline.py @@ -78,7 +78,7 @@ class GuiOutlineView(QWidget): # Assemble self.outerBox = QVBoxLayout() - self.outerBox.setContentsMargins(0, 0, CONFIG.pxInt(4), 0) + self.outerBox.setContentsMargins(0, 0, 4, 0) self.outerBox.addWidget(self.outlineBar) self.outerBox.addWidget(self.splitOutline) @@ -225,11 +225,11 @@ class GuiOutlineToolBar(QToolBar): self.novelLabel = NColourLabel( self.tr("Outline of"), self, scale=NColourLabel.HEADER_SCALE, bold=True ) - self.novelLabel.setContentsMargins(0, 0, CONFIG.pxInt(12), 0) + self.novelLabel.setContentsMargins(0, 0, 12, 0) self.novelValue = NovelSelector(self) self.novelValue.setIncludeAll(True) - self.novelValue.setMinimumWidth(CONFIG.pxInt(200)) + self.novelValue.setMinimumWidth(200) self.novelValue.novelSelectionChanged.connect(self._novelValueChanged) # Actions @@ -390,8 +390,8 @@ class GuiOutlineTree(QTreeWidget): self.setIconSize(SHARED.theme.baseIconSize) self.setIndentation(0) - self.treeHead = self.header() - self.treeHead.sectionMoved.connect(self._columnMoved) + if header := self.header(): + header.sectionMoved.connect(self._columnMoved) # Pre-Generate Tree Formatting fH1 = self.font() @@ -623,7 +623,7 @@ class GuiOutlineTree(QTreeWidget): continue tmpOrder.append(nwOutline[name]) tmpHidden[nwOutline[name]] = hidden - tmpWidth[nwOutline[name]] = CONFIG.pxInt(width) + tmpWidth[nwOutline[name]] = width except Exception: logger.error("Invalid column state") logException() @@ -647,26 +647,22 @@ class GuiOutlineTree(QTreeWidget): save the current width of hidden columns though. This preserves the last known width in case they're unhidden again. """ - # If we haven't built the tree, there is nothing to save. - if self._lastBuild == 0: - return - - colState = {} - for iCol in range(self.columnCount()): - hItem = self._treeOrder[iCol] - iLog = self.treeHead.logicalIndex(iCol) - logHidden = self.isColumnHidden(iLog) - orgWidth = CONFIG.rpxInt(self._colWidth[hItem]) - logWidth = CONFIG.rpxInt(self.columnWidth(iLog)) - colState[hItem.name] = [ - logHidden, orgWidth if logHidden and logWidth == 0 else logWidth - ] - - logger.debug("Saving State: GuiOutline") - pOptions = SHARED.project.options - pOptions.setValue("GuiOutline", "columnState", colState) - pOptions.saveSettings() + if self._lastBuild > 0 and (header := self.header()): + colState = {} + for iCol in range(self.columnCount()): + hItem = self._treeOrder[iCol] + iLog = header.logicalIndex(iCol) + logHidden = self.isColumnHidden(iLog) + orgWidth = self._colWidth[hItem] + logWidth = self.columnWidth(iLog) + colState[hItem.name] = [ + logHidden, orgWidth if logHidden and logWidth == 0 else logWidth + ] + logger.debug("Saving State: GuiOutline") + pOptions = SHARED.project.options + pOptions.setValue("GuiOutline", "columnState", colState) + pOptions.saveSettings() return def _populateTree(self, rootHandle: str | None) -> None: @@ -819,8 +815,6 @@ class GuiOutlineDetails(QScrollArea): minTitle = 30*SHARED.theme.textNWidth maxTitle = 40*SHARED.theme.textNWidth wCount = SHARED.theme.getTextWidth("999,999") - hSpace = int(CONFIG.pxInt(10)) - vSpace = int(CONFIG.pxInt(4)) bFont = SHARED.theme.guiFontB @@ -899,8 +893,8 @@ class GuiOutlineDetails(QScrollArea): self.mainForm.setColumnStretch(1, 1) self.mainForm.setRowStretch(4, 1) - self.mainForm.setHorizontalSpacing(hSpace) - self.mainForm.setVerticalSpacing(vSpace) + self.mainForm.setHorizontalSpacing(10) + self.mainForm.setVerticalSpacing(4) # Selected Item Tags self.tagsForm = QGridLayout() @@ -923,8 +917,8 @@ class GuiOutlineDetails(QScrollArea): self.tagsForm.setColumnStretch(1, 1) self.tagsForm.setRowStretch(len(self.tagValues), 1) - self.tagsForm.setHorizontalSpacing(hSpace) - self.tagsForm.setVerticalSpacing(vSpace) + self.tagsForm.setHorizontalSpacing(10) + self.tagsForm.setVerticalSpacing(4) # Assemble self.mainSplit = QSplitter(Qt.Orientation.Horizontal) @@ -965,21 +959,18 @@ class GuiOutlineDetails(QScrollArea): width = parent.width() if isinstance(parent, QWidget) else 1000 pOptions = SHARED.project.options self.mainSplit.setSizes([ - CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3)), - CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3)) + pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3), + pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3), ]) return def saveGuiSettings(self) -> None: """Run close project tasks.""" - mainSplit = self.mainSplit.sizes() - detailsWidth = CONFIG.rpxInt(mainSplit[0]) - tagsWidth = CONFIG.rpxInt(mainSplit[1]) - logger.debug("Saving State: GuiOutlineDetails") + mainSplit = self.mainSplit.sizes() pOptions = SHARED.project.options - pOptions.setValue("GuiOutlineDetails", "detailsWidth", detailsWidth) - pOptions.setValue("GuiOutlineDetails", "tagsWidth", tagsWidth) + pOptions.setValue("GuiOutlineDetails", "detailsWidth", mainSplit[0]) + pOptions.setValue("GuiOutlineDetails", "tagsWidth", mainSplit[1]) return def clearDetails(self) -> None: diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 6acaa264..2b28442d 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -40,7 +40,7 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import qtLambda +from novelwriter.common import qtAddAction, qtAddMenu, qtLambda from novelwriter.constants import nwLabels, nwStyles, nwUnicode, trConst from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter from novelwriter.core.item import NWItem @@ -243,7 +243,6 @@ class GuiProjectToolBar(QWidget): self.projTree = projView.projTree iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(2) self.setContentsMargins(0, 0, 0, 0) self.setAutoFillBackground(True) @@ -274,27 +273,27 @@ class GuiProjectToolBar(QWidget): # Add Item Menu self.mAdd = QMenu(self) - self.aAddEmpty = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["document"])) + self.aAddEmpty = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["document"])) self.aAddEmpty.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=0, isNote=False) ) - self.aAddChap = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"])) + self.aAddChap = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"])) self.aAddChap.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=2, isNote=False) ) - self.aAddScene = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"])) + self.aAddScene = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"])) self.aAddScene.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=3, isNote=False) ) - self.aAddNote = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["note"])) + self.aAddNote = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["note"])) self.aAddNote.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=1, isNote=True) ) - self.aAddFolder = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["folder"])) + self.aAddFolder = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["folder"])) self.aAddFolder.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.FOLDER) ) @@ -304,7 +303,7 @@ class GuiProjectToolBar(QWidget): self.mTemplates.menuItemTriggered.connect(lambda h: self.newDocumentFromTemplate.emit(h)) self.mAdd.addMenu(self.mTemplates) - self.mAddRoot = self.mAdd.addMenu(trConst(nwLabels.ITEM_DESCRIPTION["root"])) + self.mAddRoot = qtAddMenu(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["root"])) self._buildRootMenu() self.tbAdd = NIconToolButton(self, iSz) @@ -315,13 +314,13 @@ class GuiProjectToolBar(QWidget): # More Options Menu self.mMore = QMenu(self) - self.aExpand = self.mMore.addAction(self.tr("Expand All")) + self.aExpand = qtAddAction(self.mMore, self.tr("Expand All")) self.aExpand.triggered.connect(self.projTree.expandAll) - self.aCollapse = self.mMore.addAction(self.tr("Collapse All")) + self.aCollapse = qtAddAction(self.mMore, self.tr("Collapse All")) self.aCollapse.triggered.connect(self.projTree.collapseAll) - self.aEmptyTrash = self.mMore.addAction(self.tr("Empty Trash")) + self.aEmptyTrash = qtAddAction(self.mMore, self.tr("Empty Trash")) self.aEmptyTrash.triggered.connect(self.projTree.emptyTrash) self.tbMore = NIconToolButton(self, iSz) @@ -336,7 +335,7 @@ class GuiProjectToolBar(QWidget): self.outerBox.addWidget(self.tbMoveD) self.outerBox.addWidget(self.tbAdd) self.outerBox.addWidget(self.tbMore) - self.outerBox.setContentsMargins(mPx, mPx, 0, mPx) + self.outerBox.setContentsMargins(2, 2, 0, 2) self.outerBox.setSpacing(0) self.setLayout(self.outerBox) @@ -392,7 +391,7 @@ class GuiProjectToolBar(QWidget): logger.debug("Rebuilding quick links menu") self.mQuick.clear() for tHandle, nwItem in SHARED.project.tree.iterRoots(None): - action = self.mQuick.addAction(nwItem.itemName) + action = qtAddAction(self.mQuick, nwItem.itemName) action.setData(tHandle) action.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass], "root")) action.triggered.connect( @@ -440,7 +439,7 @@ class GuiProjectToolBar(QWidget): def _buildRootMenu(self) -> None: """Build the rood folder menu.""" def addClass(itemClass: nwItemClass) -> None: - aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass])) + aNew = qtAddAction(self.mAddRoot, trConst(nwLabels.CLASS_NAME[itemClass])) aNew.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[itemClass], "root")) aNew.triggered.connect( qtLambda(self.projTree.newTreeItem, nwItemType.ROOT, itemClass) @@ -561,17 +560,16 @@ class GuiProjectTree(QTreeView): # Lock the column sizes iPx = SHARED.theme.baseIconHeight - cMg = CONFIG.pxInt(6) - treeHeader = self.header() - treeHeader.setStretchLastSection(False) - treeHeader.setMinimumSectionSize(iPx + cMg) - treeHeader.setSectionResizeMode(ProjectNode.C_NAME, QtHeaderStretch) - treeHeader.setSectionResizeMode(ProjectNode.C_COUNT, QtHeaderToContents) - treeHeader.setSectionResizeMode(ProjectNode.C_ACTIVE, QtHeaderFixed) - treeHeader.setSectionResizeMode(ProjectNode.C_STATUS, QtHeaderFixed) - treeHeader.resizeSection(ProjectNode.C_ACTIVE, iPx + cMg) - treeHeader.resizeSection(ProjectNode.C_STATUS, iPx + cMg) + if header := self.header(): + header.setStretchLastSection(False) + header.setMinimumSectionSize(iPx + 6) + header.setSectionResizeMode(ProjectNode.C_NAME, QtHeaderStretch) + header.setSectionResizeMode(ProjectNode.C_COUNT, QtHeaderToContents) + header.setSectionResizeMode(ProjectNode.C_ACTIVE, QtHeaderFixed) + header.setSectionResizeMode(ProjectNode.C_STATUS, QtHeaderFixed) + header.resizeSection(ProjectNode.C_ACTIVE, iPx + 6) + header.resizeSection(ProjectNode.C_STATUS, iPx + 6) self.restoreExpandedState() @@ -969,8 +967,9 @@ class GuiProjectTree(QTreeView): else: ctxMenu.buildSingleSelectMenu() - ctxMenu.exec(self.viewport().mapToGlobal(point)) - ctxMenu.deleteLater() + if viewport := self.viewport(): + ctxMenu.exec(viewport.mapToGlobal(point)) + ctxMenu.deleteLater() return @@ -1091,7 +1090,8 @@ class _UpdatableMenu(QMenu): def setActionsVisible(self, value: bool) -> None: """Set the visibility of root action.""" - self.menuAction().setVisible(value) + if action := self.menuAction(): + action.setVisible(value) return ## @@ -1135,7 +1135,7 @@ class _TreeContextMenu(QMenu): def buildTrashMenu(self) -> None: """Build the special menu for the Trash folder.""" - action = self.addAction(self.tr("Empty Trash")) + action = qtAddAction(self, self.tr("Empty Trash")) action.triggered.connect(self._tree.emptyTrash) if self._children: self._expandCollapse() @@ -1156,7 +1156,7 @@ class _TreeContextMenu(QMenu): self.addSeparator() # Edit Item Settings - action = self.addAction(self.tr("Rename")) + action = qtAddAction(self, self.tr("Rename")) action.triggered.connect(qtLambda(self._view.renameTreeItem, self._handle)) if isFile: self._itemHeader() @@ -1171,7 +1171,7 @@ class _TreeContextMenu(QMenu): # Process Item if self._children: self._expandCollapse() - action = self.addAction(self.tr("Duplicate")) + action = qtAddAction(self, self.tr("Duplicate")) action.triggered.connect(qtLambda(self._tree.duplicateFromHandle, self._handle)) self._deleteOrTrash() @@ -1191,12 +1191,12 @@ class _TreeContextMenu(QMenu): def _docActions(self) -> None: """Add document actions.""" - action = self.addAction(self.tr("Open Document")) + action = qtAddAction(self, self.tr("Open Document")) action.triggered.connect(qtLambda( self._view.openDocumentRequest.emit, self._handle, nwDocMode.EDIT, "", True )) - action = self.addAction(self.tr("View Document")) + action = qtAddAction(self, self.tr("View Document")) action.triggered.connect(qtLambda( self._view.openDocumentRequest.emit, self._handle, nwDocMode.VIEW, "", False @@ -1205,7 +1205,7 @@ class _TreeContextMenu(QMenu): def _itemCreation(self) -> None: """Add create item actions.""" - menu = self.addMenu(self.tr("Create New ...")) + menu = qtAddMenu(self, self.tr("Create New ...")) menu.addAction(self._view.projBar.aAddEmpty) menu.addAction(self._view.projBar.aAddChap) menu.addAction(self._view.projBar.aAddScene) @@ -1217,7 +1217,7 @@ class _TreeContextMenu(QMenu): """Check if there is a header that can be used for rename.""" SHARED.saveEditor() if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"): - action = self.addAction(self.tr("Rename to Heading")) + action = qtAddAction(self, self.tr("Rename to Heading")) action.triggered.connect( qtLambda(self._view.renameTreeItem, self._handle, hItem.title) ) @@ -1226,50 +1226,54 @@ class _TreeContextMenu(QMenu): def _itemActive(self) -> None: """Add Active/Inactive actions.""" if len(self._indices) > 1: - mSub = self.addMenu(self.tr("Set Active to ...")) - aOne = mSub.addAction(SHARED.theme.getIcon("checked"), self._tree.trActive) + mSub = qtAddMenu(self, self.tr("Set Active to ...")) + aOne = qtAddAction(mSub, self._tree.trActive) + aOne.setIcon(SHARED.theme.getIcon("checked")) aOne.triggered.connect(qtLambda(self._iterItemActive, True)) - aTwo = mSub.addAction(SHARED.theme.getIcon("unchecked"), self._tree.trInactive) + aTwo = qtAddAction(mSub, self._tree.trInactive) + aTwo.setIcon(SHARED.theme.getIcon("unchecked")) aTwo.triggered.connect(qtLambda(self._iterItemActive, False)) else: - action = self.addAction(self.tr("Toggle Active")) + action = qtAddAction(self, self.tr("Toggle Active")) action.triggered.connect(self._toggleItemActive) return def _itemStatusImport(self, multi: bool) -> None: """Add actions for changing status or importance.""" if self._item.isNovelLike(): - menu = self.addMenu(self.tr("Set Status to ...")) + menu = qtAddMenu(self, self.tr("Set Status to ...")) current = self._item.itemStatus for key, entry in SHARED.project.data.itemStatus.iterItems(): name = entry.name if not multi and current == key: name += f" ({nwUnicode.U_CHECK})" - action = menu.addAction(entry.icon, name) + action = qtAddAction(menu, name) + action.setIcon(entry.icon) if multi: action.triggered.connect(qtLambda(self._iterSetItemStatus, key)) else: action.triggered.connect(qtLambda(self._changeItemStatus, key)) menu.addSeparator() - action = menu.addAction(self.tr("Manage Labels ...")) + action = qtAddAction(menu, self.tr("Manage Labels ...")) action.triggered.connect(qtLambda( self._view.projectSettingsRequest.emit, GuiProjectSettings.PAGE_STATUS )) else: - menu = self.addMenu(self.tr("Set Importance to ...")) + menu = qtAddMenu(self, self.tr("Set Importance to ...")) current = self._item.itemImport for key, entry in SHARED.project.data.itemImport.iterItems(): name = entry.name if not multi and current == key: name += f" ({nwUnicode.U_CHECK})" - action = menu.addAction(entry.icon, name) + action = qtAddAction(menu, name) + action.setIcon(entry.icon) if multi: action.triggered.connect(qtLambda(self._iterSetItemImport, key)) else: action.triggered.connect(qtLambda(self._changeItemImport, key)) menu.addSeparator() - action = menu.addAction(self.tr("Manage Labels ...")) + action = qtAddAction(menu, self.tr("Manage Labels ...")) action.triggered.connect(qtLambda( self._view.projectSettingsRequest.emit, GuiProjectSettings.PAGE_IMPORT @@ -1278,7 +1282,7 @@ class _TreeContextMenu(QMenu): def _itemTransform(self, isFile: bool, isFolder: bool) -> None: """Add actions for the Transform menu.""" - menu = self.addMenu(self.tr("Transform ...")) + menu = qtAddMenu(self, self.tr("Transform ...")) trDoc = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT]) trNote = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE]) @@ -1288,42 +1292,42 @@ class _TreeContextMenu(QMenu): isNoteFile = isFile and self._item.isNoteLayout() if isNoteFile and self._item.documentAllowed(): - action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) + action = qtAddAction(menu, self.tr("Convert to {0}").format(trDoc)) action.triggered.connect(qtLambda(self._changeItemLayout, loDoc)) if isDocFile: - action = menu.addAction(self.tr("Convert to {0}").format(trNote)) + action = qtAddAction(menu, self.tr("Convert to {0}").format(trNote)) action.triggered.connect(qtLambda(self._changeItemLayout, loNote)) if isFolder and self._item.documentAllowed(): - action = menu.addAction(self.tr("Convert to {0}").format(trDoc)) + action = qtAddAction(menu, self.tr("Convert to {0}").format(trDoc)) action.triggered.connect(qtLambda(self._convertFolderToFile, loDoc)) if isFolder: - action = menu.addAction(self.tr("Convert to {0}").format(trNote)) + action = qtAddAction(menu, self.tr("Convert to {0}").format(trNote)) action.triggered.connect(qtLambda(self._convertFolderToFile, loNote)) if self._children and isFile: - action = menu.addAction(self.tr("Merge Child Items into Self")) + action = qtAddAction(menu, self.tr("Merge Child Items into Self")) action.triggered.connect(qtLambda(self._tree.mergeDocuments, self._handle, False)) - action = menu.addAction(self.tr("Merge Child Items into New")) + action = qtAddAction(menu, self.tr("Merge Child Items into New")) action.triggered.connect(qtLambda(self._tree.mergeDocuments, self._handle, True)) if self._children and isFolder: - action = menu.addAction(self.tr("Merge Documents in Folder")) + action = qtAddAction(menu, self.tr("Merge Documents in Folder")) action.triggered.connect(qtLambda(self._tree.mergeDocuments, self._handle, True)) if isFile: - action = menu.addAction(self.tr("Split Document by Headings")) + action = qtAddAction(menu, self.tr("Split Document by Headings")) action.triggered.connect(qtLambda(self._tree.splitDocument, self._handle)) return def _expandCollapse(self) -> None: """Add actions for expand and collapse.""" - action = self.addAction(self.tr("Expand All")) + action = qtAddAction(self, self.tr("Expand All")) action.triggered.connect(qtLambda(self._tree.expandFromIndex, self._indices[0])) - action = self.addAction(self.tr("Collapse All")) + action = qtAddAction(self, self.tr("Collapse All")) action.triggered.connect(qtLambda(self._tree.collapseFromIndex, self._indices[0])) return @@ -1336,7 +1340,7 @@ class _TreeContextMenu(QMenu): text = self.tr("Delete Permanently") else: text = self.tr("Move to Trash") - action = self.addAction(text) + action = qtAddAction(self, text) action.triggered.connect(self._tree.processDeleteRequest) return diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index 78f06838..3c44c82a 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -28,14 +28,14 @@ import logging from time import time from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot -from PyQt6.QtGui import QCursor, QKeyEvent +from PyQt6.QtGui import QAction, QCursor, QKeyEvent from PyQt6.QtWidgets import ( QApplication, QFrame, QHBoxLayout, QLabel, QLineEdit, QToolBar, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED -from novelwriter.common import checkInt, cssCol +from novelwriter.common import checkInt, cssCol, qtAddAction from novelwriter.core.coretools import DocSearch from novelwriter.core.item import NWItem from novelwriter.types import ( @@ -65,8 +65,6 @@ class GuiProjectSearch(QWidget): iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize - mPx = CONFIG.pxInt(2) - tPx = CONFIG.pxInt(4) self._time = time() self._search = DocSearch() @@ -76,7 +74,7 @@ class GuiProjectSearch(QWidget): # Header self.viewLabel = QLabel(self.tr("Project Search"), self) self.viewLabel.setFont(SHARED.theme.guiFontB) - self.viewLabel.setContentsMargins(mPx, tPx, 0, mPx) + self.viewLabel.setContentsMargins(2, 4, 0, 2) # Options self.searchOpt = QToolBar(self) @@ -84,30 +82,30 @@ class GuiProjectSearch(QWidget): self.searchOpt.setIconSize(iSz) self.searchOpt.setContentsMargins(0, 0, 0, 0) - self.toggleCase = self.searchOpt.addAction(self.tr("Case Sensitive")) + self.toggleCase = qtAddAction(self.searchOpt, self.tr("Case Sensitive")) self.toggleCase.setCheckable(True) self.toggleCase.setChecked(CONFIG.searchProjCase) self.toggleCase.toggled.connect(self._toggleCase) - self.toggleWord = self.searchOpt.addAction(self.tr("Whole Words Only")) + self.toggleWord = qtAddAction(self.searchOpt, self.tr("Whole Words Only")) self.toggleWord.setCheckable(True) self.toggleWord.setChecked(CONFIG.searchProjWord) self.toggleWord.toggled.connect(self._toggleWord) - self.toggleRegEx = self.searchOpt.addAction(self.tr("RegEx Mode")) + self.toggleRegEx = qtAddAction(self.searchOpt, self.tr("RegEx Mode")) self.toggleRegEx.setCheckable(True) self.toggleRegEx.setChecked(CONFIG.searchProjRegEx) self.toggleRegEx.toggled.connect(self._toggleRegEx) # Search Box + self.searchAction = QAction("", self) + self.searchAction.setIcon(SHARED.theme.getIcon("search", "blue")) + self.searchAction.triggered.connect(self._processSearch) + self.searchText = QLineEdit(self) self.searchText.setPlaceholderText(self.tr("Search for")) self.searchText.setClearButtonEnabled(True) - - self.searchAction = self.searchText.addAction( - SHARED.theme.getIcon("search", "blue"), QLineEdit.ActionPosition.TrailingPosition - ) - self.searchAction.triggered.connect(self._processSearch) + self.searchText.addAction(self.searchAction, QLineEdit.ActionPosition.TrailingPosition) # Search Result self.searchResult = QTreeWidget(self) @@ -121,10 +119,10 @@ class GuiProjectSearch(QWidget): self.searchResult.itemDoubleClicked.connect(self._searchResultDoubleClicked) self.searchResult.itemSelectionChanged.connect(self._searchResultSelected) - treeHeader = self.searchResult.header() - treeHeader.setStretchLastSection(False) - treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch) - treeHeader.setSectionResizeMode(self.C_COUNT, QtHeaderToContents) + if header := self.searchResult.header(): + header.setStretchLastSection(False) + header.setSectionResizeMode(self.C_NAME, QtHeaderStretch) + header.setSectionResizeMode(self.C_COUNT, QtHeaderToContents) # Assemble self.headerBox = QHBoxLayout() @@ -138,7 +136,7 @@ class GuiProjectSearch(QWidget): self.outerBox.addWidget(self.searchText, 0) self.outerBox.addWidget(self.searchResult, 1) self.outerBox.setContentsMargins(0, 0, 0, 0) - self.outerBox.setSpacing(mPx) + self.outerBox.setSpacing(2) self.setLayout(self.outerBox) self.updateTheme() @@ -153,8 +151,6 @@ class GuiProjectSearch(QWidget): def updateTheme(self) -> None: """Update theme elements.""" - bPx = CONFIG.pxInt(1) - mPx = CONFIG.pxInt(2) qPalette = self.palette() colBase = cssCol(qPalette.base().color()) @@ -162,8 +158,8 @@ class GuiProjectSearch(QWidget): self.setStyleSheet( "QToolBar {padding: 0; background: none;} " - f"QLineEdit {{border: {bPx}px solid {colBase}; padding: {mPx}px;}} " - f"QLineEdit:focus {{border: {bPx}px solid {colFocus};}} " + f"QLineEdit {{border: 1px solid {colBase}; padding: 2px;}} " + f"QLineEdit:focus {{border: 1px solid {colFocus};}} " ) self.searchAction.setIcon(SHARED.theme.getIcon("search", "blue")) diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index cf9d26bf..71e06973 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -31,7 +31,7 @@ from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal from PyQt6.QtGui import QPalette from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget -from novelwriter import CONFIG, SHARED +from novelwriter import SHARED from novelwriter.common import qtLambda from novelwriter.enum import nwView from novelwriter.extensions.eventfilters import StatusTipFilter @@ -114,7 +114,7 @@ class GuiSideBar(QWidget): self.outerBox.addWidget(self.tbStats) self.outerBox.addWidget(self.tbSettings) self.outerBox.setContentsMargins(0, 0, 0, 0) - self.outerBox.setSpacing(CONFIG.pxInt(6)) + self.outerBox.setSpacing(6) self.setLayout(self.outerBox) self.updateTheme() diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py index 413b93df..6dd75830 100644 --- a/novelwriter/gui/statusbar.py +++ b/novelwriter/gui/statusbar.py @@ -57,13 +57,11 @@ class GuiMainStatus(QStatusBar): # Permanent Widgets # ================= - xM = CONFIG.pxInt(8) - # The Spell Checker Language self.langIcon = QLabel("", self) self.langText = QLabel(self.tr("None"), self) self.langIcon.setContentsMargins(0, 0, 0, 0) - self.langText.setContentsMargins(0, 0, xM, 0) + self.langText.setContentsMargins(0, 0, 8, 0) self.addPermanentWidget(self.langIcon) self.addPermanentWidget(self.langText) @@ -71,7 +69,7 @@ class GuiMainStatus(QStatusBar): self.docIcon = StatusLED(iPx, iPx, self) self.docText = QLabel(self.tr("Editor"), self) self.docIcon.setContentsMargins(0, 0, 0, 0) - self.docText.setContentsMargins(0, 0, xM, 0) + self.docText.setContentsMargins(0, 0, 8, 0) self.addPermanentWidget(self.docIcon) self.addPermanentWidget(self.docText) @@ -79,7 +77,7 @@ class GuiMainStatus(QStatusBar): self.projIcon = StatusLED(iPx, iPx, self) self.projText = QLabel(self.tr("Project"), self) self.projIcon.setContentsMargins(0, 0, 0, 0) - self.projText.setContentsMargins(0, 0, xM, 0) + self.projText.setContentsMargins(0, 0, 8, 0) self.addPermanentWidget(self.projIcon) self.addPermanentWidget(self.projText) @@ -87,7 +85,7 @@ class GuiMainStatus(QStatusBar): self.statsIcon = QLabel(self) self.statsText = QLabel("", self) self.statsIcon.setContentsMargins(0, 0, 0, 0) - self.statsText.setContentsMargins(0, 0, xM, 0) + self.statsText.setContentsMargins(0, 0, 8, 0) self.addPermanentWidget(self.statsIcon) self.addPermanentWidget(self.statsText) diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 3f85e2c1..0348d70b 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -544,31 +544,26 @@ class GuiTheme: """Build default style sheets.""" self._styleSheets = {} - aPx = CONFIG.pxInt(2) - bPx = CONFIG.pxInt(4) - cPx = CONFIG.pxInt(6) - dPx = CONFIG.pxInt(8) - tCol = palette.text().color() hCol = palette.highlight().color() # Flat Tab Widget and Tab Bar: self._styleSheets[STYLES_FLAT_TABS] = ( "QTabWidget::pane {border: 0;} " - f"QTabWidget QTabBar::tab {{border: 0; padding: {bPx}px {dPx}px;}} " + "QTabWidget QTabBar::tab {border: 0; padding: 4px 8px;} " f"QTabWidget QTabBar::tab:selected {{color: {cssCol(hCol)};}} " ) # Minimal Tool Button self._styleSheets[STYLES_MIN_TOOLBUTTON] = ( - f"QToolButton {{padding: {aPx}px; margin: 0; border: none; background: transparent;}} " + "QToolButton {padding: 2px; margin: 0; border: none; background: transparent;} " f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} " "QToolButton::menu-indicator {image: none;} " ) # Big Tool Button self._styleSheets[STYLES_BIG_TOOLBUTTON] = ( - f"QToolButton {{padding: {cPx}px; margin: 0; border: none; background: transparent;}} " + "QToolButton {padding: 6px; margin: 0; border: none; background: transparent;} " f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} " "QToolButton::menu-indicator {image: none;} " )