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