diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py index 5eefc616..72e68449 100644 --- a/novelwriter/core/tokenizer.py +++ b/novelwriter/core/tokenizer.py @@ -36,7 +36,6 @@ 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 @@ -141,7 +140,7 @@ class Tokenizer(ABC): self._markdown: list[str] = [] # User Settings - self._textFont = CONFIG.textFont # Output text font + self._textFont = QFont("Serif", 11) # 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 diff --git a/novelwriter/core/toodt.py b/novelwriter/core/toodt.py index cd81d100..661e3998 100644 --- a/novelwriter/core/toodt.py +++ b/novelwriter/core/toodt.py @@ -35,11 +35,14 @@ from hashlib import sha256 from pathlib import Path from zipfile import ZipFile +from PyQt5.QtGui import QFont + from novelwriter import __version__ from novelwriter.common import xmlIndent from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import T_Formats, Tokenizer, stripEscape +from novelwriter.types import FONT_WEIGHTS logger = logging.getLogger(__name__) @@ -108,6 +111,10 @@ S_TEXT = "Text_20_body" S_META = "Text_20_Meta" S_HNF = "Header_20_and_20_Footer" +# Font Data +FONT_WEIGHT_NUM = ["100", "200", "300", "400", "500", "600", "700", "800", "900"] +FONT_WEIGHT_MAP = {"400": "normal", "700": "bold"} + class ToOdt(Tokenizer): """Core: Open Document Writer @@ -149,16 +156,17 @@ class ToOdt(Tokenizer): self._errData = [] # List of errors encountered # Properties - self._textFont = "Liberation Serif" - self._textSize = 12 - self._textFixed = False + self._textFont = QFont("Liberation Serif", 12) self._colourHead = False self._headerFormat = "" self._pageOffset = 0 # Internal - self._fontFamily = "'Liberation Serif'" + self._fontFamily = "Liberation Serif" + self._fontSize = 12 + self._fontWeight = "normal" self._fontPitch = "variable" + self._fontBold = "bold" self._fSizeTitle = "30pt" self._fSizeHead1 = "24pt" self._fSizeHead2 = "20pt" @@ -260,19 +268,24 @@ class ToOdt(Tokenizer): # Initialise Variables # ==================== - self._fontFamily = self._textFont - if len(self._textFont.split()) > 1: - self._fontFamily = f"'{self._textFont}'" - self._fontPitch = "fixed" if self._textFixed else "variable" + intWeight = FONT_WEIGHTS.get(self._textFont.weight(), 400) + fontWeight = str(intWeight) + fontBold = str(min(intWeight + 300, 900)) - self._fSizeTitle = f"{round(2.50 * self._textSize):d}pt" - self._fSizeHead1 = f"{round(2.00 * self._textSize):d}pt" - self._fSizeHead2 = f"{round(1.60 * self._textSize):d}pt" - self._fSizeHead3 = f"{round(1.30 * self._textSize):d}pt" - self._fSizeHead4 = f"{round(1.15 * self._textSize):d}pt" - self._fSizeHead = f"{round(1.15 * self._textSize):d}pt" - self._fSizeText = f"{self._textSize:d}pt" - self._fSizeFoot = f"{round(0.8*self._textSize):d}pt" + self._fontFamily = self._textFont.family() + self._fontSize = self._textFont.pointSize() + self._fontWeight = FONT_WEIGHT_MAP.get(fontWeight, fontWeight) + self._fontPitch = "fixed" if self._textFont.fixedPitch() else "variable" + self._fontBold = FONT_WEIGHT_MAP.get(fontBold, fontBold) + + self._fSizeTitle = f"{round(2.50 * self._fontSize):d}pt" + self._fSizeHead1 = f"{round(2.00 * self._fontSize):d}pt" + self._fSizeHead2 = f"{round(1.60 * self._fontSize):d}pt" + self._fSizeHead3 = f"{round(1.30 * self._fontSize):d}pt" + self._fSizeHead4 = f"{round(1.15 * self._fontSize):d}pt" + self._fSizeHead = f"{round(1.15 * self._fontSize):d}pt" + self._fSizeText = f"{self._fontSize:d}pt" + self._fSizeFoot = f"{round(0.8*self._fontSize):d}pt" mScale = self._lineHeight/1.15 @@ -320,8 +333,9 @@ class ToOdt(Tokenizer): tAttr[_mkTag("office", "version")] = X_VERS fAttr = {} - fAttr[_mkTag("style", "name")] = self._textFont + fAttr[_mkTag("style", "name")] = self._fontFamily fAttr[_mkTag("style", "font-pitch")] = self._fontPitch + fAttr[_mkTag("style", "font-weight")] = self._fontWeight if self._isFlat: @@ -726,7 +740,7 @@ class ToOdt(Tokenizer): style = ODTTextStyle(f"T{len(self._autoText)+1:d}") if hFmt & X_BLD: - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) if hFmt & X_ITA: style.setFontStyle("italic") if hFmt & X_DEL: @@ -764,7 +778,7 @@ class ToOdt(Tokenizer): def _emToCm(self, value: float) -> str: """Converts an em value to centimetres.""" - return f"{value*2.54/72*self._textSize:.3f}cm" + return f"{value*2.54/72*self._fontSize:.3f}cm" ## # Style Elements @@ -808,8 +822,9 @@ class ToOdt(Tokenizer): _mkTag("style", "writing-mode"): "page", }) ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ - _mkTag("style", "font-name"): self._textFont, + _mkTag("style", "font-name"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily, + _mkTag("fo", "font-weight"): self._fontWeight, _mkTag("fo", "font-size"): self._fSizeText, _mkTag("fo", "language"): self._dLanguage, _mkTag("fo", "country"): self._dCountry, @@ -822,8 +837,9 @@ class ToOdt(Tokenizer): _mkTag("style", "class"): "text", }) ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ - _mkTag("style", "font-name"): self._textFont, + _mkTag("style", "font-name"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily, + _mkTag("fo", "font-weight"): self._fontWeight, _mkTag("fo", "font-size"): self._fSizeText, }) @@ -841,8 +857,9 @@ class ToOdt(Tokenizer): _mkTag("fo", "keep-with-next"): "always", }) ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ - _mkTag("style", "font-name"): self._textFont, + _mkTag("style", "font-name"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily, + _mkTag("fo", "font-weight"): self._fontWeight, _mkTag("fo", "font-size"): self._fSizeHead, }) @@ -868,9 +885,10 @@ class ToOdt(Tokenizer): style.setMarginBottom(self._mBotText) style.setLineHeight(self._fLineHeight) style.setTextAlign(self._textAlign) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeText) + style.setFontWeight(self._fontWeight) style.packXML(self._xStyl) self._mainPara[style.name] = style @@ -891,9 +909,10 @@ class ToOdt(Tokenizer): style.setMarginTop(self._mTopMeta) style.setMarginBottom(self._mBotMeta) style.setLineHeight(self._fLineHeight) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeText) + style.setFontWeight(self._fontWeight) style.setColour(self._colMetaTx) style.setOpacity(self._opaMetaTx) style.packXML(self._xStyl) @@ -908,10 +927,10 @@ class ToOdt(Tokenizer): style.setMarginTop(self._mTopTitle) style.setMarginBottom(self._mBotTitle) style.setTextAlign("center") - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeTitle) - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) style.packXML(self._xStyl) self._mainPara[style.name] = style @@ -925,9 +944,10 @@ class ToOdt(Tokenizer): style.setMarginBottom(self._mBotText) style.setLineHeight(self._fLineHeight) style.setTextAlign("center") - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeText) + style.setFontWeight(self._fontWeight) style.packXML(self._xStyl) self._mainPara[style.name] = style @@ -940,10 +960,10 @@ class ToOdt(Tokenizer): style.setClass("text") style.setMarginTop(self._mTopHead1) style.setMarginBottom(self._mBotHead1) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeHead1) - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) style.setColour(self._colHead12) style.setOpacity(self._opaHead12) style.packXML(self._xStyl) @@ -958,10 +978,10 @@ class ToOdt(Tokenizer): style.setClass("text") style.setMarginTop(self._mTopHead2) style.setMarginBottom(self._mBotHead2) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeHead2) - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) style.setColour(self._colHead12) style.setOpacity(self._opaHead12) style.packXML(self._xStyl) @@ -976,10 +996,10 @@ class ToOdt(Tokenizer): style.setClass("text") style.setMarginTop(self._mTopHead3) style.setMarginBottom(self._mBotHead3) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeHead3) - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) style.setColour(self._colHead34) style.setOpacity(self._opaHead34) style.packXML(self._xStyl) @@ -994,10 +1014,10 @@ class ToOdt(Tokenizer): style.setClass("text") style.setMarginTop(self._mTopHead4) style.setMarginBottom(self._mBotHead4) - style.setFontName(self._textFont) + style.setFontName(self._fontFamily) style.setFontFamily(self._fontFamily) style.setFontSize(self._fSizeHead4) - style.setFontWeight("bold") + style.setFontWeight(self._fontBold) style.setColour(self._colHead34) style.setOpacity(self._opaHead34) style.packXML(self._xStyl) @@ -1077,7 +1097,7 @@ class ODTParagraphStyle: VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"] VALID_LEVEL = ["1", "2", "3", "4"] VALID_CLASS = ["text", "chapter", "extra"] - VALID_WEIGHT = ["normal", "inherit", "bold"] + VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM def __init__(self, name: str) -> None: @@ -1320,8 +1340,8 @@ class ODTTextStyle: Only the used settings are exposed here to keep the class minimal and fast. """ - VALID_WEIGHT = ["normal", "inherit", "bold"] - VALID_STYLE = ["normal", "inherit", "italic"] + VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM + VALID_STYLE = ["normal", "italic", "oblique"] VALID_POS = ["super", "sub"] VALID_LSTYLE = ["none", "solid"] VALID_LTYPE = ["single", "double"]