diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index c85d949b..85ac0d62 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -241,8 +241,11 @@ def main(sysArgs=None): # Connect the exception handler before making the main GUI sys.excepthook = exceptionHandler - # Launch main GUI + # Run Config steps that require the QApplication CONFIG.initLocalisation(nwApp) + CONFIG.setTextFont(CONFIG.textFont, CONFIG.textSize) # Makes sure these are valid + + # Launch main GUI nwGUI = GuiMain() nwGUI.postLaunchTasks(cmdOpen) diff --git a/novelwriter/config.py b/novelwriter/config.py index 68f44ec4..bb4fa9dc 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -23,6 +23,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +from __future__ import annotations + import sys import json import logging @@ -30,6 +32,7 @@ import logging from time import time from pathlib import Path +from PyQt5.QtGui import QFontDatabase from PyQt5.QtCore import ( QT_VERSION, QT_VERSION_STR, PYQT_VERSION, PYQT_VERSION_STR, QStandardPaths, QSysInfo, QLocale, QLibraryInfo, QTranslator @@ -120,7 +123,7 @@ class Config: self.askBeforeBackup = True # Flag for asking before running automatic backup # Text Editor Settings - self.textFont = None # Editor font + self.textFont = "" # Editor font self.textSize = 12 # Editor font size self.textWidth = 700 # Editor text width self.textMargin = 40 # Editor/viewer text margin @@ -335,40 +338,59 @@ class Config: logger.debug("Last path updated: %s" % self._lastPath) return - def setBackupPath(self, backupPath): + def setBackupPath(self, backupPath: Path | None): """Set the current backup path.""" self._backupPath = checkPath(backupPath, None) return + def setTextFont(self, family: str | None, pointSize: int = 12): + """Set the text font if it exists. If it doesn't, or is None, + set to default font. + """ + fontDB = QFontDatabase() + fontFam = fontDB.families() + self.textSize = pointSize + if family is None or family not in fontFam: + logger.warning("Unknown font '%s'", family) + if self.osWindows and "Arial" in fontFam: + self.textFont = "Arial" + elif self.osDarwin and "Courier" in fontFam: + self.textFont = "Courier" + else: + self.textFont = fontDB.systemFont(QFontDatabase.GeneralFont).family() + else: + self.textFont = family + return + ## # Methods ## - def pxInt(self, theSize): + def pxInt(self, value: int) -> int: """Used to scale fixed gui sizes by the screen scale factor. This function returns an int, which is always rounded down. """ - return int(theSize*self.guiScale) + return int(value*self.guiScale) - def rpxInt(self, theSize): + def rpxInt(self, value: int) -> int: """Used to un-scale fixed gui sizes by the screen scale factor. This function returns an int, which is always rounded down. """ - return int(theSize/self.guiScale) + return int(value/self.guiScale) - def dataPath(self, target=None): + def dataPath(self, target: str | None = None) -> Path: """Return a path in the data folder.""" if isinstance(target, str): return self._dataPath / target return self._dataPath - def assetPath(self, target=None): + def assetPath(self, target: str | None = None) -> Path: """Return a path in the assets folder.""" if isinstance(target, str): return self._appPath / "assets" / target return self._appPath / "assets" - def lastPath(self): + def lastPath(self) -> Path: """Return the last path used by the user, but ensure it exists. """ if isinstance(self._lastPath, Path): @@ -376,14 +398,14 @@ class Config: return self._lastPath return self._homePath - def backupPath(self): + def backupPath(self) -> Path | None: """Return the backup path.""" if isinstance(self._backupPath, Path): if self._backupPath.is_dir(): return self._backupPath return None - def errorText(self): + def errorText(self) -> str: """Compile and return error messages from the initialisation of the Config class, and clear the error buffer. """ @@ -392,7 +414,7 @@ class Config: self._errData = [] return errMessage - def listLanguages(self, lngSet): + def listLanguages(self, lngSet: int) -> list[tuple[str, str]]: """List localisation files in the i18n folder. The default GUI language is British English (en_GB). """ @@ -423,7 +445,7 @@ class Config: # Config Actions ## - def initConfig(self, confPath=None, dataPath=None): + def initConfig(self, confPath: str | Path | None = None, dataPath: str | Path | None = None): """Initialise the config class. The manual setting of confPath and dataPath is mainly intended for the test suite. """ @@ -449,9 +471,10 @@ class Config: # Also create the syntax, themes and icons folders if possible if self._dataPath.is_dir(): + (self._dataPath / "cache").mkdir(exist_ok=True) + (self._dataPath / "icons").mkdir(exist_ok=True) (self._dataPath / "syntax").mkdir(exist_ok=True) (self._dataPath / "themes").mkdir(exist_ok=True) - (self._dataPath / "icons").mkdir(exist_ok=True) # Check if config file exists, and load it. If not, we save defaults if (self._confPath / nwFiles.CONF_FILE).is_file(): diff --git a/novelwriter/constants.py b/novelwriter/constants.py index e0d6e053..46e1c1d6 100644 --- a/novelwriter/constants.py +++ b/novelwriter/constants.py @@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtGui import QFontDatabase from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP from novelwriter.enum import nwItemClass, nwItemLayout, nwOutline @@ -54,9 +53,6 @@ class nwConst: URL_HELP = "https://github.com/vkbo/novelWriter/discussions" URL_RELEASE = "https://github.com/vkbo/novelWriter/releases/latest" - # System Values - SYSTEM_FONT = QFontDatabase.systemFont(QFontDatabase.GeneralFont).family() - # END Class nwConst diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 845634d6..cc4b3df1 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -36,7 +36,7 @@ from pathlib import Path from PyQt5.QtCore import QT_TRANSLATE_NOOP from novelwriter.common import checkUuid, isHandle, jsonEncode -from novelwriter.constants import nwConst, nwFiles, nwHeadFmt +from novelwriter.constants import nwFiles, nwHeadFmt from novelwriter.core.item import NWItem from novelwriter.core.project import NWProject from novelwriter.error import logException @@ -65,7 +65,7 @@ SETTINGS_TEMPLATE = { "text.includeBodyText": (bool, True), "text.addNoteHeadings": (bool, True), "format.buildLang": (str, "en_GB"), - "format.textFont": (str, nwConst.SYSTEM_FONT), + "format.textFont": (str, ""), "format.textSize": (int, 12), "format.lineHeight": (float, 1.15, 0.75, 3.0), "format.justifyText": (bool, False), diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 21fd101f..6a685eaf 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -613,8 +613,7 @@ class GuiPreferencesDocuments(QWidget): """Save the values set for this tab. """ # Text Style - CONFIG.textFont = self.textFont.text() - CONFIG.textSize = self.textSize.value() + CONFIG.setTextFont(self.textFont.text(), self.textSize.value()) # Text Flow CONFIG.textWidth = self.textWidth.value() diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index c7681759..2425d6be 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -276,31 +276,16 @@ class GuiDocEditor(QTextEdit): self.setDictionaries() # Set font - theFont = QFont() - qDoc = self.document() - if CONFIG.textFont is None: - # If none is defined, set a default font - theFont = QFont() - if CONFIG.osWindows and "Arial" in self.mainTheme.guiFontDB.families(): - theFont.setFamily("Arial") - theFont.setPointSize(12) - elif CONFIG.osDarwin and "Courier" in self.mainTheme.guiFontDB.families(): - theFont.setFamily("Courier") - theFont.setPointSize(12) - else: - theFont = qDoc.defaultFont() - - CONFIG.textFont = theFont.family() - CONFIG.textSize = theFont.pointSize() - - theFont.setFamily(CONFIG.textFont) - theFont.setPointSize(CONFIG.textSize) - self.setFont(theFont) + textFont = QFont() + textFont.setFamily(CONFIG.textFont) + textFont.setPointSize(CONFIG.textSize) + self.setFont(textFont) # Set default text margins # Due to cursor visibility, a part of the margin must be # allocated to the document itself. See issue #1112. cW = self.cursorWidth() + qDoc = self.document() qDoc.setDocumentMargin(cW) self._vpMargin = max(CONFIG.getTextMargin() - cW, 0) self.setViewportMargins(self._vpMargin, self._vpMargin, self._vpMargin, self._vpMargin) diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 7cb8be4d..bae5c39a 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -114,13 +114,10 @@ class GuiDocViewer(QTextBrowser): self._makeStyleSheet() # Set Font - theFont = QFont() - if CONFIG.textFont is None: - # If none is defined, set the default back to config - CONFIG.textFont = self.document().defaultFont().family() - theFont.setFamily(CONFIG.textFont) - theFont.setPointSize(CONFIG.textSize) - self.setFont(theFont) + textFont = QFont() + textFont.setFamily(CONFIG.textFont) + textFont.setPointSize(CONFIG.textSize) + self.setFont(textFont) # Set the widget colours to match syntax theme mainPalette = self.palette() diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 0d61423a..f1c3f0a4 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -107,7 +107,6 @@ class GuiTheme: # =========== # Init GUI Font - self.guiFontDB = QFontDatabase() self._setGuiFont() # Load Themes @@ -366,13 +365,14 @@ class GuiTheme: """Update the GUI's font style from settings. """ theFont = QFont() - if CONFIG.guiFont not in self.guiFontDB.families(): - if CONFIG.osWindows and "Arial" in self.guiFontDB.families(): + fontDB = QFontDatabase() + if CONFIG.guiFont not in fontDB.families(): + if CONFIG.osWindows and "Arial" in fontDB.families(): # On Windows we default to Arial if possible theFont.setFamily("Arial") theFont.setPointSize(10) else: - theFont = self.guiFontDB.systemFont(QFontDatabase.GeneralFont) + theFont = fontDB.systemFont(QFontDatabase.GeneralFont) CONFIG.guiFont = theFont.family() CONFIG.guiFontSize = theFont.pointSize() else: diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py index 9fe56440..c013c7b8 100644 --- a/novelwriter/tools/build.py +++ b/novelwriter/tools/build.py @@ -1258,9 +1258,6 @@ class GuiBuildNovelDocView(QTextBrowser): )) theFont = QFont() - if CONFIG.textFont is None: - # If none is defined, set the default back to config - CONFIG.textFont = self.document().defaultFont().family() theFont.setFamily(CONFIG.textFont) theFont.setPointSize(CONFIG.textSize) self.setFont(theFont) diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index 777ffa13..5f2a904e 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -41,7 +41,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG -from novelwriter.constants import nwConst, nwHeadFmt +from novelwriter.constants import nwHeadFmt from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switchbox import NSwitchBox @@ -1032,8 +1032,6 @@ class GuiBuildFormatTab(QWidget): textFont = self._build.getStr("format.textFont") if not textFont: textFont = str(CONFIG.textFont) - if not textFont: - textFont = nwConst.SYSTEM_FONT self.textFont.setText(textFont) self.textSize.setValue(self._build.getInt("format.textSize")) diff --git a/tests/conftest.py b/tests/conftest.py index 9435eee6..d333a1b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -49,6 +49,7 @@ def resetConfigVars(): """ CONFIG.setLastPath(_TMP_ROOT) CONFIG.setBackupPath(_TMP_ROOT) + CONFIG.setTextFont(None) CONFIG._homePath = _TMP_ROOT CONFIG.guiLocale = "en_GB" return diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf index 185fbd50..fa12d483 100644 --- a/tests/reference/baseConfig_novelwriter.conf +++ b/tests/reference/baseConfig_novelwriter.conf @@ -1,5 +1,5 @@ [Meta] -timestamp = 2022-11-11 12:48:18 +timestamp = 2023-05-31 10:52:21 [Main] theme = default @@ -29,7 +29,7 @@ backuponclose = False askbeforebackup = True [Editor] -textfont = None +textfont = textsize = 12 width = 700 margin = 40 diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py index cc386515..34f9dfd1 100644 --- a/tests/test_gui/test_gui_doceditor.py +++ b/tests/test_gui/test_gui_doceditor.py @@ -56,7 +56,7 @@ def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd): assert nwGUI.docEditor._typPadChar == nwUnicode.U_NBSP # Check that editor handles settings - CONFIG.textFont = None + CONFIG.textFont = "" CONFIG.doJustify = True CONFIG.showTabsNSpaces = True CONFIG.showLineEndings = True