Move colour theme to Tokenizer class
This commit is contained in:
@@ -29,6 +29,8 @@ import re
|
||||
|
||||
from enum import Flag, IntEnum
|
||||
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
|
||||
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
|
||||
|
||||
@@ -40,6 +42,23 @@ def stripEscape(text: str) -> str:
|
||||
return text
|
||||
|
||||
|
||||
class TextDocumentTheme:
|
||||
"""Default document theme."""
|
||||
|
||||
text: QColor = QColor(0, 0, 0)
|
||||
highlight: QColor = QColor(255, 255, 166)
|
||||
head: QColor = QColor(66, 113, 174)
|
||||
comment: QColor = QColor(100, 100, 100)
|
||||
note: QColor = QColor(129, 55, 9)
|
||||
code: QColor = QColor(66, 113, 174)
|
||||
modifier: QColor = QColor(129, 55, 9)
|
||||
keyword: QColor = QColor(245, 135, 31)
|
||||
tag: QColor = QColor(66, 113, 174)
|
||||
optional: QColor = QColor(66, 113, 174)
|
||||
dialog: QColor = QColor(66, 113, 174)
|
||||
altdialog: QColor = QColor(129, 55, 9)
|
||||
|
||||
|
||||
# Enums
|
||||
# =====
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ from typing import NamedTuple
|
||||
from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
||||
from PyQt5.QtCore import QMarginsF, QSizeF
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import firstFloat, xmlSubElem
|
||||
@@ -41,6 +42,7 @@ from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.types import QtHexRgb
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -80,6 +82,11 @@ def _mkTag(ns: str, tag: str) -> str:
|
||||
return tag
|
||||
|
||||
|
||||
def _docXCol(color: QColor) -> str:
|
||||
"""Format a QColor as the DocX accepted value."""
|
||||
return color.name(QtHexRgb).lstrip("#")
|
||||
|
||||
|
||||
# Formatting Codes
|
||||
X_BLD = 0x001 # Bold format
|
||||
X_ITA = 0x002 # Italic format
|
||||
@@ -115,8 +122,6 @@ S_HEAD = "Header"
|
||||
S_FNOTE = "FootnoteText"
|
||||
|
||||
# Colours
|
||||
COL_HEAD_L12 = "2a6099"
|
||||
COL_HEAD_L34 = "444444"
|
||||
COL_DIALOG_M = "2a6099"
|
||||
COL_DIALOG_A = "813709"
|
||||
COL_META_TXT = "813709"
|
||||
@@ -535,7 +540,7 @@ class ToDocX(Tokenizer):
|
||||
styles: list[DocXParStyle] = []
|
||||
|
||||
hScale = self._scaleHeads
|
||||
hColor = self._colorHeads
|
||||
hColor = _docXCol(self._theme.head) if self._colorHeads else None
|
||||
fSz = self._fontSize
|
||||
fnSz = 0.8 * self._fontSize
|
||||
fSz0 = (nwStyles.H_SIZES[0] * fSz) if hScale else fSz
|
||||
@@ -582,7 +587,7 @@ class ToDocX(Tokenizer):
|
||||
after=fSz * self._marginHead1[1],
|
||||
line=fSz1 * self._lineHeight,
|
||||
level=0,
|
||||
color=COL_HEAD_L12 if hColor else None,
|
||||
color=hColor,
|
||||
bold=self._boldHeads,
|
||||
))
|
||||
|
||||
@@ -597,7 +602,7 @@ class ToDocX(Tokenizer):
|
||||
after=fSz * self._marginHead2[1],
|
||||
line=fSz2 * self._lineHeight,
|
||||
level=1,
|
||||
color=COL_HEAD_L12 if hColor else None,
|
||||
color=hColor,
|
||||
bold=self._boldHeads,
|
||||
))
|
||||
|
||||
@@ -612,7 +617,7 @@ class ToDocX(Tokenizer):
|
||||
after=fSz * self._marginHead3[1],
|
||||
line=fSz3 * self._lineHeight,
|
||||
level=1,
|
||||
color=COL_HEAD_L34 if hColor else None,
|
||||
color=hColor,
|
||||
bold=self._boldHeads,
|
||||
))
|
||||
|
||||
@@ -627,7 +632,7 @@ class ToDocX(Tokenizer):
|
||||
after=fSz * self._marginHead4[1],
|
||||
line=fSz4 * self._lineHeight,
|
||||
level=1,
|
||||
color=COL_HEAD_L34 if hColor else None,
|
||||
color=hColor,
|
||||
bold=self._boldHeads,
|
||||
))
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ from novelwriter.constants import nwHeadFmt, nwHtmlUnicode, nwKeyWords, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
|
||||
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS, QtHexRgb
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -354,16 +354,18 @@ class ToHtml(Tokenizer):
|
||||
return []
|
||||
|
||||
mScale = self._lineHeight/1.15
|
||||
tColor = self._theme.text.name(QtHexRgb)
|
||||
hColor = self._theme.head.name(QtHexRgb) if self._colorHeads else tColor
|
||||
|
||||
styles = []
|
||||
font = self._textFont
|
||||
styles.append((
|
||||
"body {{"
|
||||
"font-family: '{0:s}'; font-size: {1:d}pt; "
|
||||
"font-weight: {2:d}; font-style: {3:s};"
|
||||
"color: {0:s}; font-family: '{1:s}'; font-size: {2:d}pt; "
|
||||
"font-weight: {3:d}; font-style: {4:s};"
|
||||
"}}"
|
||||
).format(
|
||||
font.family(), font.pointSize(),
|
||||
tColor, font.family(), font.pointSize(),
|
||||
FONT_WEIGHTS.get(font.weight(), 400),
|
||||
FONT_STYLE.get(font.style(), "normal"),
|
||||
))
|
||||
@@ -380,43 +382,43 @@ class ToHtml(Tokenizer):
|
||||
))
|
||||
styles.append((
|
||||
"h1 {{"
|
||||
"color: rgb(66, 113, 174); "
|
||||
"color: {0:s}; "
|
||||
"page-break-after: avoid; "
|
||||
"margin-top: {0:.2f}em; "
|
||||
"margin-bottom: {1:.2f}em;"
|
||||
"margin-top: {1:.2f}em; "
|
||||
"margin-bottom: {2:.2f}em;"
|
||||
"}}"
|
||||
).format(
|
||||
mScale * self._marginHead1[0], mScale * self._marginHead1[1]
|
||||
hColor, mScale * self._marginHead1[0], mScale * self._marginHead1[1]
|
||||
))
|
||||
styles.append((
|
||||
"h2 {{"
|
||||
"color: rgb(66, 113, 174); "
|
||||
"color: {0:s}; "
|
||||
"page-break-after: avoid; "
|
||||
"margin-top: {0:.2f}em; "
|
||||
"margin-bottom: {1:.2f}em;"
|
||||
"margin-top: {1:.2f}em; "
|
||||
"margin-bottom: {2:.2f}em;"
|
||||
"}}"
|
||||
).format(
|
||||
mScale * self._marginHead2[0], mScale * self._marginHead2[1]
|
||||
hColor, mScale * self._marginHead2[0], mScale * self._marginHead2[1]
|
||||
))
|
||||
styles.append((
|
||||
"h3 {{"
|
||||
"color: rgb(50, 50, 50); "
|
||||
"color: {0:s}; "
|
||||
"page-break-after: avoid; "
|
||||
"margin-top: {0:.2f}em; "
|
||||
"margin-bottom: {1:.2f}em;"
|
||||
"margin-top: {1:.2f}em; "
|
||||
"margin-bottom: {2:.2f}em;"
|
||||
"}}"
|
||||
).format(
|
||||
mScale * self._marginHead3[0], mScale * self._marginHead3[1]
|
||||
hColor, mScale * self._marginHead3[0], mScale * self._marginHead3[1]
|
||||
))
|
||||
styles.append((
|
||||
"h4 {{"
|
||||
"color: rgb(50, 50, 50); "
|
||||
"color: {0:s}; "
|
||||
"page-break-after: avoid; "
|
||||
"margin-top: {0:.2f}em; "
|
||||
"margin-bottom: {1:.2f}em;"
|
||||
"margin-top: {1:.2f}em; "
|
||||
"margin-bottom: {2:.2f}em;"
|
||||
"}}"
|
||||
).format(
|
||||
mScale * self._marginHead4[0], mScale * self._marginHead4[1]
|
||||
hColor, mScale * self._marginHead4[0], mScale * self._marginHead4[1]
|
||||
))
|
||||
styles.append((
|
||||
".title {{"
|
||||
|
||||
@@ -44,7 +44,9 @@ from novelwriter.constants import (
|
||||
from novelwriter.core.index import processComment
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwComment, nwItemLayout
|
||||
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextFmt
|
||||
from novelwriter.formats.shared import (
|
||||
BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt
|
||||
)
|
||||
from novelwriter.text.patterns import REGEX_PATTERNS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -110,6 +112,9 @@ class Tokenizer(ABC):
|
||||
self._keepBreaks = True # Keep line breaks in paragraphs
|
||||
self._defaultAlign = "left" # The default text alignment
|
||||
|
||||
# Other Setting
|
||||
self._theme = TextDocumentTheme()
|
||||
|
||||
# Margins
|
||||
self._marginTitle = nwStyles.T_MARGIN["H0"]
|
||||
self._marginHead1 = nwStyles.T_MARGIN["H1"]
|
||||
@@ -218,6 +223,11 @@ class Tokenizer(ABC):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setTheme(self, theme: TextDocumentTheme) -> None:
|
||||
"""Set the document colour theme."""
|
||||
self._theme = theme
|
||||
return
|
||||
|
||||
def setPartitionFormat(self, hFormat: str, hide: bool = False) -> None:
|
||||
"""Set the partition format pattern."""
|
||||
self._fmtPart = hFormat.strip()
|
||||
|
||||
@@ -35,7 +35,7 @@ from hashlib import sha256
|
||||
from pathlib import Path
|
||||
from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtGui import QColor, QFont
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import xmlIndent, xmlSubElem
|
||||
@@ -220,10 +220,6 @@ class ToOdt(Tokenizer):
|
||||
self._mDocRight = "2.000cm"
|
||||
|
||||
# Colour
|
||||
self._colHead12 = None
|
||||
self._opaHead12 = None
|
||||
self._colHead34 = None
|
||||
self._opaHead34 = None
|
||||
self._colDialogM = "#2a6099"
|
||||
self._colDialogA = "#813709"
|
||||
self._colMetaTx = "#813709"
|
||||
@@ -318,12 +314,6 @@ class ToOdt(Tokenizer):
|
||||
self._mLeftFoot = self._emToCm(self._marginFoot[0])
|
||||
self._mBotFoot = self._emToCm(self._marginFoot[1])
|
||||
|
||||
if self._colorHeads:
|
||||
self._colHead12 = "#2a6099"
|
||||
self._opaHead12 = "100%"
|
||||
self._colHead34 = "#444444"
|
||||
self._opaHead34 = "100%"
|
||||
|
||||
self._fLineHeight = f"{round(100 * self._lineHeight):d}%"
|
||||
self._fBlockIndent = self._emToCm(self._blockIndent)
|
||||
self._fTextIndent = self._emToCm(self._firstWidth)
|
||||
@@ -894,6 +884,8 @@ class ToOdt(Tokenizer):
|
||||
|
||||
def _useableStyles(self) -> None:
|
||||
"""Set the usable styles."""
|
||||
hColor = self._theme.head if self._colorHeads else None
|
||||
|
||||
# Add Text Body Style
|
||||
style = ODTParagraphStyle(S_TEXT)
|
||||
style.setDisplayName("Text body")
|
||||
@@ -931,8 +923,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeText)
|
||||
style.setFontWeight(self._fontWeight)
|
||||
style.setColour(self._colMetaTx)
|
||||
style.setOpacity(self._opaMetaTx)
|
||||
style.setColour(self._theme.note)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -982,8 +973,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead1)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(self._colHead12)
|
||||
style.setOpacity(self._opaHead12)
|
||||
style.setColour(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1000,8 +990,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead2)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(self._colHead12)
|
||||
style.setOpacity(self._opaHead12)
|
||||
style.setColour(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1018,8 +1007,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead3)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(self._colHead34)
|
||||
style.setOpacity(self._opaHead34)
|
||||
style.setColour(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1036,8 +1024,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead4)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(self._colHead34)
|
||||
style.setOpacity(self._opaHead34)
|
||||
style.setColour(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1298,14 +1285,14 @@ class ODTParagraphStyle:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setColour(self, value: str | None) -> None:
|
||||
def setColour(self, value: QColor | None) -> None:
|
||||
"""Set text colour."""
|
||||
self._tAttr["color"][1] = value
|
||||
return
|
||||
|
||||
def setOpacity(self, value: str | None) -> None:
|
||||
"""Set text opacity."""
|
||||
self._tAttr["opacity"][1] = value
|
||||
if isinstance(value, QColor):
|
||||
self._tAttr["color"][1] = value.name(QColor.NameFormat.HexRgb)
|
||||
self._tAttr["opacity"][1] = f"{int(100.0 * value.alphaF())}%"
|
||||
else:
|
||||
self._tAttr["color"][1] = None
|
||||
self._tAttr["opacity"][1] = None
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
@@ -29,7 +29,7 @@ from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import QMarginsF, QSizeF
|
||||
from PyQt5.QtGui import (
|
||||
QColor, QFont, QFontMetricsF, QPageSize, QTextBlockFormat, QTextCharFormat,
|
||||
QFont, QFontMetricsF, QPageSize, QTextBlockFormat, QTextCharFormat,
|
||||
QTextCursor, QTextDocument
|
||||
)
|
||||
from PyQt5.QtPrintSupport import QPrinter
|
||||
@@ -49,21 +49,6 @@ logger = logging.getLogger(__name__)
|
||||
T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
|
||||
|
||||
|
||||
class TextDocumentTheme:
|
||||
text: QColor = QColor(0, 0, 0)
|
||||
highlight: QColor = QColor(255, 255, 166)
|
||||
head: QColor = QColor(66, 113, 174)
|
||||
comment: QColor = QColor(100, 100, 100)
|
||||
note: QColor = QColor(129, 55, 9)
|
||||
code: QColor = QColor(66, 113, 174)
|
||||
modifier: QColor = QColor(129, 55, 9)
|
||||
keyword: QColor = QColor(245, 135, 31)
|
||||
tag: QColor = QColor(66, 113, 174)
|
||||
optional: QColor = QColor(66, 113, 174)
|
||||
dialog: QColor = QColor(66, 113, 174)
|
||||
altdialog: QColor = QColor(129, 55, 9)
|
||||
|
||||
|
||||
def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None:
|
||||
if cursor.position() > 0:
|
||||
cursor.insertBlock(bFmt)
|
||||
@@ -84,7 +69,6 @@ class ToQTextDocument(Tokenizer):
|
||||
self._document.setUndoRedoEnabled(False)
|
||||
self._document.setDocumentMargin(0)
|
||||
|
||||
self._theme = TextDocumentTheme()
|
||||
self._styles: dict[int, T_TextStyle] = {}
|
||||
self._usedNotes: dict[str, int] = {}
|
||||
|
||||
@@ -110,11 +94,6 @@ class ToQTextDocument(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setTheme(self, theme: TextDocumentTheme) -> None:
|
||||
"""Set the document colour theme."""
|
||||
self._theme = theme
|
||||
return
|
||||
|
||||
def setPageLayout(
|
||||
self, width: float, height: float, top: float, bottom: float, left: float, right: float
|
||||
) -> None:
|
||||
|
||||
@@ -44,7 +44,8 @@ from novelwriter.error import logException
|
||||
from novelwriter.extensions.configlayout import NColourLabel
|
||||
from novelwriter.extensions.eventfilters import WheelEventFilter
|
||||
from novelwriter.extensions.modified import NIconToolButton
|
||||
from novelwriter.formats.toqdoc import TextDocumentTheme, ToQTextDocument
|
||||
from novelwriter.formats.shared import TextDocumentTheme
|
||||
from novelwriter.formats.toqdoc import ToQTextDocument
|
||||
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
||||
from novelwriter.types import (
|
||||
QtAlignCenterTop, QtKeepAnchor, QtMouseLeft, QtMoveAnchor,
|
||||
|
||||
@@ -65,6 +65,10 @@ QtPaintAnitAlias = QPainter.RenderHint.Antialiasing
|
||||
QtMouseOver = QStyle.StateFlag.State_MouseOver
|
||||
QtSelected = QStyle.StateFlag.State_Selected
|
||||
|
||||
# Qt Colour Types
|
||||
|
||||
QtHexRgb = QColor.NameFormat.HexRgb
|
||||
|
||||
# Qt Tree and Table Types
|
||||
|
||||
QtDecoration = Qt.ItemDataRole.DecorationRole
|
||||
|
||||
Reference in New Issue
Block a user