novelWriter 2.3.1__py3-none-any.whl → 2.4b1__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.3.1.dist-info → novelWriter-2.4b1.dist-info}/METADATA +1 -1
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/RECORD +81 -70
- novelwriter/__init__.py +5 -5
- novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_light/icons.conf +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
- 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 +25 -23
- novelwriter/common.py +1 -1
- novelwriter/config.py +35 -12
- novelwriter/constants.py +5 -6
- novelwriter/core/buildsettings.py +60 -40
- novelwriter/core/coretools.py +98 -13
- novelwriter/core/docbuild.py +74 -7
- novelwriter/core/document.py +24 -3
- novelwriter/core/index.py +31 -112
- novelwriter/core/project.py +10 -15
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/status.py +4 -4
- novelwriter/core/storage.py +8 -2
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +416 -232
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +65 -7
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/docsplit.py +7 -8
- novelwriter/dialogs/preferences.py +3 -6
- novelwriter/enum.py +17 -14
- novelwriter/extensions/modified.py +20 -2
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/gui/doceditor.py +257 -279
- novelwriter/gui/dochighlight.py +29 -25
- novelwriter/gui/docviewer.py +139 -148
- novelwriter/gui/docviewerpanel.py +4 -24
- novelwriter/gui/editordocument.py +12 -1
- novelwriter/gui/itemdetails.py +6 -6
- novelwriter/gui/mainmenu.py +37 -16
- novelwriter/gui/noveltree.py +11 -19
- novelwriter/gui/outline.py +43 -20
- novelwriter/gui/projtree.py +35 -43
- novelwriter/gui/search.py +316 -0
- novelwriter/gui/sidebar.py +25 -30
- novelwriter/gui/theme.py +59 -6
- novelwriter/guimain.py +176 -173
- novelwriter/shared.py +26 -1
- novelwriter/text/__init__.py +3 -0
- novelwriter/text/counting.py +137 -0
- novelwriter/tools/manuscript.py +344 -55
- novelwriter/tools/manussettings.py +213 -71
- novelwriter/tools/welcome.py +1 -1
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/top_level.txt +0 -0
novelwriter/core/tomd.py
CHANGED
@@ -27,7 +27,7 @@ import logging
|
|
27
27
|
|
28
28
|
from pathlib import Path
|
29
29
|
|
30
|
-
from novelwriter.constants import nwHeadFmt, nwLabels
|
30
|
+
from novelwriter.constants import nwHeadFmt, nwLabels, nwUnicode
|
31
31
|
from novelwriter.core.project import NWProject
|
32
32
|
from novelwriter.core.tokenizer import Tokenizer
|
33
33
|
|
@@ -49,6 +49,7 @@ class ToMarkdown(Tokenizer):
|
|
49
49
|
super().__init__(project)
|
50
50
|
self._genMode = self.M_STD
|
51
51
|
self._fullMD: list[str] = []
|
52
|
+
self._preserveBreaks = True
|
52
53
|
return
|
53
54
|
|
54
55
|
##
|
@@ -74,6 +75,11 @@ class ToMarkdown(Tokenizer):
|
|
74
75
|
self._genMode = self.M_EXT
|
75
76
|
return
|
76
77
|
|
78
|
+
def setPreserveBreaks(self, state: bool) -> None:
|
79
|
+
"""Preserve line breaks in paragraphs."""
|
80
|
+
self._preserveBreaks = state
|
81
|
+
return
|
82
|
+
|
77
83
|
##
|
78
84
|
# Class Methods
|
79
85
|
##
|
@@ -95,11 +101,14 @@ class ToMarkdown(Tokenizer):
|
|
95
101
|
self.FMT_D_E: "",
|
96
102
|
self.FMT_U_B: "",
|
97
103
|
self.FMT_U_E: "",
|
104
|
+
self.FMT_M_B: "",
|
105
|
+
self.FMT_M_E: "",
|
98
106
|
self.FMT_SUP_B: "",
|
99
107
|
self.FMT_SUP_E: "",
|
100
108
|
self.FMT_SUB_B: "",
|
101
109
|
self.FMT_SUB_E: "",
|
102
110
|
}
|
111
|
+
cSkip = ""
|
103
112
|
else:
|
104
113
|
# Extended Markdown
|
105
114
|
mdTags = {
|
@@ -111,22 +120,26 @@ class ToMarkdown(Tokenizer):
|
|
111
120
|
self.FMT_D_E: "~~",
|
112
121
|
self.FMT_U_B: "",
|
113
122
|
self.FMT_U_E: "",
|
123
|
+
self.FMT_M_B: "==",
|
124
|
+
self.FMT_M_E: "==",
|
114
125
|
self.FMT_SUP_B: "^",
|
115
126
|
self.FMT_SUP_E: "^",
|
116
127
|
self.FMT_SUB_B: "~",
|
117
128
|
self.FMT_SUB_E: "~",
|
118
129
|
}
|
130
|
+
cSkip = nwUnicode.U_MMSP
|
119
131
|
|
120
132
|
self._result = ""
|
121
133
|
|
122
134
|
para = []
|
123
135
|
lines = []
|
136
|
+
lineSep = " \n" if self._preserveBreaks else " "
|
124
137
|
|
125
138
|
for tType, _, tText, tFormat, tStyle in self._tokens:
|
126
139
|
|
127
140
|
if tType == self.T_EMPTY:
|
128
|
-
if
|
129
|
-
tTemp = (
|
141
|
+
if para:
|
142
|
+
tTemp = (lineSep.join(para)).rstrip(" ")
|
130
143
|
lines.append(f"{tTemp}\n\n")
|
131
144
|
para = []
|
132
145
|
|
@@ -134,10 +147,6 @@ class ToMarkdown(Tokenizer):
|
|
134
147
|
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
135
148
|
lines.append(f"# {tHead}\n\n")
|
136
149
|
|
137
|
-
elif tType == self.T_UNNUM:
|
138
|
-
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
139
|
-
lines.append(f"## {tHead}\n\n")
|
140
|
-
|
141
150
|
elif tType == self.T_HEAD1:
|
142
151
|
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
143
152
|
lines.append(f"# {tHead}\n\n")
|
@@ -158,7 +167,7 @@ class ToMarkdown(Tokenizer):
|
|
158
167
|
lines.append(f"{tText}\n\n")
|
159
168
|
|
160
169
|
elif tType == self.T_SKIP:
|
161
|
-
lines.append("\n\n
|
170
|
+
lines.append(f"{cSkip}\n\n")
|
162
171
|
|
163
172
|
elif tType == self.T_TEXT:
|
164
173
|
tTemp = tText
|
novelwriter/core/toodt.py
CHANGED
@@ -84,14 +84,16 @@ X_BLD = 0x01 # Bold format
|
|
84
84
|
X_ITA = 0x02 # Italic format
|
85
85
|
X_DEL = 0x04 # Strikethrough format
|
86
86
|
X_UND = 0x08 # Underline format
|
87
|
-
|
88
|
-
|
87
|
+
X_MRK = 0x10 # Marked format
|
88
|
+
X_SUP = 0x20 # Superscript
|
89
|
+
X_SUB = 0x40 # Subscript
|
89
90
|
|
90
91
|
# Formatting Masks
|
91
92
|
M_BLD = ~X_BLD
|
92
93
|
M_ITA = ~X_ITA
|
93
94
|
M_DEL = ~X_DEL
|
94
95
|
M_UND = ~X_UND
|
96
|
+
M_MRK = ~X_MRK
|
95
97
|
M_SUP = ~X_SUP
|
96
98
|
M_SUB = ~X_SUB
|
97
99
|
|
@@ -136,6 +138,7 @@ class ToOdt(Tokenizer):
|
|
136
138
|
self._textSize = 12
|
137
139
|
self._textFixed = False
|
138
140
|
self._colourHead = False
|
141
|
+
self._firstIndent = False
|
139
142
|
self._headerFormat = ""
|
140
143
|
self._pageOffset = 0
|
141
144
|
|
@@ -151,6 +154,7 @@ class ToOdt(Tokenizer):
|
|
151
154
|
self._fSizeText = "12pt"
|
152
155
|
self._fLineHeight = "115%"
|
153
156
|
self._fBlockIndent = "1.693cm"
|
157
|
+
self._fTextIndent = "0.499cm"
|
154
158
|
self._textAlign = "left"
|
155
159
|
self._dLanguage = "en"
|
156
160
|
self._dCountry = "GB"
|
@@ -189,6 +193,7 @@ class ToOdt(Tokenizer):
|
|
189
193
|
self._opaHead34 = None
|
190
194
|
self._colMetaTx = None
|
191
195
|
self._opaMetaTx = None
|
196
|
+
self._markText = "#ffffa6"
|
192
197
|
|
193
198
|
return
|
194
199
|
|
@@ -229,6 +234,11 @@ class ToOdt(Tokenizer):
|
|
229
234
|
self._pageOffset = offset
|
230
235
|
return
|
231
236
|
|
237
|
+
def setFirstLineIndent(self, state: bool) -> None:
|
238
|
+
"""Enable or disable first line indent."""
|
239
|
+
self._firstIndent = state
|
240
|
+
return
|
241
|
+
|
232
242
|
##
|
233
243
|
# Class Methods
|
234
244
|
##
|
@@ -394,6 +404,7 @@ class ToOdt(Tokenizer):
|
|
394
404
|
pFmt = []
|
395
405
|
pText = []
|
396
406
|
pStyle = None
|
407
|
+
pIndent = True
|
397
408
|
for tType, _, tText, tFormat, tStyle in self._tokens:
|
398
409
|
|
399
410
|
# Styles
|
@@ -424,6 +435,9 @@ class ToOdt(Tokenizer):
|
|
424
435
|
if tStyle & self.A_IND_R:
|
425
436
|
oStyle.setMarginRight(self._fBlockIndent)
|
426
437
|
|
438
|
+
if tType not in (self.T_EMPTY, self.T_TEXT):
|
439
|
+
pIndent = False
|
440
|
+
|
427
441
|
# Process Text Types
|
428
442
|
if tType == self.T_EMPTY:
|
429
443
|
if len(pText) > 1 and pStyle is not None:
|
@@ -437,7 +451,14 @@ class ToOdt(Tokenizer):
|
|
437
451
|
tLen = len(tTxt)
|
438
452
|
tTxt += f"{nText}\n"
|
439
453
|
tFmt.extend((p+tLen, fmt) for p, fmt in nFmt)
|
440
|
-
|
454
|
+
|
455
|
+
# Don't indent a paragraph if it has alignment set
|
456
|
+
tIndent = self._firstIndent and pIndent and pStyle.isUnaligned()
|
457
|
+
self._addTextPar(
|
458
|
+
"First_20_line_20_indent" if tIndent else "Text_20_body",
|
459
|
+
pStyle, tTxt.rstrip(), tFmt=tFmt
|
460
|
+
)
|
461
|
+
pIndent = True
|
441
462
|
|
442
463
|
pFmt = []
|
443
464
|
pText = []
|
@@ -447,10 +468,6 @@ class ToOdt(Tokenizer):
|
|
447
468
|
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
448
469
|
self._addTextPar("Title", oStyle, tHead, isHead=False) # Title must be text:p
|
449
470
|
|
450
|
-
elif tType == self.T_UNNUM:
|
451
|
-
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
452
|
-
self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2")
|
453
|
-
|
454
471
|
elif tType == self.T_HEAD1:
|
455
472
|
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
456
473
|
self._addTextPar("Heading_20_1", oStyle, tHead, isHead=True, oLevel="1")
|
@@ -643,6 +660,10 @@ class ToOdt(Tokenizer):
|
|
643
660
|
xFmt |= X_UND
|
644
661
|
elif fFmt == self.FMT_U_E:
|
645
662
|
xFmt &= M_UND
|
663
|
+
elif fFmt == self.FMT_M_B:
|
664
|
+
xFmt |= X_MRK
|
665
|
+
elif fFmt == self.FMT_M_E:
|
666
|
+
xFmt &= M_MRK
|
646
667
|
elif fFmt == self.FMT_SUP_B:
|
647
668
|
xFmt |= X_SUP
|
648
669
|
elif fFmt == self.FMT_SUP_E:
|
@@ -710,6 +731,8 @@ class ToOdt(Tokenizer):
|
|
710
731
|
newStyle.setUnderlineStyle("solid")
|
711
732
|
newStyle.setUnderlineWidth("auto")
|
712
733
|
newStyle.setUnderlineColour("font-color")
|
734
|
+
if hFmt & X_MRK:
|
735
|
+
newStyle.setBackgroundColor(self._markText)
|
713
736
|
if hFmt & X_SUP:
|
714
737
|
newStyle.setTextPosition("super")
|
715
738
|
if hFmt & X_SUB:
|
@@ -850,6 +873,18 @@ class ToOdt(Tokenizer):
|
|
850
873
|
|
851
874
|
self._mainPara["Text_20_body"] = oStyle
|
852
875
|
|
876
|
+
# Add First Line Indent Style
|
877
|
+
# ===========================
|
878
|
+
|
879
|
+
oStyle = ODTParagraphStyle()
|
880
|
+
oStyle.setDisplayName("First line indent")
|
881
|
+
oStyle.setParentStyleName("Text_20_body")
|
882
|
+
oStyle.setClass("text")
|
883
|
+
oStyle.setTextIndent(self._fTextIndent)
|
884
|
+
oStyle.packXML(self._xStyl, "First_20_line_20_indent")
|
885
|
+
|
886
|
+
self._mainPara["First_20_line_20_indent"] = oStyle
|
887
|
+
|
853
888
|
# Add Text Meta Style
|
854
889
|
# ===================
|
855
890
|
|
@@ -1077,6 +1112,7 @@ class ODTParagraphStyle:
|
|
1077
1112
|
"margin-bottom": ["fo", None],
|
1078
1113
|
"margin-left": ["fo", None],
|
1079
1114
|
"margin-right": ["fo", None],
|
1115
|
+
"text-indent": ["fo", None],
|
1080
1116
|
"line-height": ["fo", None],
|
1081
1117
|
"text-align": ["fo", None],
|
1082
1118
|
"break-before": ["fo", None],
|
@@ -1095,6 +1131,16 @@ class ODTParagraphStyle:
|
|
1095
1131
|
|
1096
1132
|
return
|
1097
1133
|
|
1134
|
+
##
|
1135
|
+
# Checkers
|
1136
|
+
##
|
1137
|
+
|
1138
|
+
def isUnaligned(self) -> bool:
|
1139
|
+
"""Check if paragraph has any sort of alignment or margins."""
|
1140
|
+
return all(
|
1141
|
+
self._pAttr[n][1] is None for n in ["text-align", "margin-left", "margin-right"]
|
1142
|
+
)
|
1143
|
+
|
1098
1144
|
##
|
1099
1145
|
# Attribute Setters
|
1100
1146
|
##
|
@@ -1145,6 +1191,10 @@ class ODTParagraphStyle:
|
|
1145
1191
|
self._pAttr["margin-right"][1] = value
|
1146
1192
|
return
|
1147
1193
|
|
1194
|
+
def setTextIndent(self, value: str | None) -> None:
|
1195
|
+
self._pAttr["text-indent"][1] = value
|
1196
|
+
return
|
1197
|
+
|
1148
1198
|
def setLineHeight(self, value: str | None) -> None:
|
1149
1199
|
self._pAttr["line-height"][1] = value
|
1150
1200
|
return
|
@@ -1279,6 +1329,7 @@ class ODTTextStyle:
|
|
1279
1329
|
self._tAttr = {
|
1280
1330
|
"font-weight": ["fo", None],
|
1281
1331
|
"font-style": ["fo", None],
|
1332
|
+
"background-color": ["fo", None],
|
1282
1333
|
"text-position": ["style", None],
|
1283
1334
|
"text-line-through-style": ["style", None],
|
1284
1335
|
"text-line-through-type": ["style", None],
|
@@ -1306,6 +1357,13 @@ class ODTTextStyle:
|
|
1306
1357
|
self._tAttr["font-style"][1] = None
|
1307
1358
|
return
|
1308
1359
|
|
1360
|
+
def setBackgroundColor(self, value: str | None) -> None:
|
1361
|
+
if value and len(value) == 7 and value[0] == "#":
|
1362
|
+
self._tAttr["background-color"][1] = value
|
1363
|
+
else:
|
1364
|
+
self._tAttr["background-color"][1] = None
|
1365
|
+
return
|
1366
|
+
|
1309
1367
|
def setTextPosition(self, value: str | None) -> None:
|
1310
1368
|
if value in self.VALID_POS:
|
1311
1369
|
self._tAttr["text-position"][1] = f"{value} 58%"
|
novelwriter/core/tree.py
CHANGED
@@ -28,7 +28,7 @@ import logging
|
|
28
28
|
|
29
29
|
from typing import TYPE_CHECKING, Literal, overload
|
30
30
|
from pathlib import Path
|
31
|
-
from collections.abc import Iterator
|
31
|
+
from collections.abc import Iterable, Iterator
|
32
32
|
|
33
33
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
34
34
|
from novelwriter.error import logException
|
@@ -351,16 +351,16 @@ class NWTree:
|
|
351
351
|
return False
|
352
352
|
return tItem.itemType == itemType
|
353
353
|
|
354
|
-
def getItemPath(self, tHandle: str) -> list[str]:
|
354
|
+
def getItemPath(self, tHandle: str, asName: bool = False) -> list[str]:
|
355
355
|
"""Iterate upwards in the tree until we find the item with
|
356
|
-
parent None, the root item, and return the list of handles
|
357
|
-
We do this with a for loop with a
|
358
|
-
infinite loops impossible.
|
356
|
+
parent None, the root item, and return the list of handles, or
|
357
|
+
alternatively item names. We do this with a for loop with a
|
358
|
+
maximum depth to make infinite loops impossible.
|
359
359
|
"""
|
360
360
|
tTree = []
|
361
361
|
tItem = self.__getitem__(tHandle)
|
362
362
|
if tItem is not None:
|
363
|
-
tTree.append(tHandle)
|
363
|
+
tTree.append(tItem.itemName if asName else tHandle)
|
364
364
|
for _ in range(MAX_DEPTH):
|
365
365
|
if tItem.itemParent is None:
|
366
366
|
return tTree
|
@@ -370,7 +370,7 @@ class NWTree:
|
|
370
370
|
if tItem is None:
|
371
371
|
return tTree
|
372
372
|
else:
|
373
|
-
tTree.append(tHandle)
|
373
|
+
tTree.append(tItem.itemName if asName else tHandle)
|
374
374
|
else:
|
375
375
|
raise RecursionError("Critical internal error")
|
376
376
|
|
@@ -387,7 +387,7 @@ class NWTree:
|
|
387
387
|
rootClasses.add(nwItem.itemClass)
|
388
388
|
return rootClasses
|
389
389
|
|
390
|
-
def iterRoots(self, itemClass: nwItemClass | None) ->
|
390
|
+
def iterRoots(self, itemClass: nwItemClass | None) -> Iterable[tuple[str, NWItem]]:
|
391
391
|
"""Iterate over all root items of a given class in order."""
|
392
392
|
for tHandle in self._order:
|
393
393
|
nwItem = self.__getitem__(tHandle)
|
novelwriter/dialogs/docsplit.py
CHANGED
@@ -57,7 +57,7 @@ class GuiDocSplit(QDialog):
|
|
57
57
|
|
58
58
|
self.setWindowTitle(self.tr("Split Document"))
|
59
59
|
|
60
|
-
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document
|
60
|
+
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document Headings")))
|
61
61
|
self.helpLabel = NColourLabel(
|
62
62
|
self.tr("Select the maximum level to split into files."),
|
63
63
|
SHARED.theme.helpText, parent=self, wrap=True
|
@@ -74,17 +74,17 @@ class GuiDocSplit(QDialog):
|
|
74
74
|
intoFolder = pOptions.getBool("GuiDocSplit", "intoFolder", True)
|
75
75
|
docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
|
76
76
|
|
77
|
-
#
|
77
|
+
# Heading Selection
|
78
78
|
self.listBox = QListWidget()
|
79
79
|
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
|
80
80
|
self.listBox.setMinimumWidth(CONFIG.pxInt(400))
|
81
81
|
self.listBox.setMinimumHeight(CONFIG.pxInt(180))
|
82
82
|
|
83
83
|
self.splitLevel = QComboBox(self)
|
84
|
-
self.splitLevel.addItem(self.tr("Split on
|
85
|
-
self.splitLevel.addItem(self.tr("Split up to
|
86
|
-
self.splitLevel.addItem(self.tr("Split up to
|
87
|
-
self.splitLevel.addItem(self.tr("Split up to
|
84
|
+
self.splitLevel.addItem(self.tr("Split on Heading Level 1 (Partition)"), 1)
|
85
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 2 (Chapter)"), 2)
|
86
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 3 (Scene)"), 3)
|
87
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 4 (Section)"), 4)
|
88
88
|
spIndex = self.splitLevel.findData(spLevel)
|
89
89
|
if spIndex != -1:
|
90
90
|
self.splitLevel.setCurrentIndex(spIndex)
|
@@ -214,8 +214,7 @@ class GuiDocSplit(QDialog):
|
|
214
214
|
|
215
215
|
spLevel = self.splitLevel.currentData()
|
216
216
|
if not self._text:
|
217
|
-
|
218
|
-
self._text = (inDoc.readDocument() or "").splitlines()
|
217
|
+
self._text = SHARED.project.storage.getDocumentText(sHandle).splitlines()
|
219
218
|
|
220
219
|
for lineNo, aLine in enumerate(self._text):
|
221
220
|
|
@@ -151,8 +151,7 @@ class GuiPreferences(QDialog):
|
|
151
151
|
self.guiLocale.setMinimumWidth(minWidth)
|
152
152
|
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
|
153
153
|
self.guiLocale.addItem(name, lang)
|
154
|
-
|
155
|
-
self.guiLocale.setCurrentIndex(idx)
|
154
|
+
self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB")
|
156
155
|
|
157
156
|
self.mainForm.addRow(
|
158
157
|
self.tr("Display language"), self.guiLocale,
|
@@ -164,8 +163,7 @@ class GuiPreferences(QDialog):
|
|
164
163
|
self.guiTheme.setMinimumWidth(minWidth)
|
165
164
|
for theme, name in SHARED.theme.listThemes():
|
166
165
|
self.guiTheme.addItem(name, theme)
|
167
|
-
|
168
|
-
self.guiTheme.setCurrentIndex(idx)
|
166
|
+
self.guiTheme.setCurrentData(CONFIG.guiTheme, "default")
|
169
167
|
|
170
168
|
self.mainForm.addRow(
|
171
169
|
self.tr("Colour theme"), self.guiTheme,
|
@@ -226,8 +224,7 @@ class GuiPreferences(QDialog):
|
|
226
224
|
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
|
227
225
|
for syntax, name in SHARED.theme.listSyntax():
|
228
226
|
self.guiSyntax.addItem(name, syntax)
|
229
|
-
|
230
|
-
self.guiSyntax.setCurrentIndex(idx)
|
227
|
+
self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light")
|
231
228
|
|
232
229
|
self.mainForm.addRow(
|
233
230
|
self.tr("Document colour theme"), self.guiSyntax,
|
novelwriter/enum.py
CHANGED
@@ -112,20 +112,22 @@ class nwDocAction(Enum):
|
|
112
112
|
BLOCK_TXT = 19
|
113
113
|
BLOCK_TTL = 20
|
114
114
|
BLOCK_UNN = 21
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
115
|
+
BLOCK_HSC = 22
|
116
|
+
REPL_SNG = 23
|
117
|
+
REPL_DBL = 24
|
118
|
+
RM_BREAKS = 25
|
119
|
+
ALIGN_L = 26
|
120
|
+
ALIGN_C = 27
|
121
|
+
ALIGN_R = 28
|
122
|
+
INDENT_L = 29
|
123
|
+
INDENT_R = 30
|
124
|
+
SC_ITALIC = 31
|
125
|
+
SC_BOLD = 32
|
126
|
+
SC_STRIKE = 33
|
127
|
+
SC_ULINE = 34
|
128
|
+
SC_MARK = 35
|
129
|
+
SC_SUP = 36
|
130
|
+
SC_SUB = 37
|
129
131
|
|
130
132
|
# END Enum nwDocAction
|
131
133
|
|
@@ -153,6 +155,7 @@ class nwView(Enum):
|
|
153
155
|
PROJECT = 1
|
154
156
|
NOVEL = 2
|
155
157
|
OUTLINE = 3
|
158
|
+
SEARCH = 4
|
156
159
|
|
157
160
|
# END Enum nwView
|
158
161
|
|
@@ -25,9 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
25
25
|
"""
|
26
26
|
from __future__ import annotations
|
27
27
|
|
28
|
-
from PyQt5.QtCore import Qt
|
28
|
+
from PyQt5.QtCore import QSize, Qt
|
29
29
|
from PyQt5.QtGui import QWheelEvent
|
30
|
-
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QWidget
|
30
|
+
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
|
31
31
|
|
32
32
|
|
33
33
|
class NComboBox(QComboBox):
|
@@ -44,6 +44,12 @@ class NComboBox(QComboBox):
|
|
44
44
|
event.ignore()
|
45
45
|
return
|
46
46
|
|
47
|
+
def setCurrentData(self, data: str, default: str) -> None:
|
48
|
+
"""Set the current index from data, with a fallback."""
|
49
|
+
idx = self.findData(data)
|
50
|
+
self.setCurrentIndex(self.findData(default) if idx < 0 else idx)
|
51
|
+
return
|
52
|
+
|
47
53
|
# END Class NComboBox
|
48
54
|
|
49
55
|
|
@@ -79,3 +85,15 @@ class NDoubleSpinBox(QDoubleSpinBox):
|
|
79
85
|
return
|
80
86
|
|
81
87
|
# END Class NDoubleSpinBox
|
88
|
+
|
89
|
+
|
90
|
+
class NIconToolButton(QToolButton):
|
91
|
+
|
92
|
+
def __init__(self, parent: QWidget, iconSize: int) -> None:
|
93
|
+
super().__init__(parent=parent)
|
94
|
+
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
95
|
+
self.setIconSize(QSize(iconSize, iconSize))
|
96
|
+
self.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
97
|
+
return
|
98
|
+
|
99
|
+
# END Class NIconToolButton
|
@@ -57,7 +57,7 @@ class VersionInfoWidget(QWidget):
|
|
57
57
|
# Labels
|
58
58
|
self._lblInfo = QLabel("{0} {1} \u2013 {2} {3} \u2013 {4}".format(
|
59
59
|
self.tr("Version"), formatVersion(__version__),
|
60
|
-
self.tr("Released on"), datetime.strptime(__date__, "%Y-%m-%d")
|
60
|
+
self.tr("Released on"), CONFIG.localDate(datetime.strptime(__date__, "%Y-%m-%d")),
|
61
61
|
"<a href='#notes'>{0}</a>".format(self.tr("Release Notes")),
|
62
62
|
), self)
|
63
63
|
self._lblInfo.linkActivated.connect(self._processLink)
|