novelWriter 2.2rc1__py3-none-any.whl → 2.3b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +141 -129
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +11 -6
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_de_DE.json +1 -0
- novelwriter/assets/i18n/project_en_US.json +1 -0
- novelwriter/assets/i18n/project_es_419.json +11 -0
- novelwriter/assets/i18n/project_fr_FR.json +11 -0
- novelwriter/assets/i18n/project_it_IT.json +11 -0
- novelwriter/assets/i18n/project_ja_JP.json +2 -1
- novelwriter/assets/i18n/project_nb_NO.json +1 -0
- novelwriter/assets/i18n/project_zh_CN.json +11 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +9 -2
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
- novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +9 -2
- novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
- novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
- novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
- novelwriter/assets/images/novelwriter-text-light.svg +4 -0
- novelwriter/assets/images/welcome-dark.jpg +0 -0
- novelwriter/assets/images/welcome-light.jpg +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +4 -2
- novelwriter/assets/themes/default_dark.conf +2 -2
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +64 -66
- novelwriter/config.py +39 -44
- novelwriter/constants.py +39 -17
- novelwriter/core/buildsettings.py +8 -8
- novelwriter/core/coretools.py +194 -155
- novelwriter/core/docbuild.py +7 -4
- novelwriter/core/document.py +7 -7
- novelwriter/core/index.py +90 -57
- novelwriter/core/item.py +23 -5
- novelwriter/core/options.py +11 -10
- novelwriter/core/project.py +72 -47
- novelwriter/core/projectdata.py +3 -16
- novelwriter/core/projectxml.py +14 -42
- novelwriter/core/sessions.py +4 -3
- novelwriter/core/spellcheck.py +6 -4
- novelwriter/core/status.py +5 -4
- novelwriter/core/storage.py +179 -141
- novelwriter/core/tohtml.py +6 -4
- novelwriter/core/tokenizer.py +74 -46
- novelwriter/core/tomd.py +2 -2
- novelwriter/core/toodt.py +41 -31
- novelwriter/core/tree.py +5 -4
- novelwriter/dialogs/about.py +88 -179
- novelwriter/dialogs/docmerge.py +30 -20
- novelwriter/dialogs/docsplit.py +33 -22
- novelwriter/dialogs/editlabel.py +20 -8
- novelwriter/dialogs/preferences.py +562 -725
- novelwriter/dialogs/{projsettings.py → projectsettings.py} +301 -270
- novelwriter/dialogs/quotes.py +47 -36
- novelwriter/dialogs/wordlist.py +128 -59
- novelwriter/enum.py +25 -22
- novelwriter/error.py +2 -2
- novelwriter/extensions/circularprogress.py +12 -12
- novelwriter/extensions/configlayout.py +185 -146
- novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
- novelwriter/extensions/modified.py +81 -0
- novelwriter/extensions/novelselector.py +27 -13
- novelwriter/extensions/pagedsidebar.py +15 -20
- novelwriter/extensions/simpleprogress.py +8 -9
- novelwriter/extensions/statusled.py +9 -9
- novelwriter/extensions/switch.py +32 -64
- novelwriter/extensions/switchbox.py +2 -7
- novelwriter/extensions/versioninfo.py +153 -0
- novelwriter/gui/doceditor.py +250 -214
- novelwriter/gui/dochighlight.py +66 -94
- novelwriter/gui/docviewer.py +71 -98
- novelwriter/gui/docviewerpanel.py +140 -47
- novelwriter/gui/editordocument.py +3 -3
- novelwriter/gui/itemdetails.py +9 -9
- novelwriter/gui/mainmenu.py +47 -46
- novelwriter/gui/noveltree.py +53 -61
- novelwriter/gui/outline.py +100 -76
- novelwriter/gui/projtree.py +193 -67
- novelwriter/gui/sidebar.py +9 -8
- novelwriter/gui/statusbar.py +49 -7
- novelwriter/gui/theme.py +65 -74
- novelwriter/guimain.py +173 -330
- novelwriter/shared.py +68 -30
- novelwriter/tools/dictionaries.py +7 -8
- novelwriter/tools/lipsum.py +34 -28
- novelwriter/tools/manusbuild.py +3 -4
- novelwriter/tools/manuscript.py +25 -32
- novelwriter/tools/manussettings.py +194 -225
- novelwriter/tools/noveldetails.py +525 -0
- novelwriter/tools/welcome.py +802 -0
- novelwriter/tools/writingstats.py +26 -13
- novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
- novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
- novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
- novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
- novelwriter/assets/images/wizard-back.jpg +0 -0
- novelwriter/assets/text/gplv3_en.htm +0 -641
- novelwriter/assets/text/release_notes.htm +0 -17
- novelwriter/dialogs/projdetails.py +0 -525
- novelwriter/dialogs/projload.py +0 -298
- novelwriter/dialogs/updates.py +0 -182
- novelwriter/extensions/pageddialog.py +0 -130
- novelwriter/tools/projwizard.py +0 -478
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
novelwriter/gui/dochighlight.py
CHANGED
@@ -3,10 +3,11 @@ novelWriter – GUI Syntax Highlighter
|
|
3
3
|
====================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2019-04-06 [0.0.1]
|
6
|
+
Created: 2019-04-06 [0.0.1] GuiDocHighlighter
|
7
|
+
Created: 2023-09-10 [2.2b1] TextBlockData
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
10
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
11
|
|
11
12
|
This program is free software: you can redistribute it and/or modify
|
12
13
|
it under the terms of the GNU General Public License as published by
|
@@ -34,10 +35,10 @@ from PyQt5.QtGui import (
|
|
34
35
|
)
|
35
36
|
|
36
37
|
from novelwriter import CONFIG, SHARED
|
38
|
+
from novelwriter.enum import nwComment
|
37
39
|
from novelwriter.common import checkInt
|
38
40
|
from novelwriter.constants import nwRegEx, nwUnicode
|
39
41
|
from novelwriter.core.index import processComment
|
40
|
-
from novelwriter.enum import nwComment
|
41
42
|
|
42
43
|
logger = logging.getLogger(__name__)
|
43
44
|
|
@@ -47,6 +48,8 @@ SPELLRX.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
|
47
48
|
|
48
49
|
class GuiDocHighlighter(QSyntaxHighlighter):
|
49
50
|
|
51
|
+
__slots__ = ("_tItem", "_tHandle", "_spellCheck", "_spellErr", "_hRules", "_hStyles")
|
52
|
+
|
50
53
|
BLOCK_NONE = 0
|
51
54
|
BLOCK_TEXT = 1
|
52
55
|
BLOCK_META = 2
|
@@ -57,29 +60,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
57
60
|
|
58
61
|
logger.debug("Create: GuiDocHighlighter")
|
59
62
|
|
60
|
-
self.
|
61
|
-
self.
|
63
|
+
self._tHandle = None
|
64
|
+
self._isInactive = False
|
62
65
|
self._spellCheck = False
|
66
|
+
self._spellErr = QTextCharFormat()
|
63
67
|
|
64
68
|
self._hRules: list[tuple[str, dict]] = []
|
65
69
|
self._hStyles: dict[str, QTextCharFormat] = {}
|
66
70
|
|
67
|
-
self._colHead = QColor(0, 0, 0)
|
68
|
-
self._colHeadH = QColor(0, 0, 0)
|
69
|
-
self._colEmph = QColor(0, 0, 0)
|
70
|
-
self._colDialN = QColor(0, 0, 0)
|
71
|
-
self._colDialD = QColor(0, 0, 0)
|
72
|
-
self._colDialS = QColor(0, 0, 0)
|
73
|
-
self._colHidden = QColor(0, 0, 0)
|
74
|
-
self._colCode = QColor(0, 0, 0)
|
75
|
-
self._colKey = QColor(0, 0, 0)
|
76
|
-
self._colVal = QColor(0, 0, 0)
|
77
|
-
self._colSpell = QColor(0, 0, 0)
|
78
|
-
self._colError = QColor(0, 0, 0)
|
79
|
-
self._colRepTag = QColor(0, 0, 0)
|
80
|
-
self._colMod = QColor(0, 0, 0)
|
81
|
-
self._colBreak = QColor(0, 0, 0)
|
82
|
-
|
83
71
|
self.initHighlighter()
|
84
72
|
|
85
73
|
logger.debug("Ready: GuiDocHighlighter")
|
@@ -92,54 +80,43 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
92
80
|
"""
|
93
81
|
logger.debug("Setting up highlighting rules")
|
94
82
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
self._colDialD = QColor(*SHARED.theme.colDialD)
|
99
|
-
self._colDialS = QColor(*SHARED.theme.colDialS)
|
100
|
-
self._colHidden = QColor(*SHARED.theme.colHidden)
|
101
|
-
self._colCode = QColor(*SHARED.theme.colCode)
|
102
|
-
self._colKey = QColor(*SHARED.theme.colKey)
|
103
|
-
self._colVal = QColor(*SHARED.theme.colVal)
|
104
|
-
self._colSpell = QColor(*SHARED.theme.colSpell)
|
105
|
-
self._colError = QColor(*SHARED.theme.colError)
|
106
|
-
self._colRepTag = QColor(*SHARED.theme.colRepTag)
|
107
|
-
self._colMod = QColor(*SHARED.theme.colMod)
|
108
|
-
self._colBreak = QColor(*SHARED.theme.colEmph)
|
109
|
-
self._colBreak.setAlpha(64)
|
110
|
-
|
111
|
-
self._colEmph = None
|
112
|
-
if CONFIG.highlightEmph:
|
113
|
-
self._colEmph = QColor(*SHARED.theme.colEmph)
|
83
|
+
colEmph = SHARED.theme.colEmph if CONFIG.highlightEmph else None
|
84
|
+
colBreak = QColor(SHARED.theme.colEmph)
|
85
|
+
colBreak.setAlpha(64)
|
114
86
|
|
87
|
+
self._hRules = []
|
115
88
|
self._hStyles = {
|
116
|
-
"header1": self._makeFormat(
|
117
|
-
"header2": self._makeFormat(
|
118
|
-
"header3": self._makeFormat(
|
119
|
-
"header4": self._makeFormat(
|
120
|
-
"header1h": self._makeFormat(
|
121
|
-
"header2h": self._makeFormat(
|
122
|
-
"header3h": self._makeFormat(
|
123
|
-
"header4h": self._makeFormat(
|
124
|
-
"bold": self._makeFormat(
|
125
|
-
"italic": self._makeFormat(
|
126
|
-
"strike": self._makeFormat(
|
127
|
-
"mspaces": self._makeFormat(
|
128
|
-
"nobreak": self._makeFormat(
|
129
|
-
"dialogue1": self._makeFormat(
|
130
|
-
"dialogue2": self._makeFormat(
|
131
|
-
"dialogue3": self._makeFormat(
|
132
|
-
"replace": self._makeFormat(
|
133
|
-
"hidden": self._makeFormat(
|
134
|
-
"code": self._makeFormat(
|
135
|
-
"keyword": self._makeFormat(
|
136
|
-
"modifier": self._makeFormat(
|
137
|
-
"value": self._makeFormat(
|
138
|
-
"
|
89
|
+
"header1": self._makeFormat(SHARED.theme.colHead, "bold", 1.8),
|
90
|
+
"header2": self._makeFormat(SHARED.theme.colHead, "bold", 1.6),
|
91
|
+
"header3": self._makeFormat(SHARED.theme.colHead, "bold", 1.4),
|
92
|
+
"header4": self._makeFormat(SHARED.theme.colHead, "bold", 1.2),
|
93
|
+
"header1h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.8),
|
94
|
+
"header2h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.6),
|
95
|
+
"header3h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.4),
|
96
|
+
"header4h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.2),
|
97
|
+
"bold": self._makeFormat(colEmph, "bold"),
|
98
|
+
"italic": self._makeFormat(colEmph, "italic"),
|
99
|
+
"strike": self._makeFormat(SHARED.theme.colHidden, "strike"),
|
100
|
+
"mspaces": self._makeFormat(SHARED.theme.colError, "errline"),
|
101
|
+
"nobreak": self._makeFormat(colBreak, "background"),
|
102
|
+
"dialogue1": self._makeFormat(SHARED.theme.colDialN),
|
103
|
+
"dialogue2": self._makeFormat(SHARED.theme.colDialD),
|
104
|
+
"dialogue3": self._makeFormat(SHARED.theme.colDialS),
|
105
|
+
"replace": self._makeFormat(SHARED.theme.colRepTag),
|
106
|
+
"hidden": self._makeFormat(SHARED.theme.colHidden),
|
107
|
+
"code": self._makeFormat(SHARED.theme.colCode),
|
108
|
+
"keyword": self._makeFormat(SHARED.theme.colKey),
|
109
|
+
"modifier": self._makeFormat(SHARED.theme.colMod),
|
110
|
+
"value": self._makeFormat(SHARED.theme.colVal),
|
111
|
+
"optional": self._makeFormat(SHARED.theme.colOpt),
|
112
|
+
"codevalue": self._makeFormat(SHARED.theme.colVal),
|
139
113
|
"codeinval": self._makeFormat(None, "errline"),
|
140
114
|
}
|
141
115
|
|
142
|
-
|
116
|
+
# Cache Spell Error Format
|
117
|
+
self._spellErr = QTextCharFormat()
|
118
|
+
self._spellErr.setUnderlineColor(SHARED.theme.colSpell)
|
119
|
+
self._spellErr.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
143
120
|
|
144
121
|
# Multiple or Trailing Spaces
|
145
122
|
if CONFIG.showMultiSpaces:
|
@@ -261,11 +238,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
261
238
|
def setHandle(self, tHandle: str) -> None:
|
262
239
|
"""Set the handle of the currently highlighted document."""
|
263
240
|
self._tHandle = tHandle
|
264
|
-
self.
|
265
|
-
|
266
|
-
"Syntax highlighter %s for item '%s'",
|
267
|
-
"enabled" if self._tItem else "disabled", tHandle
|
241
|
+
self._isInactive = (
|
242
|
+
item.isInactiveClass() if (item := SHARED.project.tree[tHandle]) else False
|
268
243
|
)
|
244
|
+
logger.debug("Syntax highlighter enabled for item '%s'", tHandle)
|
269
245
|
return
|
270
246
|
|
271
247
|
##
|
@@ -280,9 +256,9 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
280
256
|
nBlocks = qDoc.blockCount()
|
281
257
|
tStart = time()
|
282
258
|
for i in range(nBlocks):
|
283
|
-
|
284
|
-
if
|
285
|
-
self.rehighlightBlock(
|
259
|
+
block = qDoc.findBlockByNumber(i)
|
260
|
+
if block.userState() & cType > 0:
|
261
|
+
self.rehighlightBlock(block)
|
286
262
|
logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart)))
|
287
263
|
return
|
288
264
|
|
@@ -302,24 +278,23 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
302
278
|
|
303
279
|
if text.startswith("@"): # Keywords and commands
|
304
280
|
self.setCurrentBlockState(self.BLOCK_META)
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
self.setFormat(xPos, xLen, kwFmt)
|
281
|
+
index = SHARED.project.index
|
282
|
+
isValid, bits, pos = index.scanThis(text)
|
283
|
+
isGood = index.checkThese(bits, self._tHandle)
|
284
|
+
if isValid:
|
285
|
+
for n, bit in enumerate(bits):
|
286
|
+
xPos = pos[n]
|
287
|
+
xLen = len(bit)
|
288
|
+
if n == 0 and isGood[n]:
|
289
|
+
self.setFormat(xPos, xLen, self._hStyles["keyword"])
|
290
|
+
elif isGood[n] and not self._isInactive:
|
291
|
+
one, two = index.parseValue(bit)
|
292
|
+
self.setFormat(xPos, len(one), self._hStyles["value"])
|
293
|
+
if two:
|
294
|
+
yPos = xPos + len(bit) - len(two)
|
295
|
+
self.setFormat(yPos, len(two), self._hStyles["optional"])
|
296
|
+
elif not self._isInactive:
|
297
|
+
self.setFormat(xPos, xLen, self._hStyles["codeinval"])
|
323
298
|
|
324
299
|
# We never want to run the spell checker on keyword/values,
|
325
300
|
# so we force a return here
|
@@ -401,8 +376,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
401
376
|
for xPos, xLen in data.spellCheck(text):
|
402
377
|
for x in range(xPos, xPos+xLen):
|
403
378
|
spFmt = self.format(x)
|
404
|
-
spFmt.
|
405
|
-
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
379
|
+
spFmt.merge(self._spellErr)
|
406
380
|
self.setFormat(x, 1, spFmt)
|
407
381
|
|
408
382
|
return
|
@@ -430,10 +404,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
430
404
|
if "strike" in styles:
|
431
405
|
charFormat.setFontStrikeOut(True)
|
432
406
|
if "errline" in styles:
|
433
|
-
charFormat.setUnderlineColor(
|
407
|
+
charFormat.setUnderlineColor(SHARED.theme.colError)
|
434
408
|
charFormat.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
435
|
-
if "underline" in styles:
|
436
|
-
charFormat.setFontUnderline(True)
|
437
409
|
if "background" in styles and color is not None:
|
438
410
|
charFormat.setBackground(QBrush(color, Qt.SolidPattern))
|
439
411
|
|
novelwriter/gui/docviewer.py
CHANGED
@@ -9,7 +9,7 @@ Created: 2020-06-09 [0.8] GuiDocViewFooter
|
|
9
9
|
Created: 2020-09-08 [1.0b1] GuiDocViewHistory
|
10
10
|
|
11
11
|
This file is a part of novelWriter
|
12
|
-
Copyright 2018–
|
12
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
13
13
|
|
14
14
|
This program is free software: you can redistribute it and/or modify
|
15
15
|
it under the terms of the GNU General Public License as published by
|
@@ -33,7 +33,7 @@ from typing import TYPE_CHECKING
|
|
33
33
|
|
34
34
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QPoint, QSize, Qt, QUrl
|
35
35
|
from PyQt5.QtGui import (
|
36
|
-
|
36
|
+
QCursor, QFont, QMouseEvent, QPalette, QResizeEvent, QTextCursor,
|
37
37
|
QTextOption
|
38
38
|
)
|
39
39
|
from PyQt5.QtWidgets import (
|
@@ -46,7 +46,7 @@ from novelwriter.enum import nwItemType, nwDocAction, nwDocMode
|
|
46
46
|
from novelwriter.error import logException
|
47
47
|
from novelwriter.constants import nwUnicode
|
48
48
|
from novelwriter.core.tohtml import ToHtml
|
49
|
-
from novelwriter.extensions.
|
49
|
+
from novelwriter.extensions.eventfilters import WheelEventFilter
|
50
50
|
|
51
51
|
if TYPE_CHECKING: # pragma: no cover
|
52
52
|
from novelwriter.guimain import GuiMain
|
@@ -142,21 +142,21 @@ class GuiDocViewer(QTextBrowser):
|
|
142
142
|
self._makeStyleSheet()
|
143
143
|
|
144
144
|
# Set Font
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
self.setFont(
|
145
|
+
font = QFont()
|
146
|
+
font.setFamily(CONFIG.textFont)
|
147
|
+
font.setPointSize(CONFIG.textSize)
|
148
|
+
self.setFont(font)
|
149
149
|
|
150
150
|
# Set the widget colours to match syntax theme
|
151
151
|
mainPalette = self.palette()
|
152
|
-
mainPalette.setColor(QPalette.ColorRole.Window,
|
153
|
-
mainPalette.setColor(QPalette.ColorRole.Base,
|
154
|
-
mainPalette.setColor(QPalette.ColorRole.Text,
|
152
|
+
mainPalette.setColor(QPalette.ColorRole.Window, SHARED.theme.colBack)
|
153
|
+
mainPalette.setColor(QPalette.ColorRole.Base, SHARED.theme.colBack)
|
154
|
+
mainPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
155
155
|
self.setPalette(mainPalette)
|
156
156
|
|
157
157
|
docPalette = self.viewport().palette()
|
158
|
-
docPalette.setColor(QPalette.ColorRole.Base,
|
159
|
-
docPalette.setColor(QPalette.ColorRole.Text,
|
158
|
+
docPalette.setColor(QPalette.ColorRole.Base, SHARED.theme.colBack)
|
159
|
+
docPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
160
160
|
self.viewport().setPalette(docPalette)
|
161
161
|
|
162
162
|
self.docHeader.matchColours()
|
@@ -164,10 +164,10 @@ class GuiDocViewer(QTextBrowser):
|
|
164
164
|
|
165
165
|
# Set default text margins
|
166
166
|
self.document().setDocumentMargin(0)
|
167
|
-
|
167
|
+
options = QTextOption()
|
168
168
|
if CONFIG.doJustify:
|
169
|
-
|
170
|
-
self.document().setDefaultTextOption(
|
169
|
+
options.setAlignment(Qt.AlignmentFlag.AlignJustify)
|
170
|
+
self.document().setDefaultTextOption(options)
|
171
171
|
|
172
172
|
# Scroll bars
|
173
173
|
if CONFIG.hideVScroll:
|
@@ -229,7 +229,7 @@ class GuiDocViewer(QTextBrowser):
|
|
229
229
|
self.setDocumentTitle(tHandle)
|
230
230
|
|
231
231
|
# Replace tabs before setting the HTML, and then put them back in
|
232
|
-
self.setHtml(aDoc.
|
232
|
+
self.setHtml(aDoc.result.replace("\t", "!!tab!!"))
|
233
233
|
while self.find("!!tab!!"):
|
234
234
|
self.textCursor().insertText("\t")
|
235
235
|
|
@@ -367,9 +367,9 @@ class GuiDocViewer(QTextBrowser):
|
|
367
367
|
link = url.url()
|
368
368
|
logger.debug("Clicked link: '%s'", link)
|
369
369
|
if len(link) > 0:
|
370
|
-
|
371
|
-
if len(
|
372
|
-
self.loadDocumentTagRequest.emit(
|
370
|
+
bits = link.split("=")
|
371
|
+
if len(bits) == 2:
|
372
|
+
self.loadDocumentTagRequest.emit(bits[1], nwDocMode.VIEW)
|
373
373
|
return
|
374
374
|
|
375
375
|
@pyqtSlot("QPoint")
|
@@ -378,33 +378,34 @@ class GuiDocViewer(QTextBrowser):
|
|
378
378
|
userCursor = self.textCursor()
|
379
379
|
userSelection = userCursor.hasSelection()
|
380
380
|
|
381
|
-
|
381
|
+
ctxMenu = QMenu(self)
|
382
382
|
|
383
383
|
if userSelection:
|
384
|
-
mnuCopy = QAction(self.tr("Copy"),
|
384
|
+
mnuCopy = QAction(self.tr("Copy"), ctxMenu)
|
385
385
|
mnuCopy.triggered.connect(lambda: self.docAction(nwDocAction.COPY))
|
386
|
-
|
386
|
+
ctxMenu.addAction(mnuCopy)
|
387
387
|
|
388
|
-
|
388
|
+
ctxMenu.addSeparator()
|
389
389
|
|
390
|
-
mnuSelAll = QAction(self.tr("Select All"),
|
390
|
+
mnuSelAll = QAction(self.tr("Select All"), ctxMenu)
|
391
391
|
mnuSelAll.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL))
|
392
|
-
|
392
|
+
ctxMenu.addAction(mnuSelAll)
|
393
393
|
|
394
|
-
mnuSelWord = QAction(self.tr("Select Word"),
|
394
|
+
mnuSelWord = QAction(self.tr("Select Word"), ctxMenu)
|
395
395
|
mnuSelWord.triggered.connect(
|
396
396
|
lambda: self._makePosSelection(QTextCursor.SelectionType.WordUnderCursor, point)
|
397
397
|
)
|
398
|
-
|
398
|
+
ctxMenu.addAction(mnuSelWord)
|
399
399
|
|
400
|
-
mnuSelPara = QAction(self.tr("Select Paragraph"),
|
400
|
+
mnuSelPara = QAction(self.tr("Select Paragraph"), ctxMenu)
|
401
401
|
mnuSelPara.triggered.connect(
|
402
402
|
lambda: self._makePosSelection(QTextCursor.SelectionType.BlockUnderCursor, point)
|
403
403
|
)
|
404
|
-
|
404
|
+
ctxMenu.addAction(mnuSelPara)
|
405
405
|
|
406
406
|
# Open the context menu
|
407
|
-
|
407
|
+
ctxMenu.exec_(self.viewport().mapToGlobal(point))
|
408
|
+
ctxMenu.deleteLater()
|
408
409
|
|
409
410
|
return
|
410
411
|
|
@@ -460,9 +461,16 @@ class GuiDocViewer(QTextBrowser):
|
|
460
461
|
|
461
462
|
def _makeStyleSheet(self) -> None:
|
462
463
|
"""Generate an appropriate style sheet for the document viewer,
|
463
|
-
based on the current syntax highlighter theme
|
464
|
+
based on the current syntax highlighter theme.
|
464
465
|
"""
|
465
|
-
|
466
|
+
colText = SHARED.theme.colText
|
467
|
+
colHead = SHARED.theme.colHead
|
468
|
+
colVals = SHARED.theme.colVal
|
469
|
+
colEmph = SHARED.theme.colEmph
|
470
|
+
colKeys = SHARED.theme.colKey
|
471
|
+
colHide = SHARED.theme.colHidden
|
472
|
+
colMods = SHARED.theme.colMod
|
473
|
+
colOpts = SHARED.theme.colOpt
|
466
474
|
styleSheet = (
|
467
475
|
"body {{"
|
468
476
|
" color: rgb({tColR}, {tColG}, {tColB});"
|
@@ -479,6 +487,9 @@ class GuiDocViewer(QTextBrowser):
|
|
479
487
|
".tags {{"
|
480
488
|
" color: rgb({kColR}, {kColG}, {kColB});"
|
481
489
|
"}}\n"
|
490
|
+
".optional {{"
|
491
|
+
" color: rgb({oColR}, {oColG}, {oColB});"
|
492
|
+
"}}\n"
|
482
493
|
".comment {{"
|
483
494
|
" color: rgb({cColR}, {cColG}, {cColB});"
|
484
495
|
"}}\n"
|
@@ -489,27 +500,14 @@ class GuiDocViewer(QTextBrowser):
|
|
489
500
|
" text-align: center;"
|
490
501
|
"}}\n"
|
491
502
|
).format(
|
492
|
-
tColR=
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
aColB=pTheme.colVal[2],
|
501
|
-
eColR=pTheme.colEmph[0],
|
502
|
-
eColG=pTheme.colEmph[1],
|
503
|
-
eColB=pTheme.colEmph[2],
|
504
|
-
kColR=pTheme.colKey[0],
|
505
|
-
kColG=pTheme.colKey[1],
|
506
|
-
kColB=pTheme.colKey[2],
|
507
|
-
cColR=pTheme.colHidden[0],
|
508
|
-
cColG=pTheme.colHidden[1],
|
509
|
-
cColB=pTheme.colHidden[2],
|
510
|
-
mColR=pTheme.colMod[0],
|
511
|
-
mColG=pTheme.colMod[1],
|
512
|
-
mColB=pTheme.colMod[2],
|
503
|
+
tColR=colText.red(), tColG=colText.green(), tColB=colText.blue(),
|
504
|
+
hColR=colHead.red(), hColG=colHead.green(), hColB=colHead.blue(),
|
505
|
+
aColR=colVals.red(), aColG=colVals.green(), aColB=colVals.blue(),
|
506
|
+
eColR=colEmph.red(), eColG=colEmph.green(), eColB=colEmph.blue(),
|
507
|
+
kColR=colKeys.red(), kColG=colKeys.green(), kColB=colKeys.blue(),
|
508
|
+
cColR=colHide.red(), cColG=colHide.green(), cColB=colHide.blue(),
|
509
|
+
mColR=colMods.red(), mColG=colMods.green(), mColB=colMods.blue(),
|
510
|
+
oColR=colOpts.red(), oColG=colOpts.green(), oColB=colOpts.blue(),
|
513
511
|
)
|
514
512
|
self.document().setDefaultStyleSheet(styleSheet)
|
515
513
|
|
@@ -743,10 +741,11 @@ class GuiDocViewHeader(QWidget):
|
|
743
741
|
self.refreshButton.setIcon(SHARED.theme.getIcon("refresh"))
|
744
742
|
self.closeButton.setIcon(SHARED.theme.getIcon("close"))
|
745
743
|
|
744
|
+
colText = SHARED.theme.colText
|
746
745
|
buttonStyle = (
|
747
746
|
"QToolButton {{border: none; background: transparent;}} "
|
748
|
-
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
749
|
-
).format(
|
747
|
+
"QToolButton:hover {{border: none; background: rgba({0}, {1}, {2}, 0.2);}}"
|
748
|
+
).format(colText.red(), colText.green(), colText.blue())
|
750
749
|
|
751
750
|
self.backButton.setStyleSheet(buttonStyle)
|
752
751
|
self.forwardButton.setStyleSheet(buttonStyle)
|
@@ -762,9 +761,9 @@ class GuiDocViewHeader(QWidget):
|
|
762
761
|
theme rather than the main GUI.
|
763
762
|
"""
|
764
763
|
palette = QPalette()
|
765
|
-
palette.setColor(QPalette.ColorRole.Window,
|
766
|
-
palette.setColor(QPalette.ColorRole.WindowText,
|
767
|
-
palette.setColor(QPalette.ColorRole.Text,
|
764
|
+
palette.setColor(QPalette.ColorRole.Window, SHARED.theme.colBack)
|
765
|
+
palette.setColor(QPalette.ColorRole.WindowText, SHARED.theme.colText)
|
766
|
+
palette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
768
767
|
self.setPalette(palette)
|
769
768
|
self.docTitle.setPalette(palette)
|
770
769
|
return
|
@@ -861,8 +860,7 @@ class GuiDocViewFooter(QWidget):
|
|
861
860
|
self._docHandle = None
|
862
861
|
|
863
862
|
fPx = int(0.9*SHARED.theme.fontPixelSize)
|
864
|
-
|
865
|
-
hSp = CONFIG.pxInt(8)
|
863
|
+
hSp = CONFIG.pxInt(4)
|
866
864
|
|
867
865
|
# Main Widget Settings
|
868
866
|
self.setContentsMargins(0, 0, 0, 0)
|
@@ -872,64 +870,41 @@ class GuiDocViewFooter(QWidget):
|
|
872
870
|
self.showHide = QToolButton(self)
|
873
871
|
self.showHide.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
874
872
|
self.showHide.setIconSize(QSize(fPx, fPx))
|
875
|
-
self.showHide.setFixedSize(QSize(fPx, fPx))
|
876
873
|
self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit())
|
877
874
|
self.showHide.setToolTip(self.tr("Show/Hide Viewer Panel"))
|
878
875
|
|
879
876
|
# Show Comments
|
880
877
|
self.showComments = QToolButton(self)
|
878
|
+
self.showComments.setText(self.tr("Comments"))
|
881
879
|
self.showComments.setCheckable(True)
|
882
880
|
self.showComments.setChecked(CONFIG.viewComments)
|
883
|
-
self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.
|
881
|
+
self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
884
882
|
self.showComments.setIconSize(QSize(fPx, fPx))
|
885
|
-
self.showComments.setFixedSize(QSize(fPx, fPx))
|
886
883
|
self.showComments.toggled.connect(self._doToggleComments)
|
887
884
|
self.showComments.setToolTip(self.tr("Show Comments"))
|
888
885
|
|
889
886
|
# Show Synopsis
|
890
887
|
self.showSynopsis = QToolButton(self)
|
888
|
+
self.showSynopsis.setText(self.tr("Synopsis"))
|
891
889
|
self.showSynopsis.setCheckable(True)
|
892
890
|
self.showSynopsis.setChecked(CONFIG.viewSynopsis)
|
893
|
-
self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.
|
891
|
+
self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
894
892
|
self.showSynopsis.setIconSize(QSize(fPx, fPx))
|
895
|
-
self.showSynopsis.setFixedSize(QSize(fPx, fPx))
|
896
893
|
self.showSynopsis.toggled.connect(self._doToggleSynopsis)
|
897
894
|
self.showSynopsis.setToolTip(self.tr("Show Synopsis Comments"))
|
898
895
|
|
899
|
-
# Labels
|
900
|
-
self.lblComments = QLabel(self.tr("Comments"))
|
901
|
-
self.lblComments.setBuddy(self.showComments)
|
902
|
-
self.lblComments.setIndent(0)
|
903
|
-
self.lblComments.setMargin(0)
|
904
|
-
self.lblComments.setContentsMargins(0, 0, 0, 0)
|
905
|
-
self.lblComments.setAutoFillBackground(True)
|
906
|
-
self.lblComments.setFixedHeight(fPx)
|
907
|
-
self.lblComments.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
|
908
|
-
|
909
|
-
self.lblSynopsis = QLabel(self.tr("Synopsis"))
|
910
|
-
self.lblSynopsis.setBuddy(self.showSynopsis)
|
911
|
-
self.lblSynopsis.setIndent(0)
|
912
|
-
self.lblSynopsis.setMargin(0)
|
913
|
-
self.lblSynopsis.setContentsMargins(0, 0, 0, 0)
|
914
|
-
self.lblSynopsis.setAutoFillBackground(True)
|
915
|
-
self.lblSynopsis.setFixedHeight(fPx)
|
916
|
-
self.lblSynopsis.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
|
917
|
-
|
918
896
|
lblFont = self.font()
|
919
897
|
lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
|
920
|
-
self.
|
921
|
-
self.
|
898
|
+
self.showComments.setFont(lblFont)
|
899
|
+
self.showSynopsis.setFont(lblFont)
|
922
900
|
|
923
901
|
# Assemble Layout
|
924
902
|
self.outerBox = QHBoxLayout()
|
925
|
-
self.outerBox.setSpacing(bSp)
|
926
903
|
self.outerBox.addWidget(self.showHide, 0)
|
927
904
|
self.outerBox.addStretch(1)
|
928
905
|
self.outerBox.addWidget(self.showComments, 0)
|
929
|
-
self.outerBox.addWidget(self.lblComments, 0)
|
930
|
-
self.outerBox.addSpacing(hSp)
|
931
906
|
self.outerBox.addWidget(self.showSynopsis, 0)
|
932
|
-
self.outerBox.
|
907
|
+
self.outerBox.setSpacing(hSp)
|
933
908
|
self.setLayout(self.outerBox)
|
934
909
|
|
935
910
|
# Fix Margins and Size
|
@@ -960,11 +935,11 @@ class GuiDocViewFooter(QWidget):
|
|
960
935
|
self.showComments.setIcon(bulletIcon)
|
961
936
|
self.showSynopsis.setIcon(bulletIcon)
|
962
937
|
|
963
|
-
|
938
|
+
colText = SHARED.theme.colText
|
964
939
|
buttonStyle = (
|
965
940
|
"QToolButton {{border: none; background: transparent;}} "
|
966
|
-
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
|
967
|
-
).format(
|
941
|
+
"QToolButton:hover {{border: none; background: rgba({0}, {1}, {2}, 0.2);}}"
|
942
|
+
).format(colText.red(), colText.green(), colText.blue())
|
968
943
|
|
969
944
|
self.showHide.setStyleSheet(buttonStyle)
|
970
945
|
self.showComments.setStyleSheet(buttonStyle)
|
@@ -979,12 +954,10 @@ class GuiDocViewFooter(QWidget):
|
|
979
954
|
theme rather than the main GUI.
|
980
955
|
"""
|
981
956
|
palette = QPalette()
|
982
|
-
palette.setColor(QPalette.ColorRole.Window,
|
983
|
-
palette.setColor(QPalette.ColorRole.WindowText,
|
984
|
-
palette.setColor(QPalette.ColorRole.Text,
|
957
|
+
palette.setColor(QPalette.ColorRole.Window, SHARED.theme.colBack)
|
958
|
+
palette.setColor(QPalette.ColorRole.WindowText, SHARED.theme.colText)
|
959
|
+
palette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
985
960
|
self.setPalette(palette)
|
986
|
-
self.lblComments.setPalette(palette)
|
987
|
-
self.lblSynopsis.setPalette(palette)
|
988
961
|
return
|
989
962
|
|
990
963
|
##
|