Clean up after switching to Qt6 (#2187)

This commit is contained in:
Veronica Berglyd Olsen
2025-01-14 22:51:52 +01:00
committed by GitHub
54 changed files with 1280 additions and 1279 deletions
+16 -1
View File
@@ -38,7 +38,8 @@ from urllib.parse import urljoin
from urllib.request import pathname2url from urllib.request import pathname2url
from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl 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.constants import nwConst, nwLabels, nwUnicode, trConst
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
@@ -461,6 +462,20 @@ def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable:
return wrapper 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: def encodeMimeHandles(mimeData: QMimeData, handles: list[str]) -> None:
"""Encode handles into a mime data object.""" """Encode handles into a mime data object."""
mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles)) mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles))
+51 -81
View File
@@ -52,6 +52,31 @@ logger = logging.getLogger(__name__)
class Config: 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_NW = 1
LANG_PROJ = 2 LANG_PROJ = 2
@@ -126,12 +151,12 @@ class Config:
self.iconColDocs = False # Keep theme colours on documents self.iconColDocs = False # Keep theme colours on documents
# Size Settings # Size Settings
self._mainWinSize = [1200, 650] # Last size of the main GUI window self.mainWinSize = [1200, 650] # Last size of the main GUI window
self._welcomeSize = [800, 550] # Last size of the welcome window self.welcomeWinSize = [800, 550] # Last size of the welcome window
self._prefsWinSize = [700, 615] # Last size of the Preferences dialog self.prefsWinSize = [700, 615] # Last size of the Preferences dialog
self._mainPanePos = [300, 800] # Last position of the main window splitter self.mainPanePos = [300, 800] # Last position of the main window splitter
self._viewPanePos = [500, 150] # Last position of the document viewer splitter self.viewPanePos = [500, 150] # Last position of the document viewer splitter
self._outlnPanePos = [500, 150] # Last position of the outline panel splitter self.outlinePanePos = [500, 150] # Last position of the outline panel splitter
# Project Settings # Project Settings
self.autoSaveProj = 60 # Interval for auto-saving project, in seconds self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
@@ -269,30 +294,6 @@ class Config:
def recentProjects(self) -> RecentProjects: def recentProjects(self) -> RecentProjects:
return 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 # Getters
## ##
@@ -300,17 +301,9 @@ class Config:
def getTextWidth(self, focusMode: bool = False) -> int: def getTextWidth(self, focusMode: bool = False) -> int:
"""Get the text with for the correct editor mode.""" """Get the text with for the correct editor mode."""
if focusMode: if focusMode:
return self.pxInt(max(self.focusWidth, 200)) return max(self.focusWidth, 200)
else: else:
return self.pxInt(max(self.textWidth, 200)) return 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))
## ##
# Setters # Setters
@@ -322,35 +315,20 @@ class Config:
adjust it a bit, and we don't want the main window to shrink or adjust it a bit, and we don't want the main window to shrink or
grow each time the app is opened. grow each time the app is opened.
""" """
if abs(self._mainWinSize[0] - width) > 5: if abs(self.mainWinSize[0] - width) > 5:
self._mainWinSize[0] = width self.mainWinSize[0] = width
if abs(self._mainWinSize[1] - height) > 5: if abs(self.mainWinSize[1] - height) > 5:
self._mainWinSize[1] = height self.mainWinSize[1] = height
return return
def setWelcomeWinSize(self, width: int, height: int) -> None: def setWelcomeWinSize(self, width: int, height: int) -> None:
"""Set the size of the Preferences dialog window.""" """Set the size of the Preferences dialog window."""
self._welcomeSize = [width, height] self.welcomeWinSize = [width, height]
return return
def setPreferencesWinSize(self, width: int, height: int) -> None: def setPreferencesWinSize(self, width: int, height: int) -> None:
"""Set the size of the Preferences dialog window.""" """Set the size of the Preferences dialog window."""
self._prefsWinSize = [width, height] 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
return return
def setLastPath(self, key: str, path: str | Path) -> None: def setLastPath(self, key: str, path: str | Path) -> None:
@@ -421,14 +399,6 @@ class Config:
# Methods # 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: def homePath(self) -> Path:
"""The user's home folder.""" """The user's home folder."""
return self._homePath return self._homePath
@@ -614,12 +584,12 @@ class Config:
# Sizes # Sizes
sec = "Sizes" sec = "Sizes"
self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize) self.mainWinSize = conf.rdIntList(sec, "mainwindow", self.mainWinSize)
self._welcomeSize = conf.rdIntList(sec, "welcome", self._welcomeSize) self.welcomeWinSize = conf.rdIntList(sec, "welcome", self.welcomeWinSize)
self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize) self.prefsWinSize = conf.rdIntList(sec, "preferences", self.prefsWinSize)
self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos) self.mainPanePos = conf.rdIntList(sec, "mainpane", self.mainPanePos)
self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos) self.viewPanePos = conf.rdIntList(sec, "viewpane", self.viewPanePos)
self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos) self.outlinePanePos = conf.rdIntList(sec, "outlinepane", self.outlinePanePos)
# Project # Project
sec = "Project" sec = "Project"
@@ -728,12 +698,12 @@ class Config:
} }
conf["Sizes"] = { conf["Sizes"] = {
"mainwindow": self._packList(self._mainWinSize), "mainwindow": self._packList(self.mainWinSize),
"welcome": self._packList(self._welcomeSize), "welcome": self._packList(self.welcomeWinSize),
"preferences": self._packList(self._prefsWinSize), "preferences": self._packList(self.prefsWinSize),
"mainpane": self._packList(self._mainPanePos), "mainpane": self._packList(self.mainPanePos),
"viewpane": self._packList(self._viewPanePos), "viewpane": self._packList(self.viewPanePos),
"outlinepane": self._packList(self._outlnPanePos), "outlinepane": self._packList(self.outlinePanePos),
} }
conf["Project"] = { conf["Project"] = {
+8 -14
View File
@@ -49,18 +49,13 @@ class GuiAbout(NDialog):
self.setObjectName("GuiAbout") self.setObjectName("GuiAbout")
self.setWindowTitle(self.tr("About novelWriter")) self.setWindowTitle(self.tr("About novelWriter"))
self.resize(CONFIG.pxInt(700), CONFIG.pxInt(500)) self.resize(700, 500)
hA = CONFIG.pxInt(8)
hB = CONFIG.pxInt(16)
nwH = CONFIG.pxInt(36)
nwPx = CONFIG.pxInt(128)
# Logo and Banner # 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 = 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 = QLabel(self)
self.nwLabel.setPixmap(self.nwImage) self.nwLabel.setPixmap(self.nwImage)
@@ -79,8 +74,7 @@ class GuiAbout(NDialog):
self.txtCredits = QTextBrowser(self) self.txtCredits = QTextBrowser(self)
self.txtCredits.setOpenExternalLinks(True) self.txtCredits.setOpenExternalLinks(True)
self.txtCredits.document().setDocumentMargin(0) self.txtCredits.setViewportMargins(0, 8, 8, 0)
self.txtCredits.setViewportMargins(0, hA, hA, 0)
# Buttons # Buttons
self.btnBox = QDialogButtonBox(QtDialogClose, self) self.btnBox = QDialogButtonBox(QtDialogClose, self)
@@ -88,15 +82,15 @@ class GuiAbout(NDialog):
# Assemble # Assemble
self.innerBox = QVBoxLayout() self.innerBox = QVBoxLayout()
self.innerBox.addSpacing(hB) self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.nwLabel) self.innerBox.addWidget(self.nwLabel)
self.innerBox.addWidget(self.nwInfo) self.innerBox.addWidget(self.nwInfo)
self.innerBox.addSpacing(hA) self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.nwLicence) self.innerBox.addWidget(self.nwLicence)
self.innerBox.addSpacing(hA) self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.lblCredits) self.innerBox.addWidget(self.lblCredits)
self.innerBox.addWidget(self.txtCredits) self.innerBox.addWidget(self.txtCredits)
self.innerBox.addSpacing(hB) self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.btnBox) self.innerBox.addWidget(self.btnBox)
self.outerBox = QHBoxLayout() self.outerBox = QHBoxLayout()
+9 -11
View File
@@ -32,7 +32,7 @@ from PyQt6.QtWidgets import (
QListWidgetItem, QVBoxLayout, QWidget QListWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.extensions.configlayout import NColourLabel from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NDialog from novelwriter.extensions.modified import NDialog
from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switch import NSwitch
@@ -63,14 +63,11 @@ class GuiDocMerge(NDialog):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
hSp = CONFIG.pxInt(12)
vSp = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(12)
self.listBox = QListWidget(self) self.listBox = QListWidget(self)
self.listBox.setIconSize(iSz) self.listBox.setIconSize(iSz)
self.listBox.setMinimumWidth(CONFIG.pxInt(400)) self.listBox.setMinimumWidth(400)
self.listBox.setMinimumHeight(CONFIG.pxInt(180)) self.listBox.setMinimumHeight(180)
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
@@ -82,7 +79,7 @@ class GuiDocMerge(NDialog):
self.optBox = QGridLayout() self.optBox = QGridLayout()
self.optBox.addWidget(self.trashLabel, 0, 0) self.optBox.addWidget(self.trashLabel, 0, 0)
self.optBox.addWidget(self.trashSwitch, 0, 1) self.optBox.addWidget(self.trashSwitch, 0, 1)
self.optBox.setHorizontalSpacing(hSp) self.optBox.setHorizontalSpacing(12)
self.optBox.setColumnStretch(2, 1) self.optBox.setColumnStretch(2, 1)
# Buttons # Buttons
@@ -91,18 +88,19 @@ class GuiDocMerge(NDialog):
self.buttonBox.rejected.connect(self.reject) self.buttonBox.rejected.connect(self.reject)
self.resetButton = self.buttonBox.addButton(QtDialogReset) self.resetButton = self.buttonBox.addButton(QtDialogReset)
self.resetButton.clicked.connect(self._resetList) if self.resetButton:
self.resetButton.clicked.connect(self._resetList)
# Assemble # Assemble
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
self.outerBox.addWidget(self.headLabel) self.outerBox.addWidget(self.headLabel)
self.outerBox.addWidget(self.helpLabel) self.outerBox.addWidget(self.helpLabel)
self.outerBox.addSpacing(vSp) self.outerBox.addSpacing(8)
self.outerBox.addWidget(self.listBox) self.outerBox.addWidget(self.listBox)
self.outerBox.addSpacing(vSp) self.outerBox.addSpacing(8)
self.outerBox.addLayout(self.optBox) self.outerBox.addLayout(self.optBox)
self.outerBox.addSpacing(bSp) self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
+9 -12
View File
@@ -32,7 +32,7 @@ from PyQt6.QtWidgets import (
QListWidget, QListWidgetItem, QVBoxLayout, QWidget QListWidget, QListWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.extensions.configlayout import NColourLabel from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NDialog from novelwriter.extensions.modified import NDialog
from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switch import NSwitch
@@ -67,9 +67,6 @@ class GuiDocSplit(NDialog):
# Values # Values
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
hSp = CONFIG.pxInt(12)
vSp = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(12)
pOptions = SHARED.project.options pOptions = SHARED.project.options
spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3) spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3)
@@ -79,11 +76,11 @@ class GuiDocSplit(NDialog):
# Heading Selection # Heading Selection
self.listBox = QListWidget(self) self.listBox = QListWidget(self)
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
self.listBox.setMinimumWidth(CONFIG.pxInt(400)) self.listBox.setMinimumWidth(400)
self.listBox.setMinimumHeight(CONFIG.pxInt(180)) self.listBox.setMinimumHeight(180)
self.splitLevel = QComboBox(self) 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 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 3 (Scene)"), 3)
self.splitLevel.addItem(self.tr("Split up to Heading Level 4 (Section)"), 4) 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.hierarchySwitch, 1, 1)
self.optBox.addWidget(self.trashLabel, 2, 0) self.optBox.addWidget(self.trashLabel, 2, 0)
self.optBox.addWidget(self.trashSwitch, 2, 1) self.optBox.addWidget(self.trashSwitch, 2, 1)
self.optBox.setVerticalSpacing(vSp) self.optBox.setVerticalSpacing(8)
self.optBox.setHorizontalSpacing(hSp) self.optBox.setHorizontalSpacing(12)
self.optBox.setColumnStretch(3, 1) self.optBox.setColumnStretch(3, 1)
# Buttons # Buttons
@@ -125,12 +122,12 @@ class GuiDocSplit(NDialog):
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
self.outerBox.addWidget(self.headLabel) self.outerBox.addWidget(self.headLabel)
self.outerBox.addWidget(self.helpLabel) self.outerBox.addWidget(self.helpLabel)
self.outerBox.addSpacing(vSp) self.outerBox.addSpacing(8)
self.outerBox.addWidget(self.listBox) self.outerBox.addWidget(self.listBox)
self.outerBox.addWidget(self.splitLevel) self.outerBox.addWidget(self.splitLevel)
self.outerBox.addSpacing(vSp) self.outerBox.addSpacing(8)
self.outerBox.addLayout(self.optBox) self.outerBox.addLayout(self.optBox)
self.outerBox.addSpacing(bSp) self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
+3 -7
View File
@@ -27,7 +27,6 @@ import logging
from PyQt6.QtWidgets import QDialogButtonBox, QHBoxLayout, QLabel, QLineEdit, QVBoxLayout, QWidget from PyQt6.QtWidgets import QDialogButtonBox, QHBoxLayout, QLabel, QLineEdit, QVBoxLayout, QWidget
from novelwriter import CONFIG
from novelwriter.extensions.modified import NDialog from novelwriter.extensions.modified import NDialog
from novelwriter.types import QtAccepted, QtDialogCancel, QtDialogOk from novelwriter.types import QtAccepted, QtDialogCancel, QtDialogOk
@@ -43,12 +42,9 @@ class GuiEditLabel(NDialog):
self.setObjectName("GuiEditLabel") self.setObjectName("GuiEditLabel")
self.setWindowTitle(self.tr("Item Label")) self.setWindowTitle(self.tr("Item Label"))
mVd = CONFIG.pxInt(220)
mSp = CONFIG.pxInt(12)
# Item Label # Item Label
self.labelValue = QLineEdit(self) self.labelValue = QLineEdit(self)
self.labelValue.setMinimumWidth(mVd) self.labelValue.setMinimumWidth(220)
self.labelValue.setMaxLength(200) self.labelValue.setMaxLength(200)
self.labelValue.setText(text) self.labelValue.setText(text)
self.labelValue.selectAll() self.labelValue.selectAll()
@@ -62,10 +58,10 @@ class GuiEditLabel(NDialog):
self.innerBox = QHBoxLayout() self.innerBox = QHBoxLayout()
self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0) self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
self.innerBox.addWidget(self.labelValue, 1) self.innerBox.addWidget(self.labelValue, 1)
self.innerBox.setSpacing(mSp) self.innerBox.setSpacing(12)
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.setSpacing(mSp) self.outerBox.setSpacing(12)
self.outerBox.addLayout(self.innerBox, 1) self.outerBox.addLayout(self.innerBox, 1)
self.outerBox.addWidget(self.buttonBox, 0) self.outerBox.addWidget(self.buttonBox, 0)
+20 -24
View File
@@ -27,7 +27,7 @@ from __future__ import annotations
import logging import logging
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot 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 ( from PyQt6.QtWidgets import (
QCompleter, QDialogButtonBox, QFileDialog, QHBoxLayout, QLineEdit, QCompleter, QDialogButtonBox, QFileDialog, QHBoxLayout, QLineEdit,
QPushButton, QVBoxLayout, QWidget QPushButton, QVBoxLayout, QWidget
@@ -58,23 +58,23 @@ class GuiPreferences(NDialog):
logger.debug("Create: GuiPreferences") logger.debug("Create: GuiPreferences")
self.setObjectName("GuiPreferences") self.setObjectName("GuiPreferences")
self.setWindowTitle(self.tr("Preferences")) self.setWindowTitle(self.tr("Preferences"))
self.setMinimumSize(CONFIG.pxInt(600), CONFIG.pxInt(500)) self.setMinimumSize(600, 500)
self.resize(*CONFIG.preferencesWinSize) self.resize(*CONFIG.prefsWinSize)
# Title # Title
self.titleLabel = NColourLabel( self.titleLabel = NColourLabel(
self.tr("Preferences"), self, color=SHARED.theme.helpText, self.tr("Preferences"), self, color=SHARED.theme.helpText,
scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4) scale=NColourLabel.HEADER_SCALE, indent=4,
) )
# Search Box # Search Box
self.searchAction = QAction(SHARED.theme.getIcon("search"), "")
self.searchAction.triggered.connect(self._gotoSearch)
self.searchText = QLineEdit(self) self.searchText = QLineEdit(self)
self.searchText.setPlaceholderText(self.tr("Search")) self.searchText.setPlaceholderText(self.tr("Search"))
self.searchText.setMinimumWidth(CONFIG.pxInt(200)) self.searchText.setMinimumWidth(200)
self.searchAction = self.searchText.addAction( self.searchText.addAction(self.searchAction, QLineEdit.ActionPosition.TrailingPosition)
SHARED.theme.getIcon("search"), QLineEdit.ActionPosition.TrailingPosition
)
self.searchAction.triggered.connect(self._gotoSearch)
# SideBar # SideBar
self.sidebar = NPagedSideBar(self) self.sidebar = NPagedSideBar(self)
@@ -105,7 +105,7 @@ class GuiPreferences(NDialog):
self.outerBox.addLayout(self.searchBox) self.outerBox.addLayout(self.searchBox)
self.outerBox.addLayout(self.mainBox) self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.outerBox.setSpacing(CONFIG.pxInt(8)) self.outerBox.setSpacing(8)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.setSizeGripEnabled(True) self.setSizeGripEnabled(True)
@@ -134,8 +134,6 @@ class GuiPreferences(NDialog):
section = 0 section = 0
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
boxFixed = 6*SHARED.theme.textNWidth boxFixed = 6*SHARED.theme.textNWidth
minWidth = CONFIG.pxInt(200)
fontWidth = CONFIG.pxInt(162)
# Temporary Variables # Temporary Variables
self._guiFont = CONFIG.guiFont self._guiFont = CONFIG.guiFont
@@ -154,7 +152,7 @@ class GuiPreferences(NDialog):
# Display Language # Display Language
self.guiLocale = NComboBox(self) self.guiLocale = NComboBox(self)
self.guiLocale.setMinimumWidth(minWidth) self.guiLocale.setMinimumWidth(200)
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW): for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
self.guiLocale.addItem(name, lang) self.guiLocale.addItem(name, lang)
self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB") self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB")
@@ -166,7 +164,7 @@ class GuiPreferences(NDialog):
# Colour Theme # Colour Theme
self.guiTheme = NComboBox(self) self.guiTheme = NComboBox(self)
self.guiTheme.setMinimumWidth(minWidth) self.guiTheme.setMinimumWidth(200)
for theme, name in SHARED.theme.listThemes(): for theme, name in SHARED.theme.listThemes():
self.guiTheme.addItem(name, theme) self.guiTheme.addItem(name, theme)
self.guiTheme.setCurrentData(CONFIG.guiTheme, "default") self.guiTheme.setCurrentData(CONFIG.guiTheme, "default")
@@ -178,7 +176,7 @@ class GuiPreferences(NDialog):
# Icon Theme # Icon Theme
self.iconTheme = NComboBox(self) self.iconTheme = NComboBox(self)
self.iconTheme.setMinimumWidth(minWidth) self.iconTheme.setMinimumWidth(200)
for theme, name in SHARED.theme.iconCache.listThemes(): for theme, name in SHARED.theme.iconCache.listThemes():
self.iconTheme.addItem(name, theme) self.iconTheme.addItem(name, theme)
self.iconTheme.setCurrentData(CONFIG.iconTheme, "material_rounded_bold") self.iconTheme.setCurrentData(CONFIG.iconTheme, "material_rounded_bold")
@@ -190,7 +188,7 @@ class GuiPreferences(NDialog):
# Tree Icon Colours # Tree Icon Colours
self.iconColTree = NComboBox(self) self.iconColTree = NComboBox(self)
self.iconColTree.setMinimumWidth(minWidth) self.iconColTree.setMinimumWidth(200)
for key, label in nwLabels.THEME_COLORS.items(): for key, label in nwLabels.THEME_COLORS.items():
self.iconColTree.addItem(trConst(label), key) self.iconColTree.addItem(trConst(label), key)
self.iconColTree.setCurrentData(CONFIG.iconColTree, "theme") self.iconColTree.setCurrentData(CONFIG.iconColTree, "theme")
@@ -211,7 +209,7 @@ class GuiPreferences(NDialog):
# Application Font Family # Application Font Family
self.guiFont = QLineEdit(self) self.guiFont = QLineEdit(self)
self.guiFont.setReadOnly(True) self.guiFont.setReadOnly(True)
self.guiFont.setMinimumWidth(fontWidth) self.guiFont.setMinimumWidth(162)
self.guiFont.setText(describeFont(self._guiFont)) self.guiFont.setText(describeFont(self._guiFont))
self.guiFont.setCursorPosition(0) self.guiFont.setCursorPosition(0)
self.guiFontButton = NIconToolButton(self, iSz, "font") self.guiFontButton = NIconToolButton(self, iSz, "font")
@@ -256,7 +254,7 @@ class GuiPreferences(NDialog):
# Document Colour Theme # Document Colour Theme
self.guiSyntax = NComboBox(self) self.guiSyntax = NComboBox(self)
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200)) self.guiSyntax.setMinimumWidth(200)
for syntax, name in SHARED.theme.listSyntax(): for syntax, name in SHARED.theme.listSyntax():
self.guiSyntax.addItem(name, syntax) self.guiSyntax.addItem(name, syntax)
self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light") self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light")
@@ -269,7 +267,7 @@ class GuiPreferences(NDialog):
# Document Font Family # Document Font Family
self.textFont = QLineEdit(self) self.textFont = QLineEdit(self)
self.textFont.setReadOnly(True) self.textFont.setReadOnly(True)
self.textFont.setMinimumWidth(fontWidth) self.textFont.setMinimumWidth(162)
self.textFont.setText(describeFont(CONFIG.textFont)) self.textFont.setText(describeFont(CONFIG.textFont))
self.textFont.setCursorPosition(0) self.textFont.setCursorPosition(0)
self.textFontButton = NIconToolButton(self, iSz, "font") self.textFontButton = NIconToolButton(self, iSz, "font")
@@ -482,7 +480,7 @@ class GuiPreferences(NDialog):
# Spell Checking # Spell Checking
self.spellLanguage = NComboBox(self) self.spellLanguage = NComboBox(self)
self.spellLanguage.setMinimumWidth(minWidth) self.spellLanguage.setMinimumWidth(200)
if CONFIG.hasEnchant: if CONFIG.hasEnchant:
for tag, language in SHARED.spelling.listDictionaries(): for tag, language in SHARED.spelling.listDictionaries():
@@ -651,8 +649,6 @@ class GuiPreferences(NDialog):
self.sidebar.addButton(title, section) self.sidebar.addButton(title, section)
self.mainForm.addGroupLabel(title, section) self.mainForm.addGroupLabel(title, section)
boxWidth = CONFIG.pxInt(150)
# Auto-Replace as You Type Main Switch # Auto-Replace as You Type Main Switch
self.doReplace = NSwitch(self) self.doReplace = NSwitch(self)
self.doReplace.setChecked(CONFIG.doReplace) self.doReplace.setChecked(CONFIG.doReplace)
@@ -701,7 +697,7 @@ class GuiPreferences(NDialog):
# Pad Before # Pad Before
self.fmtPadBefore = QLineEdit(self) self.fmtPadBefore = QLineEdit(self)
self.fmtPadBefore.setMaxLength(32) self.fmtPadBefore.setMaxLength(32)
self.fmtPadBefore.setMinimumWidth(boxWidth) self.fmtPadBefore.setMinimumWidth(150)
self.fmtPadBefore.setText(CONFIG.fmtPadBefore) self.fmtPadBefore.setText(CONFIG.fmtPadBefore)
self.mainForm.addRow( self.mainForm.addRow(
self.tr("Insert non-breaking space before"), self.fmtPadBefore, self.tr("Insert non-breaking space before"), self.fmtPadBefore,
@@ -711,7 +707,7 @@ class GuiPreferences(NDialog):
# Pad After # Pad After
self.fmtPadAfter = QLineEdit(self) self.fmtPadAfter = QLineEdit(self)
self.fmtPadAfter.setMaxLength(32) self.fmtPadAfter.setMaxLength(32)
self.fmtPadAfter.setMinimumWidth(boxWidth) self.fmtPadAfter.setMinimumWidth(150)
self.fmtPadAfter.setText(CONFIG.fmtPadAfter) self.fmtPadAfter.setText(CONFIG.fmtPadAfter)
self.mainForm.addRow( self.mainForm.addRow(
self.tr("Insert non-breaking space after"), self.fmtPadAfter, self.tr("Insert non-breaking space after"), self.fmtPadAfter,
+26 -33
View File
@@ -30,7 +30,7 @@ import logging
from pathlib import Path from pathlib import Path
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QCloseEvent, QColor from PyQt6.QtGui import QAction, QCloseEvent, QColor
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox, QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget, QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget,
@@ -71,16 +71,16 @@ class GuiProjectSettings(NDialog):
self.setWindowTitle(self.tr("Project Settings")) self.setWindowTitle(self.tr("Project Settings"))
options = SHARED.project.options options = SHARED.project.options
self.setMinimumSize(CONFIG.pxInt(500), CONFIG.pxInt(400)) self.setMinimumSize(500, 400)
self.resize( self.resize(
CONFIG.pxInt(options.getInt("GuiProjectSettings", "winWidth", CONFIG.pxInt(650))), options.getInt("GuiProjectSettings", "winWidth", 650),
CONFIG.pxInt(options.getInt("GuiProjectSettings", "winHeight", CONFIG.pxInt(500))) options.getInt("GuiProjectSettings", "winHeight", 500),
) )
# Title # Title
self.titleLabel = NColourLabel( self.titleLabel = NColourLabel(
self.tr("Project Settings"), self, color=SHARED.theme.helpText, self.tr("Project Settings"), self, color=SHARED.theme.helpText,
scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4) scale=NColourLabel.HEADER_SCALE, indent=4,
) )
# SideBar # SideBar
@@ -125,7 +125,7 @@ class GuiProjectSettings(NDialog):
self.outerBox.addLayout(self.topBox) self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox) self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.outerBox.setSpacing(CONFIG.pxInt(8)) self.outerBox.setSpacing(8)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.setSizeGripEnabled(True) self.setSizeGripEnabled(True)
@@ -210,16 +210,14 @@ class GuiProjectSettings(NDialog):
def _saveSettings(self) -> None: def _saveSettings(self) -> None:
"""Save GUI settings.""" """Save GUI settings."""
winWidth = CONFIG.rpxInt(self.width()) statusColW = self.statusPage.columnWidth()
winHeight = CONFIG.rpxInt(self.height()) importColW = self.importPage.columnWidth()
statusColW = CONFIG.rpxInt(self.statusPage.columnWidth()) replaceColW = self.replacePage.columnWidth()
importColW = CONFIG.rpxInt(self.importPage.columnWidth())
replaceColW = CONFIG.rpxInt(self.replacePage.columnWidth())
logger.debug("Saving State: GuiProjectSettings") logger.debug("Saving State: GuiProjectSettings")
options = SHARED.project.options options = SHARED.project.options
options.setValue("GuiProjectSettings", "winWidth", winWidth) options.setValue("GuiProjectSettings", "winWidth", self.width())
options.setValue("GuiProjectSettings", "winHeight", winHeight) options.setValue("GuiProjectSettings", "winHeight", self.height())
options.setValue("GuiProjectSettings", "statusColW", statusColW) options.setValue("GuiProjectSettings", "statusColW", statusColW)
options.setValue("GuiProjectSettings", "importColW", importColW) options.setValue("GuiProjectSettings", "importColW", importColW)
options.setValue("GuiProjectSettings", "replaceColW", replaceColW) options.setValue("GuiProjectSettings", "replaceColW", replaceColW)
@@ -232,7 +230,6 @@ class _SettingsPage(NScrollableForm):
def __init__(self, parent: QWidget) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
xW = CONFIG.pxInt(200)
data = SHARED.project.data data = SHARED.project.data
self.setHelpTextStyle(SHARED.theme.helpText) self.setHelpTextStyle(SHARED.theme.helpText)
self.setRowIndent(0) self.setRowIndent(0)
@@ -240,7 +237,7 @@ class _SettingsPage(NScrollableForm):
# Project Name # Project Name
self.projName = QLineEdit(self) self.projName = QLineEdit(self)
self.projName.setMaxLength(200) self.projName.setMaxLength(200)
self.projName.setMinimumWidth(xW) self.projName.setMinimumWidth(200)
self.projName.setText(data.name) self.projName.setText(data.name)
self.addRow( self.addRow(
self.tr("Project name"), self.projName, self.tr("Project name"), self.projName,
@@ -251,7 +248,7 @@ class _SettingsPage(NScrollableForm):
# Project Author # Project Author
self.projAuthor = QLineEdit(self) self.projAuthor = QLineEdit(self)
self.projAuthor.setMaxLength(200) self.projAuthor.setMaxLength(200)
self.projAuthor.setMinimumWidth(xW) self.projAuthor.setMinimumWidth(200)
self.projAuthor.setText(data.author) self.projAuthor.setText(data.author)
self.addRow( self.addRow(
self.tr("Author(s)"), self.projAuthor, self.tr("Author(s)"), self.projAuthor,
@@ -262,7 +259,7 @@ class _SettingsPage(NScrollableForm):
# Project Language # Project Language
projLang = data.language or CONFIG.guiLocale projLang = data.language or CONFIG.guiLocale
self.projLang = NComboBox(self) self.projLang = NComboBox(self)
self.projLang.setMinimumWidth(xW) self.projLang.setMinimumWidth(200)
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ): for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
self.projLang.addItem(language, tag) self.projLang.addItem(language, tag)
self.projLang.setCurrentData(projLang, projLang) self.projLang.setCurrentData(projLang, projLang)
@@ -274,7 +271,7 @@ class _SettingsPage(NScrollableForm):
# Spell Check Language # Spell Check Language
self.spellLang = NComboBox(self) self.spellLang = NComboBox(self)
self.spellLang.setMinimumWidth(xW) self.spellLang.setMinimumWidth(200)
self.spellLang.addItem(self.tr("Default"), "None") self.spellLang.addItem(self.tr("Default"), "None")
if CONFIG.hasEnchant: if CONFIG.hasEnchant:
for tag, language in SHARED.spelling.listDictionaries(): for tag, language in SHARED.spelling.listDictionaries():
@@ -323,9 +320,7 @@ class _StatusPage(NFixedPage):
pageLabel = self.tr("Project Note Importance Levels") pageLabel = self.tr("Project Note Importance Levels")
colSetting = "importColW" colSetting = "importColW"
wCol0 = CONFIG.pxInt( wCol0 = SHARED.project.options.getInt("GuiProjectSettings", colSetting, 130)
SHARED.project.options.getInt("GuiProjectSettings", colSetting, 130)
)
self._changed = False self._changed = False
self._color = QColor(100, 100, 100) self._color = QColor(100, 100, 100)
@@ -334,7 +329,6 @@ class _StatusPage(NFixedPage):
self._iPx = SHARED.theme.baseIconHeight self._iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
bPd = CONFIG.pxInt(4)
iColor = self.palette().text().color() iColor = self.palette().text().color()
@@ -395,7 +389,7 @@ class _StatusPage(NFixedPage):
self.labelText.textEdited.connect(self._onNameEdit) self.labelText.textEdited.connect(self._onNameEdit)
buttonStyle = ( buttonStyle = (
f"QToolButton {{padding: 0 {bPd}px;}} " "QToolButton {padding: 0 4px;} "
"QToolButton::menu-indicator {image: none;}" "QToolButton::menu-indicator {image: none;}"
) )
@@ -406,12 +400,14 @@ class _StatusPage(NFixedPage):
self.colorButton.setEnabled(False) self.colorButton.setEnabled(False)
self.colorButton.clicked.connect(self._onColourSelect) self.colorButton.clicked.connect(self._onColourSelect)
def buildMenu(menu: QMenu, items: dict[nwStatusShape, str]) -> None: def buildMenu(menu: QMenu | None, items: dict[nwStatusShape, str]) -> None:
for shape, label in items.items(): if menu is not None:
icon = NWStatus.createIcon(self._iPx, iColor, shape) for shape, label in items.items():
action = menu.addAction(icon, trConst(label)) icon = NWStatus.createIcon(self._iPx, iColor, shape)
action.triggered.connect(qtLambda(self._selectShape, shape)) action = QAction(icon, trConst(label))
self._icons[shape] = icon action.triggered.connect(qtLambda(self._selectShape, shape))
menu.addAction(action)
self._icons[shape] = icon
self.shapeMenu = QMenu(self) self.shapeMenu = QMenu(self)
buildMenu(self.shapeMenu, nwLabels.SHAPES_PLAIN) buildMenu(self.shapeMenu, nwLabels.SHAPES_PLAIN)
@@ -676,10 +672,7 @@ class _ReplacePage(NFixedPage):
self._changed = False self._changed = False
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
wCol0 = SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
wCol0 = CONFIG.pxInt(
SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
)
# Title # Title
self.pageTitle = NColourLabel( self.pageTitle = NColourLabel(
+5 -10
View File
@@ -32,7 +32,6 @@ from PyQt6.QtWidgets import (
QListWidgetItem, QVBoxLayout, QWidget QListWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG
from novelwriter.constants import nwQuotes, trConst from novelwriter.constants import nwQuotes, trConst
from novelwriter.extensions.modified import NDialog from novelwriter.extensions.modified import NDialog
from novelwriter.types import ( from novelwriter.types import (
@@ -62,18 +61,14 @@ class GuiQuoteSelect(NDialog):
self._selected = current 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 = self.font()
lblFont.setPointSizeF(4*lblFont.pointSizeF()) lblFont.setPointSizeF(4*lblFont.pointSizeF())
metrics = QFontMetrics(self.font())
# Preview Label # Preview Label
self.previewLabel = QLabel(current, self) self.previewLabel = QLabel(current, self)
self.previewLabel.setFont(lblFont) 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.setAlignment(QtAlignCenter)
self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain) self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain)
@@ -84,15 +79,15 @@ class GuiQuoteSelect(NDialog):
minSize = 100 minSize = 100
for sKey, sLabel in nwQuotes.SYMBOLS.items(): for sKey, sLabel in nwQuotes.SYMBOLS.items():
text = "[ %s ] %s" % (sKey, trConst(sLabel)) text = "[ %s ] %s" % (sKey, trConst(sLabel))
minSize = max(minSize, qMetrics.boundingRect(text).width()) minSize = max(minSize, metrics.boundingRect(text).width())
qtItem = QListWidgetItem(text) qtItem = QListWidgetItem(text)
qtItem.setData(self.D_KEY, sKey) qtItem.setData(self.D_KEY, sKey)
self.listBox.addItem(qtItem) self.listBox.addItem(qtItem)
if sKey == current: if sKey == current:
self.listBox.setCurrentItem(qtItem) self.listBox.setCurrentItem(qtItem)
self.listBox.setMinimumWidth(minSize + CONFIG.pxInt(40)) self.listBox.setMinimumWidth(minSize + 40)
self.listBox.setMinimumHeight(CONFIG.pxInt(150)) self.listBox.setMinimumHeight(150)
# Buttons # Buttons
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self) self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
+8 -15
View File
@@ -56,15 +56,12 @@ class GuiWordList(NDialog):
self.setWindowTitle(self.tr("Project Word List")) self.setWindowTitle(self.tr("Project Word List"))
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mS = CONFIG.pxInt(250)
wW = CONFIG.pxInt(320)
wH = CONFIG.pxInt(340)
self.setMinimumWidth(mS) self.setMinimumWidth(250)
self.setMinimumHeight(mS) self.setMinimumHeight(250)
self.resize( self.resize(
CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winWidth", wW)), SHARED.project.options.getInt("GuiWordList", "winWidth", 320),
CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winHeight", wH)) SHARED.project.options.getInt("GuiWordList", "winHeight", 340),
) )
# Header # Header
@@ -118,9 +115,9 @@ class GuiWordList(NDialog):
self.outerBox.addLayout(self.headerBox, 0) self.outerBox.addLayout(self.headerBox, 0)
self.outerBox.addWidget(self.listBox, 1) self.outerBox.addWidget(self.listBox, 1)
self.outerBox.addLayout(self.editBox, 0) self.outerBox.addLayout(self.editBox, 0)
self.outerBox.addSpacing(CONFIG.pxInt(12)) self.outerBox.addSpacing(12)
self.outerBox.addWidget(self.buttonBox, 0) self.outerBox.addWidget(self.buttonBox, 0)
self.outerBox.setSpacing(CONFIG.pxInt(4)) self.outerBox.setSpacing(4)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -230,14 +227,10 @@ class GuiWordList(NDialog):
def _saveGuiSettings(self) -> None: def _saveGuiSettings(self) -> None:
"""Save GUI settings.""" """Save GUI settings."""
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
logger.debug("Saving State: GuiWordList") logger.debug("Saving State: GuiWordList")
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiWordList", "winWidth", winWidth) pOptions.setValue("GuiWordList", "winWidth", self.width())
pOptions.setValue("GuiWordList", "winHeight", winHeight) pOptions.setValue("GuiWordList", "winHeight", self.height())
return return
def _addWord(self, word: str) -> None: def _addWord(self, word: str) -> None:
+5 -5
View File
@@ -65,11 +65,11 @@ class NWErrorMessage(QDialog):
# Widgets # Widgets
self.msgIcon = QLabel() self.msgIcon = QLabel()
self.msgIcon.setPixmap( if style := QApplication.style():
QApplication.style().standardIcon( self.msgIcon.setPixmap(
QStyle.StandardPixmap.SP_MessageBoxCritical style.standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical).pixmap(64, 64)
).pixmap(64, 64) )
)
self.msgHead = QLabel() self.msgHead = QLabel()
self.msgHead.setOpenExternalLinks(True) self.msgHead.setOpenExternalLinks(True)
self.msgHead.setWordWrap(True) self.msgHead.setWordWrap(True)
+13 -13
View File
@@ -33,7 +33,6 @@ from PyQt6.QtWidgets import (
QVBoxLayout, QWidget QVBoxLayout, QWidget
) )
from novelwriter import CONFIG
from novelwriter.types import QtScrollAsNeeded from novelwriter.types import QtScrollAsNeeded
DEFAULT_SCALE = 0.9 DEFAULT_SCALE = 0.9
@@ -99,14 +98,14 @@ class NScrollableForm(QScrollArea):
self._helpCol = QColor(0, 0, 0) self._helpCol = QColor(0, 0, 0)
self._fontScale = DEFAULT_SCALE self._fontScale = DEFAULT_SCALE
self._first = True self._first = True
self._indent = CONFIG.pxInt(12) self._indent = 12
self._sections: dict[int, QLabel] = {} self._sections: dict[int, QLabel] = {}
self._editable: dict[str, NColourLabel] = {} self._editable: dict[str, NColourLabel] = {}
self._index: dict[str, QWidget] = {} self._index: dict[str, QWidget] = {}
self._layout = QVBoxLayout() self._layout = QVBoxLayout()
self._layout.setSpacing(CONFIG.pxInt(12)) self._layout.setSpacing(12)
self._widget = QWidget(self) self._widget = QWidget(self)
self._widget.setLayout(self._layout) self._widget.setLayout(self._layout)
@@ -156,24 +155,25 @@ class NScrollableForm(QScrollArea):
def scrollToSection(self, identifier: int) -> None: def scrollToSection(self, identifier: int) -> None:
"""Scroll to the requested section identifier.""" """Scroll to the requested section identifier."""
if identifier in self._sections: if identifier in self._sections:
yPos = self._sections[identifier].pos().y() - CONFIG.pxInt(8) yPos = self._sections[identifier].pos().y() - 8
self.verticalScrollBar().setValue(yPos) if vBar := self.verticalScrollBar():
vBar.setValue(yPos)
return return
def scrollToLabel(self, label: str) -> None: def scrollToLabel(self, label: str) -> None:
"""Scroll to the requested label.""" """Scroll to the requested label."""
if label in self._index: if label in self._index:
yPos = self._index[label].pos().y() - CONFIG.pxInt(8) yPos = self._index[label].pos().y() - 8
self.verticalScrollBar().setValue(yPos) if vBar := self.verticalScrollBar():
vBar.setValue(yPos)
return return
def addGroupLabel(self, label: str, identifier: int | None = None) -> None: def addGroupLabel(self, label: str, identifier: int | None = None) -> None:
"""Add a text label to separate groups of settings.""" """Add a text label to separate groups of settings."""
hM = CONFIG.pxInt(4)
qLabel = QLabel(f"<b>{label}</b>", self) qLabel = QLabel(f"<b>{label}</b>", self)
qLabel.setContentsMargins(0, hM, 0, hM) qLabel.setContentsMargins(0, 4, 0, 4)
if not self._first: if not self._first:
self._layout.addSpacing(5*hM) self._layout.addSpacing(20)
self._layout.addWidget(qLabel) self._layout.addWidget(qLabel)
self._first = False self._first = False
if identifier is not None: if identifier is not None:
@@ -192,7 +192,7 @@ class NScrollableForm(QScrollArea):
) -> None: ) -> None:
"""Add a label and a widget as a new row of the form.""" """Add a label and a widget as a new row of the form."""
row = QHBoxLayout() row = QHBoxLayout()
row.setSpacing(CONFIG.pxInt(12)) row.setSpacing(12)
if isinstance(widget, list): if isinstance(widget, list):
wBox = QHBoxLayout() wBox = QHBoxLayout()
@@ -205,7 +205,7 @@ class NScrollableForm(QScrollArea):
icon.setPixmap(item) icon.setPixmap(item)
wBox.addWidget(icon) wBox.addWidget(icon)
elif isinstance(item, int): elif isinstance(item, int):
wBox.addSpacing(CONFIG.pxInt(item)) wBox.addSpacing(item)
qWidget = QWidget(self) qWidget = QWidget(self)
qWidget.setLayout(wBox) qWidget.setLayout(wBox)
else: else:
@@ -252,7 +252,7 @@ class NScrollableForm(QScrollArea):
def finalise(self) -> None: def finalise(self) -> None:
"""Finalise the layout when the form is built.""" """Finalise the layout when the form is built."""
self._layout.addSpacing(CONFIG.pxInt(20)) self._layout.addSpacing(20)
self._layout.addStretch(1) self._layout.addStretch(1)
return return
+36 -46
View File
@@ -26,10 +26,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations from __future__ import annotations
from PyQt6.QtCore import QPoint, QRectF, QSize, Qt, pyqtSignal, pyqtSlot 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 ( from PyQt6.QtWidgets import (
QAbstractButton, QButtonGroup, QLabel, QStyle, QStyleOptionToolButton, QAbstractButton, QButtonGroup, QLabel, QStyleOptionToolButton, QToolBar,
QToolBar, QToolButton, QWidget QToolButton, QWidget
) )
from novelwriter.types import ( from novelwriter.types import (
@@ -83,21 +83,19 @@ class NPagedSideBar(QToolBar):
self.insertWidget(self._stretchAction, label) self.insertWidget(self._stretchAction, label)
return 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.""" """Add a new button to the toolbar."""
button = _PagedToolButton(self) button = _PagedToolButton(self)
button.setText(text) button.setText(text)
self.insertWidget(self._stretchAction, button)
action = self.insertWidget(self._stretchAction, button)
self._group.addButton(button, id=buttonId) self._group.addButton(button, id=buttonId)
self._buttons[buttonId] = button self._buttons[buttonId] = button
return
return action
def setSelected(self, buttonId: int) -> None: def setSelected(self, buttonId: int) -> None:
"""Set the selected button.""" """Set the selected button."""
self._group.button(buttonId).setChecked(True) if button := self._group.button(buttonId):
button.setChecked(True)
return return
## ##
@@ -115,7 +113,7 @@ class NPagedSideBar(QToolBar):
class _PagedToolButton(QToolButton): class _PagedToolButton(QToolButton):
__slots__ = ("_bH", "_tM", "_lM", "_cR", "_aH") __slots__ = ("_bH", "_tM", "_aH")
def __init__(self, parent: QWidget) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
@@ -126,8 +124,6 @@ class _PagedToolButton(QToolButton):
fH = self.fontMetrics().height() fH = self.fontMetrics().height()
self._bH = round(fH * 1.7) self._bH = round(fH * 1.7)
self._tM = (self._bH - fH)//2 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._aH = 2*fH//7
self.setFixedHeight(self._bH) self.setFixedHeight(self._bH)
@@ -145,53 +141,51 @@ class _PagedToolButton(QToolButton):
opt = QStyleOptionToolButton() opt = QStyleOptionToolButton()
opt.initFrom(self) opt.initFrom(self)
paint = QPainter(self) painter = QPainter(self)
paint.setRenderHint(QtPaintAntiAlias, True) painter.setRenderHint(QtPaintAntiAlias, True)
paint.setPen(QtNoPen) painter.setPen(QtNoPen)
paint.setBrush(QtNoBrush) painter.setBrush(QtNoBrush)
width = self.width() width = self.width()
height = self.height() height = self.height()
palette = self.palette() palette = self.palette()
if opt.state & QtMouseOver == QtMouseOver: # pragma: no cover if opt.state & QtMouseOver == QtMouseOver: # pragma: no cover
backCol = palette.base() painter.setBrush(palette.light())
paint.setBrush(backCol) painter.drawRoundedRect(0, 0, width, height, 4, 4)
paint.setOpacity(0.75)
paint.drawRoundedRect(0, 0, width, height, self._cR, self._cR)
if self.isChecked(): if self.isChecked():
backCol = palette.highlight() painter.setBrush(palette.highlight())
paint.setBrush(backCol) painter.setOpacity(0.35)
paint.setOpacity(0.35) painter.drawRoundedRect(0, 0, width, height, 4, 4)
paint.drawRoundedRect(0, 0, width, height, self._cR, self._cR)
textCol = palette.highlightedText().color() textCol = palette.highlightedText().color()
else: else:
textCol = palette.text().color() textCol = palette.text().color()
tW = width - 2*self._lM tW = width - 24
tH = height - 2*self._tM tH = height - 2*self._tM
paint.setPen(textCol) painter.setPen(textCol)
paint.setOpacity(1.0) painter.setOpacity(1.0)
paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text()) painter.drawText(QRectF(12, self._tM, tW, tH), QtAlignLeft, self.text())
tC = self.height()//2 tC = self.height()//2
tW = self.width() - self._aH - self._lM tW = self.width() - self._aH - 12
if self.isChecked(): if self.isChecked():
paint.setBrush(textCol) painter.setBrush(textCol)
paint.drawPolygon(QPolygon([ painter.drawPolygon(QPolygon([
QPoint(tW, tC - self._aH), QPoint(tW, tC - self._aH),
QPoint(tW + self._aH, tC), QPoint(tW + self._aH, tC),
QPoint(tW, tC + self._aH), QPoint(tW, tC + self._aH),
])) ]))
painter.end()
return return
class _NPagedToolLabel(QLabel): class _NPagedToolLabel(QLabel):
__slots__ = ("_bH", "_tM", "_lM", "_textCol") __slots__ = ("_bH", "_tM", "_textCol")
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None: def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
@@ -201,7 +195,6 @@ class _NPagedToolLabel(QLabel):
fH = self.fontMetrics().height() fH = self.fontMetrics().height()
self._bH = round(fH * 1.7) self._bH = round(fH * 1.7)
self._tM = (self._bH - fH)//2 self._tM = (self._bH - fH)//2
self._lM = self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
self.setFixedHeight(self._bH) self.setFixedHeight(self._bH)
self._textCol = textColor or self.palette().text().color() 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 """Overload the paint event to draw a simple, left aligned text
label that matches the button style. label that matches the button style.
""" """
paint = QPainter(self) tW = self.width() - 8
paint.setRenderHint(QtPaintAntiAlias, True) tH = self.height() - 2*self._tM
paint.setPen(QtNoPen)
width = self.width() painter = QPainter(self)
height = self.height() painter.setRenderHint(QtPaintAntiAlias, True)
painter.setPen(QtNoPen)
tW = width - 2*self._lM painter.setPen(self._textCol)
tH = height - 2*self._tM painter.setOpacity(1.0)
painter.drawText(QRectF(4, self._tM, tW, tH), QtAlignLeft, self.text())
paint.setPen(self._textCol) painter.end()
paint.setOpacity(1.0)
paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
return return
+4 -11
View File
@@ -28,7 +28,6 @@ import logging
from PyQt6.QtGui import QColor, QPainter, QPaintEvent from PyQt6.QtGui import QColor, QPainter, QPaintEvent
from PyQt6.QtWidgets import QAbstractButton, QWidget from PyQt6.QtWidgets import QAbstractButton, QWidget
from novelwriter import CONFIG
from novelwriter.enum import nwTrinary from novelwriter.enum import nwTrinary
from novelwriter.types import QtBlack, QtPaintAntiAlias from novelwriter.types import QtBlack, QtPaintAntiAlias
@@ -37,9 +36,7 @@ logger = logging.getLogger(__name__)
class StatusLED(QAbstractButton): class StatusLED(QAbstractButton):
__slots__ = ( __slots__ = ("_neutral", "_postitve", "_negative", "_color", "_state")
"_neutral", "_postitve", "_negative", "_color", "_state", "_bPx"
)
def __init__(self, sW: int, sH: int, parent: QWidget | None = None) -> None: def __init__(self, sW: int, sH: int, parent: QWidget | None = None) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
@@ -48,7 +45,6 @@ class StatusLED(QAbstractButton):
self._negative = QtBlack self._negative = QtBlack
self._color = QtBlack self._color = QtBlack
self._state = nwTrinary.NEUTRAL self._state = nwTrinary.NEUTRAL
self._bPx = CONFIG.pxInt(1)
self.setFixedWidth(sW) self.setFixedWidth(sW)
self.setFixedHeight(sH) self.setFixedHeight(sH)
return return
@@ -82,12 +78,9 @@ class StatusLED(QAbstractButton):
"""Draw the LED.""" """Draw the LED."""
painter = QPainter(self) painter = QPainter(self)
painter.setRenderHint(QtPaintAntiAlias, True) painter.setRenderHint(QtPaintAntiAlias, True)
painter.setPen(self.palette().windowText().color()) painter.setPen(self.palette().text().color())
painter.setBrush(self._color) painter.setBrush(self._color)
painter.setOpacity(1.0) painter.setOpacity(1.0)
painter.drawEllipse( painter.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
self._bPx, self._bPx, painter.end()
self.width() - 2*self._bPx,
self.height() - 2*self._bPx
)
return return
+7 -8
View File
@@ -27,13 +27,13 @@ from PyQt6.QtCore import QPropertyAnimation, Qt, pyqtProperty
from PyQt6.QtGui import QEnterEvent, QMouseEvent, QPainter, QPaintEvent, QResizeEvent from PyQt6.QtGui import QEnterEvent, QMouseEvent, QPainter, QPaintEvent, QResizeEvent
from PyQt6.QtWidgets import QAbstractButton, QWidget from PyQt6.QtWidgets import QAbstractButton, QWidget
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixed from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAntiAlias, QtSizeFixed
class NSwitch(QAbstractButton): 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: def __init__(self, parent: QWidget, height: int = 0) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
@@ -41,9 +41,8 @@ class NSwitch(QAbstractButton):
self._xH = height or SHARED.theme.baseButtonHeight self._xH = height or SHARED.theme.baseButtonHeight
self._xW = 2*self._xH self._xW = 2*self._xH
self._xR = int(self._xH*0.5) self._xR = int(self._xH*0.5)
self._rB = CONFIG.pxInt(2) self._rH = self._xH - 4
self._rH = self._xH - 2*self._rB self._rR = self._xR - 2
self._rR = self._xR - self._rB
self.setCheckable(True) self.setCheckable(True)
self.setSizePolicy(QtSizeFixed, QtSizeFixed) self.setSizePolicy(QtSizeFixed, QtSizeFixed)
@@ -98,14 +97,14 @@ class NSwitch(QAbstractButton):
trackBrush = palette.highlight() trackBrush = palette.highlight()
thumbBrush = palette.highlightedText() thumbBrush = palette.highlightedText()
else: else:
trackBrush = palette.mid() trackBrush = palette.midlight()
thumbBrush = palette.light() thumbBrush = palette.light()
if self.isEnabled(): if self.isEnabled():
trackOpacity = 1.0 trackOpacity = 1.0
else: else:
trackOpacity = 0.6 trackOpacity = 0.6
trackBrush = palette.dark() trackBrush = palette.mid()
thumbBrush = palette.mid() thumbBrush = palette.mid()
painter.setBrush(trackBrush) painter.setBrush(trackBrush)
@@ -113,7 +112,7 @@ class NSwitch(QAbstractButton):
painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR) painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
painter.setBrush(thumbBrush) 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() painter.end()
return return
+1 -1
View File
@@ -70,7 +70,7 @@ class VersionInfoWidget(QWidget):
self._layout = QVBoxLayout() self._layout = QVBoxLayout()
self._layout.addWidget(self._lblInfo) self._layout.addWidget(self._lblInfo)
self._layout.addWidget(self._lblRelease) self._layout.addWidget(self._lblRelease)
self._layout.setSpacing(CONFIG.pxInt(2)) self._layout.setSpacing(2)
self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self._layout) self.setLayout(self._layout)
-3
View File
@@ -29,8 +29,6 @@ from enum import Flag, IntEnum
from PyQt6.QtGui import QColor from PyQt6.QtGui import QColor
from novelwriter.types import nwDataClass
ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""} ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL) 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 return text
@nwDataClass
class TextDocumentTheme: class TextDocumentTheme:
"""Default document theme.""" """Default document theme."""
+6 -3
View File
@@ -278,8 +278,10 @@ class ToQTextDocument(Tokenizer):
printer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter) printer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter)
printer.setOutputFileName(str(path)) printer.setOutputFileName(str(path))
self._document.documentLayout().setPaintDevice(printer) if layout := self._document.documentLayout():
self._document.setPageSize(printer.pageRect(QPrinter.Unit.Millimeter).size()) layout.setPaintDevice(printer)
self._document.setPageSize(printer.pageRect(QPrinter.Unit.DevicePixel).size())
self._document.print(printer) self._document.print(printer)
return return
@@ -458,7 +460,8 @@ class ToQTextDocument(Tokenizer):
cursor.insertFrame(fFmt) cursor.insertFrame(fFmt)
cursor.setBlockFormat(bFmt) cursor.setBlockFormat(bFmt)
cursor.insertText(self._project.localLookup("New Page"), cFmt) cursor.insertText(self._project.localLookup("New Page"), cFmt)
cursor.swap(self._document.rootFrame().lastCursorPosition()) if root := self._document.rootFrame():
cursor.swap(root.lastCursorPosition())
return return
+87 -92
View File
@@ -52,7 +52,9 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
from novelwriter.core.document import NWDocument from novelwriter.core.document import NWDocument
from novelwriter.enum import ( from novelwriter.enum import (
@@ -168,7 +170,7 @@ class GuiDocEditor(QPlainTextEdit):
self.customContextMenuRequested.connect(self._openContextMenu) self.customContextMenuRequested.connect(self._openContextMenu)
# Editor Settings # Editor Settings
self.setMinimumWidth(CONFIG.pxInt(300)) self.setMinimumWidth(300)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
self.setFrameStyle(QFrame.Shape.NoFrame) self.setFrameStyle(QFrame.Shape.NoFrame)
self.setAcceptDrops(True) self.setAcceptDrops(True)
@@ -295,10 +297,11 @@ class GuiDocEditor(QPlainTextEdit):
palette.setColor(QPalette.ColorRole.Text, syntax.text) palette.setColor(QPalette.ColorRole.Text, syntax.text)
self.setPalette(palette) self.setPalette(palette)
palette = self.viewport().palette() if viewport := self.viewport():
palette.setColor(QPalette.ColorRole.Base, syntax.back) palette = viewport.palette()
palette.setColor(QPalette.ColorRole.Text, syntax.text) palette.setColor(QPalette.ColorRole.Base, syntax.back)
self.viewport().setPalette(palette) palette.setColor(QPalette.ColorRole.Text, syntax.text)
viewport.setPalette(palette)
self.docHeader.matchColours() self.docHeader.matchColours()
self.docFooter.matchColours() self.docFooter.matchColours()
@@ -331,7 +334,7 @@ class GuiDocEditor(QPlainTextEdit):
# Due to cursor visibility, a part of the margin must be # Due to cursor visibility, a part of the margin must be
# allocated to the document itself. See issue #1112. # allocated to the document itself. See issue #1112.
self._qDocument.setDocumentMargin(4) 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) self.setViewportMargins(self._vpMargin, self._vpMargin, self._vpMargin, self._vpMargin)
# Also set the document text options for the document text flow # Also set the document text options for the document text flow
@@ -359,7 +362,7 @@ class GuiDocEditor(QPlainTextEdit):
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded) self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
# Refresh the tab stops # 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 # If we have a document open, we should refresh it in case the
# font changed, otherwise we just clear the editor entirely, # font changed, otherwise we just clear the editor entirely,
@@ -513,29 +516,27 @@ class GuiDocEditor(QPlainTextEdit):
def cursorIsVisible(self) -> bool: def cursorIsVisible(self) -> bool:
"""Check if the cursor is visible in the editor.""" """Check if the cursor is visible in the editor."""
return ( viewport = self.viewport()
0 < self.cursorRect().top() height = viewport.height() if viewport else 0
and self.cursorRect().bottom() < self.viewport().height() return 0 < self.cursorRect().top() and self.cursorRect().bottom() < height
)
def ensureCursorVisibleNoCentre(self) -> None: def ensureCursorVisibleNoCentre(self) -> None:
"""Ensure cursor is visible, but don't force it to centre.""" """Ensure cursor is visible, but don't force it to centre."""
cT = self.cursorRect().top() if (viewport := self.viewport()) and (vBar := self.verticalScrollBar()):
cB = self.cursorRect().bottom() cT = self.cursorRect().top()
vH = self.viewport().height() cB = self.cursorRect().bottom()
if cT < 0: vH = viewport.height()
count = 0 if cT < 0:
vBar = self.verticalScrollBar() count = 0
while self.cursorRect().top() < 0 and count < 100000: while self.cursorRect().top() < 0 and count < 100000:
vBar.setValue(vBar.value() - 1) vBar.setValue(vBar.value() - 1)
count += 1 count += 1
elif cB > vH: elif cB > vH:
count = 0 count = 0
vBar = self.verticalScrollBar() while self.cursorRect().bottom() > vH and count < 100000:
while self.cursorRect().bottom() > vH and count < 100000: vBar.setValue(vBar.value() + 1)
vBar.setValue(vBar.value() + 1) count += 1
count += 1 QApplication.processEvents()
QApplication.processEvents()
return return
def updateDocMargins(self) -> None: def updateDocMargins(self) -> None:
@@ -547,10 +548,10 @@ class GuiDocEditor(QPlainTextEdit):
wH = self.height() wH = self.height()
vBar = self.verticalScrollBar() vBar = self.verticalScrollBar()
sW = vBar.width() if vBar.isVisible() else 0 sW = vBar.width() if vBar and vBar.isVisible() else 0
hBar = self.horizontalScrollBar() hBar = self.horizontalScrollBar()
sH = hBar.height() if hBar.isVisible() else 0 sH = hBar.height() if hBar and hBar.isVisible() else 0
tM = self._vpMargin tM = self._vpMargin
if CONFIG.textWidth > 0 or SHARED.focusMode: if CONFIG.textWidth > 0 or SHARED.focusMode:
@@ -959,10 +960,9 @@ class GuiDocEditor(QPlainTextEdit):
kMod = event.modifiers() kMod = event.modifiers()
okMod = kMod in (QtModNone, QtModShift) okMod = kMod in (QtModNone, QtModShift)
okKey = event.key() not in self.MOVE_KEYS okKey = event.key() not in self.MOVE_KEYS
if nPos != cPos and okMod and okKey: if nPos != cPos and okMod and okKey and (viewport := self.viewport()):
mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height() mPos = CONFIG.autoScrollPos*0.01 * viewport.height()
if cPos > mPos: if cPos > mPos and (vBar := self.verticalScrollBar()):
vBar = self.verticalScrollBar()
vBar.setValue(vBar.value() + (1 if nPos > cPos else -1)) vBar.setValue(vBar.value() + (1 if nPos > cPos else -1))
else: else:
super().keyPressEvent(event) super().keyPressEvent(event)
@@ -971,7 +971,7 @@ class GuiDocEditor(QPlainTextEdit):
def dragEnterEvent(self, event: QDragEnterEvent) -> None: def dragEnterEvent(self, event: QDragEnterEvent) -> None:
"""Overload drag enter event to handle dragged items.""" """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() event.acceptProposedAction()
else: else:
super().dragEnterEvent(event) super().dragEnterEvent(event)
@@ -979,7 +979,7 @@ class GuiDocEditor(QPlainTextEdit):
def dragMoveEvent(self, event: QDragMoveEvent) -> None: def dragMoveEvent(self, event: QDragMoveEvent) -> None:
"""Overload drag move event to handle dragged items.""" """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() event.acceptProposedAction()
else: else:
super().dragMoveEvent(event) super().dragMoveEvent(event)
@@ -987,8 +987,8 @@ class GuiDocEditor(QPlainTextEdit):
def dropEvent(self, event: QDropEvent) -> None: def dropEvent(self, event: QDropEvent) -> None:
"""Overload drop event to handle dragged items.""" """Overload drop event to handle dragged items."""
if event.mimeData().hasFormat(nwConst.MIME_HANDLE): if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE):
if handles := decodeMimeHandles(event.mimeData()): if handles := decodeMimeHandles(data):
if SHARED.project.tree.checkType(handles[0], nwItemType.FILE): if SHARED.project.tree.checkType(handles[0], nwItemType.FILE):
self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True) self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True)
else: else:
@@ -1098,10 +1098,10 @@ class GuiDocEditor(QPlainTextEdit):
# at unwanted times when other changes are made to the document # at unwanted times when other changes are made to the document
cursor = self.textCursor() cursor = self.textCursor()
bPos = cursor.positionInBlock() bPos = cursor.positionInBlock()
if bPos > 0: if bPos > 0 and (viewport := self.viewport()):
show = self._completer.updateText(text, bPos) show = self._completer.updateText(text, bPos)
point = self.cursorRect().bottomRight() point = self.cursorRect().bottomRight()
self._completer.move(self.viewport().mapToGlobal(point)) self._completer.move(viewport.mapToGlobal(point))
self._completer.setVisible(show) self._completer.setVisible(show)
else: else:
self._completer.setVisible(False) self._completer.setVisible(False)
@@ -1148,46 +1148,46 @@ class GuiDocEditor(QPlainTextEdit):
ctxMenu = QMenu(self) ctxMenu = QMenu(self)
ctxMenu.setObjectName("ContextMenu") ctxMenu.setObjectName("ContextMenu")
if pBlock.userState() == BLOCK_TITLE: 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)) action.triggered.connect(qtLambda(self._emitRenameItem, pBlock))
# URL # URL
(mData, mType) = self._qDocument.metaDataAtPos(pCursor.position()) (mData, mType) = self._qDocument.metaDataAtPos(pCursor.position())
if mData and mType == "url": 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)) action.triggered.connect(qtLambda(SHARED.openWebsite, mData))
ctxMenu.addSeparator() ctxMenu.addSeparator()
# Follow # Follow
status = self._processTag(cursor=pCursor, follow=False) status = self._processTag(cursor=pCursor, follow=False)
if status == nwTrinary.POSITIVE: 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)) action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, follow=True))
ctxMenu.addSeparator() ctxMenu.addSeparator()
elif status == nwTrinary.NEGATIVE: 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)) action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, create=True))
ctxMenu.addSeparator() ctxMenu.addSeparator()
# Cut, Copy and Paste # Cut, Copy and Paste
if uCursor.hasSelection(): if uCursor.hasSelection():
action = ctxMenu.addAction(self.tr("Cut")) action = qtAddAction(ctxMenu, self.tr("Cut"))
action.triggered.connect(qtLambda(self.docAction, nwDocAction.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.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)) action.triggered.connect(qtLambda(self.docAction, nwDocAction.PASTE))
ctxMenu.addSeparator() ctxMenu.addSeparator()
# Selections # 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.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( action.triggered.connect(qtLambda(
self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, pos, self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, pos,
)) ))
action = ctxMenu.addAction(self.tr("Select Paragraph")) action = qtAddAction(ctxMenu, self.tr("Select Paragraph"))
action.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, pos self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, pos
)) ))
@@ -1203,23 +1203,24 @@ class GuiDocEditor(QPlainTextEdit):
sCursor.movePosition(QtMoveRight, QtKeepAnchor, cLen) sCursor.movePosition(QtMoveRight, QtKeepAnchor, cLen)
if suggest: if suggest:
ctxMenu.addSeparator() ctxMenu.addSeparator()
ctxMenu.addAction(self.tr("Spelling Suggestion(s)")) qtAddAction(ctxMenu, self.tr("Spelling Suggestion(s)"))
for option in suggest[:15]: 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)) action.triggered.connect(qtLambda(self._correctWord, sCursor, option))
else: else:
trNone = self.tr("No Suggestions") trNone = self.tr("No Suggestions")
ctxMenu.addAction(f"{nwUnicode.U_ENDASH} {trNone}") qtAddAction(ctxMenu, f"{nwUnicode.U_ENDASH} {trNone}")
ctxMenu.addSeparator() 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.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)) action.triggered.connect(qtLambda(self._addWord, word, block, True))
# Execute the context menu # Execute the context menu
ctxMenu.exec(self.viewport().mapToGlobal(pos)) if viewport := self.viewport():
ctxMenu.deleteLater() ctxMenu.exec(viewport.mapToGlobal(pos))
ctxMenu.deleteLater()
return return
@@ -2007,8 +2008,8 @@ class GuiDocEditor(QPlainTextEdit):
sPos = cPos sPos = cPos
for i in range(cPos - bPos): for i in range(cPos - bPos):
sPos = cPos - i - 1 sPos = cPos - i - 1
cOne = self._qDocument.characterAt(sPos) cOne = str(self._qDocument.characterAt(sPos))
cTwo = self._qDocument.characterAt(sPos - 1) cTwo = str(self._qDocument.characterAt(sPos - 1))
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()): if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
sPos += 1 sPos += 1
break break
@@ -2017,8 +2018,8 @@ class GuiDocEditor(QPlainTextEdit):
ePos = cPos ePos = cPos
for i in range(bPos + bLen - cPos): for i in range(bPos + bLen - cPos):
ePos = cPos + i ePos = cPos + i
cOne = self._qDocument.characterAt(ePos) cOne = str(self._qDocument.characterAt(ePos))
cTwo = self._qDocument.characterAt(ePos + 1) cTwo = str(self._qDocument.characterAt(ePos + 1))
if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()): if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
break break
@@ -2122,7 +2123,7 @@ class MetaCompleter(QMenu):
for value in sorted(options): for value in sorted(options):
rep = value + suffix rep = value + suffix
action = self.addAction(value) action = qtAddAction(self, value)
action.triggered.connect(qtLambda(self._emitComplete, offset, length, rep)) action.triggered.connect(qtLambda(self._emitComplete, offset, length, rep))
return True return True
@@ -2339,7 +2340,6 @@ class GuiDocToolBar(QWidget):
logger.debug("Create: GuiDocToolBar") logger.debug("Create: GuiDocToolBar")
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
cM = CONFIG.pxInt(4)
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
# General Buttons # General Buttons
@@ -2412,7 +2412,7 @@ class GuiDocToolBar(QWidget):
self.outerBox.addWidget(self.tbBoldMD) self.outerBox.addWidget(self.tbBoldMD)
self.outerBox.addWidget(self.tbItalicMD) self.outerBox.addWidget(self.tbItalicMD)
self.outerBox.addWidget(self.tbStrikeMD) self.outerBox.addWidget(self.tbStrikeMD)
self.outerBox.addSpacing(cM) self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.tbBold) self.outerBox.addWidget(self.tbBold)
self.outerBox.addWidget(self.tbItalic) self.outerBox.addWidget(self.tbItalic)
self.outerBox.addWidget(self.tbStrike) self.outerBox.addWidget(self.tbStrike)
@@ -2420,8 +2420,8 @@ class GuiDocToolBar(QWidget):
self.outerBox.addWidget(self.tbMark) self.outerBox.addWidget(self.tbMark)
self.outerBox.addWidget(self.tbSuperscript) self.outerBox.addWidget(self.tbSuperscript)
self.outerBox.addWidget(self.tbSubscript) self.outerBox.addWidget(self.tbSubscript)
self.outerBox.setContentsMargins(cM, cM, cM, cM) self.outerBox.setContentsMargins(4, 4, 4, 4)
self.outerBox.setSpacing(cM) self.outerBox.setSpacing(4)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.updateTheme() self.updateTheme()
@@ -2472,7 +2472,6 @@ class GuiDocEditSearch(QFrame):
self.docEditor = docEditor self.docEditor = docEditor
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(6)
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
@@ -2498,7 +2497,7 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.setContentsMargins(0, 0, 0, 0) self.searchOpt.setContentsMargins(0, 0, 0, 0)
self.searchLabel = QLabel(self.tr("Search"), self) self.searchLabel = QLabel(self.tr("Search"), self)
self.searchLabel.setIndent(CONFIG.pxInt(6)) self.searchLabel.setIndent(6)
self.resultLabel = QLabel("?/?", self) self.resultLabel = QLabel("?/?", self)
@@ -2575,12 +2574,11 @@ class GuiDocEditSearch(QFrame):
self.mainBox.setColumnStretch(3, 0) self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0) self.mainBox.setColumnStretch(4, 0)
self.mainBox.setColumnStretch(5, 0) self.mainBox.setColumnStretch(5, 0)
self.mainBox.setSpacing(CONFIG.pxInt(2)) self.mainBox.setSpacing(2)
self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx) self.mainBox.setContentsMargins(6, 6, 6, 6)
boxWidth = CONFIG.pxInt(200) self.searchBox.setFixedWidth(200)
self.searchBox.setFixedWidth(boxWidth) self.replaceBox.setFixedWidth(200)
self.replaceBox.setFixedWidth(boxWidth)
self.replaceBox.setVisible(False) self.replaceBox.setVisible(False)
self.replaceButton.setVisible(False) self.replaceButton.setVisible(False)
self.adjustSize() self.adjustSize()
@@ -2848,7 +2846,6 @@ class GuiDocEditHeader(QWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(4)
# Main Widget Settings # Main Widget Settings
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
@@ -2895,13 +2892,13 @@ class GuiDocEditHeader(QWidget):
self.outerBox.addWidget(self.tbButton, 0) self.outerBox.addWidget(self.tbButton, 0)
self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.outlineButton, 0)
self.outerBox.addWidget(self.searchButton, 0) self.outerBox.addWidget(self.searchButton, 0)
self.outerBox.addSpacing(mPx) self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.itemTitle, 1) self.outerBox.addWidget(self.itemTitle, 1)
self.outerBox.addSpacing(mPx) self.outerBox.addSpacing(4)
self.outerBox.addSpacing(iPx) self.outerBox.addSpacing(iPx)
self.outerBox.addWidget(self.minmaxButton, 0) self.outerBox.addWidget(self.minmaxButton, 0)
self.outerBox.addWidget(self.closeButton, 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.outerBox.setSpacing(0)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -2912,7 +2909,7 @@ class GuiDocEditHeader(QWidget):
# Fix Margins and Size # Fix Margins and Size
# This is needed for high DPI systems. See issue #499. # This is needed for high DPI systems. See issue #499.
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setMinimumHeight(iPx + 2*mPx) self.setMinimumHeight(iPx + 8)
self.updateFont() self.updateFont()
self.updateTheme() self.updateTheme()
@@ -2945,7 +2942,7 @@ class GuiDocEditHeader(QWidget):
tStart = time() tStart = time()
self.outlineMenu.clear() self.outlineMenu.clear()
for number, text in data.items(): for number, text in data.items():
action = self.outlineMenu.addAction(text) action = qtAddAction(self.outlineMenu, text)
action.triggered.connect(qtLambda(self._gotoBlock, number)) action.triggered.connect(qtLambda(self._gotoBlock, number))
self._docOutline = data self._docOutline = data
logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart)) 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) iPx = round(0.9*SHARED.theme.baseIconHeight)
fPx = int(0.9*SHARED.theme.fontPixelSize) fPx = int(0.9*SHARED.theme.fontPixelSize)
mPx = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(4)
hSp = CONFIG.pxInt(6)
# Cached Translations # Cached Translations
self._trLineCount = self.tr("Line: {0} ({1})") self._trLineCount = self.tr("Line: {0} ({1})")
@@ -3127,23 +3121,23 @@ class GuiDocEditFooter(QWidget):
# Assemble Layout # Assemble Layout
self.outerBox = QHBoxLayout() self.outerBox = QHBoxLayout()
self.outerBox.setSpacing(bSp) self.outerBox.setSpacing(4)
self.outerBox.addWidget(self.statusIcon) self.outerBox.addWidget(self.statusIcon)
self.outerBox.addWidget(self.statusText) self.outerBox.addWidget(self.statusText)
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
self.outerBox.addWidget(self.linesIcon) self.outerBox.addWidget(self.linesIcon)
self.outerBox.addWidget(self.linesText) self.outerBox.addWidget(self.linesText)
self.outerBox.addSpacing(hSp) self.outerBox.addSpacing(6)
self.outerBox.addWidget(self.wordsIcon) self.outerBox.addWidget(self.wordsIcon)
self.outerBox.addWidget(self.wordsText) self.outerBox.addWidget(self.wordsText)
self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) self.outerBox.setContentsMargins(8, 8, 8, 8)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
# Fix Margins and Size # Fix Margins and Size
# This is needed for high DPI systems. See issue #499. # This is needed for high DPI systems. See issue #499.
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setMinimumHeight(fPx + 2*mPx) self.setMinimumHeight(fPx + 16)
# Fix the Colours # Fix the Colours
self.updateFont() self.updateFont()
@@ -3226,12 +3220,13 @@ class GuiDocEditFooter(QWidget):
def updateLineCount(self, cursor: QTextCursor) -> None: def updateLineCount(self, cursor: QTextCursor) -> None:
"""Update the line and document position counter.""" """Update the line and document position counter."""
cPos = cursor.position() + 1 if document := cursor.document():
cLine = cursor.blockNumber() + 1 cPos = cursor.position() + 1
cCount = max(cursor.document().characterCount(), 1) cLine = cursor.blockNumber() + 1
self.linesText.setText( cCount = max(document.characterCount(), 1)
self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %") self.linesText.setText(
) self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %")
)
return return
def updateWordCount(self, wCount: int, selection: bool) -> None: def updateWordCount(self, wCount: int, selection: bool) -> None:
+8 -8
View File
@@ -272,14 +272,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"""Loop through all blocks and re-highlight those of a given """Loop through all blocks and re-highlight those of a given
content type. content type.
""" """
qDoc = self.document() if document := self.document():
nBlocks = qDoc.blockCount() nBlocks = document.blockCount()
tStart = time() tStart = time()
for i in range(nBlocks): for i in range(nBlocks):
block = qDoc.findBlockByNumber(i) block = document.findBlockByNumber(i)
if block.userState() & cType > 0: if block.userState() & cType > 0:
self.rehighlightBlock(block) self.rehighlightBlock(block)
logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart))) logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart)))
return return
## ##
+48 -53
View File
@@ -32,8 +32,8 @@ from enum import Enum
from PyQt6.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot from PyQt6.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QAction, QCursor, QDesktopServices, QDragEnterEvent, QDragMoveEvent, QCursor, QDesktopServices, QDragEnterEvent, QDragMoveEvent, QDropEvent,
QDropEvent, QMouseEvent, QPalette, QResizeEvent, QTextCursor QMouseEvent, QPalette, QResizeEvent, QTextCursor
) )
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QApplication, QFrame, QHBoxLayout, QMenu, QTextBrowser, QToolButton, QApplication, QFrame, QHBoxLayout, QMenu, QTextBrowser, QToolButton,
@@ -41,7 +41,7 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwConst, nwStyles, nwUnicode
from novelwriter.enum import nwChange, nwDocAction, nwDocMode, nwItemType from novelwriter.enum import nwChange, nwDocAction, nwDocMode, nwItemType
from novelwriter.error import logException from novelwriter.error import logException
@@ -79,7 +79,7 @@ class GuiDocViewer(QTextBrowser):
self._docTheme = TextDocumentTheme() self._docTheme = TextDocumentTheme()
# Settings # Settings
self.setMinimumWidth(CONFIG.pxInt(300)) self.setMinimumWidth(300)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
self.setOpenLinks(False) self.setOpenLinks(False)
self.setOpenExternalLinks(False) self.setOpenExternalLinks(False)
@@ -124,8 +124,7 @@ class GuiDocViewer(QTextBrowser):
@property @property
def scrollPosition(self) -> int: def scrollPosition(self) -> int:
"""Return the scrollbar position.""" """Return the scrollbar position."""
vBar = self.verticalScrollBar() if (vBar := self.verticalScrollBar()) and vBar.isVisible():
if vBar.isVisible():
return vBar.value() return vBar.value()
return 0 return 0
@@ -163,12 +162,13 @@ class GuiDocViewer(QTextBrowser):
palette.setColor(QPalette.ColorRole.Text, syntax.text) palette.setColor(QPalette.ColorRole.Text, syntax.text)
self.setPalette(palette) self.setPalette(palette)
palette = self.viewport().palette() if viewport := self.viewport():
palette.setColor(QPalette.ColorRole.Base, syntax.back) palette = viewport.palette()
palette.setColor(QPalette.ColorRole.Text, syntax.text) palette.setColor(QPalette.ColorRole.Base, syntax.back)
self.viewport().setPalette(palette) palette.setColor(QPalette.ColorRole.Text, syntax.text)
self.docHeader.matchColours() viewport.setPalette(palette)
self.docFooter.matchColours() self.docHeader.matchColours()
self.docFooter.matchColours()
# Update theme colours # Update theme colours
self._docTheme.text = syntax.text self._docTheme.text = syntax.text
@@ -186,7 +186,8 @@ class GuiDocViewer(QTextBrowser):
self._docTheme.altdialog = syntax.dialA self._docTheme.altdialog = syntax.dialA
# Set default text margins # Set default text margins
self.document().setDocumentMargin(0) if document := self.document():
document.setDocumentMargin(0)
# Scroll bars # Scroll bars
if CONFIG.hideVScroll: if CONFIG.hideVScroll:
@@ -200,7 +201,7 @@ class GuiDocViewer(QTextBrowser):
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded) self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
# Refresh the tab stops # 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 # If we have a document open, we should reload it in case the font changed
self.reloadText() self.reloadText()
@@ -217,7 +218,9 @@ class GuiDocViewer(QTextBrowser):
logger.debug("Generating preview for item '%s'", tHandle) logger.debug("Generating preview for item '%s'", tHandle)
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) 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 = ToQTextDocument(SHARED.project)
qDoc.setJustify(CONFIG.doJustify) qDoc.setJustify(CONFIG.doJustify)
qDoc.setDialogHighlight(True) qDoc.setDialogHighlight(True)
@@ -250,11 +253,11 @@ class GuiDocViewer(QTextBrowser):
self.setDocumentTitle(tHandle) self.setDocumentTitle(tHandle)
self.setDocument(qDoc.document) 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 # This is a refresh, so we set the scrollbar back to where it was
self.verticalScrollBar().setValue(sPos) vBar.setValue(sPos)
self._docHandle = tHandle self._docHandle = tHandle
SHARED.project.data.setLastHandle(tHandle, "viewer") SHARED.project.data.setLastHandle(tHandle, "viewer")
@@ -308,13 +311,13 @@ class GuiDocViewer(QTextBrowser):
"""Automatically adjust the margins so the text is centred.""" """Automatically adjust the margins so the text is centred."""
wW = self.width() wW = self.width()
wH = self.height() wH = self.height()
cM = CONFIG.getTextMargin() cM = CONFIG.textMargin
vBar = self.verticalScrollBar() vBar = self.verticalScrollBar()
sW = vBar.width() if vBar.isVisible() else 0 sW = vBar.width() if vBar and vBar.isVisible() else 0
hBar = self.horizontalScrollBar() hBar = self.horizontalScrollBar()
sH = hBar.height() if hBar.isVisible() else 0 sH = hBar.height() if hBar and hBar.isVisible() else 0
tM = cM tM = cM
if CONFIG.textWidth > 0: if CONFIG.textWidth > 0:
@@ -339,8 +342,7 @@ class GuiDocViewer(QTextBrowser):
def setScrollPosition(self, pos: int) -> None: def setScrollPosition(self, pos: int) -> None:
"""Set the scrollbar position.""" """Set the scrollbar position."""
vBar = self.verticalScrollBar() if (vBar := self.verticalScrollBar()) and vBar.isVisible():
if vBar.isVisible():
vBar.setValue(pos) vBar.setValue(pos)
return return
@@ -402,31 +404,27 @@ class GuiDocViewer(QTextBrowser):
ctxMenu = QMenu(self) ctxMenu = QMenu(self)
if userSelection: if userSelection:
mnuCopy = QAction(self.tr("Copy"), ctxMenu) action = qtAddAction(ctxMenu, self.tr("Copy"))
mnuCopy.triggered.connect(qtLambda(self.docAction, nwDocAction.COPY)) action.triggered.connect(qtLambda(self.docAction, nwDocAction.COPY))
ctxMenu.addAction(mnuCopy)
ctxMenu.addSeparator() ctxMenu.addSeparator()
mnuSelAll = QAction(self.tr("Select All"), ctxMenu) action = qtAddAction(ctxMenu, self.tr("Select All"))
mnuSelAll.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL)) action.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL))
ctxMenu.addAction(mnuSelAll)
mnuSelWord = QAction(self.tr("Select Word"), ctxMenu) action = qtAddAction(ctxMenu, self.tr("Select Word"))
mnuSelWord.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, point self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, point
)) ))
ctxMenu.addAction(mnuSelWord)
mnuSelPara = QAction(self.tr("Select Paragraph"), ctxMenu) action = qtAddAction(ctxMenu, self.tr("Select Paragraph"))
mnuSelPara.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, point self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, point
)) ))
ctxMenu.addAction(mnuSelPara)
# Open the context menu # Open the context menu
ctxMenu.exec(self.viewport().mapToGlobal(point)) if viewport := self.viewport():
ctxMenu.deleteLater() ctxMenu.exec(viewport.mapToGlobal(point))
ctxMenu.deleteLater()
return return
@@ -452,7 +450,7 @@ class GuiDocViewer(QTextBrowser):
def dragEnterEvent(self, event: QDragEnterEvent) -> None: def dragEnterEvent(self, event: QDragEnterEvent) -> None:
"""Overload drag enter event to handle dragged items.""" """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() event.acceptProposedAction()
else: else:
super().dragEnterEvent(event) super().dragEnterEvent(event)
@@ -460,7 +458,7 @@ class GuiDocViewer(QTextBrowser):
def dragMoveEvent(self, event: QDragMoveEvent) -> None: def dragMoveEvent(self, event: QDragMoveEvent) -> None:
"""Overload drag move event to handle dragged items.""" """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() event.acceptProposedAction()
else: else:
super().dragMoveEvent(event) super().dragMoveEvent(event)
@@ -468,8 +466,8 @@ class GuiDocViewer(QTextBrowser):
def dropEvent(self, event: QDropEvent) -> None: def dropEvent(self, event: QDropEvent) -> None:
"""Overload drop event to handle dragged items.""" """Overload drop event to handle dragged items."""
if event.mimeData().hasFormat(nwConst.MIME_HANDLE): if (data := event.mimeData()) and data.hasFormat(nwConst.MIME_HANDLE):
if handles := decodeMimeHandles(event.mimeData()): if handles := decodeMimeHandles(data):
if SHARED.project.tree.checkType(handles[0], nwItemType.FILE): if SHARED.project.tree.checkType(handles[0], nwItemType.FILE):
self.openDocumentRequest.emit(handles[0], nwDocMode.VIEW, "", True) self.openDocumentRequest.emit(handles[0], nwDocMode.VIEW, "", True)
else: else:
@@ -640,7 +638,6 @@ class GuiDocViewHeader(QWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(4)
# Main Widget Settings # Main Widget Settings
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
@@ -692,9 +689,9 @@ class GuiDocViewHeader(QWidget):
self.outerBox.addWidget(self.outlineButton, 0) self.outerBox.addWidget(self.outlineButton, 0)
self.outerBox.addWidget(self.backButton, 0) self.outerBox.addWidget(self.backButton, 0)
self.outerBox.addWidget(self.forwardButton, 0) self.outerBox.addWidget(self.forwardButton, 0)
self.outerBox.addSpacing(mPx) self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.itemTitle, 1) self.outerBox.addWidget(self.itemTitle, 1)
self.outerBox.addSpacing(mPx) self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.editButton, 0) self.outerBox.addWidget(self.editButton, 0)
self.outerBox.addWidget(self.refreshButton, 0) self.outerBox.addWidget(self.refreshButton, 0)
self.outerBox.addWidget(self.closeButton, 0) self.outerBox.addWidget(self.closeButton, 0)
@@ -705,8 +702,8 @@ class GuiDocViewHeader(QWidget):
# Fix Margins and Size # Fix Margins and Size
# This is needed for high DPI systems. See issue #499. # This is needed for high DPI systems. See issue #499.
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) self.outerBox.setContentsMargins(4, 4, 4, 4)
self.setMinimumHeight(iPx + 2*mPx) self.setMinimumHeight(iPx + 8)
self.updateFont() self.updateFont()
self.updateTheme() self.updateTheme()
@@ -747,7 +744,7 @@ class GuiDocViewHeader(QWidget):
minLevel = min(minLevel, level) minLevel = min(minLevel, level)
for title, text, level in entries[:30]: for title, text, level in entries[:30]:
indent = " "*(level - minLevel) indent = " "*(level - minLevel)
action = self.outlineMenu.addAction(f"{indent}{text}") action = qtAddAction(self.outlineMenu, f"{indent}{text}")
action.triggered.connect( action.triggered.connect(
lambda _, title=title: self.docViewer.navigateTo(f"#{tHandle}:{title}") lambda _, title=title: self.docViewer.navigateTo(f"#{tHandle}:{title}")
) )
@@ -885,8 +882,6 @@ class GuiDocViewFooter(QWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
hSp = CONFIG.pxInt(4)
mPx = CONFIG.pxInt(4)
# Main Widget Settings # Main Widget Settings
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
@@ -923,14 +918,14 @@ class GuiDocViewFooter(QWidget):
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
self.outerBox.addWidget(self.showComments, 0) self.outerBox.addWidget(self.showComments, 0)
self.outerBox.addWidget(self.showSynopsis, 0) self.outerBox.addWidget(self.showSynopsis, 0)
self.outerBox.setSpacing(hSp) self.outerBox.setSpacing(4)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
# Fix Margins and Size # Fix Margins and Size
# This is needed for high DPI systems. See issue #499. # This is needed for high DPI systems. See issue #499.
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.outerBox.setContentsMargins(mPx, mPx, mPx, mPx) self.outerBox.setContentsMargins(4, 4, 4, 4)
self.setMinimumHeight(iPx + 2*mPx) self.setMinimumHeight(iPx + 8)
self.updateFont() self.updateFont()
self.updateTheme() self.updateTheme()
+29 -31
View File
@@ -33,8 +33,8 @@ from PyQt6.QtWidgets import (
QTreeWidgetItem, QVBoxLayout, QWidget QTreeWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.common import checkInt from novelwriter.common import checkInt, qtAddAction
from novelwriter.constants import nwLabels, nwLists, nwStyles, trConst from novelwriter.constants import nwLabels, nwLists, nwStyles, trConst
from novelwriter.core.index import IndexHeading, IndexItem from novelwriter.core.index import IndexHeading, IndexItem
from novelwriter.enum import nwChange, nwDocMode, nwItemClass from novelwriter.enum import nwChange, nwDocMode, nwItemClass
@@ -63,7 +63,7 @@ class GuiDocViewerPanel(QWidget):
self.optsMenu = QMenu(self) 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.setCheckable(True)
self.aInactive.toggled.connect(self._toggleHideInactive) self.aInactive.toggled.connect(self._toggleHideInactive)
@@ -248,7 +248,6 @@ class _ViewPanelBackRefs(QTreeWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
cMg = CONFIG.pxInt(6)
self.setHeaderLabels([self.tr("Document"), "", "", self.tr("First Heading")]) self.setHeaderLabels([self.tr("Document"), "", "", self.tr("First Heading")])
self.setIndentation(0) self.setIndentation(0)
@@ -257,16 +256,16 @@ class _ViewPanelBackRefs(QTreeWidget):
self.setFrameStyle(QFrame.Shape.NoFrame) self.setFrameStyle(QFrame.Shape.NoFrame)
# Set Header Sizes # Set Header Sizes
treeHeader = self.header() if header := self.header():
treeHeader.setStretchLastSection(True) header.setStretchLastSection(True)
treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627 header.setMinimumSectionSize(iPx + 6) # See Issue #1627
treeHeader.setSectionResizeMode(self.C_DOC, QtHeaderToContents) header.setSectionResizeMode(self.C_DOC, QtHeaderToContents)
treeHeader.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) header.setSectionResizeMode(self.C_EDIT, QtHeaderFixed)
treeHeader.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) header.setSectionResizeMode(self.C_VIEW, QtHeaderFixed)
treeHeader.setSectionResizeMode(self.C_TITLE, QtHeaderToContents) header.setSectionResizeMode(self.C_TITLE, QtHeaderToContents)
treeHeader.resizeSection(self.C_EDIT, iPx + cMg) header.resizeSection(self.C_EDIT, iPx + 6)
treeHeader.resizeSection(self.C_VIEW, iPx + cMg) header.resizeSection(self.C_VIEW, iPx + 6)
treeHeader.setSectionsMovable(False) header.setSectionsMovable(False)
# Cache Icons Locally # Cache Icons Locally
self._editIcon = SHARED.theme.getIcon("edit", "green") self._editIcon = SHARED.theme.getIcon("edit", "green")
@@ -385,7 +384,6 @@ class _ViewPanelKeyWords(QTreeWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
cMg = CONFIG.pxInt(6)
self.setHeaderLabels([ self.setHeaderLabels([
self.tr("Tag"), "", "", self.tr("Importance"), self.tr("Document"), self.tr("Tag"), "", "", self.tr("Importance"), self.tr("Document"),
@@ -401,14 +399,14 @@ class _ViewPanelKeyWords(QTreeWidget):
self.sortByColumn(self.C_NAME, Qt.SortOrder.AscendingOrder) self.sortByColumn(self.C_NAME, Qt.SortOrder.AscendingOrder)
# Set Header Sizes # Set Header Sizes
treeHeader = self.header() if header := self.header():
treeHeader.setStretchLastSection(True) header.setStretchLastSection(True)
treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627 header.setMinimumSectionSize(iPx + 6) # See Issue #1627
treeHeader.setSectionResizeMode(self.C_EDIT, QtHeaderFixed) header.setSectionResizeMode(self.C_EDIT, QtHeaderFixed)
treeHeader.setSectionResizeMode(self.C_VIEW, QtHeaderFixed) header.setSectionResizeMode(self.C_VIEW, QtHeaderFixed)
treeHeader.resizeSection(self.C_EDIT, iPx + cMg) header.resizeSection(self.C_EDIT, iPx + 6)
treeHeader.resizeSection(self.C_VIEW, iPx + cMg) header.resizeSection(self.C_VIEW, iPx + 6)
treeHeader.setSectionsMovable(False) header.setSectionsMovable(False)
# Cache Icons Locally # Cache Icons Locally
self.updateTheme() self.updateTheme()
@@ -482,19 +480,19 @@ class _ViewPanelKeyWords(QTreeWidget):
def setColumnWidths(self, widths: list[int]) -> None: def setColumnWidths(self, widths: list[int]) -> None:
"""Set the column widths.""" """Set the column widths."""
if isinstance(widths, list) and len(widths) >= 4: if isinstance(widths, list) and len(widths) >= 4:
self.setColumnWidth(self.C_NAME, CONFIG.pxInt(checkInt(widths[0], 100))) self.setColumnWidth(self.C_NAME, checkInt(widths[0], 100))
self.setColumnWidth(self.C_IMPORT, CONFIG.pxInt(checkInt(widths[1], 100))) self.setColumnWidth(self.C_IMPORT, checkInt(widths[1], 100))
self.setColumnWidth(self.C_DOC, CONFIG.pxInt(checkInt(widths[2], 100))) self.setColumnWidth(self.C_DOC, checkInt(widths[2], 100))
self.setColumnWidth(self.C_TITLE, CONFIG.pxInt(checkInt(widths[3], 100))) self.setColumnWidth(self.C_TITLE, checkInt(widths[3], 100))
return return
def getColumnWidths(self) -> list[int]: def getColumnWidths(self) -> list[int]:
"""Get the widths of the user-adjustable columns.""" """Get the widths of the user-adjustable columns."""
return [ return [
CONFIG.rpxInt(self.columnWidth(self.C_NAME)), self.columnWidth(self.C_NAME),
CONFIG.rpxInt(self.columnWidth(self.C_IMPORT)), self.columnWidth(self.C_IMPORT),
CONFIG.rpxInt(self.columnWidth(self.C_DOC)), self.columnWidth(self.C_DOC),
CONFIG.rpxInt(self.columnWidth(self.C_TITLE)), self.columnWidth(self.C_TITLE),
] ]
## ##
+4 -7
View File
@@ -30,7 +30,7 @@ from enum import Enum
from PyQt6.QtCore import pyqtSlot from PyQt6.QtCore import pyqtSlot
from PyQt6.QtWidgets import QGridLayout, QLabel, QWidget from PyQt6.QtWidgets import QGridLayout, QLabel, QWidget
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.common import elide from novelwriter.common import elide
from novelwriter.constants import nwLabels, nwStats, trConst from novelwriter.constants import nwLabels, nwStats, trConst
from novelwriter.enum import nwChange from novelwriter.enum import nwChange
@@ -53,9 +53,6 @@ class GuiItemDetails(QWidget):
self._handle = None self._handle = None
# Sizes # Sizes
hSp = CONFIG.pxInt(6)
vSp = CONFIG.pxInt(1)
mPx = CONFIG.pxInt(6)
fPt = SHARED.theme.fontPointSize fPt = SHARED.theme.fontPointSize
fntLabel = self.font() fntLabel = self.font()
@@ -176,9 +173,9 @@ class GuiItemDetails(QWidget):
self.mainBox.setColumnStretch(3, 0) self.mainBox.setColumnStretch(3, 0)
self.mainBox.setColumnStretch(4, 0) self.mainBox.setColumnStretch(4, 0)
self.mainBox.setHorizontalSpacing(hSp) self.mainBox.setHorizontalSpacing(6)
self.mainBox.setVerticalSpacing(vSp) self.mainBox.setVerticalSpacing(1)
self.mainBox.setContentsMargins(mPx, mPx, mPx, mPx) self.mainBox.setContentsMargins(6, 6, 6, 6)
self.setLayout(self.mainBox) self.setLayout(self.mainBox)
+136 -136
View File
@@ -33,7 +33,7 @@ from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QMenuBar from PyQt6.QtWidgets import QMenuBar
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import openExternalPath, qtLambda from novelwriter.common import openExternalPath, qtAddAction, qtAddMenu, qtLambda
from novelwriter.constants import ( from novelwriter.constants import (
nwConst, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode, nwConst, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode,
trConst trConst
@@ -128,21 +128,21 @@ class GuiMainMenu(QMenuBar):
def _buildProjectMenu(self) -> None: def _buildProjectMenu(self) -> None:
"""Assemble the Project menu.""" """Assemble the Project menu."""
# Project # Project
self.projMenu = self.addMenu(self.tr("&Project")) self.projMenu = qtAddMenu(self, self.tr("&Project"))
# Project > Create or Open 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.setShortcut("Ctrl+Shift+O")
self.aOpenProject.triggered.connect(self.mainGui.showWelcomeDialog) self.aOpenProject.triggered.connect(self.mainGui.showWelcomeDialog)
# Project > Save Project # 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.setShortcut("Ctrl+Shift+S")
self.aSaveProject.triggered.connect(qtLambda(self.mainGui.saveProject)) self.aSaveProject.triggered.connect(qtLambda(self.mainGui.saveProject))
self.mainGui.addAction(self.aSaveProject) self.mainGui.addAction(self.aSaveProject)
# Project > Close Project # 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.setShortcut("Ctrl+Shift+W")
self.aCloseProject.triggered.connect(qtLambda(self.mainGui.closeProject, False)) self.aCloseProject.triggered.connect(qtLambda(self.mainGui.closeProject, False))
@@ -150,12 +150,12 @@ class GuiMainMenu(QMenuBar):
self.projMenu.addSeparator() self.projMenu.addSeparator()
# Project > Project Settings # 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.setShortcut("Ctrl+Shift+,")
self.aProjectSettings.triggered.connect(self.mainGui.showProjectSettingsDialog) self.aProjectSettings.triggered.connect(self.mainGui.showProjectSettingsDialog)
# Project > Novel Details # 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.setShortcut("Shift+F6")
self.aNovelDetails.triggered.connect(self.mainGui.showNovelDetailsDialog) self.aNovelDetails.triggered.connect(self.mainGui.showNovelDetailsDialog)
@@ -163,16 +163,16 @@ class GuiMainMenu(QMenuBar):
self.projMenu.addSeparator() self.projMenu.addSeparator()
# Project > Edit # Project > Edit
self.aRenameItem = self.projMenu.addAction(self.tr("Rename Item")) self.aRenameItem = qtAddAction(self.projMenu, self.tr("Rename Item"))
self.aRenameItem.setShortcut("F2") self.aRenameItem.setShortcut("F2")
# Project > Delete # 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.setShortcut("Del")
self.aDeleteItem.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) self.aDeleteItem.setShortcutContext(Qt.ShortcutContext.WidgetShortcut)
# Project > Empty Trash # 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.mainGui.projView.connectMenuActions(
self.aRenameItem, self.aDeleteItem, self.aEmptyTrash self.aRenameItem, self.aDeleteItem, self.aEmptyTrash
@@ -182,7 +182,7 @@ class GuiMainMenu(QMenuBar):
self.projMenu.addSeparator() self.projMenu.addSeparator()
# Project > Exit # 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.setShortcut("Ctrl+Q")
self.aExitNW.setMenuRole(QAction.MenuRole.QuitRole) self.aExitNW.setMenuRole(QAction.MenuRole.QuitRole)
self.aExitNW.triggered.connect(qtLambda(self.mainGui.closeMain)) self.aExitNW.triggered.connect(qtLambda(self.mainGui.closeMain))
@@ -193,21 +193,21 @@ class GuiMainMenu(QMenuBar):
def _buildDocumentMenu(self) -> None: def _buildDocumentMenu(self) -> None:
"""Assemble the Document menu.""" """Assemble the Document menu."""
# Document # Document
self.docuMenu = self.addMenu(self.tr("&Document")) self.docuMenu = qtAddMenu(self, self.tr("&Document"))
# Document > Open # 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.setShortcut("Ctrl+O")
self.aOpenDoc.triggered.connect(self.mainGui.openSelectedItem) self.aOpenDoc.triggered.connect(self.mainGui.openSelectedItem)
# Document > Save # 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.setShortcut("Ctrl+S")
self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument) self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument)
self.mainGui.addAction(self.aSaveDoc) self.mainGui.addAction(self.aSaveDoc)
# Document > Close # 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.setShortcut("Ctrl+W")
self.aCloseDoc.triggered.connect(self.mainGui.closeDocEditor) self.aCloseDoc.triggered.connect(self.mainGui.closeDocEditor)
self.mainGui.addAction(self.aCloseDoc) self.mainGui.addAction(self.aCloseDoc)
@@ -216,12 +216,12 @@ class GuiMainMenu(QMenuBar):
self.docuMenu.addSeparator() self.docuMenu.addSeparator()
# Document > Preview # 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.setShortcut("Ctrl+R")
self.aViewDoc.triggered.connect(qtLambda(self.mainGui.viewDocument, None)) self.aViewDoc.triggered.connect(qtLambda(self.mainGui.viewDocument, None))
# Document > Close Preview # 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.setShortcut("Ctrl+Shift+R")
self.aCloseView.triggered.connect(self.mainGui.closeDocViewer) self.aCloseView.triggered.connect(self.mainGui.closeDocViewer)
@@ -229,11 +229,11 @@ class GuiMainMenu(QMenuBar):
self.docuMenu.addSeparator() self.docuMenu.addSeparator()
# Document > Show File Details # 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)) self.aFileDetails.triggered.connect(qtLambda(self.mainGui.docEditor.revealLocation))
# Document > Import From File # 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)) self.aImportFile.triggered.connect(qtLambda(self.mainGui.importDocument))
return return
@@ -241,10 +241,10 @@ class GuiMainMenu(QMenuBar):
def _buildEditMenu(self) -> None: def _buildEditMenu(self) -> None:
"""Assemble the Edit menu.""" """Assemble the Edit menu."""
# Edit # Edit
self.editMenu = self.addMenu(self.tr("&Edit")) self.editMenu = qtAddMenu(self, self.tr("&Edit"))
# Edit > Undo # 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.setShortcut("Ctrl+Z")
self.aEditUndo.triggered.connect( self.aEditUndo.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.UNDO) lambda: self.requestDocAction.emit(nwDocAction.UNDO)
@@ -252,7 +252,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aEditUndo) self.mainGui.addAction(self.aEditUndo)
# Edit > Redo # 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.setShortcut("Ctrl+Y")
self.aEditRedo.triggered.connect( self.aEditRedo.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.REDO) lambda: self.requestDocAction.emit(nwDocAction.REDO)
@@ -263,7 +263,7 @@ class GuiMainMenu(QMenuBar):
self.editMenu.addSeparator() self.editMenu.addSeparator()
# Edit > Cut # 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.setShortcut("Ctrl+X")
self.aEditCut.triggered.connect( self.aEditCut.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.CUT) lambda: self.requestDocAction.emit(nwDocAction.CUT)
@@ -271,7 +271,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aEditCut) self.mainGui.addAction(self.aEditCut)
# Edit > Copy # 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.setShortcut("Ctrl+C")
self.aEditCopy.triggered.connect( self.aEditCopy.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.COPY) lambda: self.requestDocAction.emit(nwDocAction.COPY)
@@ -279,7 +279,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aEditCopy) self.mainGui.addAction(self.aEditCopy)
# Edit > Paste # 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.setShortcut("Ctrl+V")
self.aEditPaste.triggered.connect( self.aEditPaste.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.PASTE) lambda: self.requestDocAction.emit(nwDocAction.PASTE)
@@ -290,7 +290,7 @@ class GuiMainMenu(QMenuBar):
self.editMenu.addSeparator() self.editMenu.addSeparator()
# Edit > Select All # 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.setShortcut("Ctrl+A")
self.aSelectAll.triggered.connect( self.aSelectAll.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL) lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL)
@@ -298,7 +298,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aSelectAll) self.mainGui.addAction(self.aSelectAll)
# Edit > Select Paragraph # 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.setShortcut("Ctrl+Shift+A")
self.aSelectPar.triggered.connect( self.aSelectPar.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA) lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA)
@@ -310,24 +310,24 @@ class GuiMainMenu(QMenuBar):
def _buildViewMenu(self) -> None: def _buildViewMenu(self) -> None:
"""Assemble the View menu.""" """Assemble the View menu."""
# View # View
self.viewMenu = self.addMenu(self.tr("&View")) self.viewMenu = qtAddMenu(self, self.tr("&View"))
# View > TreeView # 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.setShortcut("Ctrl+T")
self.aFocusTree.triggered.connect( self.aFocusTree.triggered.connect(
lambda: self.requestFocusChange.emit(nwFocus.TREE) lambda: self.requestFocusChange.emit(nwFocus.TREE)
) )
# View > Document Editor # 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.setShortcut("Ctrl+E")
self.aFocusDocument.triggered.connect( self.aFocusDocument.triggered.connect(
lambda: self.requestFocusChange.emit(nwFocus.DOCUMENT) lambda: self.requestFocusChange.emit(nwFocus.DOCUMENT)
) )
# View > Outline # 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.setShortcut("Ctrl+Shift+T")
self.aFocusOutline.triggered.connect( self.aFocusOutline.triggered.connect(
lambda: self.requestFocusChange.emit(nwFocus.OUTLINE) lambda: self.requestFocusChange.emit(nwFocus.OUTLINE)
@@ -337,14 +337,14 @@ class GuiMainMenu(QMenuBar):
self.viewMenu.addSeparator() self.viewMenu.addSeparator()
# View > Go Backward # 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.setShortcut("Alt+Left")
self.aViewPrev.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) self.aViewPrev.setShortcutContext(Qt.ShortcutContext.WidgetShortcut)
self.aViewPrev.triggered.connect(self.mainGui.docViewer.navBackward) self.aViewPrev.triggered.connect(self.mainGui.docViewer.navBackward)
self.mainGui.docViewer.addAction(self.aViewPrev) self.mainGui.docViewer.addAction(self.aViewPrev)
# View > Go Forward # 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.setShortcut("Alt+Right")
self.aViewNext.setShortcutContext(Qt.ShortcutContext.WidgetShortcut) self.aViewNext.setShortcutContext(Qt.ShortcutContext.WidgetShortcut)
self.aViewNext.triggered.connect(self.mainGui.docViewer.navForward) self.aViewNext.triggered.connect(self.mainGui.docViewer.navForward)
@@ -354,13 +354,13 @@ class GuiMainMenu(QMenuBar):
self.viewMenu.addSeparator() self.viewMenu.addSeparator()
# View > Focus Mode # 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.setShortcut("F8")
self.aFocusMode.triggered.connect(self.mainGui.toggleFocusMode) self.aFocusMode.triggered.connect(self.mainGui.toggleFocusMode)
self.mainGui.addAction(self.aFocusMode) self.mainGui.addAction(self.aFocusMode)
# View > Toggle Full Screen # 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.setShortcut("F11")
self.aFullScreen.triggered.connect(self.mainGui.toggleFullScreenMode) self.aFullScreen.triggered.connect(self.mainGui.toggleFullScreenMode)
self.mainGui.addAction(self.aFullScreen) self.mainGui.addAction(self.aFullScreen)
@@ -370,13 +370,13 @@ class GuiMainMenu(QMenuBar):
def _buildInsertMenu(self) -> None: def _buildInsertMenu(self) -> None:
"""Assemble the Insert menu.""" """Assemble the Insert menu."""
# Insert # Insert
self.insMenu = self.addMenu(self.tr("&Insert")) self.insMenu = qtAddMenu(self, self.tr("&Insert"))
# Insert > Dashes and Dots # Insert > Dashes and Dots
self.mInsDashes = self.insMenu.addMenu(self.tr("Dashes")) self.mInsDashes = qtAddMenu(self.insMenu, self.tr("Dashes"))
# Insert > Short Dash # 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.setShortcut("Ctrl+K, -")
self.aInsENDash.triggered.connect( self.aInsENDash.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_ENDASH) lambda: self.requestDocInsertText.emit(nwUnicode.U_ENDASH)
@@ -384,7 +384,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsENDash) self.mainGui.addAction(self.aInsENDash)
# Insert > Long Dash # 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.setShortcut("Ctrl+K, _")
self.aInsEMDash.triggered.connect( self.aInsEMDash.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_EMDASH) lambda: self.requestDocInsertText.emit(nwUnicode.U_EMDASH)
@@ -392,7 +392,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsEMDash) self.mainGui.addAction(self.aInsEMDash)
# Insert > Long Dash # 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.setShortcut("Ctrl+K, Ctrl+_")
self.aInsHorBar.triggered.connect( self.aInsHorBar.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_HBAR) lambda: self.requestDocInsertText.emit(nwUnicode.U_HBAR)
@@ -400,7 +400,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsHorBar) self.mainGui.addAction(self.aInsHorBar)
# Insert > Figure Dash # 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.setShortcut("Ctrl+K, ~")
self.aInsFigDash.triggered.connect( self.aInsFigDash.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_FGDASH) lambda: self.requestDocInsertText.emit(nwUnicode.U_FGDASH)
@@ -408,10 +408,10 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsFigDash) self.mainGui.addAction(self.aInsFigDash)
# Insert > Quote Marks # 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 # 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.setShortcut("Ctrl+K, 1")
self.aInsQuoteLS.triggered.connect( self.aInsQuoteLS.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LS) lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LS)
@@ -419,7 +419,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsQuoteLS) self.mainGui.addAction(self.aInsQuoteLS)
# Insert > Right Single Quote # 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.setShortcut("Ctrl+K, 2")
self.aInsQuoteRS.triggered.connect( self.aInsQuoteRS.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RS) lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RS)
@@ -427,7 +427,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsQuoteRS) self.mainGui.addAction(self.aInsQuoteRS)
# Insert > Left Double Quote # 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.setShortcut("Ctrl+K, 3")
self.aInsQuoteLD.triggered.connect( self.aInsQuoteLD.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LD) lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LD)
@@ -435,7 +435,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsQuoteLD) self.mainGui.addAction(self.aInsQuoteLD)
# Insert > Right Double Quote # 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.setShortcut("Ctrl+K, 4")
self.aInsQuoteRD.triggered.connect( self.aInsQuoteRD.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RD) lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RD)
@@ -443,7 +443,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsQuoteRD) self.mainGui.addAction(self.aInsQuoteRD)
# Insert > Alternative Apostrophe # 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.setShortcut("Ctrl+K, '")
self.aInsMSApos.triggered.connect( self.aInsMSApos.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_MAPOS) lambda: self.requestDocInsertText.emit(nwUnicode.U_MAPOS)
@@ -451,10 +451,10 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsMSApos) self.mainGui.addAction(self.aInsMSApos)
# Insert > Symbols # Insert > Symbols
self.mInsPunct = self.insMenu.addMenu(self.tr("General Punctuation")) self.mInsPunct = qtAddMenu(self.insMenu, self.tr("General Punctuation"))
# Insert > Ellipsis # 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.setShortcut("Ctrl+K, .")
self.aInsEllipsis.triggered.connect( self.aInsEllipsis.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_HELLIP) lambda: self.requestDocInsertText.emit(nwUnicode.U_HELLIP)
@@ -462,7 +462,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsEllipsis) self.mainGui.addAction(self.aInsEllipsis)
# Insert > Prime # 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.setShortcut("Ctrl+K, Ctrl+'")
self.aInsPrime.triggered.connect( self.aInsPrime.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_PRIME) lambda: self.requestDocInsertText.emit(nwUnicode.U_PRIME)
@@ -470,7 +470,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsPrime) self.mainGui.addAction(self.aInsPrime)
# Insert > Double Prime # 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.setShortcut("Ctrl+K, Ctrl+\"")
self.aInsDPrime.triggered.connect( self.aInsDPrime.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_DPRIME) lambda: self.requestDocInsertText.emit(nwUnicode.U_DPRIME)
@@ -478,10 +478,10 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsDPrime) self.mainGui.addAction(self.aInsDPrime)
# Insert > White Spaces # 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 # 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.setShortcut("Ctrl+K, Space")
self.aInsNBSpace.triggered.connect( self.aInsNBSpace.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_NBSP) lambda: self.requestDocInsertText.emit(nwUnicode.U_NBSP)
@@ -489,7 +489,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsNBSpace) self.mainGui.addAction(self.aInsNBSpace)
# Insert > Thin Space # 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.setShortcut("Ctrl+K, Shift+Space")
self.aInsThinSpace.triggered.connect( self.aInsThinSpace.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_THSP) lambda: self.requestDocInsertText.emit(nwUnicode.U_THSP)
@@ -497,7 +497,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsThinSpace) self.mainGui.addAction(self.aInsThinSpace)
# Insert > Thin Non-Breaking Space # 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.setShortcut("Ctrl+K, Ctrl+Space")
self.aInsThinNBSpace.triggered.connect( self.aInsThinNBSpace.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_THNBSP) lambda: self.requestDocInsertText.emit(nwUnicode.U_THNBSP)
@@ -505,10 +505,10 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsThinNBSpace) self.mainGui.addAction(self.aInsThinNBSpace)
# Insert > Symbols # Insert > Symbols
self.mInsSymbol = self.insMenu.addMenu(self.tr("Other Symbols")) self.mInsSymbol = qtAddMenu(self.insMenu, self.tr("Other Symbols"))
# Insert > List Bullet # 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.setShortcut("Ctrl+K, *")
self.aInsBullet.triggered.connect( self.aInsBullet.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_BULL) lambda: self.requestDocInsertText.emit(nwUnicode.U_BULL)
@@ -516,7 +516,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsBullet) self.mainGui.addAction(self.aInsBullet)
# Insert > Hyphen Bullet # 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.setShortcut("Ctrl+K, Ctrl+-")
self.aInsHyBull.triggered.connect( self.aInsHyBull.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_HYBULL) lambda: self.requestDocInsertText.emit(nwUnicode.U_HYBULL)
@@ -524,7 +524,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsHyBull) self.mainGui.addAction(self.aInsHyBull)
# Insert > Flower Mark # 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.setShortcut("Ctrl+K, Ctrl+*")
self.aInsFlower.triggered.connect( self.aInsFlower.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_FLOWER) lambda: self.requestDocInsertText.emit(nwUnicode.U_FLOWER)
@@ -532,7 +532,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsFlower) self.mainGui.addAction(self.aInsFlower)
# Insert > Per Mille # 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.setShortcut("Ctrl+K, %")
self.aInsPerMille.triggered.connect( self.aInsPerMille.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_PERMIL) lambda: self.requestDocInsertText.emit(nwUnicode.U_PERMIL)
@@ -540,7 +540,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsPerMille) self.mainGui.addAction(self.aInsPerMille)
# Insert > Degree Symbol # 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.setShortcut("Ctrl+K, Ctrl+O")
self.aInsDegree.triggered.connect( self.aInsDegree.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_DEGREE) lambda: self.requestDocInsertText.emit(nwUnicode.U_DEGREE)
@@ -548,7 +548,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsDegree) self.mainGui.addAction(self.aInsDegree)
# Insert > Minus Sign # 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.setShortcut("Ctrl+K, Ctrl+M")
self.aInsMinus.triggered.connect( self.aInsMinus.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_MINUS) lambda: self.requestDocInsertText.emit(nwUnicode.U_MINUS)
@@ -556,7 +556,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsMinus) self.mainGui.addAction(self.aInsMinus)
# Insert > Times Sign # 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.setShortcut("Ctrl+K, Ctrl+X")
self.aInsTimes.triggered.connect( self.aInsTimes.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_TIMES) lambda: self.requestDocInsertText.emit(nwUnicode.U_TIMES)
@@ -564,7 +564,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsTimes) self.mainGui.addAction(self.aInsTimes)
# Insert > Division # 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.setShortcut("Ctrl+K, Ctrl+D")
self.aInsDivide.triggered.connect( self.aInsDivide.triggered.connect(
lambda: self.requestDocInsertText.emit(nwUnicode.U_DIVIDE) lambda: self.requestDocInsertText.emit(nwUnicode.U_DIVIDE)
@@ -572,18 +572,18 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsDivide) self.mainGui.addAction(self.aInsDivide)
# Insert > Tags and References # 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: 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.setShortcut(nwLabels.KEY_SHORTCUT[key])
action.triggered.connect(qtLambda(self.requestDocKeyWordInsert.emit, key)) action.triggered.connect(qtLambda(self.requestDocKeyWordInsert.emit, key))
self.mainGui.addAction(action) self.mainGui.addAction(action)
# Insert > Special Comments # Insert > Special Comments
self.mInsComments = self.insMenu.addMenu(self.tr("Special Comments")) self.mInsComments = qtAddMenu(self.insMenu, self.tr("Special Comments"))
# Insert > Synopsis Comment # 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.setShortcut("Ctrl+K, S")
self.aInsSynopsis.triggered.connect( self.aInsSynopsis.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.SYNOPSIS) lambda: self.requestDocInsert.emit(nwDocInsert.SYNOPSIS)
@@ -591,7 +591,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsSynopsis) self.mainGui.addAction(self.aInsSynopsis)
# Insert > Short Description Comment # 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.setShortcut("Ctrl+K, H")
self.aInsShort.triggered.connect( self.aInsShort.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.SHORT) lambda: self.requestDocInsert.emit(nwDocInsert.SHORT)
@@ -599,47 +599,47 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aInsShort) self.mainGui.addAction(self.aInsShort)
# Insert > Word/Character Count # 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: for field in nwStats.ALL_FIELDS:
value = nwShortcode.FIELD_VALUE.format(field) 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)) action.triggered.connect(qtLambda(self.requestDocInsertText.emit, value))
# Insert > Breaks and Vertical Space # 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 # 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( self.aInsNewPage.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.NEW_PAGE) lambda: self.requestDocInsert.emit(nwDocInsert.NEW_PAGE)
) )
# Insert > Forced Line Break # 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( self.aInsLineBreak.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.LINE_BRK) lambda: self.requestDocInsert.emit(nwDocInsert.LINE_BRK)
) )
# Insert > Vertical Space (Single) # 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( self.aInsVSpaceS.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_S) lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_S)
) )
# Insert > Vertical Space (Multi) # 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( self.aInsVSpaceM.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_M) lambda: self.requestDocInsert.emit(nwDocInsert.VSPACE_M)
) )
# Insert > Placeholder Text # 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( self.aLipsumText.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.LIPSUM) lambda: self.requestDocInsert.emit(nwDocInsert.LIPSUM)
) )
# Insert > Footnote # Insert > Footnote
self.aFootnote = self.insMenu.addAction(self.tr("Footnote")) self.aFootnote = qtAddAction(self.insMenu, self.tr("Footnote"))
self.aFootnote.triggered.connect( self.aFootnote.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.FOOTNOTE) lambda: self.requestDocInsert.emit(nwDocInsert.FOOTNOTE)
) )
@@ -649,10 +649,10 @@ class GuiMainMenu(QMenuBar):
def _buildFormatMenu(self) -> None: def _buildFormatMenu(self) -> None:
"""Assemble the Format menu.""" """Assemble the Format menu."""
# Format # Format
self.fmtMenu = self.addMenu(self.tr("&Format")) self.fmtMenu = qtAddMenu(self, self.tr("&Format"))
# Format > Bold # 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.setShortcut("Ctrl+B")
self.aFmtBold.triggered.connect( self.aFmtBold.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD) lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD)
@@ -660,7 +660,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtBold) self.mainGui.addAction(self.aFmtBold)
# Format > Italic # 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.setShortcut("Ctrl+I")
self.aFmtItalic.triggered.connect( self.aFmtItalic.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC) lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC)
@@ -668,7 +668,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtItalic) self.mainGui.addAction(self.aFmtItalic)
# Format > Strikethrough # 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.setShortcut("Ctrl+D")
self.aFmtStrike.triggered.connect( self.aFmtStrike.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE) lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE)
@@ -679,7 +679,7 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Double Quotes # 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.setShortcut("Ctrl+\"")
self.aFmtDQuote.triggered.connect( self.aFmtDQuote.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.D_QUOTE) lambda: self.requestDocAction.emit(nwDocAction.D_QUOTE)
@@ -687,7 +687,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtDQuote) self.mainGui.addAction(self.aFmtDQuote)
# Format > Single Quotes # 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.setShortcut("Ctrl+'")
self.aFmtSQuote.triggered.connect( self.aFmtSQuote.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.S_QUOTE) lambda: self.requestDocAction.emit(nwDocAction.S_QUOTE)
@@ -698,46 +698,46 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Shortcodes # Shortcodes
self.mShortcodes = self.fmtMenu.addMenu(self.tr("More Formats ...")) self.mShortcodes = qtAddMenu(self.fmtMenu, self.tr("More Formats ..."))
# Shortcode Bold # Shortcode Bold
self.aScBold = self.mShortcodes.addAction(self.tr("Bold (Shortcode)")) self.aScBold = qtAddAction(self.mShortcodes, self.tr("Bold (Shortcode)"))
self.aScBold.triggered.connect( self.aScBold.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_BOLD) lambda: self.requestDocAction.emit(nwDocAction.SC_BOLD)
) )
# Shortcode Italic # Shortcode Italic
self.aScItalic = self.mShortcodes.addAction(self.tr("Italics (Shortcode)")) self.aScItalic = qtAddAction(self.mShortcodes, self.tr("Italics (Shortcode)"))
self.aScItalic.triggered.connect( self.aScItalic.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC) lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC)
) )
# Shortcode Strikethrough # Shortcode Strikethrough
self.aScStrike = self.mShortcodes.addAction(self.tr("Strikethrough (Shortcode)")) self.aScStrike = qtAddAction(self.mShortcodes, self.tr("Strikethrough (Shortcode)"))
self.aScStrike.triggered.connect( self.aScStrike.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_STRIKE) lambda: self.requestDocAction.emit(nwDocAction.SC_STRIKE)
) )
# Shortcode Underline # Shortcode Underline
self.aScULine = self.mShortcodes.addAction(self.tr("Underline")) self.aScULine = qtAddAction(self.mShortcodes, self.tr("Underline"))
self.aScULine.triggered.connect( self.aScULine.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE) lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
) )
# Shortcode Mark # Shortcode Mark
self.aScMark = self.mShortcodes.addAction(self.tr("Highlight")) self.aScMark = qtAddAction(self.mShortcodes, self.tr("Highlight"))
self.aScMark.triggered.connect( self.aScMark.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK) lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
) )
# Shortcode Superscript # Shortcode Superscript
self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript")) self.aScSuper = qtAddAction(self.mShortcodes, self.tr("Superscript"))
self.aScSuper.triggered.connect( self.aScSuper.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_SUP) lambda: self.requestDocAction.emit(nwDocAction.SC_SUP)
) )
# Shortcode Subscript # Shortcode Subscript
self.aScSub = self.mShortcodes.addAction(self.tr("Subscript")) self.aScSub = qtAddAction(self.mShortcodes, self.tr("Subscript"))
self.aScSub.triggered.connect( self.aScSub.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.SC_SUB) lambda: self.requestDocAction.emit(nwDocAction.SC_SUB)
) )
@@ -746,7 +746,7 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Heading 1 (Partition) # 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.setShortcut("Ctrl+1")
self.aFmtHead1.triggered.connect( self.aFmtHead1.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1)
@@ -754,7 +754,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtHead1) self.mainGui.addAction(self.aFmtHead1)
# Format > Heading 2 (Chapter) # 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.setShortcut("Ctrl+2")
self.aFmtHead2.triggered.connect( self.aFmtHead2.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2)
@@ -762,7 +762,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtHead2) self.mainGui.addAction(self.aFmtHead2)
# Format > Heading 3 (Scene) # 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.setShortcut("Ctrl+3")
self.aFmtHead3.triggered.connect( self.aFmtHead3.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3)
@@ -770,7 +770,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtHead3) self.mainGui.addAction(self.aFmtHead3)
# Format > Heading 4 (Section) # 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.setShortcut("Ctrl+4")
self.aFmtHead4.triggered.connect( self.aFmtHead4.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4)
@@ -781,19 +781,19 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Novel Title # 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( self.aFmtTitle.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TTL) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TTL)
) )
# Format > Unnumbered Chapter # 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( self.aFmtUnNum.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN)
) )
# Format > Alternative Scene # 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( self.aFmtHardSc.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_HSC) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_HSC)
) )
@@ -802,7 +802,7 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Align Left # 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.setShortcut("Ctrl+5")
self.aFmtAlignLeft.triggered.connect( self.aFmtAlignLeft.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.ALIGN_L) lambda: self.requestDocAction.emit(nwDocAction.ALIGN_L)
@@ -810,7 +810,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtAlignLeft) self.mainGui.addAction(self.aFmtAlignLeft)
# Format > Align Centre # 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.setShortcut("Ctrl+6")
self.aFmtAlignCentre.triggered.connect( self.aFmtAlignCentre.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.ALIGN_C) lambda: self.requestDocAction.emit(nwDocAction.ALIGN_C)
@@ -818,7 +818,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtAlignCentre) self.mainGui.addAction(self.aFmtAlignCentre)
# Format > Align Right # 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.setShortcut("Ctrl+7")
self.aFmtAlignRight.triggered.connect( self.aFmtAlignRight.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.ALIGN_R) lambda: self.requestDocAction.emit(nwDocAction.ALIGN_R)
@@ -829,7 +829,7 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Indent Left # 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.setShortcut("Ctrl+8")
self.aFmtIndentLeft.triggered.connect( self.aFmtIndentLeft.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.INDENT_L) lambda: self.requestDocAction.emit(nwDocAction.INDENT_L)
@@ -837,7 +837,7 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtIndentLeft) self.mainGui.addAction(self.aFmtIndentLeft)
# Format > Indent Right # 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.setShortcut("Ctrl+9")
self.aFmtIndentRight.triggered.connect( self.aFmtIndentRight.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.INDENT_R) lambda: self.requestDocAction.emit(nwDocAction.INDENT_R)
@@ -848,7 +848,7 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Comment # 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.setShortcut("Ctrl+/")
self.aFmtComment.triggered.connect( self.aFmtComment.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_COM) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_COM)
@@ -856,14 +856,14 @@ class GuiMainMenu(QMenuBar):
self.mainGui.addAction(self.aFmtComment) self.mainGui.addAction(self.aFmtComment)
# Format > Ignore Text # 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.setShortcut("Ctrl+Shift+D")
self.aFmtIgnore.triggered.connect( self.aFmtIgnore.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_IGN) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_IGN)
) )
# Format > Remove Block Format # 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.setShortcuts(["Ctrl+0", "Ctrl+Shift+/"])
self.aFmtNoFormat.triggered.connect( self.aFmtNoFormat.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TXT) lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TXT)
@@ -874,19 +874,19 @@ class GuiMainMenu(QMenuBar):
self.fmtMenu.addSeparator() self.fmtMenu.addSeparator()
# Format > Replace Straight Single Quotes # 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( self.aFmtReplSng.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.REPL_SNG) lambda: self.requestDocAction.emit(nwDocAction.REPL_SNG)
) )
# Format > Replace Straight Double Quotes # 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( self.aFmtReplDbl.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.REPL_DBL) lambda: self.requestDocAction.emit(nwDocAction.REPL_DBL)
) )
# Format > Remove In-Paragraph Breaks # 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( self.aFmtRmBreaks.triggered.connect(
lambda: self.requestDocAction.emit(nwDocAction.RM_BREAKS) lambda: self.requestDocAction.emit(nwDocAction.RM_BREAKS)
) )
@@ -896,28 +896,28 @@ class GuiMainMenu(QMenuBar):
def _buildSearchMenu(self) -> None: def _buildSearchMenu(self) -> None:
"""Assemble the Search menu.""" """Assemble the Search menu."""
# Search # Search
self.srcMenu = self.addMenu(self.tr("&Search")) self.srcMenu = qtAddMenu(self, self.tr("&Search"))
# Search > Find # 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.setShortcut("Ctrl+F")
self.aFind.triggered.connect(qtLambda(self.mainGui.docEditor.beginSearch)) self.aFind.triggered.connect(qtLambda(self.mainGui.docEditor.beginSearch))
self.mainGui.addAction(self.aFind) self.mainGui.addAction(self.aFind)
# Search > Replace # 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.setShortcut("Ctrl+=" if CONFIG.osDarwin else "Ctrl+H")
self.aReplace.triggered.connect(qtLambda(self.mainGui.docEditor.beginReplace)) self.aReplace.triggered.connect(qtLambda(self.mainGui.docEditor.beginReplace))
self.mainGui.addAction(self.aReplace) self.mainGui.addAction(self.aReplace)
# Search > Find Next # 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.setShortcuts(["Ctrl+G", "F3"] if CONFIG.osDarwin else ["F3", "Ctrl+G"])
self.aFindNext.triggered.connect(qtLambda(self.mainGui.docEditor.findNext)) self.aFindNext.triggered.connect(qtLambda(self.mainGui.docEditor.findNext))
self.mainGui.addAction(self.aFindNext) self.mainGui.addAction(self.aFindNext)
# Search > Find Prev # Search > Find Prev
self.aFindPrev = self.srcMenu.addAction(self.tr("Find Previous")) self.aFindPrev = qtAddAction(self.srcMenu, self.tr("Find Previous"))
self.aFindPrev.setShortcuts( self.aFindPrev.setShortcuts(
["Ctrl+Shift+G", "Shift+F3"] if CONFIG.osDarwin else ["Shift+F3", "Ctrl+Shift+G"] ["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) self.mainGui.addAction(self.aFindPrev)
# Search > Replace Next # 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.setShortcut("Ctrl+Shift+1")
self.aReplaceNext.triggered.connect(qtLambda(self.mainGui.docEditor.replaceNext)) self.aReplaceNext.triggered.connect(qtLambda(self.mainGui.docEditor.replaceNext))
self.mainGui.addAction(self.aReplaceNext) self.mainGui.addAction(self.aReplaceNext)
@@ -934,7 +934,7 @@ class GuiMainMenu(QMenuBar):
self.srcMenu.addSeparator() self.srcMenu.addSeparator()
# Search > Find in Project # 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.setShortcut("Ctrl+Shift+F")
self.aFindProj.triggered.connect(lambda: self.requestViewChange.emit(nwView.SEARCH)) self.aFindProj.triggered.connect(lambda: self.requestViewChange.emit(nwView.SEARCH))
@@ -943,17 +943,17 @@ class GuiMainMenu(QMenuBar):
def _buildToolsMenu(self) -> None: def _buildToolsMenu(self) -> None:
"""Assemble the Tools menu.""" """Assemble the Tools menu."""
# Tools # Tools
self.toolsMenu = self.addMenu(self.tr("&Tools")) self.toolsMenu = qtAddMenu(self, self.tr("&Tools"))
# Tools > Check Spelling # 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.setCheckable(True)
self.aSpellCheck.setChecked(SHARED.project.data.spellCheck) self.aSpellCheck.setChecked(SHARED.project.data.spellCheck)
self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled! self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled!
self.aSpellCheck.setShortcut("Ctrl+F7") self.aSpellCheck.setShortcut("Ctrl+F7")
self.mainGui.addAction(self.aSpellCheck) 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 = SHARED.spelling.listDictionaries()
languages.insert(0, ("None", self.tr("Default"))) languages.insert(0, ("None", self.tr("Default")))
for n, (tag, language) in enumerate(languages): for n, (tag, language) in enumerate(languages):
@@ -963,25 +963,25 @@ class GuiMainMenu(QMenuBar):
self.mSelectLanguage.addAction(aSpell) self.mSelectLanguage.addAction(aSpell)
# Tools > Re-Run Spell Check # 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.setShortcut("F7")
self.aReRunSpell.triggered.connect(qtLambda(self.mainGui.docEditor.spellCheckDocument)) self.aReRunSpell.triggered.connect(qtLambda(self.mainGui.docEditor.spellCheckDocument))
self.mainGui.addAction(self.aReRunSpell) self.mainGui.addAction(self.aReRunSpell)
# Tools > Project Word List # 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) self.aEditWordList.triggered.connect(self.mainGui.showProjectWordListDialog)
# Tools > Add Dictionaries # Tools > Add Dictionaries
if CONFIG.osWindows or CONFIG.isDebug: 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) self.aAddDicts.triggered.connect(self.mainGui.showDictionariesDialog)
# Tools > Separator # Tools > Separator
self.toolsMenu.addSeparator() self.toolsMenu.addSeparator()
# Tools > Rebuild Index # 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.setShortcut("F9")
self.aRebuildIndex.triggered.connect(qtLambda(self.mainGui.rebuildIndex)) self.aRebuildIndex.triggered.connect(qtLambda(self.mainGui.rebuildIndex))
@@ -989,21 +989,21 @@ class GuiMainMenu(QMenuBar):
self.toolsMenu.addSeparator() self.toolsMenu.addSeparator()
# Tools > Backup Project # 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)) self.aBackupProject.triggered.connect(qtLambda(SHARED.project.backupProject, True))
# Tools > Build Manuscript # 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.setShortcut("F5")
self.aBuildManuscript.triggered.connect(self.mainGui.showBuildManuscriptDialog) self.aBuildManuscript.triggered.connect(self.mainGui.showBuildManuscriptDialog)
# Tools > Writing Statistics # 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.setShortcut("F6")
self.aWritingStats.triggered.connect(self.mainGui.showWritingStatsDialog) self.aWritingStats.triggered.connect(self.mainGui.showWritingStatsDialog)
# Tools > Preferences # Tools > Preferences
self.aPreferences = self.toolsMenu.addAction(self.tr("Preferences")) self.aPreferences = qtAddAction(self.toolsMenu, self.tr("Preferences"))
self.aPreferences.setShortcut("Ctrl+,") self.aPreferences.setShortcut("Ctrl+,")
self.aPreferences.setMenuRole(QAction.MenuRole.PreferencesRole) self.aPreferences.setMenuRole(QAction.MenuRole.PreferencesRole)
self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog) self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog)
@@ -1014,15 +1014,15 @@ class GuiMainMenu(QMenuBar):
def _buildHelpMenu(self) -> None: def _buildHelpMenu(self) -> None:
"""Assemble the Help menu.""" """Assemble the Help menu."""
# Help # Help
self.helpMenu = self.addMenu(self.tr("&Help")) self.helpMenu = qtAddMenu(self, self.tr("&Help"))
# Help > About # 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.setMenuRole(QAction.MenuRole.AboutRole)
self.aAboutNW.triggered.connect(self.mainGui.showAboutNWDialog) self.aAboutNW.triggered.connect(self.mainGui.showAboutNWDialog)
# Help > About Qt # 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.setMenuRole(QAction.MenuRole.AboutQtRole)
self.aAboutQt.triggered.connect(self.mainGui.showAboutQtDialog) self.aAboutQt.triggered.connect(self.mainGui.showAboutQtDialog)
@@ -1030,14 +1030,14 @@ class GuiMainMenu(QMenuBar):
self.helpMenu.addSeparator() self.helpMenu.addSeparator()
# Help > User Manual (Online) # 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.setShortcut("F1")
self.aHelpDocs.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_DOCS)) self.aHelpDocs.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_DOCS))
self.mainGui.addAction(self.aHelpDocs) self.mainGui.addAction(self.aHelpDocs)
# Help > User Manual (PDF) # Help > User Manual (PDF)
if isinstance(CONFIG.pdfDocs, Path): 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.setShortcut("Shift+F1")
self.aPdfDocs.triggered.connect(self._openUserManualFile) self.aPdfDocs.triggered.connect(self._openUserManualFile)
self.mainGui.addAction(self.aPdfDocs) self.mainGui.addAction(self.aPdfDocs)
@@ -1046,15 +1046,15 @@ class GuiMainMenu(QMenuBar):
self.helpMenu.addSeparator() self.helpMenu.addSeparator()
# Document > Report an Issue # 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)) self.aIssue.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_REPORT))
# Document > Ask a Question # 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)) self.aQuestion.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_HELP))
# Document > Main Website # 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)) self.aWebsite.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_WEB))
return return
+18 -18
View File
@@ -38,7 +38,7 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwKeyWords, nwLabels, nwStyles, trConst
from novelwriter.core.index import IndexHeading from novelwriter.core.index import IndexHeading
from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline
@@ -199,7 +199,6 @@ class GuiNovelToolBar(QWidget):
self.novelView = novelView self.novelView = novelView
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(2)
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
@@ -211,7 +210,7 @@ class GuiNovelToolBar(QWidget):
self.novelValue = NovelSelector(self) self.novelValue = NovelSelector(self)
self.novelValue.setFont(selFont) self.novelValue.setFont(selFont)
self.novelValue.setListFormat(self.tr("Outline of {0}")) 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.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot) self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
@@ -227,7 +226,7 @@ class GuiNovelToolBar(QWidget):
# More Options Menu # More Options Menu
self.mMore = QMenu(self) 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.gLastCol = QActionGroup(self.mMore)
self.aLastCol = {} self.aLastCol = {}
self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden")) self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden"))
@@ -236,7 +235,7 @@ class GuiNovelToolBar(QWidget):
self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot")) self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot"))
self.mLastCol.addSeparator() 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.aLastColSize.triggered.connect(self._selectLastColumnSize)
self.tbMore = NIconToolButton(self, iSz) self.tbMore = NIconToolButton(self, iSz)
@@ -249,7 +248,7 @@ class GuiNovelToolBar(QWidget):
self.outerBox.addWidget(self.tbNovel) self.outerBox.addWidget(self.tbNovel)
self.outerBox.addWidget(self.tbRefresh) self.outerBox.addWidget(self.tbRefresh)
self.outerBox.addWidget(self.tbMore) self.outerBox.addWidget(self.tbMore)
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx) self.outerBox.setContentsMargins(2, 2, 0, 2)
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -343,7 +342,7 @@ class GuiNovelToolBar(QWidget):
def _addLastColAction(self, colType: NovelTreeColumn, actionLabel: str) -> None: def _addLastColAction(self, colType: NovelTreeColumn, actionLabel: str) -> None:
"""Add a column selection entry to the last column menu.""" """Add a column selection entry to the last column menu."""
aLast = self.mLastCol.addAction(actionLabel) aLast = qtAddAction(self.mLastCol, actionLabel)
aLast.setCheckable(True) aLast.setCheckable(True)
aLast.setActionGroup(self.gLastCol) aLast.setActionGroup(self.gLastCol)
aLast.triggered.connect(qtLambda(self.setLastColType, colType)) aLast.triggered.connect(qtLambda(self.setLastColType, colType))
@@ -388,7 +387,6 @@ class GuiNovelTree(QTreeWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
cMg = CONFIG.pxInt(6)
self.setIconSize(iSz) self.setIconSize(iSz)
self.setFrameStyle(QFrame.Shape.NoFrame) self.setFrameStyle(QFrame.Shape.NoFrame)
@@ -403,13 +401,13 @@ class GuiNovelTree(QTreeWidget):
self.setDragEnabled(False) self.setDragEnabled(False)
# Lock the column sizes # Lock the column sizes
treeHeader = self.header() if header := self.header():
treeHeader.setStretchLastSection(False) header.setStretchLastSection(False)
treeHeader.setMinimumSectionSize(iPx + cMg) header.setMinimumSectionSize(iPx + 6)
treeHeader.setSectionResizeMode(self.C_TITLE, QtHeaderStretch) header.setSectionResizeMode(self.C_TITLE, QtHeaderStretch)
treeHeader.setSectionResizeMode(self.C_WORDS, QtHeaderToContents) header.setSectionResizeMode(self.C_WORDS, QtHeaderToContents)
treeHeader.setSectionResizeMode(self.C_EXTRA, QtHeaderToContents) header.setSectionResizeMode(self.C_EXTRA, QtHeaderToContents)
treeHeader.setSectionResizeMode(self.C_MORE, QtHeaderToContents) header.setSectionResizeMode(self.C_MORE, QtHeaderToContents)
# Pre-Generate Tree Formatting # Pre-Generate Tree Formatting
fH1 = self.font() fH1 = self.font()
@@ -678,8 +676,9 @@ class GuiNovelTree(QTreeWidget):
return return
def _updateTreeItemValues(self, trItem: QTreeWidgetItem, idxItem: IndexHeading, def _updateTreeItemValues(
tHandle: str, sTitle: str) -> None: self, trItem: QTreeWidgetItem, idxItem: IndexHeading, tHandle: str, sTitle: str
) -> None:
"""Set the tree item values from the index entry.""" """Set the tree item values from the index entry."""
iLevel = nwStyles.H_LEVEL.get(idxItem.level, 0) iLevel = nwStyles.H_LEVEL.get(idxItem.level, 0)
hDec = SHARED.theme.getHeaderDecoration(iLevel) hDec = SHARED.theme.getHeaderDecoration(iLevel)
@@ -691,7 +690,8 @@ class GuiNovelTree(QTreeWidget):
trItem.setData(self.C_MORE, QtDecoration, self._pMore) trItem.setData(self.C_MORE, QtDecoration, self._pMore)
# Custom column # 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) lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW) elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW)
trItem.setText(self.C_EXTRA, elideText) trItem.setText(self.C_EXTRA, elideText)
+30 -39
View File
@@ -78,7 +78,7 @@ class GuiOutlineView(QWidget):
# Assemble # Assemble
self.outerBox = QVBoxLayout() 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.outlineBar)
self.outerBox.addWidget(self.splitOutline) self.outerBox.addWidget(self.splitOutline)
@@ -225,11 +225,11 @@ class GuiOutlineToolBar(QToolBar):
self.novelLabel = NColourLabel( self.novelLabel = NColourLabel(
self.tr("Outline of"), self, scale=NColourLabel.HEADER_SCALE, bold=True 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 = NovelSelector(self)
self.novelValue.setIncludeAll(True) self.novelValue.setIncludeAll(True)
self.novelValue.setMinimumWidth(CONFIG.pxInt(200)) self.novelValue.setMinimumWidth(200)
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged) self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
# Actions # Actions
@@ -390,8 +390,8 @@ class GuiOutlineTree(QTreeWidget):
self.setIconSize(SHARED.theme.baseIconSize) self.setIconSize(SHARED.theme.baseIconSize)
self.setIndentation(0) self.setIndentation(0)
self.treeHead = self.header() if header := self.header():
self.treeHead.sectionMoved.connect(self._columnMoved) header.sectionMoved.connect(self._columnMoved)
# Pre-Generate Tree Formatting # Pre-Generate Tree Formatting
fH1 = self.font() fH1 = self.font()
@@ -623,7 +623,7 @@ class GuiOutlineTree(QTreeWidget):
continue continue
tmpOrder.append(nwOutline[name]) tmpOrder.append(nwOutline[name])
tmpHidden[nwOutline[name]] = hidden tmpHidden[nwOutline[name]] = hidden
tmpWidth[nwOutline[name]] = CONFIG.pxInt(width) tmpWidth[nwOutline[name]] = width
except Exception: except Exception:
logger.error("Invalid column state") logger.error("Invalid column state")
logException() logException()
@@ -647,26 +647,22 @@ class GuiOutlineTree(QTreeWidget):
save the current width of hidden columns though. This preserves save the current width of hidden columns though. This preserves
the last known width in case they're unhidden again. 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 and (header := self.header()):
if self._lastBuild == 0: colState = {}
return for iCol in range(self.columnCount()):
hItem = self._treeOrder[iCol]
colState = {} iLog = header.logicalIndex(iCol)
for iCol in range(self.columnCount()): logHidden = self.isColumnHidden(iLog)
hItem = self._treeOrder[iCol] orgWidth = self._colWidth[hItem]
iLog = self.treeHead.logicalIndex(iCol) logWidth = self.columnWidth(iLog)
logHidden = self.isColumnHidden(iLog) colState[hItem.name] = [
orgWidth = CONFIG.rpxInt(self._colWidth[hItem]) logHidden, orgWidth if logHidden and logWidth == 0 else logWidth
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()
logger.debug("Saving State: GuiOutline")
pOptions = SHARED.project.options
pOptions.setValue("GuiOutline", "columnState", colState)
pOptions.saveSettings()
return return
def _populateTree(self, rootHandle: str | None) -> None: def _populateTree(self, rootHandle: str | None) -> None:
@@ -819,8 +815,6 @@ class GuiOutlineDetails(QScrollArea):
minTitle = 30*SHARED.theme.textNWidth minTitle = 30*SHARED.theme.textNWidth
maxTitle = 40*SHARED.theme.textNWidth maxTitle = 40*SHARED.theme.textNWidth
wCount = SHARED.theme.getTextWidth("999,999") wCount = SHARED.theme.getTextWidth("999,999")
hSpace = int(CONFIG.pxInt(10))
vSpace = int(CONFIG.pxInt(4))
bFont = SHARED.theme.guiFontB bFont = SHARED.theme.guiFontB
@@ -899,8 +893,8 @@ class GuiOutlineDetails(QScrollArea):
self.mainForm.setColumnStretch(1, 1) self.mainForm.setColumnStretch(1, 1)
self.mainForm.setRowStretch(4, 1) self.mainForm.setRowStretch(4, 1)
self.mainForm.setHorizontalSpacing(hSpace) self.mainForm.setHorizontalSpacing(10)
self.mainForm.setVerticalSpacing(vSpace) self.mainForm.setVerticalSpacing(4)
# Selected Item Tags # Selected Item Tags
self.tagsForm = QGridLayout() self.tagsForm = QGridLayout()
@@ -923,8 +917,8 @@ class GuiOutlineDetails(QScrollArea):
self.tagsForm.setColumnStretch(1, 1) self.tagsForm.setColumnStretch(1, 1)
self.tagsForm.setRowStretch(len(self.tagValues), 1) self.tagsForm.setRowStretch(len(self.tagValues), 1)
self.tagsForm.setHorizontalSpacing(hSpace) self.tagsForm.setHorizontalSpacing(10)
self.tagsForm.setVerticalSpacing(vSpace) self.tagsForm.setVerticalSpacing(4)
# Assemble # Assemble
self.mainSplit = QSplitter(Qt.Orientation.Horizontal) self.mainSplit = QSplitter(Qt.Orientation.Horizontal)
@@ -965,21 +959,18 @@ class GuiOutlineDetails(QScrollArea):
width = parent.width() if isinstance(parent, QWidget) else 1000 width = parent.width() if isinstance(parent, QWidget) else 1000
pOptions = SHARED.project.options pOptions = SHARED.project.options
self.mainSplit.setSizes([ self.mainSplit.setSizes([
CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3)), pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3),
CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3)) pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3),
]) ])
return return
def saveGuiSettings(self) -> None: def saveGuiSettings(self) -> None:
"""Run close project tasks.""" """Run close project tasks."""
mainSplit = self.mainSplit.sizes()
detailsWidth = CONFIG.rpxInt(mainSplit[0])
tagsWidth = CONFIG.rpxInt(mainSplit[1])
logger.debug("Saving State: GuiOutlineDetails") logger.debug("Saving State: GuiOutlineDetails")
mainSplit = self.mainSplit.sizes()
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiOutlineDetails", "detailsWidth", detailsWidth) pOptions.setValue("GuiOutlineDetails", "detailsWidth", mainSplit[0])
pOptions.setValue("GuiOutlineDetails", "tagsWidth", tagsWidth) pOptions.setValue("GuiOutlineDetails", "tagsWidth", mainSplit[1])
return return
def clearDetails(self) -> None: def clearDetails(self) -> None:
+60 -56
View File
@@ -40,7 +40,7 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwLabels, nwStyles, nwUnicode, trConst
from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter
from novelwriter.core.item import NWItem from novelwriter.core.item import NWItem
@@ -243,7 +243,6 @@ class GuiProjectToolBar(QWidget):
self.projTree = projView.projTree self.projTree = projView.projTree
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(2)
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
@@ -274,27 +273,27 @@ class GuiProjectToolBar(QWidget):
# Add Item Menu # Add Item Menu
self.mAdd = QMenu(self) 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( self.aAddEmpty.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=0, isNote=False) 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( self.aAddChap.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=2, isNote=False) 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( self.aAddScene.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=3, isNote=False) 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( self.aAddNote.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=1, isNote=True) 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( self.aAddFolder.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FOLDER) qtLambda(self.projTree.newTreeItem, nwItemType.FOLDER)
) )
@@ -304,7 +303,7 @@ class GuiProjectToolBar(QWidget):
self.mTemplates.menuItemTriggered.connect(lambda h: self.newDocumentFromTemplate.emit(h)) self.mTemplates.menuItemTriggered.connect(lambda h: self.newDocumentFromTemplate.emit(h))
self.mAdd.addMenu(self.mTemplates) 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._buildRootMenu()
self.tbAdd = NIconToolButton(self, iSz) self.tbAdd = NIconToolButton(self, iSz)
@@ -315,13 +314,13 @@ class GuiProjectToolBar(QWidget):
# More Options Menu # More Options Menu
self.mMore = QMenu(self) 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.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.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.aEmptyTrash.triggered.connect(self.projTree.emptyTrash)
self.tbMore = NIconToolButton(self, iSz) self.tbMore = NIconToolButton(self, iSz)
@@ -336,7 +335,7 @@ class GuiProjectToolBar(QWidget):
self.outerBox.addWidget(self.tbMoveD) self.outerBox.addWidget(self.tbMoveD)
self.outerBox.addWidget(self.tbAdd) self.outerBox.addWidget(self.tbAdd)
self.outerBox.addWidget(self.tbMore) self.outerBox.addWidget(self.tbMore)
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx) self.outerBox.setContentsMargins(2, 2, 0, 2)
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -392,7 +391,7 @@ class GuiProjectToolBar(QWidget):
logger.debug("Rebuilding quick links menu") logger.debug("Rebuilding quick links menu")
self.mQuick.clear() self.mQuick.clear()
for tHandle, nwItem in SHARED.project.tree.iterRoots(None): 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.setData(tHandle)
action.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass], "root")) action.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass], "root"))
action.triggered.connect( action.triggered.connect(
@@ -440,7 +439,7 @@ class GuiProjectToolBar(QWidget):
def _buildRootMenu(self) -> None: def _buildRootMenu(self) -> None:
"""Build the rood folder menu.""" """Build the rood folder menu."""
def addClass(itemClass: nwItemClass) -> None: 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.setIcon(SHARED.theme.getIcon(nwLabels.CLASS_ICON[itemClass], "root"))
aNew.triggered.connect( aNew.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.ROOT, itemClass) qtLambda(self.projTree.newTreeItem, nwItemType.ROOT, itemClass)
@@ -561,17 +560,16 @@ class GuiProjectTree(QTreeView):
# Lock the column sizes # Lock the column sizes
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
cMg = CONFIG.pxInt(6)
treeHeader = self.header() if header := self.header():
treeHeader.setStretchLastSection(False) header.setStretchLastSection(False)
treeHeader.setMinimumSectionSize(iPx + cMg) header.setMinimumSectionSize(iPx + 6)
treeHeader.setSectionResizeMode(ProjectNode.C_NAME, QtHeaderStretch) header.setSectionResizeMode(ProjectNode.C_NAME, QtHeaderStretch)
treeHeader.setSectionResizeMode(ProjectNode.C_COUNT, QtHeaderToContents) header.setSectionResizeMode(ProjectNode.C_COUNT, QtHeaderToContents)
treeHeader.setSectionResizeMode(ProjectNode.C_ACTIVE, QtHeaderFixed) header.setSectionResizeMode(ProjectNode.C_ACTIVE, QtHeaderFixed)
treeHeader.setSectionResizeMode(ProjectNode.C_STATUS, QtHeaderFixed) header.setSectionResizeMode(ProjectNode.C_STATUS, QtHeaderFixed)
treeHeader.resizeSection(ProjectNode.C_ACTIVE, iPx + cMg) header.resizeSection(ProjectNode.C_ACTIVE, iPx + 6)
treeHeader.resizeSection(ProjectNode.C_STATUS, iPx + cMg) header.resizeSection(ProjectNode.C_STATUS, iPx + 6)
self.restoreExpandedState() self.restoreExpandedState()
@@ -969,8 +967,9 @@ class GuiProjectTree(QTreeView):
else: else:
ctxMenu.buildSingleSelectMenu() ctxMenu.buildSingleSelectMenu()
ctxMenu.exec(self.viewport().mapToGlobal(point)) if viewport := self.viewport():
ctxMenu.deleteLater() ctxMenu.exec(viewport.mapToGlobal(point))
ctxMenu.deleteLater()
return return
@@ -1091,7 +1090,8 @@ class _UpdatableMenu(QMenu):
def setActionsVisible(self, value: bool) -> None: def setActionsVisible(self, value: bool) -> None:
"""Set the visibility of root action.""" """Set the visibility of root action."""
self.menuAction().setVisible(value) if action := self.menuAction():
action.setVisible(value)
return return
## ##
@@ -1135,7 +1135,7 @@ class _TreeContextMenu(QMenu):
def buildTrashMenu(self) -> None: def buildTrashMenu(self) -> None:
"""Build the special menu for the Trash folder.""" """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) action.triggered.connect(self._tree.emptyTrash)
if self._children: if self._children:
self._expandCollapse() self._expandCollapse()
@@ -1156,7 +1156,7 @@ class _TreeContextMenu(QMenu):
self.addSeparator() self.addSeparator()
# Edit Item Settings # Edit Item Settings
action = self.addAction(self.tr("Rename")) action = qtAddAction(self, self.tr("Rename"))
action.triggered.connect(qtLambda(self._view.renameTreeItem, self._handle)) action.triggered.connect(qtLambda(self._view.renameTreeItem, self._handle))
if isFile: if isFile:
self._itemHeader() self._itemHeader()
@@ -1171,7 +1171,7 @@ class _TreeContextMenu(QMenu):
# Process Item # Process Item
if self._children: if self._children:
self._expandCollapse() self._expandCollapse()
action = self.addAction(self.tr("Duplicate")) action = qtAddAction(self, self.tr("Duplicate"))
action.triggered.connect(qtLambda(self._tree.duplicateFromHandle, self._handle)) action.triggered.connect(qtLambda(self._tree.duplicateFromHandle, self._handle))
self._deleteOrTrash() self._deleteOrTrash()
@@ -1191,12 +1191,12 @@ class _TreeContextMenu(QMenu):
def _docActions(self) -> None: def _docActions(self) -> None:
"""Add document actions.""" """Add document actions."""
action = self.addAction(self.tr("Open Document")) action = qtAddAction(self, self.tr("Open Document"))
action.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._view.openDocumentRequest.emit, self._view.openDocumentRequest.emit,
self._handle, nwDocMode.EDIT, "", True self._handle, nwDocMode.EDIT, "", True
)) ))
action = self.addAction(self.tr("View Document")) action = qtAddAction(self, self.tr("View Document"))
action.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._view.openDocumentRequest.emit, self._view.openDocumentRequest.emit,
self._handle, nwDocMode.VIEW, "", False self._handle, nwDocMode.VIEW, "", False
@@ -1205,7 +1205,7 @@ class _TreeContextMenu(QMenu):
def _itemCreation(self) -> None: def _itemCreation(self) -> None:
"""Add create item actions.""" """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.aAddEmpty)
menu.addAction(self._view.projBar.aAddChap) menu.addAction(self._view.projBar.aAddChap)
menu.addAction(self._view.projBar.aAddScene) 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.""" """Check if there is a header that can be used for rename."""
SHARED.saveEditor() SHARED.saveEditor()
if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"): 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( action.triggered.connect(
qtLambda(self._view.renameTreeItem, self._handle, hItem.title) qtLambda(self._view.renameTreeItem, self._handle, hItem.title)
) )
@@ -1226,50 +1226,54 @@ class _TreeContextMenu(QMenu):
def _itemActive(self) -> None: def _itemActive(self) -> None:
"""Add Active/Inactive actions.""" """Add Active/Inactive actions."""
if len(self._indices) > 1: if len(self._indices) > 1:
mSub = self.addMenu(self.tr("Set Active to ...")) mSub = qtAddMenu(self, self.tr("Set Active to ..."))
aOne = mSub.addAction(SHARED.theme.getIcon("checked"), self._tree.trActive) aOne = qtAddAction(mSub, self._tree.trActive)
aOne.setIcon(SHARED.theme.getIcon("checked", "green"))
aOne.triggered.connect(qtLambda(self._iterItemActive, True)) 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)) aTwo.triggered.connect(qtLambda(self._iterItemActive, False))
else: else:
action = self.addAction(self.tr("Toggle Active")) action = qtAddAction(self, self.tr("Toggle Active"))
action.triggered.connect(self._toggleItemActive) action.triggered.connect(self._toggleItemActive)
return return
def _itemStatusImport(self, multi: bool) -> None: def _itemStatusImport(self, multi: bool) -> None:
"""Add actions for changing status or importance.""" """Add actions for changing status or importance."""
if self._item.isNovelLike(): if self._item.isNovelLike():
menu = self.addMenu(self.tr("Set Status to ...")) menu = qtAddMenu(self, self.tr("Set Status to ..."))
current = self._item.itemStatus current = self._item.itemStatus
for key, entry in SHARED.project.data.itemStatus.iterItems(): for key, entry in SHARED.project.data.itemStatus.iterItems():
name = entry.name name = entry.name
if not multi and current == key: if not multi and current == key:
name += f" ({nwUnicode.U_CHECK})" name += f" ({nwUnicode.U_CHECK})"
action = menu.addAction(entry.icon, name) action = qtAddAction(menu, name)
action.setIcon(entry.icon)
if multi: if multi:
action.triggered.connect(qtLambda(self._iterSetItemStatus, key)) action.triggered.connect(qtLambda(self._iterSetItemStatus, key))
else: else:
action.triggered.connect(qtLambda(self._changeItemStatus, key)) action.triggered.connect(qtLambda(self._changeItemStatus, key))
menu.addSeparator() menu.addSeparator()
action = menu.addAction(self.tr("Manage Labels ...")) action = qtAddAction(menu, self.tr("Manage Labels ..."))
action.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._view.projectSettingsRequest.emit, self._view.projectSettingsRequest.emit,
GuiProjectSettings.PAGE_STATUS GuiProjectSettings.PAGE_STATUS
)) ))
else: else:
menu = self.addMenu(self.tr("Set Importance to ...")) menu = qtAddMenu(self, self.tr("Set Importance to ..."))
current = self._item.itemImport current = self._item.itemImport
for key, entry in SHARED.project.data.itemImport.iterItems(): for key, entry in SHARED.project.data.itemImport.iterItems():
name = entry.name name = entry.name
if not multi and current == key: if not multi and current == key:
name += f" ({nwUnicode.U_CHECK})" name += f" ({nwUnicode.U_CHECK})"
action = menu.addAction(entry.icon, name) action = qtAddAction(menu, name)
action.setIcon(entry.icon)
if multi: if multi:
action.triggered.connect(qtLambda(self._iterSetItemImport, key)) action.triggered.connect(qtLambda(self._iterSetItemImport, key))
else: else:
action.triggered.connect(qtLambda(self._changeItemImport, key)) action.triggered.connect(qtLambda(self._changeItemImport, key))
menu.addSeparator() menu.addSeparator()
action = menu.addAction(self.tr("Manage Labels ...")) action = qtAddAction(menu, self.tr("Manage Labels ..."))
action.triggered.connect(qtLambda( action.triggered.connect(qtLambda(
self._view.projectSettingsRequest.emit, self._view.projectSettingsRequest.emit,
GuiProjectSettings.PAGE_IMPORT GuiProjectSettings.PAGE_IMPORT
@@ -1278,7 +1282,7 @@ class _TreeContextMenu(QMenu):
def _itemTransform(self, isFile: bool, isFolder: bool) -> None: def _itemTransform(self, isFile: bool, isFolder: bool) -> None:
"""Add actions for the Transform menu.""" """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]) trDoc = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
trNote = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE]) trNote = trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
@@ -1288,42 +1292,42 @@ class _TreeContextMenu(QMenu):
isNoteFile = isFile and self._item.isNoteLayout() isNoteFile = isFile and self._item.isNoteLayout()
if isNoteFile and self._item.documentAllowed(): 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)) action.triggered.connect(qtLambda(self._changeItemLayout, loDoc))
if isDocFile: 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)) action.triggered.connect(qtLambda(self._changeItemLayout, loNote))
if isFolder and self._item.documentAllowed(): 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)) action.triggered.connect(qtLambda(self._convertFolderToFile, loDoc))
if isFolder: 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)) action.triggered.connect(qtLambda(self._convertFolderToFile, loNote))
if self._children and isFile: 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.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)) action.triggered.connect(qtLambda(self._tree.mergeDocuments, self._handle, True))
if self._children and isFolder: 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)) action.triggered.connect(qtLambda(self._tree.mergeDocuments, self._handle, True))
if isFile: 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)) action.triggered.connect(qtLambda(self._tree.splitDocument, self._handle))
return return
def _expandCollapse(self) -> None: def _expandCollapse(self) -> None:
"""Add actions for expand and collapse.""" """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.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])) action.triggered.connect(qtLambda(self._tree.collapseFromIndex, self._indices[0]))
return return
@@ -1336,7 +1340,7 @@ class _TreeContextMenu(QMenu):
text = self.tr("Delete Permanently") text = self.tr("Delete Permanently")
else: else:
text = self.tr("Move to Trash") text = self.tr("Move to Trash")
action = self.addAction(text) action = qtAddAction(self, text)
action.triggered.connect(self._tree.processDeleteRequest) action.triggered.connect(self._tree.processDeleteRequest)
return return
+18 -22
View File
@@ -28,14 +28,14 @@ import logging
from time import time from time import time
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QCursor, QKeyEvent from PyQt6.QtGui import QAction, QCursor, QKeyEvent
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QApplication, QFrame, QHBoxLayout, QLabel, QLineEdit, QToolBar, QApplication, QFrame, QHBoxLayout, QLabel, QLineEdit, QToolBar,
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED 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.coretools import DocSearch
from novelwriter.core.item import NWItem from novelwriter.core.item import NWItem
from novelwriter.types import ( from novelwriter.types import (
@@ -65,8 +65,6 @@ class GuiProjectSearch(QWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(2)
tPx = CONFIG.pxInt(4)
self._time = time() self._time = time()
self._search = DocSearch() self._search = DocSearch()
@@ -76,7 +74,7 @@ class GuiProjectSearch(QWidget):
# Header # Header
self.viewLabel = QLabel(self.tr("Project Search"), self) self.viewLabel = QLabel(self.tr("Project Search"), self)
self.viewLabel.setFont(SHARED.theme.guiFontB) self.viewLabel.setFont(SHARED.theme.guiFontB)
self.viewLabel.setContentsMargins(mPx, tPx, 0, mPx) self.viewLabel.setContentsMargins(2, 4, 0, 2)
# Options # Options
self.searchOpt = QToolBar(self) self.searchOpt = QToolBar(self)
@@ -84,30 +82,30 @@ class GuiProjectSearch(QWidget):
self.searchOpt.setIconSize(iSz) self.searchOpt.setIconSize(iSz)
self.searchOpt.setContentsMargins(0, 0, 0, 0) 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.setCheckable(True)
self.toggleCase.setChecked(CONFIG.searchProjCase) self.toggleCase.setChecked(CONFIG.searchProjCase)
self.toggleCase.toggled.connect(self._toggleCase) 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.setCheckable(True)
self.toggleWord.setChecked(CONFIG.searchProjWord) self.toggleWord.setChecked(CONFIG.searchProjWord)
self.toggleWord.toggled.connect(self._toggleWord) 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.setCheckable(True)
self.toggleRegEx.setChecked(CONFIG.searchProjRegEx) self.toggleRegEx.setChecked(CONFIG.searchProjRegEx)
self.toggleRegEx.toggled.connect(self._toggleRegEx) self.toggleRegEx.toggled.connect(self._toggleRegEx)
# Search Box # 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 = QLineEdit(self)
self.searchText.setPlaceholderText(self.tr("Search for")) self.searchText.setPlaceholderText(self.tr("Search for"))
self.searchText.setClearButtonEnabled(True) self.searchText.setClearButtonEnabled(True)
self.searchText.addAction(self.searchAction, QLineEdit.ActionPosition.TrailingPosition)
self.searchAction = self.searchText.addAction(
SHARED.theme.getIcon("search", "blue"), QLineEdit.ActionPosition.TrailingPosition
)
self.searchAction.triggered.connect(self._processSearch)
# Search Result # Search Result
self.searchResult = QTreeWidget(self) self.searchResult = QTreeWidget(self)
@@ -121,10 +119,10 @@ class GuiProjectSearch(QWidget):
self.searchResult.itemDoubleClicked.connect(self._searchResultDoubleClicked) self.searchResult.itemDoubleClicked.connect(self._searchResultDoubleClicked)
self.searchResult.itemSelectionChanged.connect(self._searchResultSelected) self.searchResult.itemSelectionChanged.connect(self._searchResultSelected)
treeHeader = self.searchResult.header() if header := self.searchResult.header():
treeHeader.setStretchLastSection(False) header.setStretchLastSection(False)
treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch) header.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
treeHeader.setSectionResizeMode(self.C_COUNT, QtHeaderToContents) header.setSectionResizeMode(self.C_COUNT, QtHeaderToContents)
# Assemble # Assemble
self.headerBox = QHBoxLayout() self.headerBox = QHBoxLayout()
@@ -138,7 +136,7 @@ class GuiProjectSearch(QWidget):
self.outerBox.addWidget(self.searchText, 0) self.outerBox.addWidget(self.searchText, 0)
self.outerBox.addWidget(self.searchResult, 1) self.outerBox.addWidget(self.searchResult, 1)
self.outerBox.setContentsMargins(0, 0, 0, 0) self.outerBox.setContentsMargins(0, 0, 0, 0)
self.outerBox.setSpacing(mPx) self.outerBox.setSpacing(2)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.updateTheme() self.updateTheme()
@@ -153,8 +151,6 @@ class GuiProjectSearch(QWidget):
def updateTheme(self) -> None: def updateTheme(self) -> None:
"""Update theme elements.""" """Update theme elements."""
bPx = CONFIG.pxInt(1)
mPx = CONFIG.pxInt(2)
qPalette = self.palette() qPalette = self.palette()
colBase = cssCol(qPalette.base().color()) colBase = cssCol(qPalette.base().color())
@@ -162,8 +158,8 @@ class GuiProjectSearch(QWidget):
self.setStyleSheet( self.setStyleSheet(
"QToolBar {padding: 0; background: none;} " "QToolBar {padding: 0; background: none;} "
f"QLineEdit {{border: {bPx}px solid {colBase}; padding: {mPx}px;}} " f"QLineEdit {{border: 1px solid {colBase}; padding: 2px;}} "
f"QLineEdit:focus {{border: {bPx}px solid {colFocus};}} " f"QLineEdit:focus {{border: 1px solid {colFocus};}} "
) )
self.searchAction.setIcon(SHARED.theme.getIcon("search", "blue")) self.searchAction.setIcon(SHARED.theme.getIcon("search", "blue"))
+2 -2
View File
@@ -31,7 +31,7 @@ from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal
from PyQt6.QtGui import QPalette from PyQt6.QtGui import QPalette
from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.common import qtLambda from novelwriter.common import qtLambda
from novelwriter.enum import nwView from novelwriter.enum import nwView
from novelwriter.extensions.eventfilters import StatusTipFilter from novelwriter.extensions.eventfilters import StatusTipFilter
@@ -114,7 +114,7 @@ class GuiSideBar(QWidget):
self.outerBox.addWidget(self.tbStats) self.outerBox.addWidget(self.tbStats)
self.outerBox.addWidget(self.tbSettings) self.outerBox.addWidget(self.tbSettings)
self.outerBox.setContentsMargins(0, 0, 0, 0) self.outerBox.setContentsMargins(0, 0, 0, 0)
self.outerBox.setSpacing(CONFIG.pxInt(6)) self.outerBox.setSpacing(6)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.updateTheme() self.updateTheme()
+4 -6
View File
@@ -57,13 +57,11 @@ class GuiMainStatus(QStatusBar):
# Permanent Widgets # Permanent Widgets
# ================= # =================
xM = CONFIG.pxInt(8)
# The Spell Checker Language # The Spell Checker Language
self.langIcon = QLabel("", self) self.langIcon = QLabel("", self)
self.langText = QLabel(self.tr("None"), self) self.langText = QLabel(self.tr("None"), self)
self.langIcon.setContentsMargins(0, 0, 0, 0) 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.langIcon)
self.addPermanentWidget(self.langText) self.addPermanentWidget(self.langText)
@@ -71,7 +69,7 @@ class GuiMainStatus(QStatusBar):
self.docIcon = StatusLED(iPx, iPx, self) self.docIcon = StatusLED(iPx, iPx, self)
self.docText = QLabel(self.tr("Editor"), self) self.docText = QLabel(self.tr("Editor"), self)
self.docIcon.setContentsMargins(0, 0, 0, 0) 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.docIcon)
self.addPermanentWidget(self.docText) self.addPermanentWidget(self.docText)
@@ -79,7 +77,7 @@ class GuiMainStatus(QStatusBar):
self.projIcon = StatusLED(iPx, iPx, self) self.projIcon = StatusLED(iPx, iPx, self)
self.projText = QLabel(self.tr("Project"), self) self.projText = QLabel(self.tr("Project"), self)
self.projIcon.setContentsMargins(0, 0, 0, 0) 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.projIcon)
self.addPermanentWidget(self.projText) self.addPermanentWidget(self.projText)
@@ -87,7 +85,7 @@ class GuiMainStatus(QStatusBar):
self.statsIcon = QLabel(self) self.statsIcon = QLabel(self)
self.statsText = QLabel("", self) self.statsText = QLabel("", self)
self.statsIcon.setContentsMargins(0, 0, 0, 0) 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.statsIcon)
self.addPermanentWidget(self.statsText) self.addPermanentWidget(self.statsText)
+4 -11
View File
@@ -41,7 +41,7 @@ from novelwriter.common import NWConfigParser, cssCol, minmax
from novelwriter.constants import nwLabels from novelwriter.constants import nwLabels
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.types import QtPaintAntiAlias, QtTransparent, nwDataClass from novelwriter.types import QtPaintAntiAlias, QtTransparent
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -50,7 +50,6 @@ STYLES_MIN_TOOLBUTTON = "minimalToolButton"
STYLES_BIG_TOOLBUTTON = "bigToolButton" STYLES_BIG_TOOLBUTTON = "bigToolButton"
@nwDataClass
class ThemeMeta: class ThemeMeta:
name: str = "" name: str = ""
@@ -62,7 +61,6 @@ class ThemeMeta:
licenseUrl: str = "" licenseUrl: str = ""
@nwDataClass
class SyntaxColors: class SyntaxColors:
back: QColor = QColor(255, 255, 255) back: QColor = QColor(255, 255, 255)
@@ -546,31 +544,26 @@ class GuiTheme:
"""Build default style sheets.""" """Build default style sheets."""
self._styleSheets = {} self._styleSheets = {}
aPx = CONFIG.pxInt(2)
bPx = CONFIG.pxInt(4)
cPx = CONFIG.pxInt(6)
dPx = CONFIG.pxInt(8)
tCol = palette.text().color() tCol = palette.text().color()
hCol = palette.highlight().color() hCol = palette.highlight().color()
# Flat Tab Widget and Tab Bar: # Flat Tab Widget and Tab Bar:
self._styleSheets[STYLES_FLAT_TABS] = ( self._styleSheets[STYLES_FLAT_TABS] = (
"QTabWidget::pane {border: 0;} " "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)};}} " f"QTabWidget QTabBar::tab:selected {{color: {cssCol(hCol)};}} "
) )
# Minimal Tool Button # Minimal Tool Button
self._styleSheets[STYLES_MIN_TOOLBUTTON] = ( 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)};}} " f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} "
"QToolButton::menu-indicator {image: none;} " "QToolButton::menu-indicator {image: none;} "
) )
# Big Tool Button # Big Tool Button
self._styleSheets[STYLES_BIG_TOOLBUTTON] = ( 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)};}} " f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} "
"QToolButton::menu-indicator {image: none;} " "QToolButton::menu-indicator {image: none;} "
) )
+7 -11
View File
@@ -114,10 +114,6 @@ class GuiMain(QMainWindow):
# Build the GUI # Build the GUI
# ============= # =============
# Sizes
mPx = CONFIG.pxInt(4)
hWd = CONFIG.pxInt(4)
# Main GUI Elements # Main GUI Elements
self.mainStatus = GuiMainStatus(self) self.mainStatus = GuiMainStatus(self)
self.projView = GuiProjectView(self) self.projView = GuiProjectView(self)
@@ -142,7 +138,7 @@ class GuiMain(QMainWindow):
self.treePane = QWidget(self) self.treePane = QWidget(self)
self.treeBox = QVBoxLayout() self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0) self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(mPx) self.treeBox.setSpacing(4)
self.treeBox.addWidget(self.projStack) self.treeBox.addWidget(self.projStack)
self.treeBox.addWidget(self.itemDetails) self.treeBox.addWidget(self.itemDetails)
self.treePane.setLayout(self.treeBox) self.treePane.setLayout(self.treeBox)
@@ -151,7 +147,7 @@ class GuiMain(QMainWindow):
self.splitView = QSplitter(Qt.Orientation.Vertical, self) self.splitView = QSplitter(Qt.Orientation.Vertical, self)
self.splitView.addWidget(self.docViewer) self.splitView.addWidget(self.docViewer)
self.splitView.addWidget(self.docViewerPanel) self.splitView.addWidget(self.docViewerPanel)
self.splitView.setHandleWidth(hWd) self.splitView.setHandleWidth(4)
self.splitView.setOpaqueResize(False) self.splitView.setOpaqueResize(False)
self.splitView.setSizes(CONFIG.viewPanePos) self.splitView.setSizes(CONFIG.viewPanePos)
self.splitView.setCollapsible(0, False) self.splitView.setCollapsible(0, False)
@@ -162,7 +158,7 @@ class GuiMain(QMainWindow):
self.splitDocs.addWidget(self.docEditor) self.splitDocs.addWidget(self.docEditor)
self.splitDocs.addWidget(self.splitView) self.splitDocs.addWidget(self.splitView)
self.splitDocs.setOpaqueResize(False) self.splitDocs.setOpaqueResize(False)
self.splitDocs.setHandleWidth(hWd) self.splitDocs.setHandleWidth(4)
self.splitDocs.setCollapsible(0, False) self.splitDocs.setCollapsible(0, False)
self.splitDocs.setCollapsible(1, False) self.splitDocs.setCollapsible(1, False)
@@ -172,7 +168,7 @@ class GuiMain(QMainWindow):
self.splitMain.addWidget(self.treePane) self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.splitDocs) self.splitMain.addWidget(self.splitDocs)
self.splitMain.setOpaqueResize(False) self.splitMain.setOpaqueResize(False)
self.splitMain.setHandleWidth(hWd) self.splitMain.setHandleWidth(4)
self.splitMain.setSizes(CONFIG.mainPanePos) self.splitMain.setSizes(CONFIG.mainPanePos)
self.splitMain.setCollapsible(0, False) self.splitMain.setCollapsible(0, False)
self.splitMain.setCollapsible(0, False) self.splitMain.setCollapsible(0, False)
@@ -860,10 +856,10 @@ class GuiMain(QMainWindow):
logger.info("Exiting novelWriter") logger.info("Exiting novelWriter")
if not SHARED.focusMode: if not SHARED.focusMode:
CONFIG.setMainPanePos(self.splitMain.sizes()) CONFIG.mainPanePos = self.splitMain.sizes()
CONFIG.setOutlinePanePos(self.outlineView.splitSizes()) CONFIG.outlinePanePos = self.outlineView.splitSizes()
if self.docViewerPanel.isVisible(): if self.docViewerPanel.isVisible():
CONFIG.setViewPanePos(self.splitView.sizes()) CONFIG.viewPanePos = self.splitView.sizes()
CONFIG.showViewerPanel = self.docViewerPanel.isVisible() CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
wFull = Qt.WindowState.WindowFullScreen wFull = Qt.WindowState.WindowFullScreen
+7 -10
View File
@@ -57,12 +57,9 @@ class GuiDictionaries(NNonBlockingDialog):
self._currDicts = set() self._currDicts = set()
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
iPx = CONFIG.pxInt(4)
mPx = CONFIG.pxInt(8)
sPx = CONFIG.pxInt(16)
self.setMinimumWidth(CONFIG.pxInt(500)) self.setMinimumWidth(500)
self.setMinimumHeight(CONFIG.pxInt(300)) self.setMinimumHeight(300)
# Hunspell Dictionaries # Hunspell Dictionaries
foUrl = "https://www.freeoffice.com/en/download/dictionaries" foUrl = "https://www.freeoffice.com/en/download/dictionaries"
@@ -84,7 +81,7 @@ class GuiDictionaries(NNonBlockingDialog):
self.huPathBox = QHBoxLayout() self.huPathBox = QHBoxLayout()
self.huPathBox.addWidget(self.huInput) self.huPathBox.addWidget(self.huInput)
self.huPathBox.addWidget(self.huBrowse) self.huPathBox.addWidget(self.huBrowse)
self.huPathBox.setSpacing(iPx) self.huPathBox.setSpacing(4)
self.huAddBox = QHBoxLayout() self.huAddBox = QHBoxLayout()
self.huAddBox.addStretch(1) self.huAddBox.addStretch(1)
self.huAddBox.addWidget(self.huImport) self.huAddBox.addWidget(self.huImport)
@@ -99,7 +96,7 @@ class GuiDictionaries(NNonBlockingDialog):
self.inBox = QHBoxLayout() self.inBox = QHBoxLayout()
self.inBox.addWidget(self.inPath) self.inBox.addWidget(self.inPath)
self.inBox.addWidget(self.inBrowse) self.inBox.addWidget(self.inBrowse)
self.inBox.setSpacing(iPx) self.inBox.setSpacing(4)
# Info Box # Info Box
self.infoBox = QPlainTextEdit(self) self.infoBox = QPlainTextEdit(self)
@@ -116,17 +113,17 @@ class GuiDictionaries(NNonBlockingDialog):
self.innerBox.addWidget(self.huInfo) self.innerBox.addWidget(self.huInfo)
self.innerBox.addLayout(self.huPathBox) self.innerBox.addLayout(self.huPathBox)
self.innerBox.addLayout(self.huAddBox) self.innerBox.addLayout(self.huAddBox)
self.innerBox.addSpacing(mPx) self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.inInfo) self.innerBox.addWidget(self.inInfo)
self.innerBox.addLayout(self.inBox) self.innerBox.addLayout(self.inBox)
self.innerBox.addWidget(self.infoBox) self.innerBox.addWidget(self.infoBox)
self.innerBox.setSpacing(iPx) self.innerBox.setSpacing(4)
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.innerBox, 0) self.outerBox.addLayout(self.innerBox, 0)
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
self.outerBox.addWidget(self.buttonBox, 0) self.outerBox.addWidget(self.buttonBox, 0)
self.outerBox.setSpacing(sPx) self.outerBox.setSpacing(16)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
+10 -11
View File
@@ -52,18 +52,15 @@ class GuiLipsum(NDialog):
self._lipsumText = "" self._lipsumText = ""
vSp = CONFIG.pxInt(4)
nPx = CONFIG.pxInt(64)
self.innerBox = QHBoxLayout() self.innerBox = QHBoxLayout()
self.innerBox.setSpacing(CONFIG.pxInt(16)) self.innerBox.setSpacing(16)
# Icon # Icon
self.docIcon = QLabel(self) 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 = QVBoxLayout()
self.leftBox.setSpacing(vSp) self.leftBox.setSpacing(4)
self.leftBox.addWidget(self.docIcon) self.leftBox.addWidget(self.docIcon)
self.leftBox.addStretch(1) self.leftBox.addStretch(1)
self.innerBox.addLayout(self.leftBox) 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.paraCount, 1, 1, 1, 1, QtAlignRight)
self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft) self.formBox.addWidget(self.randLabel, 2, 0, 1, 1, QtAlignLeft)
self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight) self.formBox.addWidget(self.randSwitch, 2, 1, 1, 1, QtAlignRight)
self.formBox.setVerticalSpacing(vSp) self.formBox.setVerticalSpacing(4)
self.formBox.setRowStretch(3, 1) self.formBox.setRowStretch(3, 1)
self.innerBox.addLayout(self.formBox) self.innerBox.addLayout(self.formBox)
@@ -96,17 +93,19 @@ class GuiLipsum(NDialog):
self.buttonBox.rejected.connect(self.reject) self.buttonBox.rejected.connect(self.reject)
self.btnClose = self.buttonBox.addButton(QtDialogClose) 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 = self.buttonBox.addButton(self.tr("Insert"), QtRoleAction)
self.btnInsert.clicked.connect(self._doInsert) if self.btnInsert:
self.btnInsert.setAutoDefault(False) self.btnInsert.clicked.connect(self._doInsert)
self.btnInsert.setAutoDefault(False)
# Assemble # Assemble
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.innerBox) self.outerBox.addLayout(self.innerBox)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.outerBox.setSpacing(CONFIG.pxInt(16)) self.outerBox.setSpacing(16)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
logger.debug("Ready: GuiLipsum") logger.debug("Ready: GuiLipsum")
+24 -35
View File
@@ -35,7 +35,7 @@ from PyQt6.QtWidgets import (
QPushButton, QSplitter, QVBoxLayout, QWidget QPushButton, QSplitter, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.common import makeFileNameSafe, openExternalPath from novelwriter.common import makeFileNameSafe, openExternalPath
from novelwriter.constants import nwLabels from novelwriter.constants import nwLabels
from novelwriter.core.buildsettings import BuildSettings from novelwriter.core.buildsettings import BuildSettings
@@ -68,21 +68,16 @@ class GuiManuscriptBuild(NDialog):
self._build = build self._build = build
self.setWindowTitle(self.tr("Build Manuscript")) self.setWindowTitle(self.tr("Build Manuscript"))
self.setMinimumWidth(CONFIG.pxInt(500)) self.setMinimumWidth(500)
self.setMinimumHeight(CONFIG.pxInt(300)) self.setMinimumHeight(300)
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
bSz = SHARED.theme.buttonIconSize 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 pOptions = SHARED.project.options
self.resize( self.resize(
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winWidth", wWin)), pOptions.getInt("GuiManuscriptBuild", "winWidth", 620),
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin)) pOptions.getInt("GuiManuscriptBuild", "winHeight", 360),
) )
# Output Format # Output Format
@@ -149,7 +144,7 @@ class GuiManuscriptBuild(NDialog):
self.pathBox = QHBoxLayout() self.pathBox = QHBoxLayout()
self.pathBox.addWidget(self.buildPath) self.pathBox.addWidget(self.buildPath)
self.pathBox.addWidget(self.btnBrowse) self.pathBox.addWidget(self.btnBrowse)
self.pathBox.setSpacing(sp8) self.pathBox.setSpacing(8)
# Build Name # Build Name
self.lblName = QLabel(self.tr("File Name"), self) self.lblName = QLabel(self.tr("File Name"), self)
@@ -160,14 +155,14 @@ class GuiManuscriptBuild(NDialog):
self.nameBox = QHBoxLayout() self.nameBox = QHBoxLayout()
self.nameBox.addWidget(self.buildName) self.nameBox.addWidget(self.buildName)
self.nameBox.addWidget(self.btnReset) self.nameBox.addWidget(self.btnReset)
self.nameBox.setSpacing(sp8) self.nameBox.setSpacing(8)
# Build Progress # Build Progress
self.buildProgress = NProgressSimple(self) self.buildProgress = NProgressSimple(self)
self.buildProgress.setMinimum(0) self.buildProgress.setMinimum(0)
self.buildProgress.setValue(0) self.buildProgress.setValue(0)
self.buildProgress.setTextVisible(False) self.buildProgress.setTextVisible(False)
self.buildProgress.setFixedHeight(sp8) self.buildProgress.setFixedHeight(8)
# Build Box # Build Box
self.buildBox = QGridLayout() self.buildBox = QGridLayout()
@@ -175,8 +170,8 @@ class GuiManuscriptBuild(NDialog):
self.buildBox.addLayout(self.pathBox, 0, 1) self.buildBox.addLayout(self.pathBox, 0, 1)
self.buildBox.addWidget(self.lblName, 1, 0) self.buildBox.addWidget(self.lblName, 1, 0)
self.buildBox.addLayout(self.nameBox, 1, 1) self.buildBox.addLayout(self.nameBox, 1, 1)
self.buildBox.setHorizontalSpacing(sp8) self.buildBox.setHorizontalSpacing(8)
self.buildBox.setVerticalSpacing(sp4) self.buildBox.setVerticalSpacing(4)
# Dialog Buttons # Dialog Buttons
self.buttonBox = QDialogButtonBox(self) self.buttonBox = QDialogButtonBox(self)
@@ -196,7 +191,8 @@ class GuiManuscriptBuild(NDialog):
self.buttonBox.addButton(self.btnBuild, QtRoleAction) self.buttonBox.addButton(self.btnBuild, QtRoleAction)
self.btnClose = self.buttonBox.addButton(QtDialogClose) self.btnClose = self.buttonBox.addButton(QtDialogClose)
self.btnClose.setAutoDefault(False) if self.btnClose:
self.btnClose.setAutoDefault(False)
# Assemble GUI # Assemble GUI
# ============ # ============
@@ -204,25 +200,25 @@ class GuiManuscriptBuild(NDialog):
self.mainSplit = QSplitter(self) self.mainSplit = QSplitter(self)
self.mainSplit.addWidget(self.formatWidget) self.mainSplit.addWidget(self.formatWidget)
self.mainSplit.addWidget(self.contentWidget) self.mainSplit.addWidget(self.contentWidget)
self.mainSplit.setHandleWidth(sp16) self.mainSplit.setHandleWidth(16)
self.mainSplit.setCollapsible(0, False) self.mainSplit.setCollapsible(0, False)
self.mainSplit.setCollapsible(1, False) self.mainSplit.setCollapsible(1, False)
self.mainSplit.setStretchFactor(0, 0) self.mainSplit.setStretchFactor(0, 0)
self.mainSplit.setStretchFactor(1, 1) self.mainSplit.setStretchFactor(1, 1)
self.mainSplit.setSizes([ self.mainSplit.setSizes([
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "fmtWidth", wWin//2)), pOptions.getInt("GuiManuscriptBuild", "fmtWidth", 360),
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "sumWidth", wWin//2)), pOptions.getInt("GuiManuscriptBuild", "sumWidth", 360),
]) ])
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.lblMain, 0, QtAlignCenter) self.outerBox.addWidget(self.lblMain, 0, QtAlignCenter)
self.outerBox.addSpacing(sp16) self.outerBox.addSpacing(16)
self.outerBox.addWidget(self.mainSplit, 1) self.outerBox.addWidget(self.mainSplit, 1)
self.outerBox.addSpacing(sp4) self.outerBox.addSpacing(4)
self.outerBox.addWidget(self.buildProgress, 0) self.outerBox.addWidget(self.buildProgress, 0)
self.outerBox.addSpacing(sp4) self.outerBox.addSpacing(4)
self.outerBox.addLayout(self.buildBox, 0) self.outerBox.addLayout(self.buildBox, 0)
self.outerBox.addSpacing(sp16) self.outerBox.addSpacing(16)
self.outerBox.addWidget(self.buttonBox, 0) self.outerBox.addWidget(self.buttonBox, 0)
self.outerBox.setSpacing(0) self.outerBox.setSpacing(0)
@@ -363,21 +359,14 @@ class GuiManuscriptBuild(NDialog):
def _saveSettings(self) -> None: def _saveSettings(self) -> None:
"""Save the user GUI settings.""" """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") logger.debug("Saving State: GuiManuscriptBuild")
mainSplit = self.mainSplit.sizes()
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth) pOptions.setValue("GuiManuscriptBuild", "winWidth", self.width())
pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight) pOptions.setValue("GuiManuscriptBuild", "winHeight", self.height())
pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth) pOptions.setValue("GuiManuscriptBuild", "fmtWidth", mainSplit[0])
pOptions.setValue("GuiManuscriptBuild", "sumWidth", sumWidth) pOptions.setValue("GuiManuscriptBuild", "sumWidth", mainSplit[1])
pOptions.saveSettings() pOptions.saveSettings()
return return
def _populateContentList(self) -> None: def _populateContentList(self) -> None:
+64 -77
View File
@@ -85,18 +85,16 @@ class GuiManuscript(NToolDialog):
self._buildMap: dict[str, QListWidgetItem] = {} self._buildMap: dict[str, QListWidgetItem] = {}
self.setWindowTitle(self.tr("Build Manuscript")) self.setWindowTitle(self.tr("Build Manuscript"))
self.setMinimumWidth(CONFIG.pxInt(600)) self.setMinimumWidth(600)
self.setMinimumHeight(CONFIG.pxInt(500)) self.setMinimumHeight(500)
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
wWin = CONFIG.pxInt(900)
hWin = CONFIG.pxInt(600)
pOptions = SHARED.project.options pOptions = SHARED.project.options
self.resize( self.resize(
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winWidth", wWin)), pOptions.getInt("GuiManuscript", "winWidth", 900),
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winHeight", hWin)) pOptions.getInt("GuiManuscript", "winHeight", 600),
) )
# Build Controls # Build Controls
@@ -153,9 +151,7 @@ class GuiManuscript(NToolDialog):
# ============ # ============
self.buildDetails = _DetailsWidget(self) self.buildDetails = _DetailsWidget(self)
self.buildDetails.setColumnWidth( self.buildDetails.setColumnWidth(pOptions.getInt("GuiManuscript", "detailsWidth", 100))
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsWidth", 100)),
)
self.buildOutline = _OutlineWidget(self) self.buildOutline = _OutlineWidget(self)
@@ -168,8 +164,8 @@ class GuiManuscript(NToolDialog):
self.buildSplit.addWidget(self.buildList) self.buildSplit.addWidget(self.buildList)
self.buildSplit.addWidget(self.detailsTabs) self.buildSplit.addWidget(self.detailsTabs)
self.buildSplit.setSizes([ self.buildSplit.setSizes([
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "listHeight", 50)), pOptions.getInt("GuiManuscript", "listHeight", 50),
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "detailsHeight", 50)), pOptions.getInt("GuiManuscript", "detailsHeight", 50),
]) ])
# Process Controls # Process Controls
@@ -240,8 +236,8 @@ class GuiManuscript(NToolDialog):
self.mainSplit.setStretchFactor(0, 0) self.mainSplit.setStretchFactor(0, 0)
self.mainSplit.setStretchFactor(1, 1) self.mainSplit.setStretchFactor(1, 1)
self.mainSplit.setSizes([ self.mainSplit.setSizes([
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "optsWidth", wWin//4)), pOptions.getInt("GuiManuscript", "optsWidth", 225),
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "viewWidth", 3*wWin//4)), pOptions.getInt("GuiManuscript", "viewWidth", 675),
]) ])
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
@@ -441,28 +437,20 @@ class GuiManuscript(NToolDialog):
self._builds.setBuildsState(lastBuild, buildOrder) self._builds.setBuildsState(lastBuild, buildOrder)
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
mainSplit = self.mainSplit.sizes() mainSplit = self.mainSplit.sizes()
optsWidth = CONFIG.rpxInt(mainSplit[0])
viewWidth = CONFIG.rpxInt(mainSplit[1])
buildSplit = self.buildSplit.sizes() buildSplit = self.buildSplit.sizes()
listHeight = CONFIG.rpxInt(buildSplit[0]) detailsWidth = self.buildDetails.getColumnWidth()
detailsHeight = CONFIG.rpxInt(buildSplit[1])
detailsWidth = CONFIG.rpxInt(self.buildDetails.getColumnWidth())
detailsExpanded = self.buildDetails.getExpandedState() detailsExpanded = self.buildDetails.getExpandedState()
showNewPage = self.swtNewPage.isChecked() showNewPage = self.swtNewPage.isChecked()
logger.debug("Saving State: GuiManuscript") logger.debug("Saving State: GuiManuscript")
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiManuscript", "winWidth", winWidth) pOptions.setValue("GuiManuscript", "winWidth", self.width())
pOptions.setValue("GuiManuscript", "winHeight", winHeight) pOptions.setValue("GuiManuscript", "winHeight", self.height())
pOptions.setValue("GuiManuscript", "optsWidth", optsWidth) pOptions.setValue("GuiManuscript", "optsWidth", mainSplit[0])
pOptions.setValue("GuiManuscript", "viewWidth", viewWidth) pOptions.setValue("GuiManuscript", "viewWidth", mainSplit[1])
pOptions.setValue("GuiManuscript", "listHeight", listHeight) pOptions.setValue("GuiManuscript", "listHeight", buildSplit[0])
pOptions.setValue("GuiManuscript", "detailsHeight", detailsHeight) pOptions.setValue("GuiManuscript", "detailsHeight", buildSplit[1])
pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth) pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth)
pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded) pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded)
pOptions.setValue("GuiManuscript", "showNewPage", showNewPage) pOptions.setValue("GuiManuscript", "showNewPage", showNewPage)
@@ -693,33 +681,31 @@ class _OutlineWidget(QWidget):
hFont.setBold(True) hFont.setBold(True)
hFont.setUnderline(True) hFont.setUnderline(True)
root = self.listView.invisibleRootItem() if root := self.listView.invisibleRootItem():
parent = root parent = root
indent = False indent = False
for anchor, entry in data.items(): for anchor, entry in data.items():
prefix, _, text = entry.partition("|") prefix, _, text = entry.partition("|")
if prefix in ("TT", "PT", "CH", "SC", "H1", "H2"): if prefix in ("TT", "PT", "CH", "SC", "H1", "H2"):
item = QTreeWidgetItem([text]) item = QTreeWidgetItem([text])
item.setData(0, self.D_LINE, anchor) item.setData(0, self.D_LINE, anchor)
if prefix == "TT": if prefix == "TT":
item.setFont(0, tFont) item.setFont(0, tFont)
item.setForeground(0, tBrush) item.setForeground(0, tBrush)
root.addChild(item) root.addChild(item)
parent = root parent = root
elif prefix == "PT": elif prefix == "PT":
item.setFont(0, hFont) item.setFont(0, hFont)
root.addChild(item) root.addChild(item)
parent = root parent = root
elif prefix in ("CH", "H1"): elif prefix in ("CH", "H1"):
root.addChild(item) root.addChild(item)
parent = item parent = item
elif prefix in ("SC", "H2"): elif prefix in ("SC", "H2"):
parent.addChild(item) parent.addChild(item)
indent = True indent = True
self.listView.setIndentation( self.listView.setIndentation(SHARED.theme.baseIconHeight if indent else 4)
SHARED.theme.baseIconHeight if indent else CONFIG.pxInt(4)
)
self._outline = data self._outline = data
return return
@@ -750,11 +736,13 @@ class _PreviewWidget(QTextBrowser):
self.setPalette(dPalette) self.setPalette(dPalette)
self.setMinimumWidth(40*SHARED.theme.textNWidth) self.setMinimumWidth(40*SHARED.theme.textNWidth)
self.setTabStopDistance(CONFIG.getTabWidth()) self.setTabStopDistance(CONFIG.tabWidth)
self.setOpenExternalLinks(False) self.setOpenExternalLinks(False)
self.setOpenLinks(False) self.setOpenLinks(False)
self.document().setDocumentMargin(CONFIG.getTextMargin()) if document := self.document():
document.setDocumentMargin(CONFIG.textMargin)
self.setPlaceholderText(self.tr( self.setPlaceholderText(self.tr(
"Press the \"Preview\" button to generate ..." "Press the \"Preview\" button to generate ..."
)) ))
@@ -781,7 +769,7 @@ class _PreviewWidget(QTextBrowser):
self.ageLabel.setFixedHeight(int(2.1*SHARED.theme.fontPixelSize)) self.ageLabel.setFixedHeight(int(2.1*SHARED.theme.fontPixelSize))
# Progress # Progress
self.buildProgress = NProgressCircle(self, CONFIG.pxInt(160), CONFIG.pxInt(16)) self.buildProgress = NProgressCircle(self, 160, 16)
self.buildProgress.setVisible(False) self.buildProgress.setVisible(False)
self.buildProgress.setMaximum(1) self.buildProgress.setMaximum(1)
self.buildProgress.setValue(0) self.buildProgress.setValue(0)
@@ -834,7 +822,8 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setValue(0) self.buildProgress.setValue(0)
self.buildProgress.setCentreText(None) self.buildProgress.setCentreText(None)
self.buildProgress.setVisible(True) self.buildProgress.setVisible(True)
self._scrollPos = self.verticalScrollBar().value() if vBar := self.verticalScrollBar():
self._scrollPos = vBar.value()
self.setPlaceholderText("") self.setPlaceholderText("")
self.clear() self.clear()
return return
@@ -852,9 +841,9 @@ class _PreviewWidget(QTextBrowser):
self.buildProgress.setCentreText(self.tr("Processing ...")) self.buildProgress.setCentreText(self.tr("Processing ..."))
QApplication.processEvents() QApplication.processEvents()
document.setDocumentMargin(CONFIG.getTextMargin()) document.setDocumentMargin(CONFIG.textMargin)
self.setDocument(document) self.setDocument(document)
self.setTabStopDistance(CONFIG.getTabWidth()) self.setTabStopDistance(CONFIG.tabWidth)
self._docTime = int(time()) self._docTime = int(time())
self._updateBuildAge() self._updateBuildAge()
@@ -883,10 +872,11 @@ class _PreviewWidget(QTextBrowser):
@pyqtSlot("QPrinter*") @pyqtSlot("QPrinter*")
def printPreview(self, printer: QPrinter) -> None: def printPreview(self, printer: QPrinter) -> None:
"""Connect the print preview painter to the document viewer.""" """Connect the print preview painter to the document viewer."""
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) if document := self.document():
printer.setPageOrientation(QPageLayout.Orientation.Portrait) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
self.document().print(printer) printer.setPageOrientation(QPageLayout.Orientation.Portrait)
QApplication.restoreOverrideCursor() document.print(printer)
QApplication.restoreOverrideCursor()
return return
@pyqtSlot(str) @pyqtSlot(str)
@@ -928,7 +918,8 @@ class _PreviewWidget(QTextBrowser):
def _postUpdate(self) -> None: def _postUpdate(self) -> None:
"""Run tasks after content update.""" """Run tasks after content update."""
self.buildProgress.setVisible(False) self.buildProgress.setVisible(False)
self.verticalScrollBar().setValue(self._scrollPos) if vBar := self.verticalScrollBar():
vBar.setValue(self._scrollPos)
return return
## ##
@@ -941,7 +932,7 @@ class _PreviewWidget(QTextBrowser):
""" """
vBar = self.verticalScrollBar() vBar = self.verticalScrollBar()
tB = self.frameWidth() 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 vH = self.height() - 2*tB
tH = self.ageLabel.height() tH = self.ageLabel.height()
pS = self.buildProgress.width() pS = self.buildProgress.width()
@@ -1033,10 +1024,6 @@ class _StatsWidget(QWidget):
def _buildBottomPanel(self) -> None: def _buildBottomPanel(self) -> None:
"""Build the bottom page.""" """Build the bottom page."""
mPx = CONFIG.pxInt(8)
hPx = CONFIG.pxInt(12)
vPx = CONFIG.pxInt(4)
trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS]) trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
trTextChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TEXT]) trTextChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TEXT])
trTitleChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TITLE]) trTitleChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TITLE])
@@ -1073,8 +1060,8 @@ class _StatsWidget(QWidget):
self.leftForm.addRow("", QLabel(self)) self.leftForm.addRow("", QLabel(self))
self.leftForm.addRow(trTitleCount, self.maxTitleCount) self.leftForm.addRow(trTitleCount, self.maxTitleCount)
self.leftForm.addRow(trParagraphCount, self.maxParCount) self.leftForm.addRow(trParagraphCount, self.maxParCount)
self.leftForm.setHorizontalSpacing(hPx) self.leftForm.setHorizontalSpacing(12)
self.leftForm.setVerticalSpacing(vPx) self.leftForm.setVerticalSpacing(4)
# Maximal Form, Right Column # Maximal Form, Right Column
self.maxTotalChars = QLabel(self) self.maxTotalChars = QLabel(self)
@@ -1098,25 +1085,25 @@ class _StatsWidget(QWidget):
self.rightForm.addRow(trAllWordChars, self.maxTotalWordChars) self.rightForm.addRow(trAllWordChars, self.maxTotalWordChars)
self.rightForm.addRow(trTitleWordChars, self.maxHeadWordChars) self.rightForm.addRow(trTitleWordChars, self.maxHeadWordChars)
self.rightForm.addRow(trTextWordChars, self.maxTextWordChars) self.rightForm.addRow(trTextWordChars, self.maxTextWordChars)
self.rightForm.setHorizontalSpacing(hPx) self.rightForm.setHorizontalSpacing(12)
self.rightForm.setVerticalSpacing(vPx) self.rightForm.setVerticalSpacing(4)
# Assemble # Assemble
self.minLayout = QHBoxLayout() self.minLayout = QHBoxLayout()
self.minLayout.addWidget(QLabel(trAllWords, self)) self.minLayout.addWidget(QLabel(trAllWords, self))
self.minLayout.addWidget(self.minWordCount) self.minLayout.addWidget(self.minWordCount)
self.minLayout.addSpacing(mPx) self.minLayout.addSpacing(8)
self.minLayout.addWidget(QLabel(trAllChars, self)) self.minLayout.addWidget(QLabel(trAllChars, self))
self.minLayout.addWidget(self.minCharCount) self.minLayout.addWidget(self.minCharCount)
self.minLayout.addStretch(1) self.minLayout.addStretch(1)
self.minLayout.setSpacing(mPx) self.minLayout.setSpacing(8)
self.minLayout.setContentsMargins(0, 0, 0, 0) self.minLayout.setContentsMargins(0, 0, 0, 0)
self.maxLayout = QHBoxLayout() self.maxLayout = QHBoxLayout()
self.maxLayout.addLayout(self.leftForm) self.maxLayout.addLayout(self.leftForm)
self.maxLayout.addLayout(self.rightForm) self.maxLayout.addLayout(self.rightForm)
self.maxLayout.addStretch(1) self.maxLayout.addStretch(1)
self.maxLayout.setSpacing(CONFIG.pxInt(32)) self.maxLayout.setSpacing(32)
self.maxLayout.setContentsMargins(0, 0, 0, 0) self.maxLayout.setContentsMargins(0, 0, 0, 0)
self.minWidget.setLayout(self.minLayout) self.minWidget.setLayout(self.minLayout)
+44 -54
View File
@@ -37,7 +37,7 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, trConst
from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.core.buildsettings import BuildSettings, FilterMode
from novelwriter.extensions.configlayout import ( from novelwriter.extensions.configlayout import (
@@ -83,21 +83,18 @@ class GuiBuildSettings(NToolDialog):
self._build = build self._build = build
self.setWindowTitle(self.tr("Manuscript Build Settings")) self.setWindowTitle(self.tr("Manuscript Build Settings"))
self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400)) self.setMinimumSize(700, 400)
wWin = CONFIG.pxInt(750)
hWin = CONFIG.pxInt(550)
options = SHARED.project.options options = SHARED.project.options
self.resize( self.resize(
CONFIG.pxInt(options.getInt("GuiBuildSettings", "winWidth", wWin)), options.getInt("GuiBuildSettings", "winWidth", 750),
CONFIG.pxInt(options.getInt("GuiBuildSettings", "winHeight", hWin)) options.getInt("GuiBuildSettings", "winHeight", 550),
) )
# Title # Title
self.titleLabel = NColourLabel( self.titleLabel = NColourLabel(
self.tr("Manuscript Build Settings"), self, color=SHARED.theme.helpText, 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 # Settings Name
@@ -145,7 +142,7 @@ class GuiBuildSettings(NToolDialog):
self.outerBox.addLayout(self.topBox) self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox) self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.outerBox.setSpacing(CONFIG.pxInt(12)) self.outerBox.setSpacing(12)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
@@ -240,14 +237,11 @@ class GuiBuildSettings(NToolDialog):
def _saveSettings(self) -> None: def _saveSettings(self) -> None:
"""Save the various user settings.""" """Save the various user settings."""
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
treeWidth, filterWidth = self.optTabSelect.mainSplitSizes() treeWidth, filterWidth = self.optTabSelect.mainSplitSizes()
logger.debug("Saving State: GuiBuildSettings") logger.debug("Saving State: GuiBuildSettings")
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiBuildSettings", "winWidth", winWidth) pOptions.setValue("GuiBuildSettings", "winWidth", self.width())
pOptions.setValue("GuiBuildSettings", "winHeight", winHeight) pOptions.setValue("GuiBuildSettings", "winHeight", self.height())
pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth) pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth)
pOptions.setValue("GuiBuildSettings", "filterWidth", filterWidth) pOptions.setValue("GuiBuildSettings", "filterWidth", filterWidth)
pOptions.saveSettings() pOptions.saveSettings()
@@ -300,7 +294,6 @@ class _FilterTab(NFixedPage):
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
cMg = CONFIG.pxInt(6)
# Tree Widget # Tree Widget
self.optTree = QTreeWidget(self) self.optTree = QTreeWidget(self)
@@ -311,14 +304,14 @@ class _FilterTab(NFixedPage):
self.optTree.setIndentation(iPx) self.optTree.setIndentation(iPx)
self.optTree.setColumnCount(3) self.optTree.setColumnCount(3)
treeHeader = self.optTree.header() if header := self.optTree.header():
treeHeader.setStretchLastSection(False) header.setStretchLastSection(False)
treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1551 header.setMinimumSectionSize(iPx + 6) # See Issue #1551
treeHeader.setSectionResizeMode(self.C_NAME, QtHeaderStretch) header.setSectionResizeMode(self.C_NAME, QtHeaderStretch)
treeHeader.setSectionResizeMode(self.C_ACTIVE, QtHeaderFixed) header.setSectionResizeMode(self.C_ACTIVE, QtHeaderFixed)
treeHeader.setSectionResizeMode(self.C_STATUS, QtHeaderFixed) header.setSectionResizeMode(self.C_STATUS, QtHeaderFixed)
treeHeader.resizeSection(self.C_ACTIVE, iPx + cMg) header.resizeSection(self.C_ACTIVE, iPx + 6)
treeHeader.resizeSection(self.C_STATUS, iPx + cMg) header.resizeSection(self.C_STATUS, iPx + 6)
self.optTree.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) self.optTree.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
self.optTree.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.optTree.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
@@ -347,7 +340,7 @@ class _FilterTab(NFixedPage):
self.modeBox.addWidget(self.includedButton) self.modeBox.addWidget(self.includedButton)
self.modeBox.addWidget(self.excludedButton) self.modeBox.addWidget(self.excludedButton)
self.modeBox.addWidget(self.resetButton) self.modeBox.addWidget(self.resetButton)
self.modeBox.setSpacing(CONFIG.pxInt(4)) self.modeBox.setSpacing(4)
# Filer Options # Filer Options
self.filterOpt = NSwitchBox(self, iPx) self.filterOpt = NSwitchBox(self, iPx)
@@ -375,8 +368,8 @@ class _FilterTab(NFixedPage):
self.mainSplit.setStretchFactor(0, 1) self.mainSplit.setStretchFactor(0, 1)
self.mainSplit.setStretchFactor(1, 0) self.mainSplit.setStretchFactor(1, 0)
self.mainSplit.setSizes([ self.mainSplit.setSizes([
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "treeWidth", 300)), pOptions.getInt("GuiBuildSettings", "treeWidth", 300),
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "filterWidth", 300)) pOptions.getInt("GuiBuildSettings", "filterWidth", 300),
]) ])
self.setCentralWidget(self.mainSplit) self.setCentralWidget(self.mainSplit)
@@ -393,7 +386,7 @@ class _FilterTab(NFixedPage):
"""Extract the sizes of the main splitter.""" """Extract the sizes of the main splitter."""
sizes = self.mainSplit.sizes() sizes = self.mainSplit.sizes()
m, n = (sizes[0], sizes[1]) if len(sizes) >= 2 else (0, 0) m, n = (sizes[0], sizes[1]) if len(sizes) >= 2 else (0, 0)
return CONFIG.rpxInt(m), CONFIG.rpxInt(n) return m, n
## ##
# Slots # Slots
@@ -558,15 +551,12 @@ class _HeadingsTab(NScrollablePage):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
sSp = CONFIG.pxInt(16)
vSp = CONFIG.pxInt(12)
bSp = CONFIG.pxInt(6)
trHide = self.tr("Hide") trHide = self.tr("Hide")
# Format Boxes # Format Boxes
# ============ # ============
self.formatBox = QGridLayout() self.formatBox = QGridLayout()
self.formatBox.setHorizontalSpacing(bSp) self.formatBox.setHorizontalSpacing(6)
# Title Heading # Title Heading
self.lblPart = QLabel(self._build.getLabel("headings.fmtPart"), self) 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 = NIconToolButton(self, iSz, "edit", "green")
self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE)) self.btnPart.clicked.connect(qtLambda(self._editHeading, self.EDIT_TITLE))
self.hdePart = QLabel(trHide, self) self.hdePart = QLabel(trHide, self)
self.hdePart.setIndent(bSp) self.hdePart.setIndent(6)
self.swtPart = NSwitch(self, height=iPx) self.swtPart = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblPart, 0, 0) self.formatBox.addWidget(self.lblPart, 0, 0)
@@ -591,7 +581,7 @@ class _HeadingsTab(NScrollablePage):
self.btnChapter = NIconToolButton(self, iSz, "edit", "green") self.btnChapter = NIconToolButton(self, iSz, "edit", "green")
self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER)) self.btnChapter.clicked.connect(qtLambda(self._editHeading, self.EDIT_CHAPTER))
self.hdeChapter = QLabel(trHide, self) self.hdeChapter = QLabel(trHide, self)
self.hdeChapter.setIndent(bSp) self.hdeChapter.setIndent(6)
self.swtChapter = NSwitch(self, height=iPx) self.swtChapter = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblChapter, 1, 0) self.formatBox.addWidget(self.lblChapter, 1, 0)
@@ -607,7 +597,7 @@ class _HeadingsTab(NScrollablePage):
self.btnUnnumbered = NIconToolButton(self, iSz, "edit", "green") self.btnUnnumbered = NIconToolButton(self, iSz, "edit", "green")
self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM)) self.btnUnnumbered.clicked.connect(qtLambda(self._editHeading, self.EDIT_UNNUM))
self.hdeUnnumbered = QLabel(trHide, self) self.hdeUnnumbered = QLabel(trHide, self)
self.hdeUnnumbered.setIndent(bSp) self.hdeUnnumbered.setIndent(6)
self.swtUnnumbered = NSwitch(self, height=iPx) self.swtUnnumbered = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblUnnumbered, 2, 0) self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
@@ -623,7 +613,7 @@ class _HeadingsTab(NScrollablePage):
self.btnScene = NIconToolButton(self, iSz, "edit", "green") self.btnScene = NIconToolButton(self, iSz, "edit", "green")
self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE)) self.btnScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_SCENE))
self.hdeScene = QLabel(trHide, self) self.hdeScene = QLabel(trHide, self)
self.hdeScene.setIndent(bSp) self.hdeScene.setIndent(6)
self.swtScene = NSwitch(self, height=iPx) self.swtScene = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblScene, 3, 0) self.formatBox.addWidget(self.lblScene, 3, 0)
@@ -639,7 +629,7 @@ class _HeadingsTab(NScrollablePage):
self.btnAScene = NIconToolButton(self, iSz, "edit", "green") self.btnAScene = NIconToolButton(self, iSz, "edit", "green")
self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE)) self.btnAScene.clicked.connect(qtLambda(self._editHeading, self.EDIT_HSCENE))
self.hdeAScene = QLabel(trHide, self) self.hdeAScene = QLabel(trHide, self)
self.hdeAScene.setIndent(bSp) self.hdeAScene.setIndent(6)
self.swtAScene = NSwitch(self, height=iPx) self.swtAScene = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblAScene, 4, 0) self.formatBox.addWidget(self.lblAScene, 4, 0)
@@ -655,7 +645,7 @@ class _HeadingsTab(NScrollablePage):
self.btnSection = NIconToolButton(self, iSz, "edit", "green") self.btnSection = NIconToolButton(self, iSz, "edit", "green")
self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION)) self.btnSection.clicked.connect(qtLambda(self._editHeading, self.EDIT_SECTION))
self.hdeSection = QLabel(trHide, self) self.hdeSection = QLabel(trHide, self)
self.hdeSection.setIndent(bSp) self.hdeSection.setIndent(6)
self.swtSection = NSwitch(self, height=iPx) self.swtSection = NSwitch(self, height=iPx)
self.formatBox.addWidget(self.lblSection, 5, 0) self.formatBox.addWidget(self.lblSection, 5, 0)
@@ -675,16 +665,16 @@ class _HeadingsTab(NScrollablePage):
self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document()) self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document())
self.menuInsert = QMenu(self) self.mInsert = QMenu(self)
self.aInsTitle = self.menuInsert.addAction(self.tr("Title")) self.aInsTitle = qtAddAction(self.mInsert, self.tr("Title"))
self.aInsChNum = self.menuInsert.addAction(self.tr("Chapter Number")) self.aInsChNum = qtAddAction(self.mInsert, self.tr("Chapter Number"))
self.aInsChWord = self.menuInsert.addAction(self.tr("Chapter Number (Word)")) self.aInsChWord = qtAddAction(self.mInsert, self.tr("Chapter Number (Word)"))
self.aInsChRomU = self.menuInsert.addAction(self.tr("Chapter Number (Upper Case Roman)")) self.aInsChRomU = qtAddAction(self.mInsert, self.tr("Chapter Number (Upper Case Roman)"))
self.aInsChRomL = self.menuInsert.addAction(self.tr("Chapter Number (Lower Case Roman)")) self.aInsChRomL = qtAddAction(self.mInsert, self.tr("Chapter Number (Lower Case Roman)"))
self.aInsScNum = self.menuInsert.addAction(self.tr("Scene Number (In Chapter)")) self.aInsScNum = qtAddAction(self.mInsert, self.tr("Scene Number (In Chapter)"))
self.aInsScAbs = self.menuInsert.addAction(self.tr("Scene Number (Absolute)")) self.aInsScAbs = qtAddAction(self.mInsert, self.tr("Scene Number (Absolute)"))
self.aInsCharPOV = self.menuInsert.addAction(self.tr("Point of View Character")) self.aInsCharPOV = qtAddAction(self.mInsert, self.tr("Point of View Character"))
self.aInsCharFocus = self.menuInsert.addAction(self.tr("Focus Character")) self.aInsCharFocus = qtAddAction(self.mInsert, self.tr("Focus Character"))
self.aInsTitle.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.TITLE)) self.aInsTitle.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.TITLE))
self.aInsChNum.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CH_NUM)) 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.aInsCharFocus.triggered.connect(qtLambda(self._insertIntoForm, nwHeadFmt.CHAR_FOCUS))
self.btnInsert = QPushButton(self.tr("Insert"), self) 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 = QPushButton(self.tr("Apply"), self)
self.btnApply.clicked.connect(self._saveFormat) self.btnApply.clicked.connect(self._saveFormat)
@@ -715,8 +705,8 @@ class _HeadingsTab(NScrollablePage):
# Layout Matrix # Layout Matrix
# ============= # =============
self.layoutMatrix = QGridLayout() self.layoutMatrix = QGridLayout()
self.layoutMatrix.setVerticalSpacing(vSp) self.layoutMatrix.setVerticalSpacing(12)
self.layoutMatrix.setHorizontalSpacing(vSp) self.layoutMatrix.setHorizontalSpacing(12)
self.layoutMatrix.addWidget(QLabel(self.tr("Centre"), self), 0, 1) self.layoutMatrix.addWidget(QLabel(self.tr("Centre"), self), 0, 1)
self.layoutMatrix.addWidget(QLabel(self.tr("Page Break"), self), 0, 2) self.layoutMatrix.addWidget(QLabel(self.tr("Page Break"), self), 0, 2)
@@ -764,9 +754,9 @@ class _HeadingsTab(NScrollablePage):
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.formatBox) self.outerBox.addLayout(self.formatBox)
self.outerBox.addSpacing(sSp) self.outerBox.addSpacing(16)
self.outerBox.addLayout(self.editFormBox) self.outerBox.addLayout(self.editFormBox)
self.outerBox.addSpacing(sSp) self.outerBox.addSpacing(16)
self.outerBox.addLayout(self.layoutMatrix) self.outerBox.addLayout(self.layoutMatrix)
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
@@ -904,7 +894,7 @@ class _HeadingsTab(NScrollablePage):
class _HeadingSyntaxHighlighter(QSyntaxHighlighter): class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
def __init__(self, document: QTextDocument) -> None: def __init__(self, document: QTextDocument | None) -> None:
super().__init__(document) super().__init__(document)
syntax = SHARED.theme.syntaxTheme syntax = SHARED.theme.syntaxTheme
self._fmtSymbol = QTextCharFormat() self._fmtSymbol = QTextCharFormat()
@@ -1223,7 +1213,7 @@ class _FormattingTab(NScrollableForm):
# Header # Header
self.odtPageHeader = QLineEdit(self) self.odtPageHeader = QLineEdit(self)
self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200)) self.odtPageHeader.setMinimumWidth(200)
self.btnPageHeader = NIconToolButton(self, iSz, "revert", "green") self.btnPageHeader = NIconToolButton(self, iSz, "revert", "green")
self.btnPageHeader.clicked.connect(self._resetPageHeader) self.btnPageHeader.clicked.connect(self._resetPageHeader)
self.addRow( self.addRow(
+32 -50
View File
@@ -34,7 +34,7 @@ from PyQt6.QtWidgets import (
QVBoxLayout, QWidget QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.common import formatTime, numberToRoman from novelwriter.common import formatTime, numberToRoman
from novelwriter.constants import nwUnicode from novelwriter.constants import nwUnicode
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage
@@ -60,16 +60,16 @@ class GuiNovelDetails(NNonBlockingDialog):
self.setWindowTitle(self.tr("Novel Details")) self.setWindowTitle(self.tr("Novel Details"))
options = SHARED.project.options options = SHARED.project.options
self.setMinimumSize(CONFIG.pxInt(500), CONFIG.pxInt(400)) self.setMinimumSize(500, 400)
self.resize( self.resize(
CONFIG.pxInt(options.getInt("GuiNovelDetails", "winWidth", CONFIG.pxInt(650))), options.getInt("GuiNovelDetails", "winWidth", 650),
CONFIG.pxInt(options.getInt("GuiNovelDetails", "winHeight", CONFIG.pxInt(500))) options.getInt("GuiNovelDetails", "winHeight", 500),
) )
# Title # Title
self.titleLabel = NColourLabel( self.titleLabel = NColourLabel(
self.tr("Novel Details"), self, color=SHARED.theme.helpText, 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 # Novel Selector
@@ -114,7 +114,7 @@ class GuiNovelDetails(NNonBlockingDialog):
self.outerBox.addLayout(self.topBox) self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox) self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.buttonBox) self.outerBox.addWidget(self.buttonBox)
self.outerBox.setSpacing(CONFIG.pxInt(8)) self.outerBox.setSpacing(8)
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
self.setSizeGripEnabled(True) self.setSizeGripEnabled(True)
@@ -172,18 +172,13 @@ class GuiNovelDetails(NNonBlockingDialog):
def _saveSettings(self) -> None: def _saveSettings(self) -> None:
"""Save the user GUI settings.""" """Save the user GUI settings."""
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
novelRoot = self.novelSelector.handle
logger.debug("Saving State: GuiNovelDetails") logger.debug("Saving State: GuiNovelDetails")
novelRoot = self.novelSelector.handle
options = SHARED.project.options options = SHARED.project.options
options.setValue("GuiNovelDetails", "winWidth", winWidth) options.setValue("GuiNovelDetails", "winWidth", self.width())
options.setValue("GuiNovelDetails", "winHeight", winHeight) options.setValue("GuiNovelDetails", "winHeight", self.height())
options.setValue("GuiNovelDetails", "novelRoot", novelRoot) options.setValue("GuiNovelDetails", "novelRoot", novelRoot)
self.contentsPage.saveSettings() self.contentsPage.saveSettings()
return return
@@ -192,11 +187,6 @@ class _OverviewPage(NScrollablePage):
def __init__(self, parent: QWidget) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
mPx = CONFIG.pxInt(8)
sPx = CONFIG.pxInt(16)
hPx = CONFIG.pxInt(24)
vPx = CONFIG.pxInt(4)
# Project Info # Project Info
self.projLabel = NColourLabel( self.projLabel = NColourLabel(
self.tr("Project"), self, color=SHARED.theme.helpText, self.tr("Project"), self, color=SHARED.theme.helpText,
@@ -217,9 +207,9 @@ class _OverviewPage(NScrollablePage):
self.projForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.projWords) self.projForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.projWords)
self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Novels")), self.projNovels) self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Novels")), self.projNovels)
self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes")), self.projNotes) self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes")), self.projNotes)
self.projForm.setContentsMargins(mPx, 0, 0, 0) self.projForm.setContentsMargins(8, 0, 0, 0)
self.projForm.setHorizontalSpacing(hPx) self.projForm.setHorizontalSpacing(24)
self.projForm.setVerticalSpacing(vPx) self.projForm.setVerticalSpacing(4)
# Novel Info # Novel Info
self.novelLabel = NColourLabel( self.novelLabel = NColourLabel(
@@ -237,9 +227,9 @@ class _OverviewPage(NScrollablePage):
self.novelForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.novelWords) self.novelForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.novelWords)
self.novelForm.addRow("<b>{0}</b>".format(self.tr("Chapters")), self.novelChapters) self.novelForm.addRow("<b>{0}</b>".format(self.tr("Chapters")), self.novelChapters)
self.novelForm.addRow("<b>{0}</b>".format(self.tr("Scenes")), self.novelScenes) self.novelForm.addRow("<b>{0}</b>".format(self.tr("Scenes")), self.novelScenes)
self.novelForm.setContentsMargins(mPx, 0, 0, 0) self.novelForm.setContentsMargins(8, 0, 0, 0)
self.novelForm.setHorizontalSpacing(hPx) self.novelForm.setHorizontalSpacing(24)
self.novelForm.setVerticalSpacing(vPx) self.novelForm.setVerticalSpacing(4)
# Assemble # Assemble
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
@@ -247,7 +237,7 @@ class _OverviewPage(NScrollablePage):
self.outerBox.addLayout(self.projForm) self.outerBox.addLayout(self.projForm)
self.outerBox.addWidget(self.novelLabel) self.outerBox.addWidget(self.novelLabel)
self.outerBox.addLayout(self.novelForm) self.outerBox.addLayout(self.novelForm)
self.outerBox.setSpacing(sPx) self.outerBox.setSpacing(16)
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
self.setCentralLayout(self.outerBox) self.setCentralLayout(self.outerBox)
@@ -309,8 +299,6 @@ class _ContentsPage(NFixedPage):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
hPx = CONFIG.pxInt(12)
vPx = CONFIG.pxInt(4)
options = SHARED.project.options options = SHARED.project.options
# Title # Title
@@ -341,22 +329,22 @@ class _ContentsPage(NFixedPage):
treeHeadItem.setTextAlignment(self.C_PAGE, QtAlignRight) treeHeadItem.setTextAlignment(self.C_PAGE, QtAlignRight)
treeHeadItem.setTextAlignment(self.C_PROG, QtAlignRight) treeHeadItem.setTextAlignment(self.C_PROG, QtAlignRight)
treeHeader = self.tocTree.header() if header := self.tocTree.header():
treeHeader.setStretchLastSection(True) header.setStretchLastSection(True)
treeHeader.setMinimumSectionSize(hPx) header.setMinimumSectionSize(12)
wCol0 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol0", 200)) wCol0 = options.getInt("GuiNovelDetails", "widthCol0", 200)
wCol1 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol1", 60)) wCol1 = options.getInt("GuiNovelDetails", "widthCol1", 60)
wCol2 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol2", 60)) wCol2 = options.getInt("GuiNovelDetails", "widthCol2", 60)
wCol3 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol3", 60)) wCol3 = options.getInt("GuiNovelDetails", "widthCol3", 60)
wCol4 = CONFIG.pxInt(options.getInt("GuiNovelDetails", "widthCol4", 90)) wCol4 = options.getInt("GuiNovelDetails", "widthCol4", 90)
self.tocTree.setColumnWidth(0, wCol0) self.tocTree.setColumnWidth(0, wCol0)
self.tocTree.setColumnWidth(1, wCol1) self.tocTree.setColumnWidth(1, wCol1)
self.tocTree.setColumnWidth(2, wCol2) self.tocTree.setColumnWidth(2, wCol2)
self.tocTree.setColumnWidth(3, wCol3) self.tocTree.setColumnWidth(3, wCol3)
self.tocTree.setColumnWidth(4, wCol4) self.tocTree.setColumnWidth(4, wCol4)
self.tocTree.setColumnWidth(5, hPx) self.tocTree.setColumnWidth(5, 12)
# Options # Options
wordsPerPage = options.getInt("GuiNovelDetails", "wordsPerPage", 350) wordsPerPage = options.getInt("GuiNovelDetails", "wordsPerPage", 350)
@@ -394,8 +382,8 @@ class _ContentsPage(NFixedPage):
self.optionsBox.addWidget(self.dblValue, 0, 4) self.optionsBox.addWidget(self.dblValue, 0, 4)
self.optionsBox.addWidget(self.poLabel, 1, 0) self.optionsBox.addWidget(self.poLabel, 1, 0)
self.optionsBox.addWidget(self.poValue, 1, 1) self.optionsBox.addWidget(self.poValue, 1, 1)
self.optionsBox.setHorizontalSpacing(hPx) self.optionsBox.setHorizontalSpacing(12)
self.optionsBox.setVerticalSpacing(vPx) self.optionsBox.setVerticalSpacing(4)
self.optionsBox.setColumnStretch(2, 1) self.optionsBox.setColumnStretch(2, 1)
# Assemble # Assemble
@@ -410,18 +398,12 @@ class _ContentsPage(NFixedPage):
def saveSettings(self) -> None: def saveSettings(self) -> None:
"""Save the user GUI settings.""" """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 = SHARED.project.options
options.setValue("GuiNovelDetails", "widthCol0", widthCol0) options.setValue("GuiNovelDetails", "widthCol0", self.tocTree.columnWidth(0))
options.setValue("GuiNovelDetails", "widthCol1", widthCol1) options.setValue("GuiNovelDetails", "widthCol1", self.tocTree.columnWidth(1))
options.setValue("GuiNovelDetails", "widthCol2", widthCol2) options.setValue("GuiNovelDetails", "widthCol2", self.tocTree.columnWidth(2))
options.setValue("GuiNovelDetails", "widthCol3", widthCol3) options.setValue("GuiNovelDetails", "widthCol3", self.tocTree.columnWidth(3))
options.setValue("GuiNovelDetails", "widthCol4", widthCol4) options.setValue("GuiNovelDetails", "widthCol4", self.tocTree.columnWidth(4))
options.setValue("GuiNovelDetails", "wordsPerPage", self.wpValue.value()) options.setValue("GuiNovelDetails", "wordsPerPage", self.wpValue.value())
options.setValue("GuiNovelDetails", "countFrom", self.poValue.value()) options.setValue("GuiNovelDetails", "countFrom", self.poValue.value())
options.setValue("GuiNovelDetails", "clearDouble", self.dblValue.isChecked()) options.setValue("GuiNovelDetails", "clearDouble", self.dblValue.isChecked())
+26 -37
View File
@@ -40,7 +40,7 @@ from PyQt6.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED 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.constants import nwFiles
from novelwriter.core.coretools import ProjectBuilder from novelwriter.core.coretools import ProjectBuilder
from novelwriter.enum import nwItemClass from novelwriter.enum import nwItemClass
@@ -66,29 +66,21 @@ class GuiWelcome(NDialog):
self.setObjectName("GuiWelcome") self.setObjectName("GuiWelcome")
self.setWindowTitle(self.tr("Welcome")) self.setWindowTitle(self.tr("Welcome"))
self.setMinimumWidth(CONFIG.pxInt(650)) self.setMinimumWidth(650)
self.setMinimumHeight(CONFIG.pxInt(450)) self.setMinimumHeight(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.resize(*CONFIG.welcomeWinSize) self.resize(*CONFIG.welcomeWinSize)
btnIconSize = SHARED.theme.buttonIconSize
# Elements # Elements
# ======== # ========
self.bgImage = SHARED.theme.loadDecoration("welcome") 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.bgColor = QColor(54, 54, 54) if SHARED.theme.isDarkTheme else QColor(255, 255, 255)
self.nwLogo = QLabel(self) 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 = QLabel(self)
self.nwLabel.setPixmap(self.nwImage) self.nwLabel.setPixmap(self.nwImage)
@@ -152,18 +144,18 @@ class GuiWelcome(NDialog):
# ======== # ========
self.innerBox = QVBoxLayout() self.innerBox = QVBoxLayout()
self.innerBox.addSpacing(hB) self.innerBox.addSpacing(16)
self.innerBox.addWidget(self.nwLabel) self.innerBox.addWidget(self.nwLabel)
self.innerBox.addWidget(self.nwInfo) self.innerBox.addWidget(self.nwInfo)
self.innerBox.addSpacing(hA) self.innerBox.addSpacing(8)
self.innerBox.addWidget(self.mainStack) self.innerBox.addWidget(self.mainStack)
self.innerBox.addSpacing(hB) self.innerBox.addSpacing(16)
self.innerBox.addLayout(self.btnBox) self.innerBox.addLayout(self.btnBox)
self.outerBox = QHBoxLayout() self.outerBox = QHBoxLayout()
self.outerBox.addWidget(self.nwLogo, 3, QtAlignRightTop) self.outerBox.addWidget(self.nwLogo, 3, QtAlignRightTop)
self.outerBox.addLayout(self.innerBox, 9) 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.setLayout(self.outerBox)
self.setSizeGripEnabled(True) self.setSizeGripEnabled(True)
@@ -183,7 +175,7 @@ class GuiWelcome(NDialog):
def paintEvent(self, event: QPaintEvent) -> None: def paintEvent(self, event: QPaintEvent) -> None:
"""Overload the paint event to draw the background image.""" """Overload the paint event to draw the background image."""
hWin = self.height() hWin = self.height()
hPix = min(hWin, self._hPx) hPix = min(hWin, 600)
tMode = Qt.TransformationMode.SmoothTransformation tMode = Qt.TransformationMode.SmoothTransformation
painter = QPainter(self) painter = QPainter(self)
painter.fillRect(self.rect(), self.bgColor) painter.fillRect(self.rect(), self.bgColor)
@@ -309,11 +301,10 @@ class _OpenProjectPage(QWidget):
self._selectFirstItem() self._selectFirstItem()
mPx = CONFIG.pxInt(4)
baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA) baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
self.setStyleSheet( self.setStyleSheet(
f"QListView {{border: none; background: {baseCol};}} " f"QListView {{border: none; background: {baseCol};}} "
f"QLineEdit {{border: none; background: {baseCol}; padding: {mPx}px;}} " f"QLineEdit {{border: none; background: {baseCol}; padding: 4px;}} "
) )
return return
@@ -370,9 +361,9 @@ class _OpenProjectPage(QWidget):
"""Open the custom context menu.""" """Open the custom context menu."""
ctxMenu = QMenu(self) ctxMenu = QMenu(self)
ctxMenu.setObjectName("ContextMenu") # Used for testing 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.triggered.connect(self.openSelectedItem)
action = ctxMenu.addAction(self.tr("Remove Project")) action = qtAddAction(ctxMenu, self.tr("Remove Project"))
action.triggered.connect(self._deleteSelectedItem) action.triggered.connect(self._deleteSelectedItem)
ctxMenu.exec(self.mapToGlobal(pos)) ctxMenu.exec(self.mapToGlobal(pos))
ctxMenu.deleteLater() ctxMenu.deleteLater()
@@ -400,11 +391,10 @@ class _ProjectListItem(QStyledItemDelegate):
fPx = SHARED.theme.fontPixelSize fPx = SHARED.theme.fontPixelSize
fPt = SHARED.theme.fontPointSize fPt = SHARED.theme.fontPointSize
tPx = round(1.2 * fPx) tPx = round(1.2 * fPx)
mPx = CONFIG.pxInt(4)
iPx = tPx + fPx iPx = tPx + fPx
self._pPx = (mPx//2, 3*mPx//2, iPx + mPx, mPx, mPx + tPx) # Painter coordinates self._pPx = (iPx + 4, tPx + 4) # Painter coordinates
self._hPx = 2*mPx + tPx + fPx # Fixed height self._hPx = 8 + tPx + fPx # Fixed height
self._tFont = QApplication.font() self._tFont = QApplication.font()
self._tFont.setPointSizeF(1.2*fPt) self._tFont.setPointSizeF(1.2*fPt)
@@ -423,7 +413,7 @@ class _ProjectListItem(QStyledItemDelegate):
rect = opt.rect rect = opt.rect
title, _, details = index.data() title, _, details = index.data()
tFlag = Qt.TextFlag.TextSingleLine tFlag = Qt.TextFlag.TextSingleLine
ix, iy, x, y1, y2 = self._pPx x, y = self._pPx
painter.save() painter.save()
if opt.state & QtSelected == QtSelected: if opt.state & QtSelected == QtSelected:
@@ -431,12 +421,12 @@ class _ProjectListItem(QStyledItemDelegate):
painter.fillRect(rect, QApplication.palette().highlight()) painter.fillRect(rect, QApplication.palette().highlight())
painter.setOpacity(1.0) 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.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.setFont(self._dFont)
painter.setPen(self._dPen) 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() painter.restore()
return return
@@ -557,7 +547,6 @@ class _NewProjectForm(QWidget):
iPx = SHARED.theme.baseIconHeight iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
sPx = CONFIG.pxInt(16)
# Project Settings # Project Settings
# ================ # ================
@@ -592,15 +581,15 @@ class _NewProjectForm(QWidget):
self.fillMenu = QMenu(self.browseFill) 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.setIcon(SHARED.theme.getIcon("document"))
self.fillBlank.triggered.connect(self._setFillBlank) 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.setIcon(SHARED.theme.getIcon("document_add", "blue"))
self.fillSample.triggered.connect(self._setFillSample) 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.setIcon(SHARED.theme.getIcon("project_copy", "green"))
self.fillCopy.triggered.connect(self._setFillCopy) self.fillCopy.triggered.connect(self._setFillCopy)
@@ -675,7 +664,7 @@ class _NewProjectForm(QWidget):
self.extraBox = QVBoxLayout() self.extraBox = QVBoxLayout()
self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes")), self)) self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes")), self))
self.extraBox.addLayout(self.novelForm) self.extraBox.addLayout(self.novelForm)
self.extraBox.addSpacing(sPx) self.extraBox.addSpacing(16)
self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes")), self)) self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes")), self))
self.extraBox.addLayout(self.notesForm) self.extraBox.addLayout(self.notesForm)
self.extraBox.setContentsMargins(0, 0, 0, 0) self.extraBox.setContentsMargins(0, 0, 0, 0)
@@ -687,7 +676,7 @@ class _NewProjectForm(QWidget):
self.formBox = QVBoxLayout() self.formBox = QVBoxLayout()
self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project")), self)) self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project")), self))
self.formBox.addLayout(self.projectForm) self.formBox.addLayout(self.projectForm)
self.formBox.addSpacing(sPx) self.formBox.addSpacing(16)
self.formBox.addWidget(self.extraWidget) self.formBox.addWidget(self.extraWidget)
self.formBox.addStretch(1) self.formBox.addStretch(1)
+32 -43
View File
@@ -82,26 +82,18 @@ class GuiWritingStats(NToolDialog):
pOptions = SHARED.project.options pOptions = SHARED.project.options
self.setWindowTitle(self.tr("Writing Statistics")) self.setWindowTitle(self.tr("Writing Statistics"))
self.setMinimumWidth(CONFIG.pxInt(420)) self.setMinimumWidth(420)
self.setMinimumHeight(CONFIG.pxInt(400)) self.setMinimumHeight(400)
self.resize( self.resize(
CONFIG.pxInt(pOptions.getInt("GuiWritingStats", "winWidth", 550)), pOptions.getInt("GuiWritingStats", "winWidth", 550),
CONFIG.pxInt(pOptions.getInt("GuiWritingStats", "winHeight", 500)) pOptions.getInt("GuiWritingStats", "winHeight", 500),
) )
# List Box # List Box
wCol0 = CONFIG.pxInt( wCol0 = pOptions.getInt("GuiWritingStats", "widthCol0", 180)
pOptions.getInt("GuiWritingStats", "widthCol0", 180) wCol1 = pOptions.getInt("GuiWritingStats", "widthCol1", 80)
) wCol2 = pOptions.getInt("GuiWritingStats", "widthCol2", 80)
wCol1 = CONFIG.pxInt( wCol3 = pOptions.getInt("GuiWritingStats", "widthCol3", 80)
pOptions.getInt("GuiWritingStats", "widthCol1", 80)
)
wCol2 = CONFIG.pxInt(
pOptions.getInt("GuiWritingStats", "widthCol2", 80)
)
wCol3 = CONFIG.pxInt(
pOptions.getInt("GuiWritingStats", "widthCol3", 80)
)
self.listBox = QTreeWidget(self) self.listBox = QTreeWidget(self)
self.listBox.setHeaderLabels([ self.listBox.setHeaderLabels([
@@ -133,7 +125,6 @@ class GuiWritingStats(NToolDialog):
# Word Bar # Word Bar
self.barHeight = int(round(0.5*SHARED.theme.fontPixelSize)) self.barHeight = int(round(0.5*SHARED.theme.fontPixelSize))
self.barWidth = CONFIG.pxInt(200)
self.barImage = QPixmap(self.barHeight, self.barHeight) self.barImage = QPixmap(self.barHeight, self.barHeight)
self.barImage.fill(self.palette().highlight().color()) self.barImage.fill(self.palette().highlight().color())
@@ -262,25 +253,27 @@ class GuiWritingStats(NToolDialog):
self.optsBox.addWidget(self.histMax, 0) self.optsBox.addWidget(self.histMax, 0)
# Buttons # 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 = QDialogButtonBox(self)
self.buttonBox.rejected.connect(self._doClose) self.buttonBox.rejected.connect(self._doClose)
self.btnClose = self.buttonBox.addButton(QtDialogClose) 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 = self.buttonBox.addButton(self.tr("Save As"), QtRoleAction)
self.btnSave.setAutoDefault(False) if self.btnSave:
self.btnSave.setAutoDefault(False)
self.saveMenu = QMenu(self) self.btnSave.setMenu(self.saveMenu)
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)
# Assemble # Assemble
self.outerBox = QGridLayout() self.outerBox = QGridLayout()
@@ -328,14 +321,10 @@ class GuiWritingStats(NToolDialog):
"""Save the state of the window, clear cache, end close.""" """Save the state of the window, clear cache, end close."""
self.logData = [] self.logData = []
winWidth = CONFIG.rpxInt(self.width()) header = self.listBox.header()
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))
sortCol = self.listBox.sortColumn() sortCol = self.listBox.sortColumn()
sortOrder = self.listBox.header().sortIndicatorOrder() sortOrder = header.sortIndicatorOrder() if header else 0
incNovel = self.incNovel.isChecked() incNovel = self.incNovel.isChecked()
incNotes = self.incNotes.isChecked() incNotes = self.incNotes.isChecked()
hideZeros = self.hideZeros.isChecked() hideZeros = self.hideZeros.isChecked()
@@ -346,12 +335,12 @@ class GuiWritingStats(NToolDialog):
logger.debug("Saving State: GuiWritingStats") logger.debug("Saving State: GuiWritingStats")
pOptions = SHARED.project.options pOptions = SHARED.project.options
pOptions.setValue("GuiWritingStats", "winWidth", winWidth) pOptions.setValue("GuiWritingStats", "winWidth", self.width())
pOptions.setValue("GuiWritingStats", "winHeight", winHeight) pOptions.setValue("GuiWritingStats", "winHeight", self.height())
pOptions.setValue("GuiWritingStats", "widthCol0", widthCol0) pOptions.setValue("GuiWritingStats", "widthCol0", self.listBox.columnWidth(0))
pOptions.setValue("GuiWritingStats", "widthCol1", widthCol1) pOptions.setValue("GuiWritingStats", "widthCol1", self.listBox.columnWidth(1))
pOptions.setValue("GuiWritingStats", "widthCol2", widthCol2) pOptions.setValue("GuiWritingStats", "widthCol2", self.listBox.columnWidth(2))
pOptions.setValue("GuiWritingStats", "widthCol3", widthCol3) pOptions.setValue("GuiWritingStats", "widthCol3", self.listBox.columnWidth(3))
pOptions.setValue("GuiWritingStats", "sortCol", sortCol) pOptions.setValue("GuiWritingStats", "sortCol", sortCol)
pOptions.setValue("GuiWritingStats", "sortOrder", sortOrder) pOptions.setValue("GuiWritingStats", "sortOrder", sortOrder)
pOptions.setValue("GuiWritingStats", "incNovel", incNovel) pOptions.setValue("GuiWritingStats", "incNovel", incNovel)
-29
View File
@@ -23,8 +23,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations from __future__ import annotations
from typing import Any, TypeVar
from PyQt6.QtCore import Qt from PyQt6.QtCore import Qt
from PyQt6.QtGui import QColor, QFont, QPainter, QTextCharFormat, QTextCursor, QTextFormat from PyQt6.QtGui import QColor, QFont, QPainter, QTextCharFormat, QTextCursor, QTextFormat
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QHeaderView, QSizePolicy, QStyle 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.StyleItalic: "italic",
QFont.Style.StyleOblique: "oblique", 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)
+4 -27
View File
@@ -254,52 +254,29 @@ def testBaseConfig_SettersGetters(fncPath):
tstConf.setMainWinSize(70, 70) tstConf.setMainWinSize(70, 70)
assert tstConf.mainWinSize == [70, 70] assert tstConf.mainWinSize == [70, 70]
assert tstConf._mainWinSize == [70, 70] assert tstConf.mainWinSize == [70, 70]
tstConf.setMainWinSize(1200, 650) tstConf.setMainWinSize(1200, 650)
# Welcome Window Size # Welcome Window Size
tstConf.setWelcomeWinSize(70, 70) tstConf.setWelcomeWinSize(70, 70)
assert tstConf.welcomeWinSize == [70, 70] assert tstConf.welcomeWinSize == [70, 70]
assert tstConf._welcomeSize == [70, 70] assert tstConf.welcomeWinSize == [70, 70]
tstConf.setWelcomeWinSize(800, 500) tstConf.setWelcomeWinSize(800, 500)
# Preferences Size # Preferences Size
tstConf.setPreferencesWinSize(70, 70) 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) 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 # Getters Only
# ============ # ============
assert tstConf.getTextWidth(False) == 700 assert tstConf.getTextWidth(False) == 700
assert tstConf.getTextWidth(True) == 800 assert tstConf.getTextWidth(True) == 800
assert tstConf.getTextMargin() == 40
assert tstConf.getTabWidth() == 40
@pytest.mark.base @pytest.mark.base
+1 -1
View File
@@ -398,7 +398,7 @@ def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRn
buildTwo.setName("Build Two") buildTwo.setName("Build Two")
buildIDTwo = buildTwo.buildID buildIDTwo = buildTwo.buildID
# Check that we can extract infor about the builds # Check that we can extract info about the builds
builds.setBuild(buildTwo) builds.setBuild(buildTwo)
assert len(builds) == 2 assert len(builds) == 2
assert buildsFile.exists() assert buildsFile.exists()
+3 -1
View File
@@ -41,7 +41,9 @@ def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
msgAbout = SHARED.findTopLevelWidget(GuiAbout) msgAbout = SHARED.findTopLevelWidget(GuiAbout)
assert isinstance(msgAbout, 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: with monkeypatch.context() as mp:
mp.setattr("novelwriter.config.Config.assetPath", lambda *a: Path("whatever")) mp.setattr("novelwriter.config.Config.assetPath", lambda *a: Path("whatever"))
+23 -16
View File
@@ -72,17 +72,16 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
prefs.close() prefs.close()
# Check Fallback Values # Check Fallback Values
with monkeypatch.context() as mp: CONFIG.hasEnchant = False
mp.setattr(CONFIG, "hasEnchant", False) prefs = GuiPreferences(nwGUI)
prefs = GuiPreferences(nwGUI) prefs.show()
prefs.show()
# Check Spell Checking # Check Spell Checking
spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())] spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())]
assert len(spelling) == 1 assert len(spelling) == 1
assert spelling == [""] assert spelling == [""]
prefs.close() prefs.close()
# qtbot.stop() # qtbot.stop()
@@ -97,6 +96,7 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
# Check Navigation # Check Navigation
vBar = prefs.mainForm.verticalScrollBar() vBar = prefs.mainForm.verticalScrollBar()
assert vBar is not None
old = -1 old = -1
with qtbot.waitSignal(vBar.valueChanged) as value: with qtbot.waitSignal(vBar.valueChanged) as value:
prefs.sidebar.button(1).click() prefs.sidebar.button(1).click()
@@ -120,12 +120,16 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
# Check Save Button # Check Save Button
prefs.show() prefs.show()
with qtbot.waitSignal(prefs.newPreferencesReady) as signal: 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] assert signal.args == [False, False, False, False]
# Check Close Button # Check Close Button
prefs.show() prefs.show()
prefs.buttonBox.button(QtDialogCancel).click() button = prefs.buttonBox.button(QtDialogCancel)
assert button is not None
button.click()
assert prefs.isHidden() is True assert prefs.isHidden() is True
# Close Using Escape Key # Close Using Escape Key
@@ -138,13 +142,14 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
@pytest.mark.gui @pytest.mark.gui
def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths): def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
"""Test the preferences dialog settings.""" """Test the preferences dialog settings."""
spelling = [("en", "English [en]"), ("de", "Deutch [de]")] 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(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) prefs = GuiPreferences(nwGUI)
with qtbot.waitExposed(prefs): with qtbot.waitExposed(prefs):
@@ -313,7 +318,9 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, tstPaths):
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QFontDatabase, "families", lambda *a: ["TestFont"]) mp.setattr(QFontDatabase, "families", lambda *a: ["TestFont"])
with qtbot.waitSignal(prefs.newPreferencesReady) as signal: 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] assert signal.args == [True, True, True, True]
# Check Settings # Check Settings
@@ -88,7 +88,12 @@ def testDlgProjSettings_SettingsPage(qtbot, monkeypatch, nwGUI, fncPath, projPat
"""Test the settings page of the dialog.""" """Test the settings page of the dialog."""
languages = [("en", "English"), ("de", "German")] languages = [("en", "English"), ("de", "German")]
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda *a: languages) 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 # Create new project
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
+11 -6
View File
@@ -441,6 +441,9 @@ def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
ctxMenu.deleteLater() ctxMenu.deleteLater()
# Copy Text # Copy Text
clipboard = QApplication.clipboard()
assert clipboard is not None
ctxMenu = getMenuForPos(docEditor, 31, True) ctxMenu = getMenuForPos(docEditor, 31, True)
assert ctxMenu is not None assert ctxMenu is not None
assert docEditor.textCursor().selectedText() == "text" assert docEditor.textCursor().selectedText() == "text"
@@ -448,14 +451,14 @@ def testGuiEditor_ContextMenu(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
assert actions == [ assert actions == [
"Cut", "Copy", "Paste", "Select All", "Select Word", "Select Paragraph" "Cut", "Copy", "Paste", "Select All", "Select Word", "Select Paragraph"
] ]
QApplication.clipboard().clear() clipboard.clear()
ctxMenu.actions()[1].trigger() ctxMenu.actions()[1].trigger()
assert QApplication.clipboard().text(QClipboard.Mode.Clipboard) == "text" assert clipboard.text(QClipboard.Mode.Clipboard) == "text"
# Cut Text # Cut Text
QApplication.clipboard().clear() clipboard.clear()
ctxMenu.actions()[0].trigger() 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() assert "text" not in docEditor.getText()
# Paste Text # Paste Text
@@ -572,7 +575,9 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
# Select/Cut/Copy/Paste/Undo/Redo # Select/Cut/Copy/Paste/Undo/Redo
# =============================== # ===============================
QApplication.clipboard().clear() clipboard = QApplication.clipboard()
assert clipboard is not None
clipboard.clear()
# Select All # Select All
assert docEditor.docAction(nwDocAction.SEL_ALL) is True 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[5] == ipsumText[4]
assert newPara[6] == ipsumText[2] assert newPara[6] == ipsumText[2]
QApplication.clipboard().clear() clipboard.clear()
# Emphasis/Undo/Redo # Emphasis/Undo/Redo
# ================== # ==================
+7 -6
View File
@@ -91,18 +91,19 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
docViewer.setTextCursor(cursor) docViewer.setTextCursor(cursor)
docViewer._makeSelection(QTextCursor.SelectionType.WordUnderCursor) docViewer._makeSelection(QTextCursor.SelectionType.WordUnderCursor)
qClip = QApplication.clipboard() clipboard = QApplication.clipboard()
qClip.clear() assert clipboard is not None
clipboard.clear()
# Cut # Cut
assert docViewer.docAction(nwDocAction.CUT) is True assert docViewer.docAction(nwDocAction.CUT) is True
assert qClip.text() == "laoreet" assert clipboard.text() == "laoreet"
qClip.clear() clipboard.clear()
# Copy # Copy
assert docViewer.docAction(nwDocAction.COPY) is True assert docViewer.docAction(nwDocAction.COPY) is True
assert qClip.text() == "laoreet" assert clipboard.text() == "laoreet"
qClip.clear() clipboard.clear()
# Select Paragraph # Select Paragraph
assert docViewer.docAction(nwDocAction.SEL_PARA) is True assert docViewer.docAction(nwDocAction.SEL_PARA) is True
+3 -1
View File
@@ -1148,7 +1148,9 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
def getTransformSubMenu(menu: QMenu) -> list[str]: def getTransformSubMenu(menu: QMenu) -> list[str]:
for action in menu.actions(): for action in menu.actions():
if action.text() == "Transform ...": 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 [] return []
# Context Menu on Document File Item # Context Menu on Document File Item
+6 -2
View File
@@ -95,7 +95,9 @@ def testToolManuscriptBuild_Main(
assert (fncPath / "TestBuild").with_suffix(nwLabels.BUILD_EXT[fmt]).exists() assert (fncPath / "TestBuild").with_suffix(nwLabels.BUILD_EXT[fmt]).exists()
lastFmt = fmt lastFmt = fmt
manus._dialogButtonClicked(manus.buttonBox.button(QtDialogClose)) button = manus.buttonBox.button(QtDialogClose)
assert button is not None
manus._dialogButtonClicked(button)
manus.deleteLater() manus.deleteLater()
assert build.lastBuildName == "TestBuild" assert build.lastBuildName == "TestBuild"
@@ -150,5 +152,7 @@ def testToolManuscriptBuild_Main(
assert lastUrl.startswith("file://") assert lastUrl.startswith("file://")
# Finish # Finish
manus._dialogButtonClicked(manus.buttonBox.button(QtDialogClose)) button = manus.buttonBox.button(QtDialogClose)
assert button is not None
manus._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
+15 -5
View File
@@ -67,7 +67,9 @@ def testToolManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
# Build a preview # Build a preview
manus.buildList.clearSelection() manus.buildList.clearSelection()
manus.buildList.setCurrentRow(0) 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() manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() == allText assert manus.docPreview.toPlainText().strip() == allText
@@ -113,7 +115,9 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady) 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 isinstance(build, BuildSettings)
assert build.name == "Test Build" assert build.name == "Test Build"
@@ -132,7 +136,9 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady) 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 isinstance(build, BuildSettings)
assert build.name == "Test Build" assert build.name == "Test Build"
@@ -210,7 +216,9 @@ def testToolManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
manus._builds.setBuild(build) manus._builds.setBuild(build)
manus.buildList.setCurrentRow(0) 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() manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() != "" assert manus.docPreview.toPlainText().strip() != ""
@@ -304,7 +312,9 @@ def testToolManuscript_Print(monkeypatch, qtbot, nwGUI, projPath):
manus.loadContent() manus.loadContent()
manus.buildList.setCurrentRow(0) 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() manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() != "" assert manus.docPreview.toPlainText().strip() != ""
+60 -20
View File
@@ -51,13 +51,19 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
bSettings.loadContent() bSettings.loadContent()
# Flip through pages # 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) 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) 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) assert isinstance(bSettings.toolStack.currentWidget(), _FilterTab)
# Check dialog buttons # Check dialog buttons
@@ -72,7 +78,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
# Capture Apply button # Capture Apply button
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady) 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 assert triggered
@@ -81,7 +89,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
bSettings.newSettingsReady.connect(_testNewSettingsReady) 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 assert triggered
@@ -98,7 +108,9 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
assert triggered assert triggered
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -129,7 +141,9 @@ def testToolBuildSettings_Filter(qtbot, nwGUI, projPath, mockRnd):
bSettings.loadContent() bSettings.loadContent()
filterTab = bSettings.optTabSelect 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 assert bSettings.toolStack.currentWidget() is filterTab
# Check content # Check content
@@ -308,7 +322,9 @@ def testToolBuildSettings_Filter(qtbot, nwGUI, projPath, mockRnd):
] ]
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -339,7 +355,9 @@ def testToolBuildSettings_Headings(qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
headTab = bSettings.optTabHeadings 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 assert bSettings.toolStack.currentWidget() is headTab
# Check initial values # Check initial values
@@ -478,7 +496,9 @@ def testToolBuildSettings_Headings(qtbot, nwGUI):
assert build.getBool("headings.hideSection") is True assert build.getBool("headings.hideSection") is True
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -501,7 +521,9 @@ def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormatting 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 assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -538,7 +560,9 @@ def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
assert build.getBool("text.addNoteHeadings") is True assert build.getBool("text.addNoteHeadings") is True
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -563,7 +587,9 @@ def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormatting 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 assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -610,7 +636,9 @@ def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
assert fmtTab._textFont == font assert fmtTab._textFont == font
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -629,7 +657,9 @@ def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormatting 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 assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -650,7 +680,9 @@ def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
assert build.getBool("format.indentFirstPar") is True assert build.getBool("format.indentFirstPar") is True
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -674,7 +706,9 @@ def testToolBuildSettings_FormatPageLayout(monkeypatch, qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormatting 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 assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -704,7 +738,9 @@ def testToolBuildSettings_FormatPageLayout(monkeypatch, qtbot, nwGUI):
assert fmtTab.rightMargin.value() == 1.5 assert fmtTab.rightMargin.value() == 1.5
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
@@ -728,7 +764,9 @@ def testToolBuildSettings_FormatOutput(qtbot, nwGUI):
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormatting 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 assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -769,5 +807,7 @@ def testToolBuildSettings_FormatOutput(qtbot, nwGUI):
assert fmtTab.odtPageHeader.text() == nwHeadFmt.DOC_AUTO assert fmtTab.odtPageHeader.text() == nwHeadFmt.DOC_AUTO
# Finish # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) button = bSettings.buttonBox.button(QtDialogClose)
assert button is not None
bSettings._dialogButtonClicked(button)
# qtbot.stop() # qtbot.stop()
+217 -56
View File
@@ -125,14 +125,37 @@ def testToolWritingStats_Export(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
assert sessLog.notesWords.text() == "{:n}".format(275) assert sessLog.notesWords.text() == "{:n}".format(275)
assert sessLog.totalWords.text() == "{:n}".format(875) assert sessLog.totalWords.text() == "{:n}".format(875)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(300) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-120)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-20) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(40) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-400) assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
assert sessLog.listBox.topLevelItem(7).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_CSV)
assert sessLog._saveData(sessLog.FMT_JSON) assert sessLog._saveData(sessLog.FMT_JSON)
@@ -205,14 +228,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
sessLog.populateGUI() sessLog.populateGUI()
sessLog.listBox.sortByColumn(sessLog.C_TIME, Qt.SortOrder.AscendingOrder) sessLog.listBox.sortByColumn(sessLog.C_TIME, Qt.SortOrder.AscendingOrder)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(300) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-120)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-20) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(40) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-400) assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
assert sessLog.listBox.topLevelItem(7).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 # No Novel Files
qtbot.mouseClick(sessLog.incNovel, QtMouseLeft) 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: with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read()) jsonData = json.loads(inFile.read())
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-100) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(150) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-60)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-10) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(20) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
assert sessLog.listBox.topLevelItem(7).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 == [ assert jsonData == [
{ {
@@ -268,14 +337,37 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile: with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile) jsonData = json.load(inFile)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-100) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(150) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-60)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-10) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(20) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
assert sessLog.listBox.topLevelItem(7).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 == [ assert jsonData == [
{ {
@@ -314,10 +406,21 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile: with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile) jsonData = json.load(inFile)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(300) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(40) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(200)
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 == [ assert jsonData == [
{ {
@@ -344,16 +447,45 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
with open(jsonStats, mode="r", encoding="utf-8") as inFile: with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile) jsonData = json.load(inFile)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(0) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(300)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(-120) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(-20) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(40) assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(-400)
assert sessLog.listBox.topLevelItem(8).text(sessLog.C_COUNT) == "{:n}".format(200) item = sessLog.listBox.topLevelItem(2)
assert sessLog.listBox.topLevelItem(9).text(sessLog.C_COUNT) == "{:n}".format(0) 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 == [ assert jsonData == [
{ {
@@ -390,9 +522,15 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
] ]
# Toggle Idle Time # 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) 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 # Group by Day
qtbot.mouseClick(sessLog.groupByDay, QtMouseLeft) 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: with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile) jsonData = json.load(inFile)
assert sessLog.listBox.topLevelItem(0).text(sessLog.C_COUNT) == "{:n}".format(1) item = sessLog.listBox.topLevelItem(0)
assert sessLog.listBox.topLevelItem(1).text(sessLog.C_COUNT) == "{:n}".format(-200) assert item is not None
assert sessLog.listBox.topLevelItem(2).text(sessLog.C_COUNT) == "{:n}".format(180) assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
assert sessLog.listBox.topLevelItem(3).text(sessLog.C_COUNT) == "{:n}".format(-20)
assert sessLog.listBox.topLevelItem(4).text(sessLog.C_COUNT) == "{:n}".format(40) item = sessLog.listBox.topLevelItem(1)
assert sessLog.listBox.topLevelItem(5).text(sessLog.C_COUNT) == "{:n}".format(-400) assert item is not None
assert sessLog.listBox.topLevelItem(6).text(sessLog.C_COUNT) == "{:n}".format(200) assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
assert sessLog.listBox.topLevelItem(7).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(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 == [ assert jsonData == [
{ {
+3 -1
View File
@@ -241,5 +241,7 @@ class SimpleDialog(QDialog):
def addWidget(self, widget: QWidget) -> None: def addWidget(self, widget: QWidget) -> None:
self._widget = widget self._widget = widget
self.layout().addWidget(widget) layout = self.layout()
assert layout is not None
layout.addWidget(widget)
return return