diff --git a/novelwriter/__init__.py b/novelwriter/__init__.py index 5bd034e1..91552d1e 100644 --- a/novelwriter/__init__.py +++ b/novelwriter/__init__.py @@ -235,7 +235,6 @@ def main(sysArgs: list | None = None) -> GuiMain | None: # Run Config steps that require the QApplication CONFIG.loadConfig() CONFIG.initLocalisation(nwApp) - CONFIG.setTextFont(CONFIG.textFont, CONFIG.textSize) # Makes sure these are valid # Launch main GUI nwGUI = GuiMain() diff --git a/novelwriter/config.py b/novelwriter/config.py index fe84aae1..ee85b1f1 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -131,43 +131,42 @@ class Config: self.askBeforeBackup = True # Flag for asking before running automatic backup # Text Editor Settings - self.textFont = "" # Editor font - self.textSize = 12 # Editor font size - self.textWidth = 700 # Editor text width - self.textMargin = 40 # Editor/viewer text margin - self.tabWidth = 40 # Editor tabulator width + self.textFont = QFont() # Editor font + self.textWidth = 700 # Editor text width + self.textMargin = 40 # Editor/viewer text margin + self.tabWidth = 40 # Editor tabulator width - self.focusWidth = 800 # Focus Mode text width - self.hideFocusFooter = False # Hide document footer in Focus Mode - self.showFullPath = True # Show full document path in editor header - self.autoSelect = True # Auto-select word when applying format with no selection + self.focusWidth = 800 # Focus Mode text width + self.hideFocusFooter = False # Hide document footer in Focus Mode + self.showFullPath = True # Show full document path in editor header + self.autoSelect = True # Auto-select word when applying format with no selection - self.doJustify = False # Justify text - self.showTabsNSpaces = False # Show tabs and spaces in editor - self.showLineEndings = False # Show line endings in editor - self.showMultiSpaces = True # Highlight multiple spaces in the text + self.doJustify = False # Justify text + self.showTabsNSpaces = False # Show tabs and spaces in editor + self.showLineEndings = False # Show line endings in editor + self.showMultiSpaces = True # Highlight multiple spaces in the text - self.doReplace = True # Enable auto-replace as you type - self.doReplaceSQuote = True # Smart single quotes - self.doReplaceDQuote = True # Smart double quotes - self.doReplaceDash = True # Replace multiple hyphens with dashes - self.doReplaceDots = True # Replace three dots with ellipsis + self.doReplace = True # Enable auto-replace as you type + self.doReplaceSQuote = True # Smart single quotes + self.doReplaceDQuote = True # Smart double quotes + self.doReplaceDash = True # Replace multiple hyphens with dashes + self.doReplaceDots = True # Replace three dots with ellipsis - self.autoScroll = False # Typewriter-like scrolling - self.autoScrollPos = 30 # Start point for typewriter-like scrolling - self.scrollPastEnd = True # Scroll past end of document, and centre cursor + self.autoScroll = False # Typewriter-like scrolling + self.autoScrollPos = 30 # Start point for typewriter-like scrolling + self.scrollPastEnd = True # Scroll past end of document, and centre cursor - self.dialogStyle = 2 # Quote type to use for dialogue - self.allowOpenDial = True # Allow open-ended dialogue quotes - self.narratorBreak = "" # Symbol to use for narrator break - self.dialogLine = "" # Symbol to use for dialogue line - self.altDialogOpen = "" # Alternative dialog symbol, open - self.altDialogClose = "" # Alternative dialog symbol, close - self.highlightEmph = True # Add colour to text emphasis + self.dialogStyle = 2 # Quote type to use for dialogue + self.allowOpenDial = True # Allow open-ended dialogue quotes + self.narratorBreak = "" # Symbol to use for narrator break + self.dialogLine = "" # Symbol to use for dialogue line + self.altDialogOpen = "" # Alternative dialog symbol, open + self.altDialogClose = "" # Alternative dialog symbol, close + self.highlightEmph = True # Add colour to text emphasis - self.stopWhenIdle = True # Stop the status bar clock when the user is idle - self.userIdleTime = 300 # Time of inactivity to consider user idle - self.incNotesWCount = True # The status bar word count includes notes + self.stopWhenIdle = True # Stop the status bar clock when the user is idle + self.userIdleTime = 300 # Time of inactivity to consider user idle + self.incNotesWCount = True # The status bar word count includes notes # User-Selected Symbol Settings self.fmtApostrophe = nwUnicode.U_RSQUO @@ -383,23 +382,28 @@ class Config: return - def setTextFont(self, family: str | None, pointSize: int = 12) -> None: + def setTextFont(self, value: QFont | str | None) -> None: """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 "Helvetica" in fontFam: - self.textFont = "Helvetica" - else: - self.textFont = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont).family() + if isinstance(value, QFont): + self.textFont = value + elif value and isinstance(value, str): + self.textFont = QFont() + self.textFont.fromString(value) else: - self.textFont = family + font = QFont() + fontDB = QFontDatabase() + fontFam = fontDB.families() + if self.osWindows and "Arial" in fontFam: + font.setFamily("Arial") + font.setPointSize(12) + elif self.osDarwin and "Helvetica" in fontFam: + font.setFamily("Helvetica") + font.setPointSize(12) + else: + font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont) + self.textFont = font return ## @@ -585,19 +589,17 @@ class Config: sec = "Main" self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme) self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax) - guiFont = conf.rdStr(sec, "guifont", "") + guiFont = conf.rdStr(sec, "font", "") 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}") + # If we have an old config file, we have an explicit font size, + # in which case we convert the old settings. + if fontSize := conf.rdInt(sec, "fontsize", 0): + guiFont = f"{guiFont},{fontSize}" self.setGuiFont(guiFont) @@ -621,8 +623,7 @@ class Config: # Editor sec = "Editor" - self.textFont = conf.rdStr(sec, "textfont", self.textFont) - self.textSize = conf.rdInt(sec, "textsize", self.textSize) + textFont = conf.rdStr(sec, "textfont", "") self.textWidth = conf.rdInt(sec, "width", self.textWidth) self.textMargin = conf.rdInt(sec, "margin", self.textMargin) self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth) @@ -661,6 +662,13 @@ class Config: self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle) self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime) + # If we have an old config file, we have an explicit font size, + # in which case we convert the old settings. + if textSize := conf.rdInt(sec, "textsize", 0): + textFont = f"{textFont},{textSize}" + + self.setTextFont(textFont) + # State sec = "State" self.showViewerPanel = conf.rdBool(sec, "showviewerpanel", self.showViewerPanel) @@ -731,8 +739,7 @@ class Config: } conf["Editor"] = { - "textfont": str(self.textFont), - "textsize": str(self.textSize), + "textfont": str(self.textFont.toString()), "width": str(self.textWidth), "margin": str(self.textMargin), "tabwidth": str(self.tabWidth), diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 6e13fc2f..096cc337 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -27,7 +27,7 @@ from __future__ import annotations import logging from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot -from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence +from PyQt5.QtGui import QCloseEvent, QKeyEvent, QKeySequence from PyQt5.QtWidgets import ( QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox, QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, @@ -140,6 +140,7 @@ class GuiPreferences(QDialog): # Temporary Variables self._guiFont = CONFIG.guiFont + self._textFont = CONFIG.textFont # Label self.sidebar.addLabel(self.tr("General")) @@ -230,26 +231,16 @@ class GuiPreferences(QDialog): self.textFont = QLineEdit(self) self.textFont.setReadOnly(True) self.textFont.setMinimumWidth(fontWidth) - self.textFont.setText(CONFIG.textFont) + self.textFont.setText(describeFont(CONFIG.textFont)) + self.textFont.setCursorPosition(0) self.textFontButton = NIconToolButton(self, iSz, "more") self.textFontButton.clicked.connect(self._selectTextFont) self.mainForm.addRow( - self.tr("Document font family"), self.textFont, + self.tr("Document font"), self.textFont, self.tr("Applies to both document editor and viewer."), stretch=(3, 2), button=self.textFontButton ) - # Document Font Size - self.textSize = NSpinBox(self) - self.textSize.setMinimum(8) - self.textSize.setMaximum(60) - self.textSize.setSingleStep(1) - self.textSize.setValue(CONFIG.textSize) - self.mainForm.addRow( - self.tr("Document font size"), self.textSize, - self.tr("Applies to both document editor and viewer."), unit=self.tr("pt") - ) - # Emphasise Labels self.emphLabels = NSwitch(self) self.emphLabels.setChecked(CONFIG.emphLabels) @@ -823,13 +814,11 @@ class GuiPreferences(QDialog): @pyqtSlot() def _selectTextFont(self) -> None: """Open the QFontDialog and set a font for the font style.""" - current = QFont() - current.setFamily(CONFIG.textFont) - current.setPointSize(CONFIG.textSize) - font, status = QFontDialog.getFont(current, self) + font, status = QFontDialog.getFont(CONFIG.textFont, self) if status: - self.textFont.setText(font.family()) - self.textSize.setValue(font.pointSize()) + self.textFont.setText(describeFont(font)) + self.textFont.setCursorPosition(0) + self._textFont = font return @pyqtSlot() @@ -907,7 +896,7 @@ class GuiPreferences(QDialog): CONFIG.emphLabels = emphLabels CONFIG.showFullPath = self.showFullPath.isChecked() CONFIG.incNotesWCount = self.incNotesWCount.isChecked() - CONFIG.setTextFont(self.textFont.text(), self.textSize.value()) + CONFIG.textFont = self._textFont # Auto Save CONFIG.autoSaveDoc = self.autoSaveDoc.value() diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 55e6c76a..7fdbfdf9 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -377,16 +377,10 @@ class GuiDocEditor(QPlainTextEdit): special attention since there appears to be a bug in Qt 5.15.3. See issues #1862 and #1875. """ - font = self.font() - font.setFamily(CONFIG.textFont) - font.setPointSize(CONFIG.textSize) - self.setFont(font) - - # Reset sub-widget font to GUI font + self.setFont(CONFIG.textFont) self.docHeader.updateFont() self.docFooter.updateFont() self.docSearch.updateFont() - return def loadText(self, tHandle: str, tLine: int | None = None) -> bool: diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index ddbdcaa3..0e731032 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -474,7 +474,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): charFormat.setBackground(QBrush(color, Qt.BrushStyle.SolidPattern)) if size: - charFormat.setFontPointSize(round(size*CONFIG.textSize)) + charFormat.setFontPointSize(round(size*CONFIG.textFont.pointSize())) self._hStyles[name] = charFormat diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index b6423b29..917a4f7f 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -186,15 +186,9 @@ class GuiDocViewer(QTextBrowser): special attention since there appears to be a bug in Qt 5.15.3. See issues #1862 and #1875. """ - font = self.font() - font.setFamily(CONFIG.textFont) - font.setPointSize(CONFIG.textSize) - self.setFont(font) - - # Reset sub-widget font to GUI font + self.setFont(CONFIG.textFont) self.docHeader.updateFont() self.docFooter.updateFont() - return def loadText(self, tHandle: str, updateHistory: bool = True) -> bool: