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