From c0673b8128d3ddcc7652454cebf47635e1cc0649 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 20 May 2024 16:12:27 +0200 Subject: [PATCH] Save all font info for GUI font --- novelwriter/__init__.py | 2 + novelwriter/common.py | 10 +++- novelwriter/config.py | 83 ++++++++++++++++++++---------- novelwriter/dialogs/preferences.py | 43 ++++++---------- novelwriter/gui/theme.py | 24 --------- 5 files changed, 83 insertions(+), 79 deletions(-) diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index 9172abd9..5bd034e1 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -217,6 +217,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None: # Import GUI (after dependency checks), and launch from novelwriter.guimain import GuiMain if testMode: + CONFIG.loadConfig() nwGUI = GuiMain() return nwGUI @@ -232,6 +233,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None: sys.excepthook = exceptionHandler # Run Config steps that require the QApplication + CONFIG.loadConfig() CONFIG.initLocalisation(nwApp) CONFIG.setTextFont(CONFIG.textFont, CONFIG.textSize) # Makes sure these are valid diff --git a/novelwriter/common.py b/novelwriter/common.py index b1282867..70c4ce27 100644 --- a/novelwriter/common.py +++ b/novelwriter/common.py @@ -37,7 +37,7 @@ from urllib.parse import urljoin from urllib.request import pathname2url from PyQt5.QtCore import QCoreApplication, QUrl -from PyQt5.QtGui import QColor, QDesktopServices +from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontInfo from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType @@ -401,6 +401,14 @@ def cssCol(col: QColor, alpha: int | None = None) -> str: return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})" +def describeFont(font: QFont) -> str: + """Describe a font in a way that can be displayed on the GUI.""" + if isinstance(font, QFont): + info = QFontInfo(font) + return f"{font.family()} {info.styleName()} @ {font.pointSize()} pt" + return "Error" + + ## # Encoder Functions ## diff --git a/novelwriter/config.py b/novelwriter/config.py index af21e7dd..fe84aae1 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -36,7 +36,7 @@ from PyQt5.QtCore import ( PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo, QLocale, QStandardPaths, QSysInfo, QTranslator ) -from PyQt5.QtGui import QFontDatabase +from PyQt5.QtGui import QFont, QFontDatabase from PyQt5.QtWidgets import QApplication from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp @@ -106,15 +106,14 @@ class Config: self._recentObj = RecentProjects(self) # General GUI Settings - self.guiLocale = self._qLocale.name() - self.guiTheme = "default" # GUI theme - self.guiSyntax = "default_light" # Syntax theme - self.guiFont = "" # Defaults to system default font in theme class - self.guiFontSize = 11 # Is overridden if system default is loaded - self.guiScale = 1.0 # Set automatically by Theme class - self.hideVScroll = False # Hide vertical scroll bars on main widgets - self.hideHScroll = False # Hide horizontal scroll bars on main widgets - self.lastNotes = "0x0" # The latest release notes that have been shown + self.guiLocale = self._qLocale.name() + self.guiTheme = "default" # GUI theme + self.guiSyntax = "default_light" # Syntax theme + self.guiFont = QFont() # Defaults to system default font in theme class + self.guiScale = 1.0 # Set automatically by Theme class + self.hideVScroll = False # Hide vertical scroll bars on main widgets + self.hideHScroll = False # Hide horizontal scroll bars on main widgets + self.lastNotes = "0x0" # The latest release notes that have been shown # Size Settings self._mainWinSize = [1200, 650] # Last size of the main GUI window @@ -362,6 +361,28 @@ class Config: self._backupPath = checkPath(path, self._backPath) return + def setGuiFont(self, value: QFont | str | None) -> None: + """Update the GUI's font style from settings.""" + if isinstance(value, QFont): + self.guiFont = value + elif value and isinstance(value, str): + self.guiFont = QFont() + self.guiFont.fromString(value) + else: + font = QFont() + fontDB = QFontDatabase() + if self.osWindows and "Arial" in fontDB.families(): + # On Windows we default to Arial if possible + font.setFamily("Arial") + font.setPointSize(10) + else: + font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont) + self.guiFont = font + + QApplication.setFont(self.guiFont) + + return + def setTextFont(self, family: str | None, pointSize: int = 12) -> None: """Set the text font if it exists. If it doesn't, or is None, set to default font. @@ -502,12 +523,6 @@ class Config: (self._dataPath / "syntax").mkdir(exist_ok=True) (self._dataPath / "themes").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(): - self.loadConfig() - else: - self.saveConfig() - self._recentObj.loadCache() self._checkOptionalPackages() @@ -548,6 +563,13 @@ class Config: conf = NWConfigParser() cnfPath = self._confPath / nwFiles.CONF_FILE + + if not cnfPath.exists(): + # Initial file, so we just create one from defaults + self.saveConfig() + self.setGuiFont(None) + return True + try: with open(cnfPath, mode="r", encoding="utf-8") as inFile: conf.read_file(inFile) @@ -561,15 +583,23 @@ class Config: # Main sec = "Main" - self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme) - self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax) - self.guiFont = conf.rdStr(sec, "font", self.guiFont) - self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize) - self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale) - self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll) - self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll) - self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes) - self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath) + self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme) + self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax) + guiFont = conf.rdStr(sec, "guifont", "") + self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale) + self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll) + self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll) + self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes) + self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath) + + # If we have an old config file with the following settings, use those instead + legacyFont = conf.rdStr(sec, "font", "") + legacySize = conf.rdInt(sec, "fontsize", 11) + if legacyFont: + guiFont = QFont() + guiFont.fromString(f"{legacyFont},{legacySize}") + + self.setGuiFont(guiFont) # Sizes sec = "Sizes" @@ -674,8 +704,7 @@ class Config: conf["Main"] = { "theme": str(self.guiTheme), "syntax": str(self.guiSyntax), - "font": str(self.guiFont), - "fontsize": str(self.guiFontSize), + "guifont": str(self.guiFont.toString()), "localisation": str(self.guiLocale), "hidevscroll": str(self.hideVScroll), "hidehscroll": str(self.hideHScroll), diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index af4e6980..6e13fc2f 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -35,6 +35,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG, SHARED +from novelwriter.common import describeFont from novelwriter.constants import nwConst, nwUnicode from novelwriter.dialogs.quotes import GuiQuoteSelect from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm @@ -135,6 +136,10 @@ class GuiPreferences(QDialog): iSz = SHARED.theme.baseIconSize boxFixed = 5*SHARED.theme.textNWidth minWidth = CONFIG.pxInt(200) + fontWidth = CONFIG.pxInt(162) + + # Temporary Variables + self._guiFont = CONFIG.guiFont # Label self.sidebar.addLabel(self.tr("General")) @@ -174,27 +179,17 @@ class GuiPreferences(QDialog): # Application Font Family self.guiFont = QLineEdit(self) self.guiFont.setReadOnly(True) - self.guiFont.setMinimumWidth(CONFIG.pxInt(162)) - self.guiFont.setText(CONFIG.guiFont) + self.guiFont.setMinimumWidth(fontWidth) + self.guiFont.setText(describeFont(self._guiFont)) + self.guiFont.setCursorPosition(0) self.guiFontButton = NIconToolButton(self, iSz, "more") self.guiFontButton.clicked.connect(self._selectGuiFont) self.mainForm.addRow( - self.tr("Application font family"), self.guiFont, + self.tr("Application font"), self.guiFont, self.tr("Requires restart to take effect."), stretch=(3, 2), button=self.guiFontButton ) - # Application Font Size - self.guiFontSize = NSpinBox(self) - self.guiFontSize.setMinimum(8) - self.guiFontSize.setMaximum(60) - self.guiFontSize.setSingleStep(1) - self.guiFontSize.setValue(CONFIG.guiFontSize) - self.mainForm.addRow( - self.tr("Application font size"), self.guiFontSize, - self.tr("Requires restart to take effect."), unit=self.tr("pt") - ) - # Vertical Scrollbars self.hideVScroll = NSwitch(self) self.hideVScroll.setChecked(CONFIG.hideVScroll) @@ -234,7 +229,7 @@ class GuiPreferences(QDialog): # Document Font Family self.textFont = QLineEdit(self) self.textFont.setReadOnly(True) - self.textFont.setMinimumWidth(CONFIG.pxInt(162)) + self.textFont.setMinimumWidth(fontWidth) self.textFont.setText(CONFIG.textFont) self.textFontButton = NIconToolButton(self, iSz, "more") self.textFontButton.clicked.connect(self._selectTextFont) @@ -818,13 +813,11 @@ class GuiPreferences(QDialog): @pyqtSlot() def _selectGuiFont(self) -> None: """Open the QFontDialog and set a font for the font style.""" - current = QFont() - current.setFamily(CONFIG.guiFont) - current.setPointSize(CONFIG.guiFontSize) - font, status = QFontDialog.getFont(current, self) + font, status = QFontDialog.getFont(self._guiFont, self) if status: - self.guiFont.setText(font.family()) - self.guiFontSize.setValue(font.pointSize()) + self.guiFont.setText(describeFont(font)) + self.guiFont.setCursorPosition(0) + self._guiFont = font return @pyqtSlot() @@ -892,18 +885,14 @@ class GuiPreferences(QDialog): # Appearance guiLocale = self.guiLocale.currentData() guiTheme = self.guiTheme.currentData() - guiFont = self.guiFont.text() - guiFontSize = self.guiFontSize.value() updateTheme |= CONFIG.guiTheme != guiTheme needsRestart |= CONFIG.guiLocale != guiLocale - needsRestart |= CONFIG.guiFont != guiFont - needsRestart |= CONFIG.guiFontSize != guiFontSize + needsRestart |= CONFIG.guiFont != self._guiFont CONFIG.guiLocale = guiLocale CONFIG.guiTheme = guiTheme - CONFIG.guiFont = guiFont - CONFIG.guiFontSize = guiFontSize + CONFIG.guiFont = self._guiFont CONFIG.hideVScroll = self.hideVScroll.isChecked() CONFIG.hideHScroll = self.hideHScroll.isChecked() diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 1dbf268a..a986f86a 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -114,9 +114,6 @@ class GuiTheme: # Class Setup # =========== - # Init GUI Font - self._setGuiFont() - # Load Themes self._guiPalette = QPalette() self._themeList: list[tuple[str, str]] = [] @@ -411,27 +408,6 @@ class GuiTheme: self.errorText = QColor(255, 0, 0) return - def _setGuiFont(self) -> None: - """Update the GUI's font style from settings.""" - font = QFont() - 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 - font.setFamily("Arial") - font.setPointSize(10) - else: - font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont) - CONFIG.guiFont = font.family() - CONFIG.guiFontSize = font.pointSize() - else: - font.setFamily(CONFIG.guiFont) - font.setPointSize(CONFIG.guiFontSize) - - QApplication.setFont(font) - - return - def _listConf(self, targetDict: dict, checkDir: Path) -> bool: """Scan for theme config files and populate the dictionary.""" if not checkDir.is_dir():