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/config.py b/novelwriter/config.py
index f1389253..bf32577e 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -52,6 +52,31 @@ logger = logging.getLogger(__name__)
class Config:
+ __slots__ = (
+ "_confPath", "_dataPath", "_homePath", "_backPath", "_appPath", "_appRoot", "_hasError",
+ "_errData", "_nwLangPath", "_qtLangPath", "_qLocale", "_dLocale", "_dShortDate",
+ "_dShortDateTime", "_qtTrans", "_recentProjects", "_recentPaths", "_backupPath",
+
+ "appName", "appHandle", "pdfDocs", "guiLocale", "guiTheme", "guiSyntax", "guiFont",
+ "hideVScroll", "hideHScroll", "lastNotes", "nativeFont", "iconTheme", "iconColTree",
+ "iconColDocs", "mainWinSize", "welcomeWinSize", "prefsWinSize", "mainPanePos",
+ "viewPanePos", "outlinePanePos", "autoSaveProj", "autoSaveDoc", "emphLabels",
+ "backupOnClose", "askBeforeBackup", "textFont", "textWidth", "textMargin", "tabWidth",
+ "focusWidth", "hideFocusFooter", "showFullPath", "autoSelect", "doJustify",
+ "showTabsNSpaces", "showLineEndings", "showMultiSpaces", "doReplace", "doReplaceSQuote",
+ "doReplaceDQuote", "doReplaceDash", "doReplaceDots", "autoScroll", "autoScrollPos",
+ "scrollPastEnd", "dialogStyle", "allowOpenDial", "dialogLine", "narratorBreak",
+ "narratorDialog", "altDialogOpen", "altDialogClose", "highlightEmph", "stopWhenIdle",
+ "userIdleTime", "incNotesWCount", "fmtApostrophe", "fmtSQuoteOpen", "fmtSQuoteClose",
+ "fmtDQuoteOpen", "fmtDQuoteClose", "fmtPadBefore", "fmtPadAfter", "fmtPadThin",
+ "spellLanguage", "showViewerPanel", "showEditToolBar", "showSessionTime", "viewComments",
+ "viewSynopsis", "searchCase", "searchWord", "searchRegEx", "searchLoop", "searchNextFile",
+ "searchMatchCap", "searchProjCase", "searchProjWord", "searchProjRegEx", "verQtString",
+ "verQtValue", "verPyQtString", "verPyQtValue", "verPyString", "osType", "osLinux",
+ "osWindows", "osDarwin", "osUnknown", "hostName", "kernelVer", "isDebug", "memInfo",
+ "hasEnchant",
+ )
+
LANG_NW = 1
LANG_PROJ = 2
@@ -126,12 +151,12 @@ class Config:
self.iconColDocs = False # Keep theme colours on documents
# Size Settings
- self._mainWinSize = [1200, 650] # Last size of the main GUI window
- self._welcomeSize = [800, 550] # Last size of the welcome window
- self._prefsWinSize = [700, 615] # Last size of the Preferences dialog
- self._mainPanePos = [300, 800] # Last position of the main window splitter
- self._viewPanePos = [500, 150] # Last position of the document viewer splitter
- self._outlnPanePos = [500, 150] # Last position of the outline panel splitter
+ self.mainWinSize = [1200, 650] # Last size of the main GUI window
+ self.welcomeWinSize = [800, 550] # Last size of the welcome window
+ self.prefsWinSize = [700, 615] # Last size of the Preferences dialog
+ self.mainPanePos = [300, 800] # Last position of the main window splitter
+ self.viewPanePos = [500, 150] # Last position of the document viewer splitter
+ self.outlinePanePos = [500, 150] # Last position of the outline panel splitter
# Project Settings
self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
@@ -269,30 +294,6 @@ class Config:
def recentProjects(self) -> RecentProjects:
return self._recentProjects
- @property
- def mainWinSize(self) -> list[int]:
- return self._mainWinSize
-
- @property
- def welcomeWinSize(self) -> list[int]:
- return self._welcomeSize
-
- @property
- def preferencesWinSize(self) -> list[int]:
- return self._prefsWinSize
-
- @property
- def mainPanePos(self) -> list[int]:
- return self._mainPanePos
-
- @property
- def viewPanePos(self) -> list[int]:
- return self._viewPanePos
-
- @property
- def outlinePanePos(self) -> list[int]:
- return self._outlnPanePos
-
##
# Getters
##
@@ -300,17 +301,9 @@ class Config:
def getTextWidth(self, focusMode: bool = False) -> int:
"""Get the text with for the correct editor mode."""
if focusMode:
- return self.pxInt(max(self.focusWidth, 200))
+ return max(self.focusWidth, 200)
else:
- return self.pxInt(max(self.textWidth, 200))
-
- def getTextMargin(self) -> int:
- """Get the scaled text margin."""
- return self.pxInt(max(self.textMargin, 0))
-
- def getTabWidth(self) -> int:
- """Get the scaled tab width."""
- return self.pxInt(max(self.tabWidth, 0))
+ return max(self.textWidth, 200)
##
# Setters
@@ -322,35 +315,20 @@ class Config:
adjust it a bit, and we don't want the main window to shrink or
grow each time the app is opened.
"""
- if abs(self._mainWinSize[0] - width) > 5:
- self._mainWinSize[0] = width
- if abs(self._mainWinSize[1] - height) > 5:
- self._mainWinSize[1] = height
+ if abs(self.mainWinSize[0] - width) > 5:
+ self.mainWinSize[0] = width
+ if abs(self.mainWinSize[1] - height) > 5:
+ self.mainWinSize[1] = height
return
def setWelcomeWinSize(self, width: int, height: int) -> None:
"""Set the size of the Preferences dialog window."""
- self._welcomeSize = [width, height]
+ self.welcomeWinSize = [width, height]
return
def setPreferencesWinSize(self, width: int, height: int) -> None:
"""Set the size of the Preferences dialog window."""
- self._prefsWinSize = [width, height]
- return
-
- def setMainPanePos(self, pos: list[int]) -> None:
- """Set the position of the main GUI splitter."""
- self._mainPanePos = pos
- return
-
- def setViewPanePos(self, pos: list[int]) -> None:
- """Set the position of the viewer meta data splitter."""
- self._viewPanePos = pos
- return
-
- def setOutlinePanePos(self, pos: list[int]) -> None:
- """Set the position of the outline details splitter."""
- self._outlnPanePos = pos
+ self.prefsWinSize = [width, height]
return
def setLastPath(self, key: str, path: str | Path) -> None:
@@ -421,14 +399,6 @@ class Config:
# Methods
##
- def pxInt(self, value: int) -> int:
- """Deprecated. Do not use."""
- return value
-
- def rpxInt(self, value: int) -> int:
- """Deprecated. Do not use."""
- return value
-
def homePath(self) -> Path:
"""The user's home folder."""
return self._homePath
@@ -614,12 +584,12 @@ class Config:
# Sizes
sec = "Sizes"
- self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
- self._welcomeSize = conf.rdIntList(sec, "welcome", self._welcomeSize)
- self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
- self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
- self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
- self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
+ self.mainWinSize = conf.rdIntList(sec, "mainwindow", self.mainWinSize)
+ self.welcomeWinSize = conf.rdIntList(sec, "welcome", self.welcomeWinSize)
+ self.prefsWinSize = conf.rdIntList(sec, "preferences", self.prefsWinSize)
+ self.mainPanePos = conf.rdIntList(sec, "mainpane", self.mainPanePos)
+ self.viewPanePos = conf.rdIntList(sec, "viewpane", self.viewPanePos)
+ self.outlinePanePos = conf.rdIntList(sec, "outlinepane", self.outlinePanePos)
# Project
sec = "Project"
@@ -728,12 +698,12 @@ class Config:
}
conf["Sizes"] = {
- "mainwindow": self._packList(self._mainWinSize),
- "welcome": self._packList(self._welcomeSize),
- "preferences": self._packList(self._prefsWinSize),
- "mainpane": self._packList(self._mainPanePos),
- "viewpane": self._packList(self._viewPanePos),
- "outlinepane": self._packList(self._outlnPanePos),
+ "mainwindow": self._packList(self.mainWinSize),
+ "welcome": self._packList(self.welcomeWinSize),
+ "preferences": self._packList(self.prefsWinSize),
+ "mainpane": self._packList(self.mainPanePos),
+ "viewpane": self._packList(self.viewPanePos),
+ "outlinepane": self._packList(self.outlinePanePos),
}
conf["Project"] = {
diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py
index efc61388..0d5ca304 100644
--- a/novelwriter/dialogs/about.py
+++ b/novelwriter/dialogs/about.py
@@ -49,18 +49,13 @@ class GuiAbout(NDialog):
self.setObjectName("GuiAbout")
self.setWindowTitle(self.tr("About novelWriter"))
- self.resize(CONFIG.pxInt(700), CONFIG.pxInt(500))
-
- hA = CONFIG.pxInt(8)
- hB = CONFIG.pxInt(16)
- nwH = CONFIG.pxInt(36)
- nwPx = CONFIG.pxInt(128)
+ self.resize(700, 500)
# Logo and Banner
- self.nwImage = SHARED.theme.loadDecoration("nw-text", h=nwH)
+ self.nwImage = SHARED.theme.loadDecoration("nw-text", h=36)
self.nwLogo = QLabel(self)
- self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (nwPx, nwPx)))
+ self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (128, 128)))
self.nwLabel = QLabel(self)
self.nwLabel.setPixmap(self.nwImage)
@@ -79,8 +74,7 @@ class GuiAbout(NDialog):
self.txtCredits = QTextBrowser(self)
self.txtCredits.setOpenExternalLinks(True)
- self.txtCredits.document().setDocumentMargin(0)
- self.txtCredits.setViewportMargins(0, hA, hA, 0)
+ self.txtCredits.setViewportMargins(0, 8, 8, 0)
# Buttons
self.btnBox = QDialogButtonBox(QtDialogClose, self)
@@ -88,15 +82,15 @@ class GuiAbout(NDialog):
# Assemble
self.innerBox = QVBoxLayout()
- self.innerBox.addSpacing(hB)
+ self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.nwLabel)
self.innerBox.addWidget(self.nwInfo)
- self.innerBox.addSpacing(hA)
+ self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.nwLicence)
- self.innerBox.addSpacing(hA)
+ self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.lblCredits)
self.innerBox.addWidget(self.txtCredits)
- self.innerBox.addSpacing(hB)
+ self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.btnBox)
self.outerBox = QHBoxLayout()
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 4d1d529f..2033b118 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -32,7 +32,7 @@ from PyQt6.QtWidgets import (
QListWidgetItem, QVBoxLayout, QWidget
)
-from novelwriter import CONFIG, SHARED
+from novelwriter import SHARED
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NDialog
from novelwriter.extensions.switch import NSwitch
@@ -63,14 +63,11 @@ class GuiDocMerge(NDialog):
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- hSp = CONFIG.pxInt(12)
- vSp = CONFIG.pxInt(8)
- bSp = CONFIG.pxInt(12)
self.listBox = QListWidget(self)
self.listBox.setIconSize(iSz)
- self.listBox.setMinimumWidth(CONFIG.pxInt(400))
- self.listBox.setMinimumHeight(CONFIG.pxInt(180))
+ self.listBox.setMinimumWidth(400)
+ self.listBox.setMinimumHeight(180)
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
@@ -82,7 +79,7 @@ class GuiDocMerge(NDialog):
self.optBox = QGridLayout()
self.optBox.addWidget(self.trashLabel, 0, 0)
self.optBox.addWidget(self.trashSwitch, 0, 1)
- self.optBox.setHorizontalSpacing(hSp)
+ self.optBox.setHorizontalSpacing(12)
self.optBox.setColumnStretch(2, 1)
# Buttons
@@ -91,18 +88,19 @@ class GuiDocMerge(NDialog):
self.buttonBox.rejected.connect(self.reject)
self.resetButton = self.buttonBox.addButton(QtDialogReset)
- self.resetButton.clicked.connect(self._resetList)
+ if self.resetButton:
+ self.resetButton.clicked.connect(self._resetList)
# Assemble
self.outerBox = QVBoxLayout()
self.outerBox.setSpacing(0)
self.outerBox.addWidget(self.headLabel)
self.outerBox.addWidget(self.helpLabel)
- self.outerBox.addSpacing(vSp)
+ self.outerBox.addSpacing(8)
self.outerBox.addWidget(self.listBox)
- self.outerBox.addSpacing(vSp)
+ self.outerBox.addSpacing(8)
self.outerBox.addLayout(self.optBox)
- self.outerBox.addSpacing(bSp)
+ self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox)
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index 259125a6..4707eb51 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -32,7 +32,7 @@ from PyQt6.QtWidgets import (
QListWidget, QListWidgetItem, QVBoxLayout, QWidget
)
-from novelwriter import CONFIG, SHARED
+from novelwriter import SHARED
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NDialog
from novelwriter.extensions.switch import NSwitch
@@ -67,9 +67,6 @@ class GuiDocSplit(NDialog):
# Values
iPx = SHARED.theme.baseIconHeight
- hSp = CONFIG.pxInt(12)
- vSp = CONFIG.pxInt(8)
- bSp = CONFIG.pxInt(12)
pOptions = SHARED.project.options
spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3)
@@ -79,11 +76,11 @@ class GuiDocSplit(NDialog):
# Heading Selection
self.listBox = QListWidget(self)
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
- self.listBox.setMinimumWidth(CONFIG.pxInt(400))
- self.listBox.setMinimumHeight(CONFIG.pxInt(180))
+ self.listBox.setMinimumWidth(400)
+ self.listBox.setMinimumHeight(180)
self.splitLevel = QComboBox(self)
- self.splitLevel.addItem(self.tr("Split on Heading Level 1 (Partition)"), 1)
+ self.splitLevel.addItem(self.tr("Split on Heading Level 1 (Partition)"), 1)
self.splitLevel.addItem(self.tr("Split up to Heading Level 2 (Chapter)"), 2)
self.splitLevel.addItem(self.tr("Split up to Heading Level 3 (Scene)"), 3)
self.splitLevel.addItem(self.tr("Split up to Heading Level 4 (Section)"), 4)
@@ -111,8 +108,8 @@ class GuiDocSplit(NDialog):
self.optBox.addWidget(self.hierarchySwitch, 1, 1)
self.optBox.addWidget(self.trashLabel, 2, 0)
self.optBox.addWidget(self.trashSwitch, 2, 1)
- self.optBox.setVerticalSpacing(vSp)
- self.optBox.setHorizontalSpacing(hSp)
+ self.optBox.setVerticalSpacing(8)
+ self.optBox.setHorizontalSpacing(12)
self.optBox.setColumnStretch(3, 1)
# Buttons
@@ -125,12 +122,12 @@ class GuiDocSplit(NDialog):
self.outerBox.setSpacing(0)
self.outerBox.addWidget(self.headLabel)
self.outerBox.addWidget(self.helpLabel)
- self.outerBox.addSpacing(vSp)
+ self.outerBox.addSpacing(8)
self.outerBox.addWidget(self.listBox)
self.outerBox.addWidget(self.splitLevel)
- self.outerBox.addSpacing(vSp)
+ self.outerBox.addSpacing(8)
self.outerBox.addLayout(self.optBox)
- self.outerBox.addSpacing(bSp)
+ self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox)
diff --git a/novelwriter/dialogs/editlabel.py b/novelwriter/dialogs/editlabel.py
index 9bc4c2b4..caf97335 100644
--- a/novelwriter/dialogs/editlabel.py
+++ b/novelwriter/dialogs/editlabel.py
@@ -27,7 +27,6 @@ import logging
from PyQt6.QtWidgets import QDialogButtonBox, QHBoxLayout, QLabel, QLineEdit, QVBoxLayout, QWidget
-from novelwriter import CONFIG
from novelwriter.extensions.modified import NDialog
from novelwriter.types import QtAccepted, QtDialogCancel, QtDialogOk
@@ -43,12 +42,9 @@ class GuiEditLabel(NDialog):
self.setObjectName("GuiEditLabel")
self.setWindowTitle(self.tr("Item Label"))
- mVd = CONFIG.pxInt(220)
- mSp = CONFIG.pxInt(12)
-
# Item Label
self.labelValue = QLineEdit(self)
- self.labelValue.setMinimumWidth(mVd)
+ self.labelValue.setMinimumWidth(220)
self.labelValue.setMaxLength(200)
self.labelValue.setText(text)
self.labelValue.selectAll()
@@ -62,10 +58,10 @@ class GuiEditLabel(NDialog):
self.innerBox = QHBoxLayout()
self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
self.innerBox.addWidget(self.labelValue, 1)
- self.innerBox.setSpacing(mSp)
+ self.innerBox.setSpacing(12)
self.outerBox = QVBoxLayout()
- self.outerBox.setSpacing(mSp)
+ self.outerBox.setSpacing(12)
self.outerBox.addLayout(self.innerBox, 1)
self.outerBox.addWidget(self.buttonBox, 0)
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 8e3d65f1..f746fb2b 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -27,7 +27,7 @@ from __future__ import annotations
import logging
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
-from PyQt6.QtGui import QCloseEvent, QKeyEvent, QKeySequence
+from PyQt6.QtGui import QAction, QCloseEvent, QKeyEvent, QKeySequence
from PyQt6.QtWidgets import (
QCompleter, QDialogButtonBox, QFileDialog, QHBoxLayout, QLineEdit,
QPushButton, QVBoxLayout, QWidget
@@ -58,23 +58,23 @@ class GuiPreferences(NDialog):
logger.debug("Create: GuiPreferences")
self.setObjectName("GuiPreferences")
self.setWindowTitle(self.tr("Preferences"))
- self.setMinimumSize(CONFIG.pxInt(600), CONFIG.pxInt(500))
- self.resize(*CONFIG.preferencesWinSize)
+ self.setMinimumSize(600, 500)
+ self.resize(*CONFIG.prefsWinSize)
# Title
self.titleLabel = NColourLabel(
self.tr("Preferences"), self, color=SHARED.theme.helpText,
- scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
+ scale=NColourLabel.HEADER_SCALE, indent=4,
)
# Search Box
+ self.searchAction = QAction(SHARED.theme.getIcon("search"), "")
+ self.searchAction.triggered.connect(self._gotoSearch)
+
self.searchText = QLineEdit(self)
self.searchText.setPlaceholderText(self.tr("Search"))
- self.searchText.setMinimumWidth(CONFIG.pxInt(200))
- self.searchAction = self.searchText.addAction(
- SHARED.theme.getIcon("search"), QLineEdit.ActionPosition.TrailingPosition
- )
- self.searchAction.triggered.connect(self._gotoSearch)
+ self.searchText.setMinimumWidth(200)
+ self.searchText.addAction(self.searchAction, QLineEdit.ActionPosition.TrailingPosition)
# SideBar
self.sidebar = NPagedSideBar(self)
@@ -105,7 +105,7 @@ class GuiPreferences(NDialog):
self.outerBox.addLayout(self.searchBox)
self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox)
- self.outerBox.setSpacing(CONFIG.pxInt(8))
+ self.outerBox.setSpacing(8)
self.setLayout(self.outerBox)
self.setSizeGripEnabled(True)
@@ -134,8 +134,6 @@ class GuiPreferences(NDialog):
section = 0
iSz = SHARED.theme.baseIconSize
boxFixed = 6*SHARED.theme.textNWidth
- minWidth = CONFIG.pxInt(200)
- fontWidth = CONFIG.pxInt(162)
# Temporary Variables
self._guiFont = CONFIG.guiFont
@@ -154,7 +152,7 @@ class GuiPreferences(NDialog):
# Display Language
self.guiLocale = NComboBox(self)
- self.guiLocale.setMinimumWidth(minWidth)
+ self.guiLocale.setMinimumWidth(200)
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
self.guiLocale.addItem(name, lang)
self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB")
@@ -166,7 +164,7 @@ class GuiPreferences(NDialog):
# Colour Theme
self.guiTheme = NComboBox(self)
- self.guiTheme.setMinimumWidth(minWidth)
+ self.guiTheme.setMinimumWidth(200)
for theme, name in SHARED.theme.listThemes():
self.guiTheme.addItem(name, theme)
self.guiTheme.setCurrentData(CONFIG.guiTheme, "default")
@@ -178,7 +176,7 @@ class GuiPreferences(NDialog):
# Icon Theme
self.iconTheme = NComboBox(self)
- self.iconTheme.setMinimumWidth(minWidth)
+ self.iconTheme.setMinimumWidth(200)
for theme, name in SHARED.theme.iconCache.listThemes():
self.iconTheme.addItem(name, theme)
self.iconTheme.setCurrentData(CONFIG.iconTheme, "material_rounded_bold")
@@ -190,7 +188,7 @@ class GuiPreferences(NDialog):
# Tree Icon Colours
self.iconColTree = NComboBox(self)
- self.iconColTree.setMinimumWidth(minWidth)
+ self.iconColTree.setMinimumWidth(200)
for key, label in nwLabels.THEME_COLORS.items():
self.iconColTree.addItem(trConst(label), key)
self.iconColTree.setCurrentData(CONFIG.iconColTree, "theme")
@@ -211,7 +209,7 @@ class GuiPreferences(NDialog):
# Application Font Family
self.guiFont = QLineEdit(self)
self.guiFont.setReadOnly(True)
- self.guiFont.setMinimumWidth(fontWidth)
+ self.guiFont.setMinimumWidth(162)
self.guiFont.setText(describeFont(self._guiFont))
self.guiFont.setCursorPosition(0)
self.guiFontButton = NIconToolButton(self, iSz, "font")
@@ -256,7 +254,7 @@ class GuiPreferences(NDialog):
# Document Colour Theme
self.guiSyntax = NComboBox(self)
- self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
+ self.guiSyntax.setMinimumWidth(200)
for syntax, name in SHARED.theme.listSyntax():
self.guiSyntax.addItem(name, syntax)
self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light")
@@ -269,7 +267,7 @@ class GuiPreferences(NDialog):
# Document Font Family
self.textFont = QLineEdit(self)
self.textFont.setReadOnly(True)
- self.textFont.setMinimumWidth(fontWidth)
+ self.textFont.setMinimumWidth(162)
self.textFont.setText(describeFont(CONFIG.textFont))
self.textFont.setCursorPosition(0)
self.textFontButton = NIconToolButton(self, iSz, "font")
@@ -482,7 +480,7 @@ class GuiPreferences(NDialog):
# Spell Checking
self.spellLanguage = NComboBox(self)
- self.spellLanguage.setMinimumWidth(minWidth)
+ self.spellLanguage.setMinimumWidth(200)
if CONFIG.hasEnchant:
for tag, language in SHARED.spelling.listDictionaries():
@@ -651,8 +649,6 @@ class GuiPreferences(NDialog):
self.sidebar.addButton(title, section)
self.mainForm.addGroupLabel(title, section)
- boxWidth = CONFIG.pxInt(150)
-
# Auto-Replace as You Type Main Switch
self.doReplace = NSwitch(self)
self.doReplace.setChecked(CONFIG.doReplace)
@@ -701,7 +697,7 @@ class GuiPreferences(NDialog):
# Pad Before
self.fmtPadBefore = QLineEdit(self)
self.fmtPadBefore.setMaxLength(32)
- self.fmtPadBefore.setMinimumWidth(boxWidth)
+ self.fmtPadBefore.setMinimumWidth(150)
self.fmtPadBefore.setText(CONFIG.fmtPadBefore)
self.mainForm.addRow(
self.tr("Insert non-breaking space before"), self.fmtPadBefore,
@@ -711,7 +707,7 @@ class GuiPreferences(NDialog):
# Pad After
self.fmtPadAfter = QLineEdit(self)
self.fmtPadAfter.setMaxLength(32)
- self.fmtPadAfter.setMinimumWidth(boxWidth)
+ self.fmtPadAfter.setMinimumWidth(150)
self.fmtPadAfter.setText(CONFIG.fmtPadAfter)
self.mainForm.addRow(
self.tr("Insert non-breaking space after"), self.fmtPadAfter,
diff --git a/novelwriter/dialogs/projectsettings.py b/novelwriter/dialogs/projectsettings.py
index 222a8c77..414edaa3 100644
--- a/novelwriter/dialogs/projectsettings.py
+++ b/novelwriter/dialogs/projectsettings.py
@@ -30,7 +30,7 @@ import logging
from pathlib import Path
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
-from PyQt6.QtGui import QCloseEvent, QColor
+from PyQt6.QtGui import QAction, QCloseEvent, QColor
from PyQt6.QtWidgets import (
QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget,
@@ -71,16 +71,16 @@ class GuiProjectSettings(NDialog):
self.setWindowTitle(self.tr("Project Settings"))
options = SHARED.project.options
- self.setMinimumSize(CONFIG.pxInt(500), CONFIG.pxInt(400))
+ self.setMinimumSize(500, 400)
self.resize(
- CONFIG.pxInt(options.getInt("GuiProjectSettings", "winWidth", CONFIG.pxInt(650))),
- CONFIG.pxInt(options.getInt("GuiProjectSettings", "winHeight", CONFIG.pxInt(500)))
+ options.getInt("GuiProjectSettings", "winWidth", 650),
+ options.getInt("GuiProjectSettings", "winHeight", 500),
)
# Title
self.titleLabel = NColourLabel(
self.tr("Project Settings"), self, color=SHARED.theme.helpText,
- scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
+ scale=NColourLabel.HEADER_SCALE, indent=4,
)
# SideBar
@@ -125,7 +125,7 @@ class GuiProjectSettings(NDialog):
self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox)
- self.outerBox.setSpacing(CONFIG.pxInt(8))
+ self.outerBox.setSpacing(8)
self.setLayout(self.outerBox)
self.setSizeGripEnabled(True)
@@ -210,16 +210,14 @@ class GuiProjectSettings(NDialog):
def _saveSettings(self) -> None:
"""Save GUI settings."""
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
- statusColW = CONFIG.rpxInt(self.statusPage.columnWidth())
- importColW = CONFIG.rpxInt(self.importPage.columnWidth())
- replaceColW = CONFIG.rpxInt(self.replacePage.columnWidth())
+ statusColW = self.statusPage.columnWidth()
+ importColW = self.importPage.columnWidth()
+ replaceColW = self.replacePage.columnWidth()
logger.debug("Saving State: GuiProjectSettings")
options = SHARED.project.options
- options.setValue("GuiProjectSettings", "winWidth", winWidth)
- options.setValue("GuiProjectSettings", "winHeight", winHeight)
+ options.setValue("GuiProjectSettings", "winWidth", self.width())
+ options.setValue("GuiProjectSettings", "winHeight", self.height())
options.setValue("GuiProjectSettings", "statusColW", statusColW)
options.setValue("GuiProjectSettings", "importColW", importColW)
options.setValue("GuiProjectSettings", "replaceColW", replaceColW)
@@ -232,7 +230,6 @@ class _SettingsPage(NScrollableForm):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
- xW = CONFIG.pxInt(200)
data = SHARED.project.data
self.setHelpTextStyle(SHARED.theme.helpText)
self.setRowIndent(0)
@@ -240,7 +237,7 @@ class _SettingsPage(NScrollableForm):
# Project Name
self.projName = QLineEdit(self)
self.projName.setMaxLength(200)
- self.projName.setMinimumWidth(xW)
+ self.projName.setMinimumWidth(200)
self.projName.setText(data.name)
self.addRow(
self.tr("Project name"), self.projName,
@@ -251,7 +248,7 @@ class _SettingsPage(NScrollableForm):
# Project Author
self.projAuthor = QLineEdit(self)
self.projAuthor.setMaxLength(200)
- self.projAuthor.setMinimumWidth(xW)
+ self.projAuthor.setMinimumWidth(200)
self.projAuthor.setText(data.author)
self.addRow(
self.tr("Author(s)"), self.projAuthor,
@@ -262,7 +259,7 @@ class _SettingsPage(NScrollableForm):
# Project Language
projLang = data.language or CONFIG.guiLocale
self.projLang = NComboBox(self)
- self.projLang.setMinimumWidth(xW)
+ self.projLang.setMinimumWidth(200)
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
self.projLang.addItem(language, tag)
self.projLang.setCurrentData(projLang, projLang)
@@ -274,7 +271,7 @@ class _SettingsPage(NScrollableForm):
# Spell Check Language
self.spellLang = NComboBox(self)
- self.spellLang.setMinimumWidth(xW)
+ self.spellLang.setMinimumWidth(200)
self.spellLang.addItem(self.tr("Default"), "None")
if CONFIG.hasEnchant:
for tag, language in SHARED.spelling.listDictionaries():
@@ -323,9 +320,7 @@ class _StatusPage(NFixedPage):
pageLabel = self.tr("Project Note Importance Levels")
colSetting = "importColW"
- wCol0 = CONFIG.pxInt(
- SHARED.project.options.getInt("GuiProjectSettings", colSetting, 130)
- )
+ wCol0 = SHARED.project.options.getInt("GuiProjectSettings", colSetting, 130)
self._changed = False
self._color = QColor(100, 100, 100)
@@ -334,7 +329,6 @@ class _StatusPage(NFixedPage):
self._iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- bPd = CONFIG.pxInt(4)
iColor = self.palette().text().color()
@@ -395,7 +389,7 @@ class _StatusPage(NFixedPage):
self.labelText.textEdited.connect(self._onNameEdit)
buttonStyle = (
- f"QToolButton {{padding: 0 {bPd}px;}} "
+ "QToolButton {padding: 0 4px;} "
"QToolButton::menu-indicator {image: none;}"
)
@@ -406,12 +400,14 @@ class _StatusPage(NFixedPage):
self.colorButton.setEnabled(False)
self.colorButton.clicked.connect(self._onColourSelect)
- def buildMenu(menu: QMenu, items: dict[nwStatusShape, str]) -> None:
- for shape, label in items.items():
- icon = NWStatus.createIcon(self._iPx, iColor, shape)
- action = menu.addAction(icon, trConst(label))
- action.triggered.connect(qtLambda(self._selectShape, shape))
- self._icons[shape] = icon
+ def buildMenu(menu: QMenu | None, items: dict[nwStatusShape, str]) -> None:
+ if menu is not None:
+ for shape, label in items.items():
+ icon = NWStatus.createIcon(self._iPx, iColor, shape)
+ action = QAction(icon, trConst(label))
+ action.triggered.connect(qtLambda(self._selectShape, shape))
+ menu.addAction(action)
+ self._icons[shape] = icon
self.shapeMenu = QMenu(self)
buildMenu(self.shapeMenu, nwLabels.SHAPES_PLAIN)
@@ -676,10 +672,7 @@ class _ReplacePage(NFixedPage):
self._changed = False
iSz = SHARED.theme.baseIconSize
-
- wCol0 = CONFIG.pxInt(
- SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
- )
+ wCol0 = SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
# Title
self.pageTitle = NColourLabel(
diff --git a/novelwriter/dialogs/quotes.py b/novelwriter/dialogs/quotes.py
index 373f8ca5..20c57801 100644
--- a/novelwriter/dialogs/quotes.py
+++ b/novelwriter/dialogs/quotes.py
@@ -32,7 +32,6 @@ from PyQt6.QtWidgets import (
QListWidgetItem, QVBoxLayout, QWidget
)
-from novelwriter import CONFIG
from novelwriter.constants import nwQuotes, trConst
from novelwriter.extensions.modified import NDialog
from novelwriter.types import (
@@ -62,18 +61,14 @@ class GuiQuoteSelect(NDialog):
self._selected = current
- qMetrics = QFontMetrics(self.font())
- pxW = 7*qMetrics.boundingRectChar("M").width()
- pxH = 7*qMetrics.boundingRectChar("M").height()
- pxH = 7*qMetrics.boundingRectChar("M").height()
-
lblFont = self.font()
lblFont.setPointSizeF(4*lblFont.pointSizeF())
+ metrics = QFontMetrics(self.font())
# Preview Label
self.previewLabel = QLabel(current, self)
self.previewLabel.setFont(lblFont)
- self.previewLabel.setFixedSize(QSize(pxW, pxH))
+ self.previewLabel.setFixedSize(QSize(4*metrics.maxWidth(), 5*metrics.height()))
self.previewLabel.setAlignment(QtAlignCenter)
self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain)
@@ -84,15 +79,15 @@ class GuiQuoteSelect(NDialog):
minSize = 100
for sKey, sLabel in nwQuotes.SYMBOLS.items():
text = "[ %s ] %s" % (sKey, trConst(sLabel))
- minSize = max(minSize, qMetrics.boundingRect(text).width())
+ minSize = max(minSize, metrics.boundingRect(text).width())
qtItem = QListWidgetItem(text)
qtItem.setData(self.D_KEY, sKey)
self.listBox.addItem(qtItem)
if sKey == current:
self.listBox.setCurrentItem(qtItem)
- self.listBox.setMinimumWidth(minSize + CONFIG.pxInt(40))
- self.listBox.setMinimumHeight(CONFIG.pxInt(150))
+ self.listBox.setMinimumWidth(minSize + 40)
+ self.listBox.setMinimumHeight(150)
# Buttons
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index 1988b79b..cf91b491 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -56,15 +56,12 @@ class GuiWordList(NDialog):
self.setWindowTitle(self.tr("Project Word List"))
iSz = SHARED.theme.baseIconSize
- mS = CONFIG.pxInt(250)
- wW = CONFIG.pxInt(320)
- wH = CONFIG.pxInt(340)
- self.setMinimumWidth(mS)
- self.setMinimumHeight(mS)
+ self.setMinimumWidth(250)
+ self.setMinimumHeight(250)
self.resize(
- CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winWidth", wW)),
- CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winHeight", wH))
+ SHARED.project.options.getInt("GuiWordList", "winWidth", 320),
+ SHARED.project.options.getInt("GuiWordList", "winHeight", 340),
)
# Header
@@ -118,9 +115,9 @@ class GuiWordList(NDialog):
self.outerBox.addLayout(self.headerBox, 0)
self.outerBox.addWidget(self.listBox, 1)
self.outerBox.addLayout(self.editBox, 0)
- self.outerBox.addSpacing(CONFIG.pxInt(12))
+ self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox, 0)
- self.outerBox.setSpacing(CONFIG.pxInt(4))
+ self.outerBox.setSpacing(4)
self.setLayout(self.outerBox)
@@ -230,14 +227,10 @@ class GuiWordList(NDialog):
def _saveGuiSettings(self) -> None:
"""Save GUI settings."""
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
-
logger.debug("Saving State: GuiWordList")
pOptions = SHARED.project.options
- pOptions.setValue("GuiWordList", "winWidth", winWidth)
- pOptions.setValue("GuiWordList", "winHeight", winHeight)
-
+ pOptions.setValue("GuiWordList", "winWidth", self.width())
+ pOptions.setValue("GuiWordList", "winHeight", self.height())
return
def _addWord(self, word: str) -> None:
diff --git a/novelwriter/error.py b/novelwriter/error.py
index 6f272c0b..7410cc95 100644
--- a/novelwriter/error.py
+++ b/novelwriter/error.py
@@ -65,11 +65,11 @@ class NWErrorMessage(QDialog):
# Widgets
self.msgIcon = QLabel()
- self.msgIcon.setPixmap(
- QApplication.style().standardIcon(
- QStyle.StandardPixmap.SP_MessageBoxCritical
- ).pixmap(64, 64)
- )
+ if style := QApplication.style():
+ self.msgIcon.setPixmap(
+ style.standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical).pixmap(64, 64)
+ )
+
self.msgHead = QLabel()
self.msgHead.setOpenExternalLinks(True)
self.msgHead.setWordWrap(True)
diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py
index 47b74175..f9a0d940 100644
--- a/novelwriter/extensions/configlayout.py
+++ b/novelwriter/extensions/configlayout.py
@@ -33,7 +33,6 @@ from PyQt6.QtWidgets import (
QVBoxLayout, QWidget
)
-from novelwriter import CONFIG
from novelwriter.types import QtScrollAsNeeded
DEFAULT_SCALE = 0.9
@@ -99,14 +98,14 @@ class NScrollableForm(QScrollArea):
self._helpCol = QColor(0, 0, 0)
self._fontScale = DEFAULT_SCALE
self._first = True
- self._indent = CONFIG.pxInt(12)
+ self._indent = 12
self._sections: dict[int, QLabel] = {}
self._editable: dict[str, NColourLabel] = {}
self._index: dict[str, QWidget] = {}
self._layout = QVBoxLayout()
- self._layout.setSpacing(CONFIG.pxInt(12))
+ self._layout.setSpacing(12)
self._widget = QWidget(self)
self._widget.setLayout(self._layout)
@@ -156,24 +155,25 @@ class NScrollableForm(QScrollArea):
def scrollToSection(self, identifier: int) -> None:
"""Scroll to the requested section identifier."""
if identifier in self._sections:
- yPos = self._sections[identifier].pos().y() - CONFIG.pxInt(8)
- self.verticalScrollBar().setValue(yPos)
+ yPos = self._sections[identifier].pos().y() - 8
+ if vBar := self.verticalScrollBar():
+ vBar.setValue(yPos)
return
def scrollToLabel(self, label: str) -> None:
"""Scroll to the requested label."""
if label in self._index:
- yPos = self._index[label].pos().y() - CONFIG.pxInt(8)
- self.verticalScrollBar().setValue(yPos)
+ yPos = self._index[label].pos().y() - 8
+ if vBar := self.verticalScrollBar():
+ vBar.setValue(yPos)
return
def addGroupLabel(self, label: str, identifier: int | None = None) -> None:
"""Add a text label to separate groups of settings."""
- hM = CONFIG.pxInt(4)
qLabel = QLabel(f"{label}", self)
- qLabel.setContentsMargins(0, hM, 0, hM)
+ qLabel.setContentsMargins(0, 4, 0, 4)
if not self._first:
- self._layout.addSpacing(5*hM)
+ self._layout.addSpacing(20)
self._layout.addWidget(qLabel)
self._first = False
if identifier is not None:
@@ -192,7 +192,7 @@ class NScrollableForm(QScrollArea):
) -> None:
"""Add a label and a widget as a new row of the form."""
row = QHBoxLayout()
- row.setSpacing(CONFIG.pxInt(12))
+ row.setSpacing(12)
if isinstance(widget, list):
wBox = QHBoxLayout()
@@ -205,7 +205,7 @@ class NScrollableForm(QScrollArea):
icon.setPixmap(item)
wBox.addWidget(icon)
elif isinstance(item, int):
- wBox.addSpacing(CONFIG.pxInt(item))
+ wBox.addSpacing(item)
qWidget = QWidget(self)
qWidget.setLayout(wBox)
else:
@@ -252,7 +252,7 @@ class NScrollableForm(QScrollArea):
def finalise(self) -> None:
"""Finalise the layout when the form is built."""
- self._layout.addSpacing(CONFIG.pxInt(20))
+ self._layout.addSpacing(20)
self._layout.addStretch(1)
return
diff --git a/novelwriter/extensions/pagedsidebar.py b/novelwriter/extensions/pagedsidebar.py
index 6dd835f3..b58de63a 100644
--- a/novelwriter/extensions/pagedsidebar.py
+++ b/novelwriter/extensions/pagedsidebar.py
@@ -26,10 +26,10 @@ along with this program. If not, see .
from __future__ import annotations
from PyQt6.QtCore import QPoint, QRectF, QSize, Qt, pyqtSignal, pyqtSlot
-from PyQt6.QtGui import QAction, QColor, QPainter, QPaintEvent, QPolygon
+from PyQt6.QtGui import QColor, QPainter, QPaintEvent, QPolygon
from PyQt6.QtWidgets import (
- QAbstractButton, QButtonGroup, QLabel, QStyle, QStyleOptionToolButton,
- QToolBar, QToolButton, QWidget
+ QAbstractButton, QButtonGroup, QLabel, QStyleOptionToolButton, QToolBar,
+ QToolButton, QWidget
)
from novelwriter.types import (
@@ -83,21 +83,19 @@ class NPagedSideBar(QToolBar):
self.insertWidget(self._stretchAction, label)
return
- def addButton(self, text: str, buttonId: int = -1) -> QAction:
+ def addButton(self, text: str, buttonId: int = -1) -> None:
"""Add a new button to the toolbar."""
button = _PagedToolButton(self)
button.setText(text)
-
- action = self.insertWidget(self._stretchAction, button)
+ self.insertWidget(self._stretchAction, button)
self._group.addButton(button, id=buttonId)
-
self._buttons[buttonId] = button
-
- return action
+ return
def setSelected(self, buttonId: int) -> None:
"""Set the selected button."""
- self._group.button(buttonId).setChecked(True)
+ if button := self._group.button(buttonId):
+ button.setChecked(True)
return
##
@@ -115,7 +113,7 @@ class NPagedSideBar(QToolBar):
class _PagedToolButton(QToolButton):
- __slots__ = ("_bH", "_tM", "_lM", "_cR", "_aH")
+ __slots__ = ("_bH", "_tM", "_aH")
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
@@ -126,8 +124,6 @@ class _PagedToolButton(QToolButton):
fH = self.fontMetrics().height()
self._bH = round(fH * 1.7)
self._tM = (self._bH - fH)//2
- self._lM = 3*self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
- self._cR = self._lM//2
self._aH = 2*fH//7
self.setFixedHeight(self._bH)
@@ -145,53 +141,51 @@ class _PagedToolButton(QToolButton):
opt = QStyleOptionToolButton()
opt.initFrom(self)
- paint = QPainter(self)
- paint.setRenderHint(QtPaintAntiAlias, True)
- paint.setPen(QtNoPen)
- paint.setBrush(QtNoBrush)
+ painter = QPainter(self)
+ painter.setRenderHint(QtPaintAntiAlias, True)
+ painter.setPen(QtNoPen)
+ painter.setBrush(QtNoBrush)
width = self.width()
height = self.height()
palette = self.palette()
if opt.state & QtMouseOver == QtMouseOver: # pragma: no cover
- backCol = palette.base()
- paint.setBrush(backCol)
- paint.setOpacity(0.75)
- paint.drawRoundedRect(0, 0, width, height, self._cR, self._cR)
+ painter.setBrush(palette.light())
+ painter.drawRoundedRect(0, 0, width, height, 4, 4)
if self.isChecked():
- backCol = palette.highlight()
- paint.setBrush(backCol)
- paint.setOpacity(0.35)
- paint.drawRoundedRect(0, 0, width, height, self._cR, self._cR)
+ painter.setBrush(palette.highlight())
+ painter.setOpacity(0.35)
+ painter.drawRoundedRect(0, 0, width, height, 4, 4)
textCol = palette.highlightedText().color()
else:
textCol = palette.text().color()
- tW = width - 2*self._lM
+ tW = width - 24
tH = height - 2*self._tM
- paint.setPen(textCol)
- paint.setOpacity(1.0)
- paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
+ painter.setPen(textCol)
+ painter.setOpacity(1.0)
+ painter.drawText(QRectF(12, self._tM, tW, tH), QtAlignLeft, self.text())
tC = self.height()//2
- tW = self.width() - self._aH - self._lM
+ tW = self.width() - self._aH - 12
if self.isChecked():
- paint.setBrush(textCol)
- paint.drawPolygon(QPolygon([
+ painter.setBrush(textCol)
+ painter.drawPolygon(QPolygon([
QPoint(tW, tC - self._aH),
QPoint(tW + self._aH, tC),
QPoint(tW, tC + self._aH),
]))
+ painter.end()
return
class _NPagedToolLabel(QLabel):
- __slots__ = ("_bH", "_tM", "_lM", "_textCol")
+ __slots__ = ("_bH", "_tM", "_textCol")
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
super().__init__(parent=parent)
@@ -201,7 +195,6 @@ class _NPagedToolLabel(QLabel):
fH = self.fontMetrics().height()
self._bH = round(fH * 1.7)
self._tM = (self._bH - fH)//2
- self._lM = self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
self.setFixedHeight(self._bH)
self._textCol = textColor or self.palette().text().color()
@@ -212,18 +205,15 @@ class _NPagedToolLabel(QLabel):
"""Overload the paint event to draw a simple, left aligned text
label that matches the button style.
"""
- paint = QPainter(self)
- paint.setRenderHint(QtPaintAntiAlias, True)
- paint.setPen(QtNoPen)
+ tW = self.width() - 8
+ tH = self.height() - 2*self._tM
- width = self.width()
- height = self.height()
-
- tW = width - 2*self._lM
- tH = height - 2*self._tM
-
- paint.setPen(self._textCol)
- paint.setOpacity(1.0)
- paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
+ painter = QPainter(self)
+ painter.setRenderHint(QtPaintAntiAlias, True)
+ painter.setPen(QtNoPen)
+ painter.setPen(self._textCol)
+ painter.setOpacity(1.0)
+ painter.drawText(QRectF(4, self._tM, tW, tH), QtAlignLeft, self.text())
+ painter.end()
return
diff --git a/novelwriter/extensions/statusled.py b/novelwriter/extensions/statusled.py
index f4377823..a027a112 100644
--- a/novelwriter/extensions/statusled.py
+++ b/novelwriter/extensions/statusled.py
@@ -28,7 +28,6 @@ import logging
from PyQt6.QtGui import QColor, QPainter, QPaintEvent
from PyQt6.QtWidgets import QAbstractButton, QWidget
-from novelwriter import CONFIG
from novelwriter.enum import nwTrinary
from novelwriter.types import QtBlack, QtPaintAntiAlias
@@ -37,9 +36,7 @@ logger = logging.getLogger(__name__)
class StatusLED(QAbstractButton):
- __slots__ = (
- "_neutral", "_postitve", "_negative", "_color", "_state", "_bPx"
- )
+ __slots__ = ("_neutral", "_postitve", "_negative", "_color", "_state")
def __init__(self, sW: int, sH: int, parent: QWidget | None = None) -> None:
super().__init__(parent=parent)
@@ -48,7 +45,6 @@ class StatusLED(QAbstractButton):
self._negative = QtBlack
self._color = QtBlack
self._state = nwTrinary.NEUTRAL
- self._bPx = CONFIG.pxInt(1)
self.setFixedWidth(sW)
self.setFixedHeight(sH)
return
@@ -82,12 +78,9 @@ class StatusLED(QAbstractButton):
"""Draw the LED."""
painter = QPainter(self)
painter.setRenderHint(QtPaintAntiAlias, True)
- painter.setPen(self.palette().windowText().color())
+ painter.setPen(self.palette().text().color())
painter.setBrush(self._color)
painter.setOpacity(1.0)
- painter.drawEllipse(
- self._bPx, self._bPx,
- self.width() - 2*self._bPx,
- self.height() - 2*self._bPx
- )
+ painter.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
+ painter.end()
return
diff --git a/novelwriter/extensions/switch.py b/novelwriter/extensions/switch.py
index 2b320506..ef936553 100644
--- a/novelwriter/extensions/switch.py
+++ b/novelwriter/extensions/switch.py
@@ -27,13 +27,13 @@ from PyQt6.QtCore import QPropertyAnimation, Qt, pyqtProperty
from PyQt6.QtGui import QEnterEvent, QMouseEvent, QPainter, QPaintEvent, QResizeEvent
from PyQt6.QtWidgets import QAbstractButton, QWidget
-from novelwriter import CONFIG, SHARED
+from novelwriter import SHARED
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixed
class NSwitch(QAbstractButton):
- __slots__ = ("_xW", "_xH", "_xR", "_rB", "_rH", "_rR", "_offset")
+ __slots__ = ("_xW", "_xH", "_xR", "_rH", "_rR", "_offset")
def __init__(self, parent: QWidget, height: int = 0) -> None:
super().__init__(parent=parent)
@@ -41,9 +41,8 @@ class NSwitch(QAbstractButton):
self._xH = height or SHARED.theme.baseButtonHeight
self._xW = 2*self._xH
self._xR = int(self._xH*0.5)
- self._rB = CONFIG.pxInt(2)
- self._rH = self._xH - 2*self._rB
- self._rR = self._xR - self._rB
+ self._rH = self._xH - 4
+ self._rR = self._xR - 2
self.setCheckable(True)
self.setSizePolicy(QtSizeFixed, QtSizeFixed)
@@ -98,14 +97,14 @@ class NSwitch(QAbstractButton):
trackBrush = palette.highlight()
thumbBrush = palette.highlightedText()
else:
- trackBrush = palette.mid()
+ trackBrush = palette.midlight()
thumbBrush = palette.light()
if self.isEnabled():
trackOpacity = 1.0
else:
trackOpacity = 0.6
- trackBrush = palette.dark()
+ trackBrush = palette.mid()
thumbBrush = palette.mid()
painter.setBrush(trackBrush)
@@ -113,7 +112,7 @@ class NSwitch(QAbstractButton):
painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
painter.setBrush(thumbBrush)
- painter.drawEllipse(self._offset - self._rR, self._rB, self._rH, self._rH)
+ painter.drawEllipse(self._offset - self._rR, 2, self._rH, self._rH)
painter.end()
return
diff --git a/novelwriter/extensions/versioninfo.py b/novelwriter/extensions/versioninfo.py
index c44ce820..2f13afaa 100644
--- a/novelwriter/extensions/versioninfo.py
+++ b/novelwriter/extensions/versioninfo.py
@@ -70,7 +70,7 @@ class VersionInfoWidget(QWidget):
self._layout = QVBoxLayout()
self._layout.addWidget(self._lblInfo)
self._layout.addWidget(self._lblRelease)
- self._layout.setSpacing(CONFIG.pxInt(2))
+ self._layout.setSpacing(2)
self._layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self._layout)
diff --git a/novelwriter/formats/shared.py b/novelwriter/formats/shared.py
index fecafea9..549f6f19 100644
--- a/novelwriter/formats/shared.py
+++ b/novelwriter/formats/shared.py
@@ -29,8 +29,6 @@ from enum import Flag, IntEnum
from PyQt6.QtGui import QColor
-from novelwriter.types import nwDataClass
-
ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
@@ -42,7 +40,6 @@ def stripEscape(text: str) -> str:
return text
-@nwDataClass
class TextDocumentTheme:
"""Default document theme."""
diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py
index 13647988..731990f5 100644
--- a/novelwriter/formats/toqdoc.py
+++ b/novelwriter/formats/toqdoc.py
@@ -278,8 +278,10 @@ class ToQTextDocument(Tokenizer):
printer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter)
printer.setOutputFileName(str(path))
- self._document.documentLayout().setPaintDevice(printer)
- self._document.setPageSize(printer.pageRect(QPrinter.Unit.Millimeter).size())
+ if layout := self._document.documentLayout():
+ layout.setPaintDevice(printer)
+
+ self._document.setPageSize(printer.pageRect(QPrinter.Unit.DevicePixel).size())
self._document.print(printer)
return
@@ -458,7 +460,8 @@ class ToQTextDocument(Tokenizer):
cursor.insertFrame(fFmt)
cursor.setBlockFormat(bFmt)
cursor.insertText(self._project.localLookup("New Page"), cFmt)
- cursor.swap(self._document.rootFrame().lastCursorPosition())
+ if root := self._document.rootFrame():
+ cursor.swap(root.lastCursorPosition())
return
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 1a4f7c4d..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()
@@ -331,7 +334,7 @@ class GuiDocEditor(QPlainTextEdit):
# Due to cursor visibility, a part of the margin must be
# allocated to the document itself. See issue #1112.
self._qDocument.setDocumentMargin(4)
- self._vpMargin = max(CONFIG.getTextMargin() - 4, 0)
+ self._vpMargin = max(CONFIG.textMargin - 4, 0)
self.setViewportMargins(self._vpMargin, self._vpMargin, self._vpMargin, self._vpMargin)
# Also set the document text options for the document text flow
@@ -359,7 +362,7 @@ class GuiDocEditor(QPlainTextEdit):
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
# Refresh the tab stops
- self.setTabStopDistance(CONFIG.getTabWidth())
+ self.setTabStopDistance(CONFIG.tabWidth)
# If we have a document open, we should refresh it in case the
# font changed, otherwise we just clear the editor entirely,
@@ -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 bc545b6f..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:
@@ -200,7 +201,7 @@ class GuiDocViewer(QTextBrowser):
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
# Refresh the tab stops
- self.setTabStopDistance(CONFIG.getTabWidth())
+ self.setTabStopDistance(CONFIG.tabWidth)
# If we have a document open, we should reload it in case the font changed
self.reloadText()
@@ -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)
@@ -250,11 +253,11 @@ class GuiDocViewer(QTextBrowser):
self.setDocumentTitle(tHandle)
self.setDocument(qDoc.document)
- self.setTabStopDistance(CONFIG.getTabWidth())
+ 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")
@@ -308,13 +311,13 @@ class GuiDocViewer(QTextBrowser):
"""Automatically adjust the margins so the text is centred."""
wW = self.width()
wH = self.height()
- cM = CONFIG.getTextMargin()
+ 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..181f6f31 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", "green"))
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", "red"))
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 9c583a80..0348d70b 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -41,7 +41,7 @@ from novelwriter.common import NWConfigParser, cssCol, minmax
from novelwriter.constants import nwLabels
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException
-from novelwriter.types import QtPaintAntiAlias, QtTransparent, nwDataClass
+from novelwriter.types import QtPaintAntiAlias, QtTransparent
logger = logging.getLogger(__name__)
@@ -50,7 +50,6 @@ STYLES_MIN_TOOLBUTTON = "minimalToolButton"
STYLES_BIG_TOOLBUTTON = "bigToolButton"
-@nwDataClass
class ThemeMeta:
name: str = ""
@@ -62,7 +61,6 @@ class ThemeMeta:
licenseUrl: str = ""
-@nwDataClass
class SyntaxColors:
back: QColor = QColor(255, 255, 255)
@@ -546,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;} "
)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 56e17517..47d85a4a 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -114,10 +114,6 @@ class GuiMain(QMainWindow):
# Build the GUI
# =============
- # Sizes
- mPx = CONFIG.pxInt(4)
- hWd = CONFIG.pxInt(4)
-
# Main GUI Elements
self.mainStatus = GuiMainStatus(self)
self.projView = GuiProjectView(self)
@@ -142,7 +138,7 @@ class GuiMain(QMainWindow):
self.treePane = QWidget(self)
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0)
- self.treeBox.setSpacing(mPx)
+ self.treeBox.setSpacing(4)
self.treeBox.addWidget(self.projStack)
self.treeBox.addWidget(self.itemDetails)
self.treePane.setLayout(self.treeBox)
@@ -151,7 +147,7 @@ class GuiMain(QMainWindow):
self.splitView = QSplitter(Qt.Orientation.Vertical, self)
self.splitView.addWidget(self.docViewer)
self.splitView.addWidget(self.docViewerPanel)
- self.splitView.setHandleWidth(hWd)
+ self.splitView.setHandleWidth(4)
self.splitView.setOpaqueResize(False)
self.splitView.setSizes(CONFIG.viewPanePos)
self.splitView.setCollapsible(0, False)
@@ -162,7 +158,7 @@ class GuiMain(QMainWindow):
self.splitDocs.addWidget(self.docEditor)
self.splitDocs.addWidget(self.splitView)
self.splitDocs.setOpaqueResize(False)
- self.splitDocs.setHandleWidth(hWd)
+ self.splitDocs.setHandleWidth(4)
self.splitDocs.setCollapsible(0, False)
self.splitDocs.setCollapsible(1, False)
@@ -172,7 +168,7 @@ class GuiMain(QMainWindow):
self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.splitDocs)
self.splitMain.setOpaqueResize(False)
- self.splitMain.setHandleWidth(hWd)
+ self.splitMain.setHandleWidth(4)
self.splitMain.setSizes(CONFIG.mainPanePos)
self.splitMain.setCollapsible(0, False)
self.splitMain.setCollapsible(0, False)
@@ -860,10 +856,10 @@ class GuiMain(QMainWindow):
logger.info("Exiting novelWriter")
if not SHARED.focusMode:
- CONFIG.setMainPanePos(self.splitMain.sizes())
- CONFIG.setOutlinePanePos(self.outlineView.splitSizes())
+ CONFIG.mainPanePos = self.splitMain.sizes()
+ CONFIG.outlinePanePos = self.outlineView.splitSizes()
if self.docViewerPanel.isVisible():
- CONFIG.setViewPanePos(self.splitView.sizes())
+ CONFIG.viewPanePos = self.splitView.sizes()
CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
wFull = Qt.WindowState.WindowFullScreen
diff --git a/novelwriter/tools/dictionaries.py b/novelwriter/tools/dictionaries.py
index ddb371e1..c956846c 100644
--- a/novelwriter/tools/dictionaries.py
+++ b/novelwriter/tools/dictionaries.py
@@ -57,12 +57,9 @@ class GuiDictionaries(NNonBlockingDialog):
self._currDicts = set()
iSz = SHARED.theme.baseIconSize
- iPx = CONFIG.pxInt(4)
- mPx = CONFIG.pxInt(8)
- sPx = CONFIG.pxInt(16)
- self.setMinimumWidth(CONFIG.pxInt(500))
- self.setMinimumHeight(CONFIG.pxInt(300))
+ self.setMinimumWidth(500)
+ self.setMinimumHeight(300)
# Hunspell Dictionaries
foUrl = "https://www.freeoffice.com/en/download/dictionaries"
@@ -84,7 +81,7 @@ class GuiDictionaries(NNonBlockingDialog):
self.huPathBox = QHBoxLayout()
self.huPathBox.addWidget(self.huInput)
self.huPathBox.addWidget(self.huBrowse)
- self.huPathBox.setSpacing(iPx)
+ self.huPathBox.setSpacing(4)
self.huAddBox = QHBoxLayout()
self.huAddBox.addStretch(1)
self.huAddBox.addWidget(self.huImport)
@@ -99,7 +96,7 @@ class GuiDictionaries(NNonBlockingDialog):
self.inBox = QHBoxLayout()
self.inBox.addWidget(self.inPath)
self.inBox.addWidget(self.inBrowse)
- self.inBox.setSpacing(iPx)
+ self.inBox.setSpacing(4)
# Info Box
self.infoBox = QPlainTextEdit(self)
@@ -116,17 +113,17 @@ class GuiDictionaries(NNonBlockingDialog):
self.innerBox.addWidget(self.huInfo)
self.innerBox.addLayout(self.huPathBox)
self.innerBox.addLayout(self.huAddBox)
- self.innerBox.addSpacing(mPx)
+ self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.inInfo)
self.innerBox.addLayout(self.inBox)
self.innerBox.addWidget(self.infoBox)
- self.innerBox.setSpacing(iPx)
+ self.innerBox.setSpacing(4)
self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.innerBox, 0)
self.outerBox.addStretch(1)
self.outerBox.addWidget(self.buttonBox, 0)
- self.outerBox.setSpacing(sPx)
+ self.outerBox.setSpacing(16)
self.setLayout(self.outerBox)
diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py
index f9144d49..48aefa2d 100644
--- a/novelwriter/tools/lipsum.py
+++ b/novelwriter/tools/lipsum.py
@@ -52,18 +52,15 @@ class GuiLipsum(NDialog):
self._lipsumText = ""
- vSp = CONFIG.pxInt(4)
- nPx = CONFIG.pxInt(64)
-
self.innerBox = QHBoxLayout()
- self.innerBox.setSpacing(CONFIG.pxInt(16))
+ self.innerBox.setSpacing(16)
# Icon
self.docIcon = QLabel(self)
- self.docIcon.setPixmap(SHARED.theme.getPixmap("text", (nPx, nPx), "blue"))
+ self.docIcon.setPixmap(SHARED.theme.getPixmap("text", (64, 64), "blue"))
self.leftBox = QVBoxLayout()
- self.leftBox.setSpacing(vSp)
+ self.leftBox.setSpacing(4)
self.leftBox.addWidget(self.docIcon)
self.leftBox.addStretch(1)
self.innerBox.addLayout(self.leftBox)
@@ -87,7 +84,7 @@ class GuiLipsum(NDialog):
self.formBox.addWidget(self.paraCount, 1, 1, 1, 1, QtAlignRight)
self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft)
self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight)
- self.formBox.setVerticalSpacing(vSp)
+ self.formBox.setVerticalSpacing(4)
self.formBox.setRowStretch(3, 1)
self.innerBox.addLayout(self.formBox)
@@ -96,17 +93,19 @@ class GuiLipsum(NDialog):
self.buttonBox.rejected.connect(self.reject)
self.btnClose = self.buttonBox.addButton(QtDialogClose)
- self.btnClose.setAutoDefault(False)
+ if self.btnClose:
+ self.btnClose.setAutoDefault(False)
self.btnInsert = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction)
- self.btnInsert.clicked.connect(self._doInsert)
- self.btnInsert.setAutoDefault(False)
+ if self.btnInsert:
+ self.btnInsert.clicked.connect(self._doInsert)
+ self.btnInsert.setAutoDefault(False)
# Assemble
self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.innerBox)
self.outerBox.addWidget(self.buttonBox)
- self.outerBox.setSpacing(CONFIG.pxInt(16))
+ self.outerBox.setSpacing(16)
self.setLayout(self.outerBox)
logger.debug("Ready: GuiLipsum")
diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py
index 40e6eefc..f45d7a1f 100644
--- a/novelwriter/tools/manusbuild.py
+++ b/novelwriter/tools/manusbuild.py
@@ -35,7 +35,7 @@ from PyQt6.QtWidgets import (
QPushButton, QSplitter, QVBoxLayout, QWidget
)
-from novelwriter import CONFIG, SHARED
+from novelwriter import SHARED
from novelwriter.common import makeFileNameSafe, openExternalPath
from novelwriter.constants import nwLabels
from novelwriter.core.buildsettings import BuildSettings
@@ -68,21 +68,16 @@ class GuiManuscriptBuild(NDialog):
self._build = build
self.setWindowTitle(self.tr("Build Manuscript"))
- self.setMinimumWidth(CONFIG.pxInt(500))
- self.setMinimumHeight(CONFIG.pxInt(300))
+ self.setMinimumWidth(500)
+ self.setMinimumHeight(300)
iSz = SHARED.theme.baseIconSize
bSz = SHARED.theme.buttonIconSize
- sp4 = CONFIG.pxInt(4)
- sp8 = CONFIG.pxInt(8)
- sp16 = CONFIG.pxInt(16)
- wWin = CONFIG.pxInt(620)
- hWin = CONFIG.pxInt(360)
pOptions = SHARED.project.options
self.resize(
- CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winWidth", wWin)),
- CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin))
+ pOptions.getInt("GuiManuscriptBuild", "winWidth", 620),
+ pOptions.getInt("GuiManuscriptBuild", "winHeight", 360),
)
# Output Format
@@ -149,7 +144,7 @@ class GuiManuscriptBuild(NDialog):
self.pathBox = QHBoxLayout()
self.pathBox.addWidget(self.buildPath)
self.pathBox.addWidget(self.btnBrowse)
- self.pathBox.setSpacing(sp8)
+ self.pathBox.setSpacing(8)
# Build Name
self.lblName = QLabel(self.tr("File Name"), self)
@@ -160,14 +155,14 @@ class GuiManuscriptBuild(NDialog):
self.nameBox = QHBoxLayout()
self.nameBox.addWidget(self.buildName)
self.nameBox.addWidget(self.btnReset)
- self.nameBox.setSpacing(sp8)
+ self.nameBox.setSpacing(8)
# Build Progress
self.buildProgress = NProgressSimple(self)
self.buildProgress.setMinimum(0)
self.buildProgress.setValue(0)
self.buildProgress.setTextVisible(False)
- self.buildProgress.setFixedHeight(sp8)
+ self.buildProgress.setFixedHeight(8)
# Build Box
self.buildBox = QGridLayout()
@@ -175,8 +170,8 @@ class GuiManuscriptBuild(NDialog):
self.buildBox.addLayout(self.pathBox, 0, 1)
self.buildBox.addWidget(self.lblName, 1, 0)
self.buildBox.addLayout(self.nameBox, 1, 1)
- self.buildBox.setHorizontalSpacing(sp8)
- self.buildBox.setVerticalSpacing(sp4)
+ self.buildBox.setHorizontalSpacing(8)
+ self.buildBox.setVerticalSpacing(4)
# Dialog Buttons
self.buttonBox = QDialogButtonBox(self)
@@ -196,7 +191,8 @@ class GuiManuscriptBuild(NDialog):
self.buttonBox.addButton(self.btnBuild, QtRoleAction)
self.btnClose = self.buttonBox.addButton(QtDialogClose)
- self.btnClose.setAutoDefault(False)
+ if self.btnClose:
+ self.btnClose.setAutoDefault(False)
# Assemble GUI
# ============
@@ -204,25 +200,25 @@ class GuiManuscriptBuild(NDialog):
self.mainSplit = QSplitter(self)
self.mainSplit.addWidget(self.formatWidget)
self.mainSplit.addWidget(self.contentWidget)
- self.mainSplit.setHandleWidth(sp16)
+ self.mainSplit.setHandleWidth(16)
self.mainSplit.setCollapsible(0, False)
self.mainSplit.setCollapsible(1, False)
self.mainSplit.setStretchFactor(0, 0)
self.mainSplit.setStretchFactor(1, 1)
self.mainSplit.setSizes([
- CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", wWin//2)),
- CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "sumWidth", wWin//2)),
+ pOptions.getInt("GuiManuscriptBuild", "fmtWidth", 360),
+ pOptions.getInt("GuiManuscriptBuild", "sumWidth", 360),
])
self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.lblMain, 0, QtAlignCenter)
- self.outerBox.addSpacing(sp16)
+ self.outerBox.addSpacing(16)
self.outerBox.addWidget(self.mainSplit, 1)
- self.outerBox.addSpacing(sp4)
+ self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.buildProgress, 0)
- self.outerBox.addSpacing(sp4)
+ self.outerBox.addSpacing(4)
self.outerBox.addLayout(self.buildBox, 0)
- self.outerBox.addSpacing(sp16)
+ self.outerBox.addSpacing(16)
self.outerBox.addWidget(self.buttonBox, 0)
self.outerBox.setSpacing(0)
@@ -363,21 +359,14 @@ class GuiManuscriptBuild(NDialog):
def _saveSettings(self) -> None:
"""Save the user GUI settings."""
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
-
- mainSplit = self.mainSplit.sizes()
- fmtWidth = CONFIG.rpxInt(mainSplit[0])
- sumWidth = CONFIG.rpxInt(mainSplit[1])
-
logger.debug("Saving State: GuiManuscriptBuild")
+ mainSplit = self.mainSplit.sizes()
pOptions = SHARED.project.options
- pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth)
- pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight)
- pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth)
- pOptions.setValue("GuiManuscriptBuild", "sumWidth", sumWidth)
+ pOptions.setValue("GuiManuscriptBuild", "winWidth", self.width())
+ pOptions.setValue("GuiManuscriptBuild", "winHeight", self.height())
+ pOptions.setValue("GuiManuscriptBuild", "fmtWidth", mainSplit[0])
+ pOptions.setValue("GuiManuscriptBuild", "sumWidth", mainSplit[1])
pOptions.saveSettings()
-
return
def _populateContentList(self) -> None:
diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py
index 7238ea84..d0d0708c 100644
--- a/novelwriter/tools/manuscript.py
+++ b/novelwriter/tools/manuscript.py
@@ -85,18 +85,16 @@ class GuiManuscript(NToolDialog):
self._buildMap: dict[str, QListWidgetItem] = {}
self.setWindowTitle(self.tr("Build Manuscript"))
- self.setMinimumWidth(CONFIG.pxInt(600))
- self.setMinimumHeight(CONFIG.pxInt(500))
+ self.setMinimumWidth(600)
+ self.setMinimumHeight(500)
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- wWin = CONFIG.pxInt(900)
- hWin = CONFIG.pxInt(600)
pOptions = SHARED.project.options
self.resize(
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winWidth", wWin)),
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winHeight", hWin))
+ pOptions.getInt("GuiManuscript", "winWidth", 900),
+ pOptions.getInt("GuiManuscript", "winHeight", 600),
)
# Build Controls
@@ -153,9 +151,7 @@ class GuiManuscript(NToolDialog):
# ============
self.buildDetails = _DetailsWidget(self)
- self.buildDetails.setColumnWidth(
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsWidth", 100)),
- )
+ self.buildDetails.setColumnWidth(pOptions.getInt("GuiManuscript", "detailsWidth", 100))
self.buildOutline = _OutlineWidget(self)
@@ -168,8 +164,8 @@ class GuiManuscript(NToolDialog):
self.buildSplit.addWidget(self.buildList)
self.buildSplit.addWidget(self.detailsTabs)
self.buildSplit.setSizes([
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "listHeight", 50)),
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsHeight", 50)),
+ pOptions.getInt("GuiManuscript", "listHeight", 50),
+ pOptions.getInt("GuiManuscript", "detailsHeight", 50),
])
# Process Controls
@@ -240,8 +236,8 @@ class GuiManuscript(NToolDialog):
self.mainSplit.setStretchFactor(0, 0)
self.mainSplit.setStretchFactor(1, 1)
self.mainSplit.setSizes([
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "optsWidth", wWin//4)),
- CONFIG.pxInt(pOptions.getInt("GuiManuscript", "viewWidth", 3*wWin//4)),
+ pOptions.getInt("GuiManuscript", "optsWidth", 225),
+ pOptions.getInt("GuiManuscript", "viewWidth", 675),
])
self.outerBox = QVBoxLayout()
@@ -441,28 +437,20 @@ class GuiManuscript(NToolDialog):
self._builds.setBuildsState(lastBuild, buildOrder)
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
-
mainSplit = self.mainSplit.sizes()
- optsWidth = CONFIG.rpxInt(mainSplit[0])
- viewWidth = CONFIG.rpxInt(mainSplit[1])
-
buildSplit = self.buildSplit.sizes()
- listHeight = CONFIG.rpxInt(buildSplit[0])
- detailsHeight = CONFIG.rpxInt(buildSplit[1])
- detailsWidth = CONFIG.rpxInt(self.buildDetails.getColumnWidth())
+ detailsWidth = self.buildDetails.getColumnWidth()
detailsExpanded = self.buildDetails.getExpandedState()
showNewPage = self.swtNewPage.isChecked()
logger.debug("Saving State: GuiManuscript")
pOptions = SHARED.project.options
- pOptions.setValue("GuiManuscript", "winWidth", winWidth)
- pOptions.setValue("GuiManuscript", "winHeight", winHeight)
- pOptions.setValue("GuiManuscript", "optsWidth", optsWidth)
- pOptions.setValue("GuiManuscript", "viewWidth", viewWidth)
- pOptions.setValue("GuiManuscript", "listHeight", listHeight)
- pOptions.setValue("GuiManuscript", "detailsHeight", detailsHeight)
+ pOptions.setValue("GuiManuscript", "winWidth", self.width())
+ pOptions.setValue("GuiManuscript", "winHeight", self.height())
+ pOptions.setValue("GuiManuscript", "optsWidth", mainSplit[0])
+ pOptions.setValue("GuiManuscript", "viewWidth", mainSplit[1])
+ pOptions.setValue("GuiManuscript", "listHeight", buildSplit[0])
+ pOptions.setValue("GuiManuscript", "detailsHeight", buildSplit[1])
pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth)
pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded)
pOptions.setValue("GuiManuscript", "showNewPage", showNewPage)
@@ -693,33 +681,31 @@ class _OutlineWidget(QWidget):
hFont.setBold(True)
hFont.setUnderline(True)
- root = self.listView.invisibleRootItem()
- parent = root
- indent = False
- for anchor, entry in data.items():
- prefix, _, text = entry.partition("|")
- if prefix in ("TT", "PT", "CH", "SC", "H1", "H2"):
- item = QTreeWidgetItem([text])
- item.setData(0, self.D_LINE, anchor)
- if prefix == "TT":
- item.setFont(0, tFont)
- item.setForeground(0, tBrush)
- root.addChild(item)
- parent = root
- elif prefix == "PT":
- item.setFont(0, hFont)
- root.addChild(item)
- parent = root
- elif prefix in ("CH", "H1"):
- root.addChild(item)
- parent = item
- elif prefix in ("SC", "H2"):
- parent.addChild(item)
- indent = True
+ if root := self.listView.invisibleRootItem():
+ parent = root
+ indent = False
+ for anchor, entry in data.items():
+ prefix, _, text = entry.partition("|")
+ if prefix in ("TT", "PT", "CH", "SC", "H1", "H2"):
+ item = QTreeWidgetItem([text])
+ item.setData(0, self.D_LINE, anchor)
+ if prefix == "TT":
+ item.setFont(0, tFont)
+ item.setForeground(0, tBrush)
+ root.addChild(item)
+ parent = root
+ elif prefix == "PT":
+ item.setFont(0, hFont)
+ root.addChild(item)
+ parent = root
+ elif prefix in ("CH", "H1"):
+ root.addChild(item)
+ parent = item
+ elif prefix in ("SC", "H2"):
+ parent.addChild(item)
+ indent = True
- self.listView.setIndentation(
- SHARED.theme.baseIconHeight if indent else CONFIG.pxInt(4)
- )
+ self.listView.setIndentation(SHARED.theme.baseIconHeight if indent else 4)
self._outline = data
return
@@ -750,11 +736,13 @@ class _PreviewWidget(QTextBrowser):
self.setPalette(dPalette)
self.setMinimumWidth(40*SHARED.theme.textNWidth)
- self.setTabStopDistance(CONFIG.getTabWidth())
+ self.setTabStopDistance(CONFIG.tabWidth)
self.setOpenExternalLinks(False)
self.setOpenLinks(False)
- self.document().setDocumentMargin(CONFIG.getTextMargin())
+ if document := self.document():
+ document.setDocumentMargin(CONFIG.textMargin)
+
self.setPlaceholderText(self.tr(
"Press the \"Preview\" button to generate ..."
))
@@ -781,7 +769,7 @@ class _PreviewWidget(QTextBrowser):
self.ageLabel.setFixedHeight(int(2.1*SHARED.theme.fontPixelSize))
# Progress
- self.buildProgress = NProgressCircle(self, CONFIG.pxInt(160), CONFIG.pxInt(16))
+ self.buildProgress = NProgressCircle(self, 160, 16)
self.buildProgress.setVisible(False)
self.buildProgress.setMaximum(1)
self.buildProgress.setValue(0)
@@ -834,7 +822,8 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setValue(0)
self.buildProgress.setCentreText(None)
self.buildProgress.setVisible(True)
- self._scrollPos = self.verticalScrollBar().value()
+ if vBar := self.verticalScrollBar():
+ self._scrollPos = vBar.value()
self.setPlaceholderText("")
self.clear()
return
@@ -852,9 +841,9 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setCentreText(self.tr("Processing ..."))
QApplication.processEvents()
- document.setDocumentMargin(CONFIG.getTextMargin())
+ document.setDocumentMargin(CONFIG.textMargin)
self.setDocument(document)
- self.setTabStopDistance(CONFIG.getTabWidth())
+ self.setTabStopDistance(CONFIG.tabWidth)
self._docTime = int(time())
self._updateBuildAge()
@@ -883,10 +872,11 @@ class _PreviewWidget(QTextBrowser):
@pyqtSlot("QPrinter*")
def printPreview(self, printer: QPrinter) -> None:
"""Connect the print preview painter to the document viewer."""
- QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
- printer.setPageOrientation(QPageLayout.Orientation.Portrait)
- self.document().print(printer)
- QApplication.restoreOverrideCursor()
+ if document := self.document():
+ QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
+ printer.setPageOrientation(QPageLayout.Orientation.Portrait)
+ document.print(printer)
+ QApplication.restoreOverrideCursor()
return
@pyqtSlot(str)
@@ -928,7 +918,8 @@ class _PreviewWidget(QTextBrowser):
def _postUpdate(self) -> None:
"""Run tasks after content update."""
self.buildProgress.setVisible(False)
- self.verticalScrollBar().setValue(self._scrollPos)
+ if vBar := self.verticalScrollBar():
+ vBar.setValue(self._scrollPos)
return
##
@@ -941,7 +932,7 @@ class _PreviewWidget(QTextBrowser):
"""
vBar = self.verticalScrollBar()
tB = self.frameWidth()
- vW = self.width() - 2*tB - vBar.width()
+ vW = self.width() - 2*tB - (vBar.width() if vBar else 0)
vH = self.height() - 2*tB
tH = self.ageLabel.height()
pS = self.buildProgress.width()
@@ -1033,10 +1024,6 @@ class _StatsWidget(QWidget):
def _buildBottomPanel(self) -> None:
"""Build the bottom page."""
- mPx = CONFIG.pxInt(8)
- hPx = CONFIG.pxInt(12)
- vPx = CONFIG.pxInt(4)
-
trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
trTextChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TEXT])
trTitleChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TITLE])
@@ -1073,8 +1060,8 @@ class _StatsWidget(QWidget):
self.leftForm.addRow("", QLabel(self))
self.leftForm.addRow(trTitleCount, self.maxTitleCount)
self.leftForm.addRow(trParagraphCount, self.maxParCount)
- self.leftForm.setHorizontalSpacing(hPx)
- self.leftForm.setVerticalSpacing(vPx)
+ self.leftForm.setHorizontalSpacing(12)
+ self.leftForm.setVerticalSpacing(4)
# Maximal Form, Right Column
self.maxTotalChars = QLabel(self)
@@ -1098,25 +1085,25 @@ class _StatsWidget(QWidget):
self.rightForm.addRow(trAllWordChars, self.maxTotalWordChars)
self.rightForm.addRow(trTitleWordChars, self.maxHeadWordChars)
self.rightForm.addRow(trTextWordChars, self.maxTextWordChars)
- self.rightForm.setHorizontalSpacing(hPx)
- self.rightForm.setVerticalSpacing(vPx)
+ self.rightForm.setHorizontalSpacing(12)
+ self.rightForm.setVerticalSpacing(4)
# Assemble
self.minLayout = QHBoxLayout()
self.minLayout.addWidget(QLabel(trAllWords, self))
self.minLayout.addWidget(self.minWordCount)
- self.minLayout.addSpacing(mPx)
+ self.minLayout.addSpacing(8)
self.minLayout.addWidget(QLabel(trAllChars, self))
self.minLayout.addWidget(self.minCharCount)
self.minLayout.addStretch(1)
- self.minLayout.setSpacing(mPx)
+ self.minLayout.setSpacing(8)
self.minLayout.setContentsMargins(0, 0, 0, 0)
self.maxLayout = QHBoxLayout()
self.maxLayout.addLayout(self.leftForm)
self.maxLayout.addLayout(self.rightForm)
self.maxLayout.addStretch(1)
- self.maxLayout.setSpacing(CONFIG.pxInt(32))
+ self.maxLayout.setSpacing(32)
self.maxLayout.setContentsMargins(0, 0, 0, 0)
self.minWidget.setLayout(self.minLayout)
diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py
index 549d39d1..78d59725 100644
--- a/novelwriter/tools/manussettings.py
+++ b/novelwriter/tools/manussettings.py
@@ -37,7 +37,7 @@ from PyQt6.QtWidgets import (
)
from novelwriter import CONFIG, SHARED
-from novelwriter.common import describeFont, fontMatcher, qtLambda
+from novelwriter.common import describeFont, fontMatcher, qtAddAction, qtLambda
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, trConst
from novelwriter.core.buildsettings import BuildSettings, FilterMode
from novelwriter.extensions.configlayout import (
@@ -83,21 +83,18 @@ class GuiBuildSettings(NToolDialog):
self._build = build
self.setWindowTitle(self.tr("Manuscript Build Settings"))
- self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400))
-
- wWin = CONFIG.pxInt(750)
- hWin = CONFIG.pxInt(550)
+ self.setMinimumSize(700, 400)
options = SHARED.project.options
self.resize(
- CONFIG.pxInt(options.getInt("GuiBuildSettings", "winWidth", wWin)),
- CONFIG.pxInt(options.getInt("GuiBuildSettings", "winHeight", hWin))
+ options.getInt("GuiBuildSettings", "winWidth", 750),
+ options.getInt("GuiBuildSettings", "winHeight", 550),
)
# Title
self.titleLabel = NColourLabel(
self.tr("Manuscript Build Settings"), self, color=SHARED.theme.helpText,
- scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
+ scale=NColourLabel.HEADER_SCALE, indent=4,
)
# Settings Name
@@ -145,7 +142,7 @@ class GuiBuildSettings(NToolDialog):
self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox)
- self.outerBox.setSpacing(CONFIG.pxInt(12))
+ self.outerBox.setSpacing(12)
self.setLayout(self.outerBox)
@@ -240,14 +237,11 @@ class GuiBuildSettings(NToolDialog):
def _saveSettings(self) -> None:
"""Save the various user settings."""
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
treeWidth, filterWidth = self.optTabSelect.mainSplitSizes()
-
logger.debug("Saving State: GuiBuildSettings")
pOptions = SHARED.project.options
- pOptions.setValue("GuiBuildSettings", "winWidth", winWidth)
- pOptions.setValue("GuiBuildSettings", "winHeight", winHeight)
+ pOptions.setValue("GuiBuildSettings", "winWidth", self.width())
+ pOptions.setValue("GuiBuildSettings", "winHeight", self.height())
pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth)
pOptions.setValue("GuiBuildSettings", "filterWidth", filterWidth)
pOptions.saveSettings()
@@ -300,7 +294,6 @@ class _FilterTab(NFixedPage):
iSz = SHARED.theme.baseIconSize
iPx = SHARED.theme.baseIconHeight
- cMg = CONFIG.pxInt(6)
# Tree Widget
self.optTree = QTreeWidget(self)
@@ -311,14 +304,14 @@ class _FilterTab(NFixedPage):
self.optTree.setIndentation(iPx)
self.optTree.setColumnCount(3)
- treeHeader = self.optTree.header()
- treeHeader.setStretchLastSection(False)
- treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1551
- treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
- treeHeader.setSectionResizeMode(self.C_ACTIVE, QtHeaderFixed)
- treeHeader.setSectionResizeMode(self.C_STATUS, QtHeaderFixed)
- treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg)
- treeHeader.resizeSection(self.C_STATUS, iPx + cMg)
+ if header := self.optTree.header():
+ header.setStretchLastSection(False)
+ header.setMinimumSectionSize(iPx + 6) # See Issue #1551
+ header.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
+ header.setSectionResizeMode(self.C_ACTIVE, QtHeaderFixed)
+ header.setSectionResizeMode(self.C_STATUS, QtHeaderFixed)
+ header.resizeSection(self.C_ACTIVE, iPx + 6)
+ header.resizeSection(self.C_STATUS, iPx + 6)
self.optTree.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
self.optTree.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
@@ -347,7 +340,7 @@ class _FilterTab(NFixedPage):
self.modeBox.addWidget(self.includedButton)
self.modeBox.addWidget(self.excludedButton)
self.modeBox.addWidget(self.resetButton)
- self.modeBox.setSpacing(CONFIG.pxInt(4))
+ self.modeBox.setSpacing(4)
# Filer Options
self.filterOpt = NSwitchBox(self, iPx)
@@ -375,8 +368,8 @@ class _FilterTab(NFixedPage):
self.mainSplit.setStretchFactor(0, 1)
self.mainSplit.setStretchFactor(1, 0)
self.mainSplit.setSizes([
- CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "treeWidth", 300)),
- CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "filterWidth", 300))
+ pOptions.getInt("GuiBuildSettings", "treeWidth", 300),
+ pOptions.getInt("GuiBuildSettings", "filterWidth", 300),
])
self.setCentralWidget(self.mainSplit)
@@ -393,7 +386,7 @@ class _FilterTab(NFixedPage):
"""Extract the sizes of the main splitter."""
sizes = self.mainSplit.sizes()
m, n = (sizes[0], sizes[1]) if len(sizes) >= 2 else (0, 0)
- return CONFIG.rpxInt(m), CONFIG.rpxInt(n)
+ return m, n
##
# Slots
@@ -558,15 +551,12 @@ class _HeadingsTab(NScrollablePage):
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- sSp = CONFIG.pxInt(16)
- vSp = CONFIG.pxInt(12)
- bSp = CONFIG.pxInt(6)
trHide = self.tr("Hide")
# Format Boxes
# ============
self.formatBox = QGridLayout()
- self.formatBox.setHorizontalSpacing(bSp)
+ self.formatBox.setHorizontalSpacing(6)
# Title Heading
self.lblPart = QLabel(self._build.getLabel("headings.fmtPart"), self)
@@ -575,7 +565,7 @@ class _HeadingsTab(NScrollablePage):
self.btnPart = NIconToolButton(self, iSz, "edit", "green")
self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE))
self.hdePart = QLabel(trHide, self)
- self.hdePart.setIndent(bSp)
+ self.hdePart.setIndent(6)
self.swtPart = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblPart, 0, 0)
@@ -591,7 +581,7 @@ class _HeadingsTab(NScrollablePage):
self.btnChapter = NIconToolButton(self, iSz, "edit", "green")
self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER))
self.hdeChapter = QLabel(trHide, self)
- self.hdeChapter.setIndent(bSp)
+ self.hdeChapter.setIndent(6)
self.swtChapter = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblChapter, 1, 0)
@@ -607,7 +597,7 @@ class _HeadingsTab(NScrollablePage):
self.btnUnnumbered = NIconToolButton(self, iSz, "edit", "green")
self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM))
self.hdeUnnumbered = QLabel(trHide, self)
- self.hdeUnnumbered.setIndent(bSp)
+ self.hdeUnnumbered.setIndent(6)
self.swtUnnumbered = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
@@ -623,7 +613,7 @@ class _HeadingsTab(NScrollablePage):
self.btnScene = NIconToolButton(self, iSz, "edit", "green")
self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE))
self.hdeScene = QLabel(trHide, self)
- self.hdeScene.setIndent(bSp)
+ self.hdeScene.setIndent(6)
self.swtScene = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblScene, 3, 0)
@@ -639,7 +629,7 @@ class _HeadingsTab(NScrollablePage):
self.btnAScene = NIconToolButton(self, iSz, "edit", "green")
self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE))
self.hdeAScene = QLabel(trHide, self)
- self.hdeAScene.setIndent(bSp)
+ self.hdeAScene.setIndent(6)
self.swtAScene = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblAScene, 4, 0)
@@ -655,7 +645,7 @@ class _HeadingsTab(NScrollablePage):
self.btnSection = NIconToolButton(self, iSz, "edit", "green")
self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION))
self.hdeSection = QLabel(trHide, self)
- self.hdeSection.setIndent(bSp)
+ self.hdeSection.setIndent(6)
self.swtSection = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblSection, 5, 0)
@@ -675,16 +665,16 @@ class _HeadingsTab(NScrollablePage):
self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document())
- self.menuInsert = QMenu(self)
- self.aInsTitle = self.menuInsert.addAction(self.tr("Title"))
- self.aInsChNum = self.menuInsert.addAction(self.tr("Chapter Number"))
- self.aInsChWord = self.menuInsert.addAction(self.tr("Chapter Number (Word)"))
- self.aInsChRomU = self.menuInsert.addAction(self.tr("Chapter Number (Upper Case Roman)"))
- self.aInsChRomL = self.menuInsert.addAction(self.tr("Chapter Number (Lower Case Roman)"))
- self.aInsScNum = self.menuInsert.addAction(self.tr("Scene Number (In Chapter)"))
- self.aInsScAbs = self.menuInsert.addAction(self.tr("Scene Number (Absolute)"))
- self.aInsCharPOV = self.menuInsert.addAction(self.tr("Point of View Character"))
- self.aInsCharFocus = self.menuInsert.addAction(self.tr("Focus Character"))
+ self.mInsert = QMenu(self)
+ self.aInsTitle = qtAddAction(self.mInsert, self.tr("Title"))
+ self.aInsChNum = qtAddAction(self.mInsert, self.tr("Chapter Number"))
+ self.aInsChWord = qtAddAction(self.mInsert, self.tr("Chapter Number (Word)"))
+ self.aInsChRomU = qtAddAction(self.mInsert, self.tr("Chapter Number (Upper Case Roman)"))
+ self.aInsChRomL = qtAddAction(self.mInsert, self.tr("Chapter Number (Lower Case Roman)"))
+ self.aInsScNum = qtAddAction(self.mInsert, self.tr("Scene Number (In Chapter)"))
+ self.aInsScAbs = qtAddAction(self.mInsert, self.tr("Scene Number (Absolute)"))
+ self.aInsCharPOV = qtAddAction(self.mInsert, self.tr("Point of View Character"))
+ self.aInsCharFocus = qtAddAction(self.mInsert, self.tr("Focus Character"))
self.aInsTitle.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.TITLE))
self.aInsChNum.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_NUM))
@@ -697,7 +687,7 @@ class _HeadingsTab(NScrollablePage):
self.aInsCharFocus.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CHAR_FOCUS))
self.btnInsert = QPushButton(self.tr("Insert"), self)
- self.btnInsert.setMenu(self.menuInsert)
+ self.btnInsert.setMenu(self.mInsert)
self.btnApply = QPushButton(self.tr("Apply"), self)
self.btnApply.clicked.connect(self._saveFormat)
@@ -715,8 +705,8 @@ class _HeadingsTab(NScrollablePage):
# Layout Matrix
# =============
self.layoutMatrix = QGridLayout()
- self.layoutMatrix.setVerticalSpacing(vSp)
- self.layoutMatrix.setHorizontalSpacing(vSp)
+ self.layoutMatrix.setVerticalSpacing(12)
+ self.layoutMatrix.setHorizontalSpacing(12)
self.layoutMatrix.addWidget(QLabel(self.tr("Centre"), self), 0, 1)
self.layoutMatrix.addWidget(QLabel(self.tr("Page Break"), self), 0, 2)
@@ -764,9 +754,9 @@ class _HeadingsTab(NScrollablePage):
self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.formatBox)
- self.outerBox.addSpacing(sSp)
+ self.outerBox.addSpacing(16)
self.outerBox.addLayout(self.editFormBox)
- self.outerBox.addSpacing(sSp)
+ self.outerBox.addSpacing(16)
self.outerBox.addLayout(self.layoutMatrix)
self.outerBox.addStretch(1)
@@ -904,7 +894,7 @@ class _HeadingsTab(NScrollablePage):
class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
- def __init__(self, document: QTextDocument) -> None:
+ def __init__(self, document: QTextDocument | None) -> None:
super().__init__(document)
syntax = SHARED.theme.syntaxTheme
self._fmtSymbol = QTextCharFormat()
@@ -1223,7 +1213,7 @@ class _FormattingTab(NScrollableForm):
# Header
self.odtPageHeader = QLineEdit(self)
- self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200))
+ self.odtPageHeader.setMinimumWidth(200)
self.btnPageHeader = NIconToolButton(self, iSz, "revert", "green")
self.btnPageHeader.clicked.connect(self._resetPageHeader)
self.addRow(
diff --git a/novelwriter/tools/noveldetails.py b/novelwriter/tools/noveldetails.py
index a71539e5..c23a513e 100644
--- a/novelwriter/tools/noveldetails.py
+++ b/novelwriter/tools/noveldetails.py
@@ -34,7 +34,7 @@ from PyQt6.QtWidgets import (
QVBoxLayout, QWidget
)
-from novelwriter import CONFIG, SHARED
+from novelwriter import SHARED
from novelwriter.common import formatTime, numberToRoman
from novelwriter.constants import nwUnicode
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage
@@ -60,16 +60,16 @@ class GuiNovelDetails(NNonBlockingDialog):
self.setWindowTitle(self.tr("Novel Details"))
options = SHARED.project.options
- self.setMinimumSize(CONFIG.pxInt(500), CONFIG.pxInt(400))
+ self.setMinimumSize(500, 400)
self.resize(
- CONFIG.pxInt(options.getInt("GuiNovelDetails", "winWidth", CONFIG.pxInt(650))),
- CONFIG.pxInt(options.getInt("GuiNovelDetails", "winHeight", CONFIG.pxInt(500)))
+ options.getInt("GuiNovelDetails", "winWidth", 650),
+ options.getInt("GuiNovelDetails", "winHeight", 500),
)
# Title
self.titleLabel = NColourLabel(
self.tr("Novel Details"), self, color=SHARED.theme.helpText,
- scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
+ scale=NColourLabel.HEADER_SCALE, indent=4,
)
# Novel Selector
@@ -114,7 +114,7 @@ class GuiNovelDetails(NNonBlockingDialog):
self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox)
- self.outerBox.setSpacing(CONFIG.pxInt(8))
+ self.outerBox.setSpacing(8)
self.setLayout(self.outerBox)
self.setSizeGripEnabled(True)
@@ -172,18 +172,13 @@ class GuiNovelDetails(NNonBlockingDialog):
def _saveSettings(self) -> None:
"""Save the user GUI settings."""
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
- novelRoot = self.novelSelector.handle
-
logger.debug("Saving State: GuiNovelDetails")
+ novelRoot = self.novelSelector.handle
options = SHARED.project.options
- options.setValue("GuiNovelDetails", "winWidth", winWidth)
- options.setValue("GuiNovelDetails", "winHeight", winHeight)
+ options.setValue("GuiNovelDetails", "winWidth", self.width())
+ options.setValue("GuiNovelDetails", "winHeight", self.height())
options.setValue("GuiNovelDetails", "novelRoot", novelRoot)
-
self.contentsPage.saveSettings()
-
return
@@ -192,11 +187,6 @@ class _OverviewPage(NScrollablePage):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
- mPx = CONFIG.pxInt(8)
- sPx = CONFIG.pxInt(16)
- hPx = CONFIG.pxInt(24)
- vPx = CONFIG.pxInt(4)
-
# Project Info
self.projLabel = NColourLabel(
self.tr("Project"), self, color=SHARED.theme.helpText,
@@ -217,9 +207,9 @@ class _OverviewPage(NScrollablePage):
self.projForm.addRow("{0}".format(self.tr("Word Count")), self.projWords)
self.projForm.addRow("\u2026 {0}".format(self.tr("In Novels")), self.projNovels)
self.projForm.addRow("\u2026 {0}".format(self.tr("In Notes")), self.projNotes)
- self.projForm.setContentsMargins(mPx, 0, 0, 0)
- self.projForm.setHorizontalSpacing(hPx)
- self.projForm.setVerticalSpacing(vPx)
+ self.projForm.setContentsMargins(8, 0, 0, 0)
+ self.projForm.setHorizontalSpacing(24)
+ self.projForm.setVerticalSpacing(4)
# Novel Info
self.novelLabel = NColourLabel(
@@ -237,9 +227,9 @@ class _OverviewPage(NScrollablePage):
self.novelForm.addRow("{0}".format(self.tr("Word Count")), self.novelWords)
self.novelForm.addRow("{0}".format(self.tr("Chapters")), self.novelChapters)
self.novelForm.addRow("{0}".format(self.tr("Scenes")), self.novelScenes)
- self.novelForm.setContentsMargins(mPx, 0, 0, 0)
- self.novelForm.setHorizontalSpacing(hPx)
- self.novelForm.setVerticalSpacing(vPx)
+ self.novelForm.setContentsMargins(8, 0, 0, 0)
+ self.novelForm.setHorizontalSpacing(24)
+ self.novelForm.setVerticalSpacing(4)
# Assemble
self.outerBox = QVBoxLayout()
@@ -247,7 +237,7 @@ class _OverviewPage(NScrollablePage):
self.outerBox.addLayout(self.projForm)
self.outerBox.addWidget(self.novelLabel)
self.outerBox.addLayout(self.novelForm)
- self.outerBox.setSpacing(sPx)
+ self.outerBox.setSpacing(16)
self.outerBox.addStretch(1)
self.setCentralLayout(self.outerBox)
@@ -309,8 +299,6 @@ class _ContentsPage(NFixedPage):
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- hPx = CONFIG.pxInt(12)
- vPx = CONFIG.pxInt(4)
options = SHARED.project.options
# Title
@@ -341,22 +329,22 @@ class _ContentsPage(NFixedPage):
treeHeadItem.setTextAlignment(self.C_PAGE, QtAlignRight)
treeHeadItem.setTextAlignment(self.C_PROG, QtAlignRight)
- treeHeader = self.tocTree.header()
- treeHeader.setStretchLastSection(True)
- treeHeader.setMinimumSectionSize(hPx)
+ if header := self.tocTree.header():
+ header.setStretchLastSection(True)
+ header.setMinimumSectionSize(12)
- wCol0 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol0", 200))
- wCol1 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol1", 60))
- wCol2 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol2", 60))
- wCol3 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol3", 60))
- wCol4 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol4", 90))
+ wCol0 = options.getInt("GuiNovelDetails", "widthCol0", 200)
+ wCol1 = options.getInt("GuiNovelDetails", "widthCol1", 60)
+ wCol2 = options.getInt("GuiNovelDetails", "widthCol2", 60)
+ wCol3 = options.getInt("GuiNovelDetails", "widthCol3", 60)
+ wCol4 = options.getInt("GuiNovelDetails", "widthCol4", 90)
self.tocTree.setColumnWidth(0, wCol0)
self.tocTree.setColumnWidth(1, wCol1)
self.tocTree.setColumnWidth(2, wCol2)
self.tocTree.setColumnWidth(3, wCol3)
self.tocTree.setColumnWidth(4, wCol4)
- self.tocTree.setColumnWidth(5, hPx)
+ self.tocTree.setColumnWidth(5, 12)
# Options
wordsPerPage = options.getInt("GuiNovelDetails", "wordsPerPage", 350)
@@ -394,8 +382,8 @@ class _ContentsPage(NFixedPage):
self.optionsBox.addWidget(self.dblValue, 0, 4)
self.optionsBox.addWidget(self.poLabel, 1, 0)
self.optionsBox.addWidget(self.poValue, 1, 1)
- self.optionsBox.setHorizontalSpacing(hPx)
- self.optionsBox.setVerticalSpacing(vPx)
+ self.optionsBox.setHorizontalSpacing(12)
+ self.optionsBox.setVerticalSpacing(4)
self.optionsBox.setColumnStretch(2, 1)
# Assemble
@@ -410,18 +398,12 @@ class _ContentsPage(NFixedPage):
def saveSettings(self) -> None:
"""Save the user GUI settings."""
- widthCol0 = CONFIG.rpxInt(self.tocTree.columnWidth(0))
- widthCol1 = CONFIG.rpxInt(self.tocTree.columnWidth(1))
- widthCol2 = CONFIG.rpxInt(self.tocTree.columnWidth(2))
- widthCol3 = CONFIG.rpxInt(self.tocTree.columnWidth(3))
- widthCol4 = CONFIG.rpxInt(self.tocTree.columnWidth(4))
-
options = SHARED.project.options
- options.setValue("GuiNovelDetails", "widthCol0", widthCol0)
- options.setValue("GuiNovelDetails", "widthCol1", widthCol1)
- options.setValue("GuiNovelDetails", "widthCol2", widthCol2)
- options.setValue("GuiNovelDetails", "widthCol3", widthCol3)
- options.setValue("GuiNovelDetails", "widthCol4", widthCol4)
+ options.setValue("GuiNovelDetails", "widthCol0", self.tocTree.columnWidth(0))
+ options.setValue("GuiNovelDetails", "widthCol1", self.tocTree.columnWidth(1))
+ options.setValue("GuiNovelDetails", "widthCol2", self.tocTree.columnWidth(2))
+ options.setValue("GuiNovelDetails", "widthCol3", self.tocTree.columnWidth(3))
+ options.setValue("GuiNovelDetails", "widthCol4", self.tocTree.columnWidth(4))
options.setValue("GuiNovelDetails", "wordsPerPage", self.wpValue.value())
options.setValue("GuiNovelDetails", "countFrom", self.poValue.value())
options.setValue("GuiNovelDetails", "clearDouble", self.dblValue.isChecked())
diff --git a/novelwriter/tools/welcome.py b/novelwriter/tools/welcome.py
index 88126797..32791caf 100644
--- a/novelwriter/tools/welcome.py
+++ b/novelwriter/tools/welcome.py
@@ -40,7 +40,7 @@ from PyQt6.QtWidgets import (
)
from novelwriter import CONFIG, SHARED
-from novelwriter.common import cssCol, formatInt, makeFileNameSafe, qtLambda
+from novelwriter.common import cssCol, formatInt, makeFileNameSafe, qtAddAction, qtLambda
from novelwriter.constants import nwFiles
from novelwriter.core.coretools import ProjectBuilder
from novelwriter.enum import nwItemClass
@@ -66,29 +66,21 @@ class GuiWelcome(NDialog):
self.setObjectName("GuiWelcome")
self.setWindowTitle(self.tr("Welcome"))
- self.setMinimumWidth(CONFIG.pxInt(650))
- self.setMinimumHeight(CONFIG.pxInt(450))
-
- hA = CONFIG.pxInt(8)
- hB = CONFIG.pxInt(16)
- hC = CONFIG.pxInt(24)
- hD = CONFIG.pxInt(36)
- hE = CONFIG.pxInt(48)
- hF = CONFIG.pxInt(128)
- btnIconSize = SHARED.theme.buttonIconSize
-
- self._hPx = CONFIG.pxInt(600)
+ self.setMinimumWidth(650)
+ self.setMinimumHeight(450)
self.resize(*CONFIG.welcomeWinSize)
+ btnIconSize = SHARED.theme.buttonIconSize
+
# Elements
# ========
self.bgImage = SHARED.theme.loadDecoration("welcome")
- self.nwImage = SHARED.theme.loadDecoration("nw-text", h=hD)
+ self.nwImage = SHARED.theme.loadDecoration("nw-text", h=36)
self.bgColor = QColor(54, 54, 54) if SHARED.theme.isDarkTheme else QColor(255, 255, 255)
self.nwLogo = QLabel(self)
- self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (hF, hF)))
+ self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (128, 128)))
self.nwLabel = QLabel(self)
self.nwLabel.setPixmap(self.nwImage)
@@ -152,18 +144,18 @@ class GuiWelcome(NDialog):
# ========
self.innerBox = QVBoxLayout()
- self.innerBox.addSpacing(hB)
+ self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.nwLabel)
self.innerBox.addWidget(self.nwInfo)
- self.innerBox.addSpacing(hA)
+ self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.mainStack)
- self.innerBox.addSpacing(hB)
+ self.innerBox.addSpacing(16)
self.innerBox.addLayout(self.btnBox)
self.outerBox = QHBoxLayout()
self.outerBox.addWidget(self.nwLogo, 3, QtAlignRightTop)
self.outerBox.addLayout(self.innerBox, 9)
- self.outerBox.setContentsMargins(hF, hE, hC, hE)
+ self.outerBox.setContentsMargins(128, 48, 24, 48)
self.setLayout(self.outerBox)
self.setSizeGripEnabled(True)
@@ -183,7 +175,7 @@ class GuiWelcome(NDialog):
def paintEvent(self, event: QPaintEvent) -> None:
"""Overload the paint event to draw the background image."""
hWin = self.height()
- hPix = min(hWin, self._hPx)
+ hPix = min(hWin, 600)
tMode = Qt.TransformationMode.SmoothTransformation
painter = QPainter(self)
painter.fillRect(self.rect(), self.bgColor)
@@ -309,11 +301,10 @@ class _OpenProjectPage(QWidget):
self._selectFirstItem()
- mPx = CONFIG.pxInt(4)
baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
self.setStyleSheet(
f"QListView {{border: none; background: {baseCol};}} "
- f"QLineEdit {{border: none; background: {baseCol}; padding: {mPx}px;}} "
+ f"QLineEdit {{border: none; background: {baseCol}; padding: 4px;}} "
)
return
@@ -370,9 +361,9 @@ class _OpenProjectPage(QWidget):
"""Open the custom context menu."""
ctxMenu = QMenu(self)
ctxMenu.setObjectName("ContextMenu") # Used for testing
- action = ctxMenu.addAction(self.tr("Open Project"))
+ action = qtAddAction(ctxMenu, self.tr("Open Project"))
action.triggered.connect(self.openSelectedItem)
- action = ctxMenu.addAction(self.tr("Remove Project"))
+ action = qtAddAction(ctxMenu, self.tr("Remove Project"))
action.triggered.connect(self._deleteSelectedItem)
ctxMenu.exec(self.mapToGlobal(pos))
ctxMenu.deleteLater()
@@ -400,11 +391,10 @@ class _ProjectListItem(QStyledItemDelegate):
fPx = SHARED.theme.fontPixelSize
fPt = SHARED.theme.fontPointSize
tPx = round(1.2 * fPx)
- mPx = CONFIG.pxInt(4)
iPx = tPx + fPx
- self._pPx = (mPx//2, 3*mPx//2, iPx + mPx, mPx, mPx + tPx) # Painter coordinates
- self._hPx = 2*mPx + tPx + fPx # Fixed height
+ self._pPx = (iPx + 4, tPx + 4) # Painter coordinates
+ self._hPx = 8 + tPx + fPx # Fixed height
self._tFont = QApplication.font()
self._tFont.setPointSizeF(1.2*fPt)
@@ -423,7 +413,7 @@ class _ProjectListItem(QStyledItemDelegate):
rect = opt.rect
title, _, details = index.data()
tFlag = Qt.TextFlag.TextSingleLine
- ix, iy, x, y1, y2 = self._pPx
+ x, y = self._pPx
painter.save()
if opt.state & QtSelected == QtSelected:
@@ -431,12 +421,12 @@ class _ProjectListItem(QStyledItemDelegate):
painter.fillRect(rect, QApplication.palette().highlight())
painter.setOpacity(1.0)
- painter.drawPixmap(ix, rect.top() + iy, self._icon)
+ painter.drawPixmap(2, rect.top() + 6, self._icon)
painter.setFont(self._tFont)
- painter.drawText(rect.adjusted(x, y1, 0, 0), tFlag, title)
+ painter.drawText(rect.adjusted(x, 4, 0, 0), tFlag, title)
painter.setFont(self._dFont)
painter.setPen(self._dPen)
- painter.drawText(rect.adjusted(x, y2, 0, 0), tFlag, details)
+ painter.drawText(rect.adjusted(x, y, 0, 0), tFlag, details)
painter.restore()
return
@@ -557,7 +547,6 @@ class _NewProjectForm(QWidget):
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
- sPx = CONFIG.pxInt(16)
# Project Settings
# ================
@@ -592,15 +581,15 @@ class _NewProjectForm(QWidget):
self.fillMenu = QMenu(self.browseFill)
- self.fillBlank = self.fillMenu.addAction(self.tr("Create a fresh project"))
+ self.fillBlank = qtAddAction(self.fillMenu, self.tr("Create a fresh project"))
self.fillBlank.setIcon(SHARED.theme.getIcon("document"))
self.fillBlank.triggered.connect(self._setFillBlank)
- self.fillSample = self.fillMenu.addAction(self.tr("Create an example project"))
+ self.fillSample = qtAddAction(self.fillMenu, self.tr("Create an example project"))
self.fillSample.setIcon(SHARED.theme.getIcon("document_add", "blue"))
self.fillSample.triggered.connect(self._setFillSample)
- self.fillCopy = self.fillMenu.addAction(self.tr("Copy an existing project"))
+ self.fillCopy = qtAddAction(self.fillMenu, self.tr("Copy an existing project"))
self.fillCopy.setIcon(SHARED.theme.getIcon("project_copy", "green"))
self.fillCopy.triggered.connect(self._setFillCopy)
@@ -675,7 +664,7 @@ class _NewProjectForm(QWidget):
self.extraBox = QVBoxLayout()
self.extraBox.addWidget(QLabel("{0}".format(self.tr("Chapters and Scenes")), self))
self.extraBox.addLayout(self.novelForm)
- self.extraBox.addSpacing(sPx)
+ self.extraBox.addSpacing(16)
self.extraBox.addWidget(QLabel("{0}".format(self.tr("Project Notes")), self))
self.extraBox.addLayout(self.notesForm)
self.extraBox.setContentsMargins(0, 0, 0, 0)
@@ -687,7 +676,7 @@ class _NewProjectForm(QWidget):
self.formBox = QVBoxLayout()
self.formBox.addWidget(QLabel("{0}".format(self.tr("Create New Project")), self))
self.formBox.addLayout(self.projectForm)
- self.formBox.addSpacing(sPx)
+ self.formBox.addSpacing(16)
self.formBox.addWidget(self.extraWidget)
self.formBox.addStretch(1)
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index bc59ab62..acf8d308 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -82,26 +82,18 @@ class GuiWritingStats(NToolDialog):
pOptions = SHARED.project.options
self.setWindowTitle(self.tr("Writing Statistics"))
- self.setMinimumWidth(CONFIG.pxInt(420))
- self.setMinimumHeight(CONFIG.pxInt(400))
+ self.setMinimumWidth(420)
+ self.setMinimumHeight(400)
self.resize(
- CONFIG.pxInt(pOptions.getInt("GuiWritingStats", "winWidth", 550)),
- CONFIG.pxInt(pOptions.getInt("GuiWritingStats", "winHeight", 500))
+ pOptions.getInt("GuiWritingStats", "winWidth", 550),
+ pOptions.getInt("GuiWritingStats", "winHeight", 500),
)
# List Box
- wCol0 = CONFIG.pxInt(
- pOptions.getInt("GuiWritingStats", "widthCol0", 180)
- )
- wCol1 = CONFIG.pxInt(
- pOptions.getInt("GuiWritingStats", "widthCol1", 80)
- )
- wCol2 = CONFIG.pxInt(
- pOptions.getInt("GuiWritingStats", "widthCol2", 80)
- )
- wCol3 = CONFIG.pxInt(
- pOptions.getInt("GuiWritingStats", "widthCol3", 80)
- )
+ wCol0 = pOptions.getInt("GuiWritingStats", "widthCol0", 180)
+ wCol1 = pOptions.getInt("GuiWritingStats", "widthCol1", 80)
+ wCol2 = pOptions.getInt("GuiWritingStats", "widthCol2", 80)
+ wCol3 = pOptions.getInt("GuiWritingStats", "widthCol3", 80)
self.listBox = QTreeWidget(self)
self.listBox.setHeaderLabels([
@@ -133,7 +125,6 @@ class GuiWritingStats(NToolDialog):
# Word Bar
self.barHeight = int(round(0.5*SHARED.theme.fontPixelSize))
- self.barWidth = CONFIG.pxInt(200)
self.barImage = QPixmap(self.barHeight, self.barHeight)
self.barImage.fill(self.palette().highlight().color())
@@ -262,25 +253,27 @@ class GuiWritingStats(NToolDialog):
self.optsBox.addWidget(self.histMax, 0)
# Buttons
+ self.saveJSON = QAction(self.tr("JSON Data File (.json)"), self)
+ self.saveJSON.triggered.connect(qtLambda(self._saveData, self.FMT_JSON))
+
+ self.saveCSV = QAction(self.tr("CSV Data File (.csv)"), self)
+ self.saveCSV.triggered.connect(qtLambda(self._saveData, self.FMT_CSV))
+
+ self.saveMenu = QMenu(self)
+ self.saveMenu.addAction(self.saveJSON)
+ self.saveMenu.addAction(self.saveCSV)
+
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.rejected.connect(self._doClose)
self.btnClose = self.buttonBox.addButton(QtDialogClose)
- self.btnClose.setAutoDefault(False)
+ if self.btnClose:
+ self.btnClose.setAutoDefault(False)
self.btnSave = self.buttonBox.addButton(self.tr("Save As"), QtRoleAction)
- self.btnSave.setAutoDefault(False)
-
- self.saveMenu = QMenu(self)
- self.btnSave.setMenu(self.saveMenu)
-
- self.saveJSON = QAction(self.tr("JSON Data File (.json)"), self)
- self.saveJSON.triggered.connect(qtLambda(self._saveData, self.FMT_JSON))
- self.saveMenu.addAction(self.saveJSON)
-
- self.saveCSV = QAction(self.tr("CSV Data File (.csv)"), self)
- self.saveCSV.triggered.connect(qtLambda(self._saveData, self.FMT_CSV))
- self.saveMenu.addAction(self.saveCSV)
+ if self.btnSave:
+ self.btnSave.setAutoDefault(False)
+ self.btnSave.setMenu(self.saveMenu)
# Assemble
self.outerBox = QGridLayout()
@@ -328,14 +321,10 @@ class GuiWritingStats(NToolDialog):
"""Save the state of the window, clear cache, end close."""
self.logData = []
- winWidth = CONFIG.rpxInt(self.width())
- winHeight = CONFIG.rpxInt(self.height())
- widthCol0 = CONFIG.rpxInt(self.listBox.columnWidth(0))
- widthCol1 = CONFIG.rpxInt(self.listBox.columnWidth(1))
- widthCol2 = CONFIG.rpxInt(self.listBox.columnWidth(2))
- widthCol3 = CONFIG.rpxInt(self.listBox.columnWidth(3))
+ header = self.listBox.header()
+
sortCol = self.listBox.sortColumn()
- sortOrder = self.listBox.header().sortIndicatorOrder()
+ sortOrder = header.sortIndicatorOrder() if header else 0
incNovel = self.incNovel.isChecked()
incNotes = self.incNotes.isChecked()
hideZeros = self.hideZeros.isChecked()
@@ -346,12 +335,12 @@ class GuiWritingStats(NToolDialog):
logger.debug("Saving State: GuiWritingStats")
pOptions = SHARED.project.options
- pOptions.setValue("GuiWritingStats", "winWidth", winWidth)
- pOptions.setValue("GuiWritingStats", "winHeight", winHeight)
- pOptions.setValue("GuiWritingStats", "widthCol0", widthCol0)
- pOptions.setValue("GuiWritingStats", "widthCol1", widthCol1)
- pOptions.setValue("GuiWritingStats", "widthCol2", widthCol2)
- pOptions.setValue("GuiWritingStats", "widthCol3", widthCol3)
+ pOptions.setValue("GuiWritingStats", "winWidth", self.width())
+ pOptions.setValue("GuiWritingStats", "winHeight", self.height())
+ pOptions.setValue("GuiWritingStats", "widthCol0", self.listBox.columnWidth(0))
+ pOptions.setValue("GuiWritingStats", "widthCol1", self.listBox.columnWidth(1))
+ pOptions.setValue("GuiWritingStats", "widthCol2", self.listBox.columnWidth(2))
+ pOptions.setValue("GuiWritingStats", "widthCol3", self.listBox.columnWidth(3))
pOptions.setValue("GuiWritingStats", "sortCol", sortCol)
pOptions.setValue("GuiWritingStats", "sortOrder", sortOrder)
pOptions.setValue("GuiWritingStats", "incNovel", incNovel)
diff --git a/novelwriter/types.py b/novelwriter/types.py
index e06177b7..e1b05ead 100644
--- a/novelwriter/types.py
+++ b/novelwriter/types.py
@@ -23,8 +23,6 @@ along with this program. If not, see .
"""
from __future__ import annotations
-from typing import Any, TypeVar
-
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QColor, QFont, QPainter, QTextCharFormat, QTextCursor, QTextFormat
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QHeaderView, QSizePolicy, QStyle
@@ -148,30 +146,3 @@ FONT_STYLE: dict[QFont.Style, str] = {
QFont.Style.StyleItalic: "italic",
QFont.Style.StyleOblique: "oblique",
}
-
-##
-# Decorators and MetaClasses
-##
-
-T_ = TypeVar("T_", bound=object)
-
-
-def nwDataClass(cls: T_) -> T_:
- """A simple data class decorator that generates slots automatically
- and creates an init function to match.
- """
-
- def wrap(cls: T_) -> T_:
- fields = tuple(a for a in dir(cls) if not a.startswith("__"))
- values = {a: getattr(cls, a) for a in fields}
-
- def init(self: Any) -> None:
- nonlocal values
- for a, v in values.items():
- self.__setattr__(a, v)
-
- return type(cls.__class__.__name__, (object,), { # type: ignore
- "__slots__": fields, "__init__": init
- })
-
- return wrap(cls)
diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py
index 34bac678..6d968292 100644
--- a/tests/test_base/test_base_config.py
+++ b/tests/test_base/test_base_config.py
@@ -254,52 +254,29 @@ def testBaseConfig_SettersGetters(fncPath):
tstConf.setMainWinSize(70, 70)
assert tstConf.mainWinSize == [70, 70]
- assert tstConf._mainWinSize == [70, 70]
+ assert tstConf.mainWinSize == [70, 70]
tstConf.setMainWinSize(1200, 650)
# Welcome Window Size
tstConf.setWelcomeWinSize(70, 70)
assert tstConf.welcomeWinSize == [70, 70]
- assert tstConf._welcomeSize == [70, 70]
+ assert tstConf.welcomeWinSize == [70, 70]
tstConf.setWelcomeWinSize(800, 500)
# Preferences Size
tstConf.setPreferencesWinSize(70, 70)
- assert tstConf.preferencesWinSize == [70, 70]
- assert tstConf._prefsWinSize == [70, 70]
+ assert tstConf.prefsWinSize == [70, 70]
+ assert tstConf.prefsWinSize == [70, 70]
tstConf.setPreferencesWinSize(700, 615)
- # Main Pane Splitter
- tstConf.setMainPanePos([200, 700])
- assert tstConf.mainPanePos == [200, 700]
- assert tstConf._mainPanePos == [200, 700]
-
- tstConf.setMainPanePos([300, 800])
-
- # View Pane Splitter
- tstConf.setViewPanePos([400, 250])
- assert tstConf.viewPanePos == [400, 250]
- assert tstConf._viewPanePos == [400, 250]
-
- tstConf.setViewPanePos([500, 150])
-
- # Outline Pane Splitter
- tstConf.setOutlinePanePos([400, 250])
- assert tstConf.outlinePanePos == [400, 250]
- assert tstConf._outlnPanePos == [400, 250]
-
- tstConf.setOutlinePanePos([500, 150])
-
# Getters Only
# ============
assert tstConf.getTextWidth(False) == 700
assert tstConf.getTextWidth(True) == 800
- assert tstConf.getTextMargin() == 40
- assert tstConf.getTabWidth() == 40
@pytest.mark.base
diff --git a/tests/test_core/test_core_buildsettings.py b/tests/test_core/test_core_buildsettings.py
index 1ae1360a..2b21b673 100644
--- a/tests/test_core/test_core_buildsettings.py
+++ b/tests/test_core/test_core_buildsettings.py
@@ -398,7 +398,7 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
buildTwo.setName("Build Two")
buildIDTwo = buildTwo.buildID
- # Check that we can extract infor about the builds
+ # Check that we can extract info about the builds
builds.setBuild(buildTwo)
assert len(builds) == 2
assert buildsFile.exists()
diff --git a/tests/test_dialogs/test_dlg_about.py b/tests/test_dialogs/test_dlg_about.py
index 0f659035..bde9ad7d 100644
--- a/tests/test_dialogs/test_dlg_about.py
+++ b/tests/test_dialogs/test_dlg_about.py
@@ -41,7 +41,9 @@ def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
msgAbout = SHARED.findTopLevelWidget(GuiAbout)
assert isinstance(msgAbout, GuiAbout)
- assert msgAbout.txtCredits.document().characterCount() > 100
+ document = msgAbout.txtCredits.document()
+ assert document is not None
+ assert document.characterCount() > 100
with monkeypatch.context() as mp:
mp.setattr("novelwriter.config.Config.assetPath", lambda *a: Path("whatever"))
diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py
index bdc4db27..63dbc91a 100644
--- a/tests/test_dialogs/test_dlg_preferences.py
+++ b/tests/test_dialogs/test_dlg_preferences.py
@@ -72,17 +72,16 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
prefs.close()
# Check Fallback Values
- with monkeypatch.context() as mp:
- mp.setattr(CONFIG, "hasEnchant", False)
- prefs = GuiPreferences(nwGUI)
- prefs.show()
+ CONFIG.hasEnchant = False
+ prefs = GuiPreferences(nwGUI)
+ prefs.show()
- # Check Spell Checking
- spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())]
- assert len(spelling) == 1
- assert spelling == [""]
+ # Check Spell Checking
+ spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())]
+ assert len(spelling) == 1
+ assert spelling == [""]
- prefs.close()
+ prefs.close()
# qtbot.stop()
@@ -97,6 +96,7 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
# Check Navigation
vBar = prefs.mainForm.verticalScrollBar()
+ assert vBar is not None
old = -1
with qtbot.waitSignal(vBar.valueChanged) as value:
prefs.sidebar.button(1).click()
@@ -120,12 +120,16 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
# Check Save Button
prefs.show()
with qtbot.waitSignal(prefs.newPreferencesReady) as signal:
- prefs.buttonBox.button(QtDialogSave).click()
+ button = prefs.buttonBox.button(QtDialogSave)
+ assert button is not None
+ button.click()
assert signal.args == [False, False, False, False]
# Check Close Button
prefs.show()
- prefs.buttonBox.button(QtDialogCancel).click()
+ button = prefs.buttonBox.button(QtDialogCancel)
+ assert button is not None
+ button.click()
assert prefs.isHidden() is True
# Close Using Escape Key
@@ -138,13 +142,14 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
@pytest.mark.gui
-def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths):
+def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
"""Test the preferences dialog settings."""
spelling = [("en", "English [en]"), ("de", "Deutch [de]")]
- languages = [("en_GB", "British English"), ("en_US", "US English")]
-
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: spelling)
- monkeypatch.setattr(CONFIG, "listLanguages", lambda *a: languages)
+
+ (fncPath / "nw_en_US.qm").touch()
+ (fncPath / "project_en_US.json").touch()
+ CONFIG._nwLangPath = fncPath
prefs = GuiPreferences(nwGUI)
with qtbot.waitExposed(prefs):
@@ -313,7 +318,9 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths):
with monkeypatch.context() as mp:
mp.setattr(QFontDatabase, "families", lambda *a: ["TestFont"])
with qtbot.waitSignal(prefs.newPreferencesReady) as signal:
- prefs.buttonBox.button(QtDialogSave).click()
+ button = prefs.buttonBox.button(QtDialogSave)
+ assert button is not None
+ button.click()
assert signal.args == [True, True, True, True]
# Check Settings
diff --git a/tests/test_dialogs/test_dlg_projectsettings.py b/tests/test_dialogs/test_dlg_projectsettings.py
index 54b5cd1d..d28322d4 100644
--- a/tests/test_dialogs/test_dlg_projectsettings.py
+++ b/tests/test_dialogs/test_dlg_projectsettings.py
@@ -88,7 +88,12 @@ def testDlgProjSettings_SettingsPage(qtbot, monkeypatch, nwGUI, fncPath, projPat
"""Test the settings page of the dialog."""
languages = [("en", "English"), ("de", "German")]
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda *a: languages)
- monkeypatch.setattr(CONFIG, "listLanguages", lambda *a: languages)
+
+ (fncPath / "nw_en.qm").touch()
+ (fncPath / "nw_de.qm").touch()
+ (fncPath / "project_en.json").touch()
+ (fncPath / "project_de.json").touch()
+ CONFIG._nwLangPath = fncPath
# Create new project
buildTestProject(nwGUI, projPath)
diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py
index 32198bec..428807f3 100644
--- a/tests/test_gui/test_gui_doceditor.py
+++ b/tests/test_gui/test_gui_doceditor.py
@@ -441,6 +441,9 @@ def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
ctxMenu.deleteLater()
# Copy Text
+ clipboard = QApplication.clipboard()
+ assert clipboard is not None
+
ctxMenu = getMenuForPos(docEditor, 31, True)
assert ctxMenu is not None
assert docEditor.textCursor().selectedText() == "text"
@@ -448,14 +451,14 @@ def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
assert actions == [
"Cut", "Copy", "Paste", "Select All", "Select Word", "Select Paragraph"
]
- QApplication.clipboard().clear()
+ clipboard.clear()
ctxMenu.actions()[1].trigger()
- assert QApplication.clipboard().text(QClipboard.Mode.Clipboard) == "text"
+ assert clipboard.text(QClipboard.Mode.Clipboard) == "text"
# Cut Text
- QApplication.clipboard().clear()
+ clipboard.clear()
ctxMenu.actions()[0].trigger()
- assert QApplication.clipboard().text(QClipboard.Mode.Clipboard) == "text"
+ assert clipboard.text(QClipboard.Mode.Clipboard) == "text"
assert "text" not in docEditor.getText()
# Paste Text
@@ -572,7 +575,9 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
# Select/Cut/Copy/Paste/Undo/Redo
# ===============================
- QApplication.clipboard().clear()
+ clipboard = QApplication.clipboard()
+ assert clipboard is not None
+ clipboard.clear()
# Select All
assert docEditor.docAction(nwDocAction.SEL_ALL) is True
@@ -624,7 +629,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
assert newPara[5] == ipsumText[4]
assert newPara[6] == ipsumText[2]
- QApplication.clipboard().clear()
+ clipboard.clear()
# Emphasis/Undo/Redo
# ==================
diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py
index 2eb8cb59..65c31a24 100644
--- a/tests/test_gui/test_gui_docviewer.py
+++ b/tests/test_gui/test_gui_docviewer.py
@@ -91,18 +91,19 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
docViewer.setTextCursor(cursor)
docViewer._makeSelection(QTextCursor.SelectionType.WordUnderCursor)
- qClip = QApplication.clipboard()
- qClip.clear()
+ clipboard = QApplication.clipboard()
+ assert clipboard is not None
+ clipboard.clear()
# Cut
assert docViewer.docAction(nwDocAction.CUT) is True
- assert qClip.text() == "laoreet"
- qClip.clear()
+ assert clipboard.text() == "laoreet"
+ clipboard.clear()
# Copy
assert docViewer.docAction(nwDocAction.COPY) is True
- assert qClip.text() == "laoreet"
- qClip.clear()
+ assert clipboard.text() == "laoreet"
+ clipboard.clear()
# Select Paragraph
assert docViewer.docAction(nwDocAction.SEL_PARA) is True
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index de3163d2..a38c3644 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -1148,7 +1148,9 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
def getTransformSubMenu(menu: QMenu) -> list[str]:
for action in menu.actions():
if action.text() == "Transform ...":
- return [x.text() for x in action.menu().actions() if x.text()]
+ submenu = action.menu()
+ assert submenu is not None
+ return [x.text() for x in submenu.actions() if x.text()]
return []
# Context Menu on Document File Item
diff --git a/tests/test_tools/test_tools_manusbuild.py b/tests/test_tools/test_tools_manusbuild.py
index 07b0c1c5..9a86eff6 100644
--- a/tests/test_tools/test_tools_manusbuild.py
+++ b/tests/test_tools/test_tools_manusbuild.py
@@ -95,7 +95,9 @@ def testToolManuscriptBuild_Main(
assert (fncPath / "TestBuild").with_suffix(nwLabels.BUILD_EXT[fmt]).exists()
lastFmt = fmt
- manus._dialogButtonClicked(manus.buttonBox.button(QtDialogClose))
+ button = manus.buttonBox.button(QtDialogClose)
+ assert button is not None
+ manus._dialogButtonClicked(button)
manus.deleteLater()
assert build.lastBuildName == "TestBuild"
@@ -150,5 +152,7 @@ def testToolManuscriptBuild_Main(
assert lastUrl.startswith("file://")
# Finish
- manus._dialogButtonClicked(manus.buttonBox.button(QtDialogClose))
+ button = manus.buttonBox.button(QtDialogClose)
+ assert button is not None
+ manus._dialogButtonClicked(button)
# qtbot.stop()
diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py
index bdd5b900..4e7959cb 100644
--- a/tests/test_tools/test_tools_manuscript.py
+++ b/tests/test_tools/test_tools_manuscript.py
@@ -67,7 +67,9 @@ def testToolManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
# Build a preview
manus.buildList.clearSelection()
manus.buildList.setCurrentRow(0)
- with qtbot.waitSignal(manus.docPreview.document().contentsChanged):
+ document = manus.docPreview.document()
+ assert document is not None
+ with qtbot.waitSignal(document.contentsChanged):
manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() == allText
@@ -113,7 +115,9 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady)
- bSettings.buttonBox.button(QtDialogSave).click()
+ button = bSettings.buttonBox.button(QtDialogSave)
+ assert button is not None
+ button.click()
assert isinstance(build, BuildSettings)
assert build.name == "Test Build"
@@ -132,7 +136,9 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady)
- bSettings.buttonBox.button(QtDialogApply).click() # Should leave the dialog open
+ button = bSettings.buttonBox.button(QtDialogApply)
+ assert button is not None
+ button.click() # Should leave the dialog open
assert isinstance(build, BuildSettings)
assert build.name == "Test Build"
@@ -210,7 +216,9 @@ def testToolManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
manus._builds.setBuild(build)
manus.buildList.setCurrentRow(0)
- with qtbot.waitSignal(manus.docPreview.document().contentsChanged):
+ document = manus.docPreview.document()
+ assert document is not None
+ with qtbot.waitSignal(document.contentsChanged):
manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() != ""
@@ -304,7 +312,9 @@ def testToolManuscript_Print(monkeypatch, qtbot, nwGUI, projPath):
manus.loadContent()
manus.buildList.setCurrentRow(0)
- with qtbot.waitSignal(manus.docPreview.document().contentsChanged):
+ document = manus.docPreview.document()
+ assert document is not None
+ with qtbot.waitSignal(document.contentsChanged):
manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() != ""
diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py
index 256feee7..13b57464 100644
--- a/tests/test_tools/test_tools_manussettings.py
+++ b/tests/test_tools/test_tools_manussettings.py
@@ -51,13 +51,19 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
bSettings.loadContent()
# Flip through pages
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1)
+ assert button is not None
+ button.click()
assert isinstance(bSettings.toolStack.currentWidget(), _FormattingTab)
- bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_HEADINGS)
+ assert button is not None
+ button.click()
assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab)
- bSettings.sidebar._group.button(bSettings.OPT_FILTERS).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FILTERS)
+ assert button is not None
+ button.click()
assert isinstance(bSettings.toolStack.currentWidget(), _FilterTab)
# Check dialog buttons
@@ -72,7 +78,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
# Capture Apply button
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady)
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogApply))
+ button = bSettings.buttonBox.button(QtDialogApply)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
assert triggered
@@ -81,7 +89,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady)
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogSave))
+ button = bSettings.buttonBox.button(QtDialogSave)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
assert triggered
@@ -98,7 +108,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
assert triggered
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -129,7 +141,9 @@ def testToolBuildSettings_Filter(qtbot, nwGUI, projPath, mockRnd):
bSettings.loadContent()
filterTab = bSettings.optTabSelect
- bSettings.sidebar._group.button(bSettings.OPT_FILTERS).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FILTERS)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is filterTab
# Check content
@@ -308,7 +322,9 @@ def testToolBuildSettings_Filter(qtbot, nwGUI, projPath, mockRnd):
]
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -339,7 +355,9 @@ def testToolBuildSettings_Headings(qtbot, nwGUI):
bSettings.loadContent()
headTab = bSettings.optTabHeadings
- bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_HEADINGS)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is headTab
# Check initial values
@@ -478,7 +496,9 @@ def testToolBuildSettings_Headings(qtbot, nwGUI):
assert build.getBool("headings.hideSection") is True
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -501,7 +521,9 @@ def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
bSettings.loadContent()
fmtTab = bSettings.optTabFormatting
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
@@ -538,7 +560,9 @@ def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
assert build.getBool("text.addNoteHeadings") is True
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -563,7 +587,9 @@ def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
bSettings.loadContent()
fmtTab = bSettings.optTabFormatting
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 2).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 2)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
@@ -610,7 +636,9 @@ def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
assert fmtTab._textFont == font
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -629,7 +657,9 @@ def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
bSettings.loadContent()
fmtTab = bSettings.optTabFormatting
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 3).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 3)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
@@ -650,7 +680,9 @@ def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
assert build.getBool("format.indentFirstPar") is True
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -674,7 +706,9 @@ def testToolBuildSettings_FormatPageLayout(monkeypatch, qtbot, nwGUI):
bSettings.loadContent()
fmtTab = bSettings.optTabFormatting
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 4).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 4)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
@@ -704,7 +738,9 @@ def testToolBuildSettings_FormatPageLayout(monkeypatch, qtbot, nwGUI):
assert fmtTab.rightMargin.value() == 1.5
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
@@ -728,7 +764,9 @@ def testToolBuildSettings_FormatOutput(qtbot, nwGUI):
bSettings.loadContent()
fmtTab = bSettings.optTabFormatting
- bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 5).click()
+ button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 5)
+ assert button is not None
+ button.click()
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
@@ -769,5 +807,7 @@ def testToolBuildSettings_FormatOutput(qtbot, nwGUI):
assert fmtTab.odtPageHeader.text() == nwHeadFmt.DOC_AUTO
# Finish
- bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
+ button = bSettings.buttonBox.button(QtDialogClose)
+ assert button is not None
+ bSettings._dialogButtonClicked(button)
# qtbot.stop()
diff --git a/tests/test_tools/test_tools_writingstats.py b/tests/test_tools/test_tools_writingstats.py
index 4902c3fd..53475726 100644
--- a/tests/test_tools/test_tools_writingstats.py
+++ b/tests/test_tools/test_tools_writingstats.py
@@ -125,14 +125,37 @@ def testToolWritingStats_Export(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
assert sessLog.notesWords.text() == "{:n}".format(275)
assert sessLog.totalWords.text() == "{:n}".format(875)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(300)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-120)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-20)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(40)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-400)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(200)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
assert sessLog._saveData(sessLog.FMT_CSV)
assert sessLog._saveData(sessLog.FMT_JSON)
@@ -205,14 +228,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
sessLog.populateGUI()
sessLog.listBox.sortByColumn(sessLog.C_TIME, Qt.SortOrder.AscendingOrder)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(300)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-120)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-20)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(40)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-400)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(200)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
# No Novel Files
qtbot.mouseClick(sessLog.incNovel, QtMouseLeft)
@@ -222,14 +268,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read())
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-100)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(150)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-60)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-10)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(20)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(100)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(150)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-60)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-10)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(20)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(100)
assert jsonData == [
{
@@ -268,14 +337,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-100)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(150)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-60)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-10)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(20)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(100)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(150)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-60)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-10)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(20)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(100)
assert jsonData == [
{
@@ -314,10 +406,21 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(300)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(40)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(200)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
assert jsonData == [
{
@@ -344,16 +447,45 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(0)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(300)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-120)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(-20)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(40)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(-400)
- assert sessLog.listBox.topLevelItem(8).text(sessLog.C_COUNT) == "{:n}".format(200)
- assert sessLog.listBox.topLevelItem(9).text(sessLog.C_COUNT) == "{:n}".format(0)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
+
+ item = sessLog.listBox.topLevelItem(8)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
+
+ item = sessLog.listBox.topLevelItem(9)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
assert jsonData == [
{
@@ -390,9 +522,15 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
]
# Toggle Idle Time
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_IDLE) == "4 %"
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_IDLE) == "4 %"
+
qtbot.mouseClick(sessLog.showIdleTime, QtMouseLeft)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_IDLE) == "00:01:10"
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_IDLE) == "00:01:10"
# Group by Day
qtbot.mouseClick(sessLog.groupByDay, QtMouseLeft)
@@ -402,14 +540,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
- assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1)
- assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200)
- assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(180)
- assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-20)
- assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(40)
- assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(-400)
- assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(200)
- assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(0)
+ item = sessLog.listBox.topLevelItem(0)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
+
+ item = sessLog.listBox.topLevelItem(1)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
+
+ item = sessLog.listBox.topLevelItem(2)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(180)
+
+ item = sessLog.listBox.topLevelItem(3)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
+
+ item = sessLog.listBox.topLevelItem(4)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
+
+ item = sessLog.listBox.topLevelItem(5)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
+
+ item = sessLog.listBox.topLevelItem(6)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
+
+ item = sessLog.listBox.topLevelItem(7)
+ assert item is not None
+ assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
assert jsonData == [
{
diff --git a/tests/tools.py b/tests/tools.py
index a21ac432..3be25040 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -241,5 +241,7 @@ class SimpleDialog(QDialog):
def addWidget(self, widget: QWidget) -> None:
self._widget = widget
- self.layout().addWidget(widget)
+ layout = self.layout()
+ assert layout is not None
+ layout.addWidget(widget)
return