novelWriter 2.5b1__py3-none-any.whl → 2.5.1__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.5b1.dist-info → novelWriter-2.5.1.dist-info}/METADATA +1 -1
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/RECORD +77 -75
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +3 -3
- 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_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_pl_PL.json +116 -0
- novelwriter/assets/i18n/project_pt_BR.json +74 -74
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +52 -44
- novelwriter/assets/themes/cyberpunk_night.conf +1 -0
- novelwriter/assets/themes/default_dark.conf +1 -0
- novelwriter/assets/themes/default_light.conf +1 -0
- novelwriter/assets/themes/dracula.conf +1 -0
- novelwriter/assets/themes/solarized_dark.conf +1 -0
- novelwriter/assets/themes/solarized_light.conf +1 -0
- novelwriter/common.py +12 -3
- novelwriter/config.py +67 -15
- novelwriter/constants.py +8 -10
- novelwriter/core/buildsettings.py +5 -3
- novelwriter/core/coretools.py +3 -1
- novelwriter/core/docbuild.py +1 -0
- novelwriter/core/project.py +15 -4
- novelwriter/core/status.py +4 -1
- novelwriter/core/storage.py +6 -1
- novelwriter/core/tohtml.py +69 -29
- novelwriter/core/tokenizer.py +83 -14
- novelwriter/core/toodt.py +48 -21
- novelwriter/core/toqdoc.py +37 -21
- novelwriter/dialogs/about.py +10 -15
- novelwriter/dialogs/docmerge.py +16 -16
- novelwriter/dialogs/docsplit.py +16 -16
- novelwriter/dialogs/editlabel.py +6 -8
- novelwriter/dialogs/preferences.py +106 -93
- novelwriter/dialogs/projectsettings.py +16 -20
- novelwriter/dialogs/quotes.py +9 -5
- novelwriter/dialogs/wordlist.py +6 -6
- novelwriter/enum.py +4 -5
- novelwriter/extensions/configlayout.py +38 -4
- novelwriter/extensions/modified.py +22 -3
- novelwriter/extensions/{circularprogress.py → progressbars.py} +26 -3
- novelwriter/extensions/statusled.py +39 -23
- novelwriter/gui/doceditor.py +22 -13
- novelwriter/gui/dochighlight.py +30 -39
- novelwriter/gui/docviewer.py +24 -15
- novelwriter/gui/docviewerpanel.py +7 -0
- novelwriter/gui/mainmenu.py +11 -11
- novelwriter/gui/outline.py +4 -3
- novelwriter/gui/projtree.py +85 -77
- novelwriter/gui/search.py +10 -1
- novelwriter/gui/statusbar.py +25 -29
- novelwriter/gui/theme.py +3 -0
- novelwriter/guimain.py +139 -124
- novelwriter/shared.py +19 -8
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +2 -8
- novelwriter/tools/lipsum.py +8 -12
- novelwriter/tools/manusbuild.py +9 -9
- novelwriter/tools/manuscript.py +10 -5
- novelwriter/tools/manussettings.py +7 -3
- novelwriter/tools/noveldetails.py +10 -10
- novelwriter/tools/welcome.py +19 -10
- novelwriter/tools/writingstats.py +3 -3
- novelwriter/types.py +5 -2
- novelwriter/extensions/simpleprogress.py +0 -53
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Text Pattern Functions
|
3
|
+
====================================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2024-06-01 [2.5ec1]
|
7
|
+
|
8
|
+
This file is a part of novelWriter
|
9
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
|
+
|
11
|
+
This program is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
This program is distributed in the hope that it will be useful, but
|
17
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
+
General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU General Public License
|
22
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
+
"""
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
from PyQt5.QtCore import QRegularExpression
|
27
|
+
|
28
|
+
from novelwriter import CONFIG
|
29
|
+
from novelwriter.constants import nwRegEx
|
30
|
+
from novelwriter.types import QRegExUnicode
|
31
|
+
|
32
|
+
|
33
|
+
class RegExPatterns:
|
34
|
+
|
35
|
+
@property
|
36
|
+
def markdownItalic(self) -> QRegularExpression:
|
37
|
+
"""Markdown italic style."""
|
38
|
+
rxRule = QRegularExpression(nwRegEx.FMT_EI)
|
39
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
40
|
+
return rxRule
|
41
|
+
|
42
|
+
@property
|
43
|
+
def markdownBold(self) -> QRegularExpression:
|
44
|
+
"""Markdown bold style."""
|
45
|
+
rxRule = QRegularExpression(nwRegEx.FMT_EB)
|
46
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
47
|
+
return rxRule
|
48
|
+
|
49
|
+
@property
|
50
|
+
def markdownStrike(self) -> QRegularExpression:
|
51
|
+
"""Markdown strikethrough style."""
|
52
|
+
rxRule = QRegularExpression(nwRegEx.FMT_ST)
|
53
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
54
|
+
return rxRule
|
55
|
+
|
56
|
+
@property
|
57
|
+
def shortcodePlain(self) -> QRegularExpression:
|
58
|
+
"""Plain shortcode style."""
|
59
|
+
rxRule = QRegularExpression(nwRegEx.FMT_SC)
|
60
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
61
|
+
return rxRule
|
62
|
+
|
63
|
+
@property
|
64
|
+
def shortcodeValue(self) -> QRegularExpression:
|
65
|
+
"""Plain shortcode style."""
|
66
|
+
rxRule = QRegularExpression(nwRegEx.FMT_SV)
|
67
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
68
|
+
return rxRule
|
69
|
+
|
70
|
+
@property
|
71
|
+
def dialogStyle(self) -> QRegularExpression:
|
72
|
+
"""Dialogue detection rule based on user settings."""
|
73
|
+
symO = ""
|
74
|
+
symC = ""
|
75
|
+
if CONFIG.dialogStyle in (1, 3):
|
76
|
+
symO += CONFIG.fmtSQuoteOpen
|
77
|
+
symC += CONFIG.fmtSQuoteClose
|
78
|
+
if CONFIG.dialogStyle in (2, 3):
|
79
|
+
symO += CONFIG.fmtDQuoteOpen
|
80
|
+
symC += CONFIG.fmtDQuoteClose
|
81
|
+
|
82
|
+
rxEnd = "|$" if CONFIG.allowOpenDial else ""
|
83
|
+
rxRule = QRegularExpression(f"\\B[{symO}].*?(?:[{symC}]\\B{rxEnd})")
|
84
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
85
|
+
return rxRule
|
86
|
+
|
87
|
+
@property
|
88
|
+
def dialogLine(self) -> QRegularExpression:
|
89
|
+
"""Dialogue line rule based on user settings."""
|
90
|
+
sym = QRegularExpression.escape(CONFIG.dialogLine)
|
91
|
+
rxRule = QRegularExpression(f"^{sym}.*?$")
|
92
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
93
|
+
return rxRule
|
94
|
+
|
95
|
+
@property
|
96
|
+
def narratorBreak(self) -> QRegularExpression:
|
97
|
+
"""Dialogue narrator break rule based on user settings."""
|
98
|
+
sym = QRegularExpression.escape(CONFIG.narratorBreak)
|
99
|
+
rxRule = QRegularExpression(f"\\B{sym}\\S.*?\\S{sym}\\B")
|
100
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
101
|
+
return rxRule
|
102
|
+
|
103
|
+
@property
|
104
|
+
def altDialogStyle(self) -> QRegularExpression:
|
105
|
+
"""Dialogue alternative rule based on user settings."""
|
106
|
+
symO = QRegularExpression.escape(CONFIG.altDialogOpen)
|
107
|
+
symC = QRegularExpression.escape(CONFIG.altDialogClose)
|
108
|
+
rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B")
|
109
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
110
|
+
return rxRule
|
111
|
+
|
112
|
+
|
113
|
+
REGEX_PATTERNS = RegExPatterns()
|
@@ -109,7 +109,7 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
109
109
|
|
110
110
|
# Buttons
|
111
111
|
self.buttonBox = QDialogButtonBox(QtDialogClose, self)
|
112
|
-
self.buttonBox.rejected.connect(self.
|
112
|
+
self.buttonBox.rejected.connect(self.reject)
|
113
113
|
|
114
114
|
# Assemble
|
115
115
|
self.innerBox = QVBoxLayout()
|
@@ -172,7 +172,7 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
172
172
|
def closeEvent(self, event: QCloseEvent) -> None:
|
173
173
|
"""Capture the user closing the window."""
|
174
174
|
event.accept()
|
175
|
-
self.
|
175
|
+
self.softDelete()
|
176
176
|
return
|
177
177
|
|
178
178
|
##
|
@@ -220,12 +220,6 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
220
220
|
SHARED.error("Path not found.")
|
221
221
|
return
|
222
222
|
|
223
|
-
@pyqtSlot()
|
224
|
-
def _doClose(self) -> None:
|
225
|
-
"""Close the dialog."""
|
226
|
-
self.close()
|
227
|
-
return
|
228
|
-
|
229
223
|
##
|
230
224
|
# Internal Functions
|
231
225
|
##
|
novelwriter/tools/lipsum.py
CHANGED
@@ -26,34 +26,32 @@ from __future__ import annotations
|
|
26
26
|
import logging
|
27
27
|
import random
|
28
28
|
|
29
|
-
from PyQt5.QtCore import
|
29
|
+
from PyQt5.QtCore import pyqtSlot
|
30
30
|
from PyQt5.QtWidgets import (
|
31
|
-
|
32
|
-
|
31
|
+
QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QSpinBox, QVBoxLayout,
|
32
|
+
QWidget
|
33
33
|
)
|
34
34
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
36
|
from novelwriter.common import readTextFile
|
37
|
+
from novelwriter.extensions.modified import NDialog
|
37
38
|
from novelwriter.extensions.switch import NSwitch
|
38
39
|
from novelwriter.types import QtAlignLeft, QtAlignRight, QtDialogClose, QtRoleAction
|
39
40
|
|
40
41
|
logger = logging.getLogger(__name__)
|
41
42
|
|
42
43
|
|
43
|
-
class GuiLipsum(
|
44
|
+
class GuiLipsum(NDialog):
|
44
45
|
|
45
46
|
def __init__(self, parent: QWidget) -> None:
|
46
47
|
super().__init__(parent=parent)
|
47
48
|
|
48
49
|
logger.debug("Create: GuiLipsum")
|
49
50
|
self.setObjectName("GuiLipsum")
|
50
|
-
|
51
|
-
self.setWindowFlag(Qt.WindowType.Tool)
|
51
|
+
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
52
52
|
|
53
53
|
self._lipsumText = ""
|
54
54
|
|
55
|
-
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
56
|
-
|
57
55
|
vSp = CONFIG.pxInt(4)
|
58
56
|
nPx = CONFIG.pxInt(64)
|
59
57
|
|
@@ -95,7 +93,7 @@ class GuiLipsum(QDialog):
|
|
95
93
|
|
96
94
|
# Buttons
|
97
95
|
self.buttonBox = QDialogButtonBox(self)
|
98
|
-
self.buttonBox.rejected.connect(self.
|
96
|
+
self.buttonBox.rejected.connect(self.reject)
|
99
97
|
|
100
98
|
self.btnClose = self.buttonBox.addButton(QtDialogClose)
|
101
99
|
self.btnClose.setAutoDefault(False)
|
@@ -104,8 +102,6 @@ class GuiLipsum(QDialog):
|
|
104
102
|
self.btnInsert.clicked.connect(self._doInsert)
|
105
103
|
self.btnInsert.setAutoDefault(False)
|
106
104
|
|
107
|
-
self.rejected.connect(self.close)
|
108
|
-
|
109
105
|
# Assemble
|
110
106
|
self.outerBox = QVBoxLayout()
|
111
107
|
self.outerBox.addLayout(self.innerBox)
|
@@ -132,7 +128,7 @@ class GuiLipsum(QDialog):
|
|
132
128
|
cls = GuiLipsum(parent)
|
133
129
|
cls.exec()
|
134
130
|
text = cls.lipsumText
|
135
|
-
cls.
|
131
|
+
cls.softDelete()
|
136
132
|
return text
|
137
133
|
|
138
134
|
##
|
novelwriter/tools/manusbuild.py
CHANGED
@@ -30,7 +30,7 @@ from pathlib import Path
|
|
30
30
|
from PyQt5.QtCore import QTimer, pyqtSlot
|
31
31
|
from PyQt5.QtGui import QCloseEvent
|
32
32
|
from PyQt5.QtWidgets import (
|
33
|
-
QAbstractButton, QAbstractItemView,
|
33
|
+
QAbstractButton, QAbstractItemView, QDialogButtonBox, QFileDialog,
|
34
34
|
QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
35
35
|
QPushButton, QSplitter, QVBoxLayout, QWidget
|
36
36
|
)
|
@@ -42,14 +42,14 @@ from novelwriter.core.buildsettings import BuildSettings
|
|
42
42
|
from novelwriter.core.docbuild import NWBuildDocument
|
43
43
|
from novelwriter.core.item import NWItem
|
44
44
|
from novelwriter.enum import nwBuildFmt
|
45
|
-
from novelwriter.extensions.modified import NIconToolButton
|
46
|
-
from novelwriter.extensions.
|
45
|
+
from novelwriter.extensions.modified import NDialog, NIconToolButton
|
46
|
+
from novelwriter.extensions.progressbars import NProgressSimple
|
47
47
|
from novelwriter.types import QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
|
48
48
|
|
49
49
|
logger = logging.getLogger(__name__)
|
50
50
|
|
51
51
|
|
52
|
-
class GuiManuscriptBuild(
|
52
|
+
class GuiManuscriptBuild(NDialog):
|
53
53
|
"""GUI Tools: Manuscript Build Dialog
|
54
54
|
|
55
55
|
This is the tool for running the build itself. It can be accessed
|
@@ -220,7 +220,7 @@ class GuiManuscriptBuild(QDialog):
|
|
220
220
|
|
221
221
|
self.btnBuild.setFocus()
|
222
222
|
self._populateContentList()
|
223
|
-
self.buildPath.setText(str(self._build.
|
223
|
+
self.buildPath.setText(str(self._build.lastBuildPath))
|
224
224
|
if self._build.lastBuildName:
|
225
225
|
self.buildName.setText(self._build.lastBuildName)
|
226
226
|
else:
|
@@ -250,7 +250,7 @@ class GuiManuscriptBuild(QDialog):
|
|
250
250
|
"""
|
251
251
|
self._saveSettings()
|
252
252
|
event.accept()
|
253
|
-
self.
|
253
|
+
self.softDelete()
|
254
254
|
return
|
255
255
|
|
256
256
|
##
|
@@ -274,7 +274,7 @@ class GuiManuscriptBuild(QDialog):
|
|
274
274
|
def _doSelectPath(self) -> None:
|
275
275
|
"""Select a folder for output."""
|
276
276
|
bPath = Path(self.buildPath.text())
|
277
|
-
bPath = bPath if bPath.is_dir() else self._build.
|
277
|
+
bPath = bPath if bPath.is_dir() else self._build.lastBuildPath
|
278
278
|
savePath = QFileDialog.getExistingDirectory(
|
279
279
|
self, self.tr("Select Folder"), str(bPath)
|
280
280
|
)
|
@@ -327,7 +327,7 @@ class GuiManuscriptBuild(QDialog):
|
|
327
327
|
return False
|
328
328
|
|
329
329
|
# Make sure editor content is saved before we start
|
330
|
-
SHARED.
|
330
|
+
SHARED.saveEditor()
|
331
331
|
|
332
332
|
docBuild = NWBuildDocument(SHARED.project, self._build)
|
333
333
|
docBuild.queueAll()
|
@@ -336,7 +336,7 @@ class GuiManuscriptBuild(QDialog):
|
|
336
336
|
for i, _ in docBuild.iterBuild(buildPath, bFormat):
|
337
337
|
self.buildProgress.setValue(i+1)
|
338
338
|
|
339
|
-
self._build.
|
339
|
+
self._build.setLastBuildPath(bPath)
|
340
340
|
self._build.setLastBuildName(bName)
|
341
341
|
self._build.setLastFormat(bFormat)
|
342
342
|
|
novelwriter/tools/manuscript.py
CHANGED
@@ -44,8 +44,8 @@ from novelwriter.core.buildsettings import BuildCollection, BuildSettings
|
|
44
44
|
from novelwriter.core.docbuild import NWBuildDocument
|
45
45
|
from novelwriter.core.tokenizer import HeadingFormatter
|
46
46
|
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
|
47
|
-
from novelwriter.extensions.circularprogress import NProgressCircle
|
48
47
|
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
|
48
|
+
from novelwriter.extensions.progressbars import NProgressCircle
|
49
49
|
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
|
50
50
|
from novelwriter.tools.manusbuild import GuiManuscriptBuild
|
51
51
|
from novelwriter.tools.manussettings import GuiBuildSettings
|
@@ -265,7 +265,7 @@ class GuiManuscript(NToolDialog):
|
|
265
265
|
if isinstance(obj, GuiBuildSettings) and obj.isVisible():
|
266
266
|
obj.close()
|
267
267
|
event.accept()
|
268
|
-
self.
|
268
|
+
self.softDelete()
|
269
269
|
return
|
270
270
|
|
271
271
|
##
|
@@ -322,8 +322,10 @@ class GuiManuscript(NToolDialog):
|
|
322
322
|
if not (build := self._getSelectedBuild()):
|
323
323
|
return
|
324
324
|
|
325
|
+
start = time()
|
326
|
+
|
325
327
|
# Make sure editor content is saved before we start
|
326
|
-
SHARED.
|
328
|
+
SHARED.saveEditor()
|
327
329
|
|
328
330
|
docBuild = NWBuildDocument(SHARED.project, build)
|
329
331
|
docBuild.queueAll()
|
@@ -339,6 +341,8 @@ class GuiManuscript(NToolDialog):
|
|
339
341
|
theme.keyword = QColor(245, 135, 31)
|
340
342
|
theme.tag = QColor(66, 113, 174)
|
341
343
|
theme.optional = QColor(66, 113, 174)
|
344
|
+
theme.dialog = QColor(66, 113, 174)
|
345
|
+
theme.altdialog = QColor(129, 55, 9)
|
342
346
|
|
343
347
|
self.docPreview.beginNewBuild(len(docBuild))
|
344
348
|
for step, _ in docBuild.iterBuildPreview(theme):
|
@@ -358,6 +362,8 @@ class GuiManuscript(NToolDialog):
|
|
358
362
|
self.docStats.updateStats(buildObj.textStats)
|
359
363
|
self.buildOutline.updateOutline(buildObj.textOutline)
|
360
364
|
|
365
|
+
logger.debug("Build completed in %.3f ms", 1000*(time()-start))
|
366
|
+
|
361
367
|
return
|
362
368
|
|
363
369
|
@pyqtSlot()
|
@@ -891,9 +897,8 @@ class _PreviewWidget(QTextBrowser):
|
|
891
897
|
document within the viewport.
|
892
898
|
"""
|
893
899
|
vBar = self.verticalScrollBar()
|
894
|
-
sW = vBar.width() if vBar.isVisible() else 0
|
895
900
|
tB = self.frameWidth()
|
896
|
-
vW = self.width() - 2*tB -
|
901
|
+
vW = self.width() - 2*tB - vBar.width()
|
897
902
|
vH = self.height() - 2*tB
|
898
903
|
tH = self.ageLabel.height()
|
899
904
|
pS = self.buildProgress.width()
|
@@ -98,8 +98,8 @@ class GuiBuildSettings(NToolDialog):
|
|
98
98
|
|
99
99
|
# Title
|
100
100
|
self.titleLabel = NColourLabel(
|
101
|
-
self.tr("Manuscript Build Settings"), SHARED.theme.helpText,
|
102
|
-
|
101
|
+
self.tr("Manuscript Build Settings"), self, color=SHARED.theme.helpText,
|
102
|
+
scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
|
103
103
|
)
|
104
104
|
|
105
105
|
# Settings Name
|
@@ -200,7 +200,7 @@ class GuiBuildSettings(NToolDialog):
|
|
200
200
|
self._askToSaveBuild()
|
201
201
|
self._saveSettings()
|
202
202
|
event.accept()
|
203
|
-
self.
|
203
|
+
self.softDelete()
|
204
204
|
return
|
205
205
|
|
206
206
|
##
|
@@ -1093,11 +1093,13 @@ class _FormatTab(NScrollableForm):
|
|
1093
1093
|
self.stripUnicode = NSwitch(self, height=iPx)
|
1094
1094
|
self.replaceTabs = NSwitch(self, height=iPx)
|
1095
1095
|
self.keepBreaks = NSwitch(self, height=iPx)
|
1096
|
+
self.showDialogue = NSwitch(self, height=iPx)
|
1096
1097
|
|
1097
1098
|
self.addRow(self._build.getLabel("format.justifyText"), self.justifyText)
|
1098
1099
|
self.addRow(self._build.getLabel("format.stripUnicode"), self.stripUnicode)
|
1099
1100
|
self.addRow(self._build.getLabel("format.replaceTabs"), self.replaceTabs)
|
1100
1101
|
self.addRow(self._build.getLabel("format.keepBreaks"), self.keepBreaks)
|
1102
|
+
self.addRow(self._build.getLabel("format.showDialogue"), self.showDialogue)
|
1101
1103
|
|
1102
1104
|
# First Line Indent
|
1103
1105
|
# =================
|
@@ -1180,6 +1182,7 @@ class _FormatTab(NScrollableForm):
|
|
1180
1182
|
self.stripUnicode.setChecked(self._build.getBool("format.stripUnicode"))
|
1181
1183
|
self.replaceTabs.setChecked(self._build.getBool("format.replaceTabs"))
|
1182
1184
|
self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks"))
|
1185
|
+
self.showDialogue.setChecked(self._build.getBool("format.showDialogue"))
|
1183
1186
|
|
1184
1187
|
self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent"))
|
1185
1188
|
self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth"))
|
@@ -1219,6 +1222,7 @@ class _FormatTab(NScrollableForm):
|
|
1219
1222
|
self._build.setValue("format.stripUnicode", self.stripUnicode.isChecked())
|
1220
1223
|
self._build.setValue("format.replaceTabs", self.replaceTabs.isChecked())
|
1221
1224
|
self._build.setValue("format.keepBreaks", self.keepBreaks.isChecked())
|
1225
|
+
self._build.setValue("format.showDialogue", self.showDialogue.isChecked())
|
1222
1226
|
|
1223
1227
|
self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked())
|
1224
1228
|
self._build.setValue("format.firstIndentWidth", self.indentWidth.value())
|
@@ -68,8 +68,8 @@ class GuiNovelDetails(NNonBlockingDialog):
|
|
68
68
|
|
69
69
|
# Title
|
70
70
|
self.titleLabel = NColourLabel(
|
71
|
-
self.tr("Novel Details"), SHARED.theme.helpText,
|
72
|
-
|
71
|
+
self.tr("Novel Details"), self, color=SHARED.theme.helpText,
|
72
|
+
scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
|
73
73
|
)
|
74
74
|
|
75
75
|
# Novel Selector
|
@@ -97,7 +97,7 @@ class GuiNovelDetails(NNonBlockingDialog):
|
|
97
97
|
|
98
98
|
# Buttons
|
99
99
|
self.buttonBox = QDialogButtonBox(QtDialogClose, self)
|
100
|
-
self.buttonBox.rejected.connect(self.
|
100
|
+
self.buttonBox.rejected.connect(self.reject)
|
101
101
|
|
102
102
|
# Assemble
|
103
103
|
self.topBox = QHBoxLayout()
|
@@ -150,7 +150,7 @@ class GuiNovelDetails(NNonBlockingDialog):
|
|
150
150
|
"""Capture the user closing the window and save settings."""
|
151
151
|
self._saveSettings()
|
152
152
|
event.accept()
|
153
|
-
self.
|
153
|
+
self.softDelete()
|
154
154
|
return
|
155
155
|
|
156
156
|
##
|
@@ -199,8 +199,8 @@ class _OverviewPage(NScrollablePage):
|
|
199
199
|
|
200
200
|
# Project Info
|
201
201
|
self.projLabel = NColourLabel(
|
202
|
-
self.tr("Project"), SHARED.theme.helpText,
|
203
|
-
|
202
|
+
self.tr("Project"), self, color=SHARED.theme.helpText,
|
203
|
+
scale=NColourLabel.HEADER_SCALE
|
204
204
|
)
|
205
205
|
|
206
206
|
self.projName = QLabel("", self)
|
@@ -223,8 +223,8 @@ class _OverviewPage(NScrollablePage):
|
|
223
223
|
|
224
224
|
# Novel Info
|
225
225
|
self.novelLabel = NColourLabel(
|
226
|
-
self.tr("Selected Novel"), SHARED.theme.helpText,
|
227
|
-
|
226
|
+
self.tr("Selected Novel"), self, color=SHARED.theme.helpText,
|
227
|
+
scale=NColourLabel.HEADER_SCALE
|
228
228
|
)
|
229
229
|
|
230
230
|
self.novelName = QLabel("", self)
|
@@ -315,8 +315,8 @@ class _ContentsPage(NFixedPage):
|
|
315
315
|
|
316
316
|
# Title
|
317
317
|
self.contentLabel = NColourLabel(
|
318
|
-
self.tr("Table of Contents"), SHARED.theme.helpText,
|
319
|
-
|
318
|
+
self.tr("Table of Contents"), self, color=SHARED.theme.helpText,
|
319
|
+
scale=NColourLabel.HEADER_SCALE
|
320
320
|
)
|
321
321
|
|
322
322
|
# Contents Tree
|
novelwriter/tools/welcome.py
CHANGED
@@ -34,8 +34,8 @@ from PyQt5.QtCore import (
|
|
34
34
|
)
|
35
35
|
from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPainter, QPaintEvent, QPen
|
36
36
|
from PyQt5.QtWidgets import (
|
37
|
-
QAction, QApplication,
|
38
|
-
|
37
|
+
QAction, QApplication, QFileDialog, QFormLayout, QHBoxLayout, QLabel,
|
38
|
+
QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut,
|
39
39
|
QStackedWidget, QStyledItemDelegate, QStyleOptionViewItem, QVBoxLayout,
|
40
40
|
QWidget
|
41
41
|
)
|
@@ -46,7 +46,7 @@ from novelwriter.constants import nwFiles
|
|
46
46
|
from novelwriter.core.coretools import ProjectBuilder
|
47
47
|
from novelwriter.enum import nwItemClass
|
48
48
|
from novelwriter.extensions.configlayout import NWrappedWidgetBox
|
49
|
-
from novelwriter.extensions.modified import NIconToolButton, NSpinBox
|
49
|
+
from novelwriter.extensions.modified import NDialog, NIconToolButton, NSpinBox
|
50
50
|
from novelwriter.extensions.switch import NSwitch
|
51
51
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
52
52
|
from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtSelected
|
@@ -56,7 +56,7 @@ logger = logging.getLogger(__name__)
|
|
56
56
|
PANEL_ALPHA = 178
|
57
57
|
|
58
58
|
|
59
|
-
class GuiWelcome(
|
59
|
+
class GuiWelcome(NDialog):
|
60
60
|
|
61
61
|
openProjectRequest = pyqtSignal(Path)
|
62
62
|
|
@@ -196,7 +196,7 @@ class GuiWelcome(QDialog):
|
|
196
196
|
"""Capture the user closing the window and save settings."""
|
197
197
|
self._saveSettings()
|
198
198
|
event.accept()
|
199
|
-
self.
|
199
|
+
self.softDelete()
|
200
200
|
return
|
201
201
|
|
202
202
|
##
|
@@ -208,6 +208,7 @@ class GuiWelcome(QDialog):
|
|
208
208
|
"""Show the create new project page."""
|
209
209
|
self.mainStack.setCurrentWidget(self.tabNew)
|
210
210
|
self._setButtonVisibility()
|
211
|
+
self.tabNew.enterForm()
|
211
212
|
return
|
212
213
|
|
213
214
|
@pyqtSlot()
|
@@ -220,8 +221,7 @@ class GuiWelcome(QDialog):
|
|
220
221
|
@pyqtSlot()
|
221
222
|
def _browseForProject(self) -> None:
|
222
223
|
"""Browse for a project to open."""
|
223
|
-
if path := SHARED.getProjectPath(self, path=CONFIG.
|
224
|
-
CONFIG.setLastPath(path)
|
224
|
+
if path := SHARED.getProjectPath(self, path=CONFIG.homePath(), allowZip=False):
|
225
225
|
self._openProjectPath(path)
|
226
226
|
return
|
227
227
|
|
@@ -504,6 +504,8 @@ class _NewProjectPage(QWidget):
|
|
504
504
|
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
505
505
|
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
506
506
|
|
507
|
+
self.enterForm = self.projectForm.enterForm
|
508
|
+
|
507
509
|
# Assemble
|
508
510
|
# ========
|
509
511
|
|
@@ -550,7 +552,7 @@ class _NewProjectForm(QWidget):
|
|
550
552
|
def __init__(self, parent: QWidget) -> None:
|
551
553
|
super().__init__(parent=parent)
|
552
554
|
|
553
|
-
self._basePath = CONFIG.
|
555
|
+
self._basePath = CONFIG.lastPath("project")
|
554
556
|
self._fillMode = self.FILL_BLANK
|
555
557
|
self._copyPath = None
|
556
558
|
|
@@ -697,6 +699,12 @@ class _NewProjectForm(QWidget):
|
|
697
699
|
|
698
700
|
return
|
699
701
|
|
702
|
+
def enterForm(self) -> None:
|
703
|
+
"""Focus the project name field when entering the form."""
|
704
|
+
self.projName.setFocus()
|
705
|
+
self.projName.selectAll()
|
706
|
+
return
|
707
|
+
|
700
708
|
def getProjectData(self) -> dict:
|
701
709
|
"""Collect form data and return it as a dictionary."""
|
702
710
|
roots = []
|
@@ -726,12 +734,13 @@ class _NewProjectForm(QWidget):
|
|
726
734
|
@pyqtSlot()
|
727
735
|
def _doBrowse(self) -> None:
|
728
736
|
"""Select a project folder."""
|
729
|
-
if
|
737
|
+
if path := QFileDialog.getExistingDirectory(
|
730
738
|
self, self.tr("Select Project Folder"),
|
731
739
|
str(self._basePath), options=QFileDialog.Option.ShowDirsOnly
|
732
740
|
):
|
733
|
-
self._basePath = Path(
|
741
|
+
self._basePath = Path(path)
|
734
742
|
self._updateProjPath()
|
743
|
+
CONFIG.setLastPath("project", path)
|
735
744
|
return
|
736
745
|
|
737
746
|
@pyqtSlot()
|
@@ -318,7 +318,7 @@ class GuiWritingStats(NToolDialog):
|
|
318
318
|
def closeEvent(self, event: QCloseEvent) -> None:
|
319
319
|
"""Capture the user closing the window."""
|
320
320
|
event.accept()
|
321
|
-
self.
|
321
|
+
self.softDelete()
|
322
322
|
return
|
323
323
|
|
324
324
|
##
|
@@ -384,14 +384,14 @@ class GuiWritingStats(NToolDialog):
|
|
384
384
|
return False
|
385
385
|
|
386
386
|
# Generate the file name
|
387
|
-
savePath = CONFIG.lastPath() / f"sessionStats.{fileExt}"
|
387
|
+
savePath = CONFIG.lastPath("stats") / f"sessionStats.{fileExt}"
|
388
388
|
savePath, _ = QFileDialog.getSaveFileName(
|
389
389
|
self, self.tr("Save Data As"), str(savePath), f"{textFmt} (*.{fileExt})"
|
390
390
|
)
|
391
391
|
if not savePath:
|
392
392
|
return False
|
393
393
|
|
394
|
-
CONFIG.setLastPath(savePath)
|
394
|
+
CONFIG.setLastPath("stats", savePath)
|
395
395
|
|
396
396
|
# Do the actual writing
|
397
397
|
wSuccess = False
|
novelwriter/types.py
CHANGED
@@ -25,7 +25,7 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
from PyQt5.QtCore import QRegularExpression, Qt
|
27
27
|
from PyQt5.QtGui import QColor, QFont, QPainter, QTextCharFormat, QTextCursor, QTextFormat
|
28
|
-
from PyQt5.QtWidgets import QDialogButtonBox, QSizePolicy, QStyle
|
28
|
+
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QSizePolicy, QStyle
|
29
29
|
|
30
30
|
# Qt Alignment Flags
|
31
31
|
|
@@ -73,13 +73,16 @@ QtUserRole = Qt.ItemDataRole.UserRole
|
|
73
73
|
# Keyboard and Mouse Buttons
|
74
74
|
|
75
75
|
QtModCtrl = Qt.KeyboardModifier.ControlModifier
|
76
|
-
|
76
|
+
QtModNone = Qt.KeyboardModifier.NoModifier
|
77
77
|
QtModShift = Qt.KeyboardModifier.ShiftModifier
|
78
78
|
QtMouseLeft = Qt.MouseButton.LeftButton
|
79
79
|
QtMouseMiddle = Qt.MouseButton.MiddleButton
|
80
80
|
|
81
81
|
# Dialog Button Box Types
|
82
82
|
|
83
|
+
QtAccepted = QDialog.DialogCode.Accepted
|
84
|
+
QtRejected = QDialog.DialogCode.Rejected
|
85
|
+
|
83
86
|
QtDialogApply = QDialogButtonBox.StandardButton.Apply
|
84
87
|
QtDialogCancel = QDialogButtonBox.StandardButton.Cancel
|
85
88
|
QtDialogClose = QDialogButtonBox.StandardButton.Close
|
@@ -1,53 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
novelWriter – Custom Widget: Progress Simple
|
3
|
-
============================================
|
4
|
-
|
5
|
-
File History:
|
6
|
-
Created: 2023-06-09 [2.1b1]
|
7
|
-
|
8
|
-
This file is a part of novelWriter
|
9
|
-
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
|
-
|
11
|
-
This program is free software: you can redistribute it and/or modify
|
12
|
-
it under the terms of the GNU General Public License as published by
|
13
|
-
the Free Software Foundation, either version 3 of the License, or
|
14
|
-
(at your option) any later version.
|
15
|
-
|
16
|
-
This program is distributed in the hope that it will be useful, but
|
17
|
-
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
-
General Public License for more details.
|
20
|
-
|
21
|
-
You should have received a copy of the GNU General Public License
|
22
|
-
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
-
"""
|
24
|
-
from __future__ import annotations
|
25
|
-
|
26
|
-
from math import ceil
|
27
|
-
|
28
|
-
from PyQt5.QtGui import QPainter, QPaintEvent
|
29
|
-
from PyQt5.QtWidgets import QProgressBar, QWidget
|
30
|
-
|
31
|
-
from novelwriter.types import QtPaintAnitAlias
|
32
|
-
|
33
|
-
|
34
|
-
class NProgressSimple(QProgressBar):
|
35
|
-
"""Extension: Simple Progress Widget
|
36
|
-
|
37
|
-
A custom widget that paints a plain bar with no other styling.
|
38
|
-
"""
|
39
|
-
|
40
|
-
def __init__(self, parent: QWidget) -> None:
|
41
|
-
super().__init__(parent=parent)
|
42
|
-
return
|
43
|
-
|
44
|
-
def paintEvent(self, event: QPaintEvent) -> None:
|
45
|
-
"""Custom painter for the progress bar."""
|
46
|
-
if (value := self.value()) > 0:
|
47
|
-
progress = ceil(self.width()*float(value)/self.maximum())
|
48
|
-
painter = QPainter(self)
|
49
|
-
painter.setRenderHint(QtPaintAnitAlias, True)
|
50
|
-
painter.setPen(self.palette().highlight().color())
|
51
|
-
painter.setBrush(self.palette().highlight())
|
52
|
-
painter.drawRect(0, 0, progress, self.height())
|
53
|
-
return
|
File without changes
|
File without changes
|
File without changes
|