Switch Tokenizer to use QFont instead of font family and size
This commit is contained in:
@@ -76,8 +76,7 @@ SETTINGS_TEMPLATE = {
|
||||
"text.includeBodyText": (bool, True),
|
||||
"text.ignoredKeywords": (str, ""),
|
||||
"text.addNoteHeadings": (bool, True),
|
||||
"format.textFont": (str, CONFIG.textFont.family()),
|
||||
"format.textSize": (int, 12),
|
||||
"format.textFont": (str, CONFIG.textFont.toString()),
|
||||
"format.lineHeight": (float, 1.15, 0.75, 3.0),
|
||||
"format.justifyText": (bool, False),
|
||||
"format.stripUnicode": (bool, False),
|
||||
@@ -125,8 +124,7 @@ SETTINGS_LABELS = {
|
||||
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
|
||||
|
||||
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
|
||||
"format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"),
|
||||
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
|
||||
"format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
|
||||
"format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
|
||||
|
||||
@@ -28,7 +28,7 @@ import logging
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QFont, QFontInfo
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwLabels
|
||||
@@ -279,13 +279,9 @@ class NWBuildDocument:
|
||||
def _setupBuild(self, bldObj: Tokenizer) -> dict:
|
||||
"""Configure the build object."""
|
||||
# Get Settings
|
||||
textFont = self._build.getStr("format.textFont")
|
||||
textSize = self._build.getInt("format.textSize")
|
||||
|
||||
fontFamily = textFont or CONFIG.textFont.family()
|
||||
bldFont = QFont(fontFamily, textSize)
|
||||
fontInfo = QFontInfo(bldFont)
|
||||
textFixed = fontInfo.fixedPitch()
|
||||
textFont = QFont(CONFIG.textFont)
|
||||
textFont.fromString(self._build.getStr("format.textFont"))
|
||||
bldObj.setFont(textFont)
|
||||
|
||||
bldObj.setTitleFormat(
|
||||
self._build.getStr("headings.fmtTitle"),
|
||||
@@ -324,7 +320,6 @@ class NWBuildDocument:
|
||||
self._build.getBool("headings.breakScene")
|
||||
)
|
||||
|
||||
bldObj.setFont(fontFamily, textSize, textFixed)
|
||||
bldObj.setJustify(self._build.getBool("format.justifyText"))
|
||||
bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
|
||||
bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks"))
|
||||
|
||||
@@ -34,7 +34,9 @@ from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import checkInt, formatTimeStamp, numberToRoman
|
||||
from novelwriter.constants import (
|
||||
nwHeadFmt, nwKeyWords, nwLabels, nwRegEx, nwShortcode, nwUnicode, trConst
|
||||
@@ -139,9 +141,7 @@ class Tokenizer(ABC):
|
||||
self._markdown: list[str] = []
|
||||
|
||||
# User Settings
|
||||
self._textFont = "Serif" # Output text font
|
||||
self._textSize = 11 # Output text size
|
||||
self._textFixed = False # Fixed width text
|
||||
self._textFont = CONFIG.textFont # Output text font
|
||||
self._lineHeight = 1.15 # Line height in units of em
|
||||
self._blockIndent = 4.00 # Block indent in units of em
|
||||
self._firstIndent = False # Enable first line indent
|
||||
@@ -315,11 +315,9 @@ class Tokenizer(ABC):
|
||||
)
|
||||
return
|
||||
|
||||
def setFont(self, family: str, size: int, isFixed: bool = False) -> None:
|
||||
def setFont(self, font: QFont) -> None:
|
||||
"""Set the build font."""
|
||||
self._textFont = family
|
||||
self._textSize = round(int(size))
|
||||
self._textFixed = isFixed
|
||||
self._textFont = font
|
||||
return
|
||||
|
||||
def setLineHeight(self, height: float) -> None:
|
||||
|
||||
@@ -183,7 +183,7 @@ class GuiPreferences(QDialog):
|
||||
self.guiFont.setMinimumWidth(fontWidth)
|
||||
self.guiFont.setText(describeFont(self._guiFont))
|
||||
self.guiFont.setCursorPosition(0)
|
||||
self.guiFontButton = NIconToolButton(self, iSz, "more")
|
||||
self.guiFontButton = NIconToolButton(self, iSz, "font")
|
||||
self.guiFontButton.clicked.connect(self._selectGuiFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Application font"), self.guiFont,
|
||||
@@ -233,7 +233,7 @@ class GuiPreferences(QDialog):
|
||||
self.textFont.setMinimumWidth(fontWidth)
|
||||
self.textFont.setText(describeFont(CONFIG.textFont))
|
||||
self.textFont.setCursorPosition(0)
|
||||
self.textFontButton = NIconToolButton(self, iSz, "more")
|
||||
self.textFontButton = NIconToolButton(self, iSz, "font")
|
||||
self.textFontButton.clicked.connect(self._selectTextFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Document font"), self.textFont,
|
||||
@@ -695,7 +695,7 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["SO"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["SO"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
|
||||
self.btnSingleStyleO = NIconToolButton(self, iSz, "more")
|
||||
self.btnSingleStyleO = NIconToolButton(self, iSz, "quote")
|
||||
self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Single quote open style"), self.quoteSym["SO"],
|
||||
@@ -709,7 +709,7 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["SC"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["SC"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
|
||||
self.btnSingleStyleC = NIconToolButton(self, iSz, "more")
|
||||
self.btnSingleStyleC = NIconToolButton(self, iSz, "quote")
|
||||
self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Single quote close style"), self.quoteSym["SC"],
|
||||
@@ -724,7 +724,7 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["DO"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["DO"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
|
||||
self.btnDoubleStyleO = NIconToolButton(self, iSz, "more")
|
||||
self.btnDoubleStyleO = NIconToolButton(self, iSz, "quote")
|
||||
self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Double quote open style"), self.quoteSym["DO"],
|
||||
@@ -738,7 +738,7 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["DC"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["DC"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
|
||||
self.btnDoubleStyleC = NIconToolButton(self, iSz, "more")
|
||||
self.btnDoubleStyleC = NIconToolButton(self, iSz, "quote")
|
||||
self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Double quote close style"), self.quoteSym["DC"],
|
||||
|
||||
@@ -31,7 +31,7 @@ from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QPalette, QResizeEvent
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
|
||||
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout,
|
||||
@@ -404,10 +404,10 @@ class GuiManuscript(NToolDialog):
|
||||
"""Update the preview widget and set relevant values."""
|
||||
self.docPreview.setContent(data)
|
||||
self.docPreview.setBuildName(build.name)
|
||||
self.docPreview.setTextFont(
|
||||
build.getStr("format.textFont"),
|
||||
build.getInt("format.textSize")
|
||||
)
|
||||
|
||||
textFont = QFont()
|
||||
textFont.fromString(build.getStr("format.textFont"))
|
||||
self.docPreview.setTextFont(textFont)
|
||||
self.docPreview.setJustify(
|
||||
build.getBool("format.justifyText")
|
||||
)
|
||||
@@ -787,7 +787,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
self._updateDocMargins()
|
||||
self._updateBuildAge()
|
||||
|
||||
self.setTextFont(CONFIG.textFont.family(), CONFIG.textFont.pointSize())
|
||||
self.setTextFont(CONFIG.textFont)
|
||||
|
||||
# Age Timer
|
||||
self.ageTimer = QTimer(self)
|
||||
@@ -817,18 +817,14 @@ class _PreviewWidget(QTextBrowser):
|
||||
self.document().setDefaultTextOption(pOptions)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str, size: int) -> None:
|
||||
def setTextFont(self, font: QFont) -> None:
|
||||
"""Set the text font properties and then reset for sub-widgets.
|
||||
This needs special attention since there appears to be a bug in
|
||||
Qt 5.15.3. See issues #1862 and #1875.
|
||||
"""
|
||||
if family and size > 4:
|
||||
font = self.font()
|
||||
font.setFamily(family)
|
||||
font.setPointSize(size)
|
||||
self.setFont(font)
|
||||
self.buildProgress.setFont(SHARED.theme.guiFont)
|
||||
self.ageLabel.setFont(SHARED.theme.guiFontSmall)
|
||||
self.setFont(font)
|
||||
self.buildProgress.setFont(SHARED.theme.guiFont)
|
||||
self.ageLabel.setFont(SHARED.theme.guiFontSmall)
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
@@ -37,6 +37,7 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import describeFont
|
||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
|
||||
from novelwriter.core.buildsettings import BuildSettings, FilterMode
|
||||
from novelwriter.extensions.configlayout import (
|
||||
@@ -1052,6 +1053,7 @@ class _FormatTab(NScrollableForm):
|
||||
|
||||
self._build = build
|
||||
self._unitScale = 1.0
|
||||
self._textFont = QFont(CONFIG.textFont)
|
||||
|
||||
iPx = SHARED.theme.baseIconHeight
|
||||
iSz = SHARED.theme.baseIconSize
|
||||
@@ -1063,24 +1065,16 @@ class _FormatTab(NScrollableForm):
|
||||
|
||||
self.addGroupLabel(self._build.getLabel("format.grpFormat"))
|
||||
|
||||
# Font Family
|
||||
# Text Font
|
||||
self.textFont = QLineEdit(self)
|
||||
self.textFont.setReadOnly(True)
|
||||
self.btnTextFont = NIconToolButton(self, iSz, "more")
|
||||
self.btnTextFont = NIconToolButton(self, iSz, "font")
|
||||
self.btnTextFont.clicked.connect(self._selectFont)
|
||||
self.addRow(
|
||||
self._build.getLabel("format.textFont"), self.textFont,
|
||||
button=self.btnTextFont, stretch=(3, 2)
|
||||
button=self.btnTextFont, stretch=(1, 1)
|
||||
)
|
||||
|
||||
# Font Size
|
||||
self.textSize = NSpinBox(self)
|
||||
self.textSize.setMinimum(8)
|
||||
self.textSize.setMaximum(60)
|
||||
self.textSize.setSingleStep(1)
|
||||
self.textSize.setMinimumWidth(spW)
|
||||
self.addRow(self._build.getLabel("format.textSize"), self.textSize, unit="pt")
|
||||
|
||||
# Line Height
|
||||
self.lineHeight = NDoubleSpinBox(self)
|
||||
self.lineHeight.setFixedWidth(spW)
|
||||
@@ -1175,14 +1169,13 @@ class _FormatTab(NScrollableForm):
|
||||
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
textFont = self._build.getStr("format.textFont")
|
||||
if not textFont:
|
||||
textFont = str(CONFIG.textFont.family())
|
||||
self._textFont = QFont()
|
||||
self._textFont.fromString(self._build.getStr("format.textFont"))
|
||||
|
||||
self.textFont.setText(describeFont(self._textFont))
|
||||
self.textFont.setCursorPosition(0)
|
||||
|
||||
self.textFont.setText(textFont)
|
||||
self.textSize.setValue(self._build.getInt("format.textSize"))
|
||||
self.lineHeight.setValue(self._build.getFloat("format.lineHeight"))
|
||||
|
||||
self.justifyText.setChecked(self._build.getBool("format.justifyText"))
|
||||
self.stripUnicode.setChecked(self._build.getBool("format.stripUnicode"))
|
||||
self.replaceTabs.setChecked(self._build.getBool("format.replaceTabs"))
|
||||
@@ -1219,8 +1212,7 @@ class _FormatTab(NScrollableForm):
|
||||
|
||||
def saveContent(self) -> None:
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("format.textFont", self.textFont.text())
|
||||
self._build.setValue("format.textSize", self.textSize.value())
|
||||
self._build.setValue("format.textFont", self._textFont.toString())
|
||||
self._build.setValue("format.lineHeight", self.lineHeight.value())
|
||||
|
||||
self._build.setValue("format.justifyText", self.justifyText.isChecked())
|
||||
@@ -1249,13 +1241,11 @@ class _FormatTab(NScrollableForm):
|
||||
@pyqtSlot()
|
||||
def _selectFont(self) -> None:
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
currFont = QFont()
|
||||
currFont.setFamily(self.textFont.text())
|
||||
currFont.setPointSize(self.textSize.value())
|
||||
newFont, status = QFontDialog.getFont(currFont, self)
|
||||
font, status = QFontDialog.getFont(self._textFont, self)
|
||||
if status:
|
||||
self.textFont.setText(newFont.family())
|
||||
self.textSize.setValue(newFont.pointSize())
|
||||
self.textFont.setText(describeFont(font))
|
||||
self.textFont.setCursorPosition(0)
|
||||
self._textFont = font
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
|
||||
+34
-1
@@ -24,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import QRegularExpression, Qt
|
||||
from PyQt5.QtGui import QColor, QPainter, QTextCursor, QTextFormat
|
||||
from PyQt5.QtGui import QColor, QFont, QPainter, QTextCursor, QTextFormat
|
||||
from PyQt5.QtWidgets import QDialogButtonBox, QSizePolicy, QStyle
|
||||
|
||||
# Qt Alignment Flags
|
||||
@@ -105,3 +105,36 @@ QtSizeMinimumExpanding = QSizePolicy.Policy.MinimumExpanding
|
||||
# Other
|
||||
|
||||
QRegExUnicode = QRegularExpression.PatternOption.UseUnicodePropertiesOption
|
||||
|
||||
# Maps
|
||||
|
||||
FONT_WEIGHTS: dict[int, int] = {
|
||||
QFont.Weight.Thin: 100,
|
||||
QFont.Weight.ExtraLight: 200,
|
||||
QFont.Weight.Light: 300,
|
||||
QFont.Weight.Normal: 400,
|
||||
QFont.Weight.Medium: 500,
|
||||
QFont.Weight.DemiBold: 600,
|
||||
QFont.Weight.Bold: 700,
|
||||
QFont.Weight.ExtraBold: 800,
|
||||
QFont.Weight.Black: 900,
|
||||
}
|
||||
|
||||
FONT_STRETCH: dict[int, str] = {
|
||||
QFont.AnyStretch: "normal",
|
||||
QFont.UltraCondensed: "ultra-condensed",
|
||||
QFont.ExtraCondensed: "extra-condensed",
|
||||
QFont.Condensed: "condensed",
|
||||
QFont.SemiCondensed: "semi-condensed",
|
||||
QFont.Unstretched: "normal",
|
||||
QFont.SemiExpanded: "semi-expanded",
|
||||
QFont.Expanded: "expanded",
|
||||
QFont.ExtraExpanded: "extra-expanded",
|
||||
QFont.UltraExpanded: "ultra-expanded",
|
||||
}
|
||||
|
||||
FONT_STYLE: dict[int, str] = {
|
||||
QFont.Style.StyleNormal: "normal",
|
||||
QFont.Style.StyleItalic: "italic",
|
||||
QFont.Style.StyleOblique: "oblique",
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import json
|
||||
|
||||
import pytest
|
||||
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter.constants import nwHeadFmt
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import HeadingFormatter, Tokenizer, stripEscape
|
||||
@@ -50,9 +52,7 @@ def testCoreToken_Setters(mockGUI):
|
||||
assert tokens._fmtScene == nwHeadFmt.TITLE
|
||||
assert tokens._fmtHScene == nwHeadFmt.TITLE
|
||||
assert tokens._fmtSection == nwHeadFmt.TITLE
|
||||
assert tokens._textFont == "Serif"
|
||||
assert tokens._textSize == 11
|
||||
assert tokens._textFixed is False
|
||||
assert tokens._textFont == QFont("Serif", 11)
|
||||
assert tokens._lineHeight == 1.15
|
||||
assert tokens._blockIndent == 4.0
|
||||
assert tokens._doJustify is False
|
||||
@@ -82,7 +82,7 @@ def testCoreToken_Setters(mockGUI):
|
||||
tokens.setSceneFormat(f"S: {nwHeadFmt.TITLE}", True)
|
||||
tokens.setHardSceneFormat(f"H: {nwHeadFmt.TITLE}", True)
|
||||
tokens.setSectionFormat(f"X: {nwHeadFmt.TITLE}", True)
|
||||
tokens.setFont("Monospace", 10, True)
|
||||
tokens.setFont(QFont("Monospace", 10))
|
||||
tokens.setLineHeight(2.0)
|
||||
tokens.setBlockIndent(6.0)
|
||||
tokens.setJustify(True)
|
||||
@@ -106,9 +106,7 @@ def testCoreToken_Setters(mockGUI):
|
||||
assert tokens._fmtScene == f"S: {nwHeadFmt.TITLE}"
|
||||
assert tokens._fmtHScene == f"H: {nwHeadFmt.TITLE}"
|
||||
assert tokens._fmtSection == f"X: {nwHeadFmt.TITLE}"
|
||||
assert tokens._textFont == "Monospace"
|
||||
assert tokens._textSize == 10
|
||||
assert tokens._textFixed is True
|
||||
assert tokens._textFont == QFont("Monospace", 10)
|
||||
assert tokens._lineHeight == 2.0
|
||||
assert tokens._blockIndent == 6.0
|
||||
assert tokens._doJustify is True
|
||||
|
||||
Reference in New Issue
Block a user