novelWriter 2.2b1__py3-none-any.whl → 2.2.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.2b1.dist-info → novelWriter-2.2.1.dist-info}/METADATA +3 -3
- {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/RECORD +128 -114
- {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +10 -5
- 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_GB.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/novelwriter.ico +0 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +11 -3
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -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_eye.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +11 -3
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -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_eye.svg +4 -0
- novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/release_notes.htm +50 -7
- novelwriter/common.py +35 -27
- novelwriter/config.py +13 -28
- novelwriter/constants.py +21 -4
- novelwriter/core/buildsettings.py +2 -2
- novelwriter/core/coretools.py +8 -2
- novelwriter/core/docbuild.py +1 -1
- novelwriter/core/document.py +1 -1
- novelwriter/core/index.py +102 -36
- novelwriter/core/item.py +2 -2
- novelwriter/core/options.py +6 -3
- novelwriter/core/project.py +5 -5
- novelwriter/core/projectdata.py +3 -3
- novelwriter/core/projectxml.py +1 -1
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/spellcheck.py +4 -3
- novelwriter/core/status.py +3 -3
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tohtml.py +11 -5
- novelwriter/core/tokenizer.py +28 -21
- novelwriter/core/tomd.py +6 -2
- novelwriter/core/toodt.py +12 -5
- novelwriter/core/tree.py +2 -2
- novelwriter/dialogs/about.py +30 -31
- novelwriter/dialogs/docmerge.py +24 -15
- novelwriter/dialogs/docsplit.py +27 -16
- novelwriter/dialogs/editlabel.py +19 -7
- novelwriter/dialogs/preferences.py +116 -131
- novelwriter/dialogs/projdetails.py +29 -36
- novelwriter/dialogs/projload.py +32 -36
- novelwriter/dialogs/projsettings.py +20 -15
- novelwriter/dialogs/quotes.py +32 -25
- novelwriter/dialogs/updates.py +17 -16
- novelwriter/dialogs/wordlist.py +34 -21
- novelwriter/enum.py +19 -8
- novelwriter/error.py +1 -1
- novelwriter/extensions/circularprogress.py +1 -1
- novelwriter/extensions/configlayout.py +3 -15
- novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
- novelwriter/extensions/novelselector.py +1 -1
- novelwriter/extensions/pageddialog.py +1 -1
- novelwriter/extensions/pagedsidebar.py +2 -5
- novelwriter/extensions/simpleprogress.py +8 -9
- novelwriter/extensions/statusled.py +1 -1
- novelwriter/extensions/switch.py +4 -4
- novelwriter/extensions/switchbox.py +1 -6
- novelwriter/gui/doceditor.py +349 -236
- novelwriter/gui/dochighlight.py +10 -11
- novelwriter/gui/docviewer.py +158 -360
- novelwriter/gui/docviewerpanel.py +502 -0
- novelwriter/gui/editordocument.py +4 -4
- novelwriter/gui/itemdetails.py +2 -2
- novelwriter/gui/mainmenu.py +50 -36
- novelwriter/gui/noveltree.py +44 -53
- novelwriter/gui/outline.py +12 -7
- novelwriter/gui/projtree.py +465 -381
- novelwriter/gui/sidebar.py +9 -7
- novelwriter/gui/statusbar.py +48 -5
- novelwriter/gui/theme.py +26 -8
- novelwriter/guimain.py +212 -208
- novelwriter/shared.py +76 -30
- novelwriter/tools/dictionaries.py +268 -0
- novelwriter/tools/lipsum.py +34 -28
- novelwriter/tools/manusbuild.py +20 -10
- novelwriter/tools/manuscript.py +20 -27
- novelwriter/tools/manussettings.py +2 -4
- novelwriter/tools/projwizard.py +3 -3
- novelwriter/tools/writingstats.py +18 -5
- 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_dark/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
- novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
- novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
- {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/top_level.txt +0 -0
novelwriter/gui/sidebar.py
CHANGED
@@ -3,10 +3,10 @@ novelWriter – GUI Main Window SideBar
|
|
3
3
|
=====================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2022-05-10 [2.0rc1]
|
6
|
+
Created: 2022-05-10 [2.0rc1] GuiSideBar
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
9
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -27,12 +27,13 @@ import logging
|
|
27
27
|
|
28
28
|
from typing import TYPE_CHECKING
|
29
29
|
|
30
|
-
from PyQt5.QtCore import QEvent, QPoint, Qt, QSize, pyqtSignal
|
31
30
|
from PyQt5.QtGui import QPalette
|
31
|
+
from PyQt5.QtCore import QEvent, QPoint, Qt, QSize, pyqtSignal
|
32
32
|
from PyQt5.QtWidgets import QMenu, QToolButton, QVBoxLayout, QWidget
|
33
33
|
|
34
34
|
from novelwriter import CONFIG, SHARED
|
35
35
|
from novelwriter.enum import nwView
|
36
|
+
from novelwriter.extensions.eventfilters import StatusTipFilter
|
36
37
|
|
37
38
|
if TYPE_CHECKING: # pragma: no cover
|
38
39
|
from novelwriter.guimain import GuiMain
|
@@ -54,6 +55,7 @@ class GuiSideBar(QWidget):
|
|
54
55
|
iPx = CONFIG.pxInt(24)
|
55
56
|
iconSize = QSize(iPx, iPx)
|
56
57
|
self.setContentsMargins(0, 0, 0, 0)
|
58
|
+
self.installEventFilter(StatusTipFilter(mainGui))
|
57
59
|
|
58
60
|
# Buttons
|
59
61
|
self.tbProject = QToolButton(self)
|
@@ -67,7 +69,7 @@ class GuiSideBar(QWidget):
|
|
67
69
|
self.tbNovel.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
|
68
70
|
|
69
71
|
self.tbOutline = QToolButton(self)
|
70
|
-
self.tbOutline.setToolTip(
|
72
|
+
self.tbOutline.setToolTip("{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View")))
|
71
73
|
self.tbOutline.setIconSize(iconSize)
|
72
74
|
self.tbOutline.clicked.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
|
73
75
|
|
@@ -111,7 +113,7 @@ class GuiSideBar(QWidget):
|
|
111
113
|
self.outerBox.addWidget(self.tbDetails)
|
112
114
|
self.outerBox.addWidget(self.tbStats)
|
113
115
|
self.outerBox.addWidget(self.tbSettings)
|
114
|
-
self.outerBox.setContentsMargins(0, 0,
|
116
|
+
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
115
117
|
self.outerBox.setSpacing(CONFIG.pxInt(4))
|
116
118
|
|
117
119
|
self.setLayout(self.outerBox)
|
@@ -131,7 +133,7 @@ class GuiSideBar(QWidget):
|
|
131
133
|
buttonStyle = (
|
132
134
|
"QToolButton {{padding: {0}px; border: none; background: transparent;}} "
|
133
135
|
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
|
134
|
-
).format(CONFIG.pxInt(
|
136
|
+
).format(CONFIG.pxInt(6), fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
135
137
|
buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}"
|
136
138
|
|
137
139
|
self.tbProject.setIcon(SHARED.theme.getIcon("view_editor"))
|
@@ -162,7 +164,7 @@ class GuiSideBar(QWidget):
|
|
162
164
|
|
163
165
|
class _PopRightMenu(QMenu):
|
164
166
|
|
165
|
-
def event(self, event: QEvent):
|
167
|
+
def event(self, event: QEvent) -> bool:
|
166
168
|
"""Overload the show event and move the menu popup location."""
|
167
169
|
if event.type() == QEvent.Show:
|
168
170
|
parent = self.parent()
|
novelwriter/gui/statusbar.py
CHANGED
@@ -3,10 +3,10 @@ novelWriter – GUI Main Window Status Bar
|
|
3
3
|
========================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2019-04-20 [0.0.1]
|
6
|
+
Created: 2019-04-20 [0.0.1] GuiMainStatus
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
9
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -27,9 +27,10 @@ import logging
|
|
27
27
|
|
28
28
|
from time import time
|
29
29
|
from typing import TYPE_CHECKING, Literal
|
30
|
+
from datetime import datetime
|
30
31
|
|
31
|
-
from PyQt5.QtCore import pyqtSlot, QLocale
|
32
32
|
from PyQt5.QtGui import QColor
|
33
|
+
from PyQt5.QtCore import pyqtSlot, QLocale
|
33
34
|
from PyQt5.QtWidgets import qApp, QStatusBar, QLabel
|
34
35
|
|
35
36
|
from novelwriter import CONFIG, SHARED
|
@@ -50,8 +51,9 @@ class GuiMainStatus(QStatusBar):
|
|
50
51
|
|
51
52
|
logger.debug("Create: GuiMainStatus")
|
52
53
|
|
53
|
-
self._refTime
|
54
|
+
self._refTime = -1.0
|
54
55
|
self._userIdle = False
|
56
|
+
self._debugInfo = False
|
55
57
|
|
56
58
|
colNone = QColor(*SHARED.theme.statNone)
|
57
59
|
colSaved = QColor(*SHARED.theme.statSaved)
|
@@ -97,7 +99,7 @@ class GuiMainStatus(QStatusBar):
|
|
97
99
|
self.addPermanentWidget(self.statsText)
|
98
100
|
|
99
101
|
# The Session Clock
|
100
|
-
# Set the
|
102
|
+
# Set the minimum width so the label doesn't rescale every second
|
101
103
|
self.timeIcon = QLabel()
|
102
104
|
self.timeText = QLabel("")
|
103
105
|
self.timeText.setToolTip(self.tr("Session Time"))
|
@@ -223,4 +225,45 @@ class GuiMainStatus(QStatusBar):
|
|
223
225
|
self.setDocumentStatus(StatusLED.S_BAD if status else StatusLED.S_GOOD)
|
224
226
|
return
|
225
227
|
|
228
|
+
##
|
229
|
+
# Debug
|
230
|
+
##
|
231
|
+
|
232
|
+
def memInfo(self) -> None: # pragma: no cover
|
233
|
+
"""Display memory info on the status bar. This is used to
|
234
|
+
investigate memory usage and Qt widgets that get left in memory.
|
235
|
+
Enabled by the --meminfo command line flag.
|
236
|
+
|
237
|
+
By default, this tracks memory usage diff after launch. To track
|
238
|
+
full memory usage, set environment variable PYTHONTRACEMALLOC=1
|
239
|
+
before starting novelWriter.
|
240
|
+
"""
|
241
|
+
import tracemalloc
|
242
|
+
from collections import Counter
|
243
|
+
|
244
|
+
widgets = qApp.allWidgets()
|
245
|
+
if not self._debugInfo:
|
246
|
+
if tracemalloc.is_tracing():
|
247
|
+
self._traceMallocRef = "Total"
|
248
|
+
else:
|
249
|
+
self._traceMallocRef = "Relative"
|
250
|
+
tracemalloc.start()
|
251
|
+
self._debugInfo = True
|
252
|
+
self._wCounts = Counter([type(x).__name__ for x in widgets])
|
253
|
+
|
254
|
+
if hasattr(self, "_wCounts"):
|
255
|
+
diff = Counter([type(x).__name__ for x in widgets]) - self._wCounts
|
256
|
+
for name, count in diff.items():
|
257
|
+
logger.debug("Widget '%s': +%d", name, count)
|
258
|
+
|
259
|
+
mem = tracemalloc.get_traced_memory()
|
260
|
+
stamp = datetime.now().strftime("%H:%M:%S")
|
261
|
+
self.showMessage((
|
262
|
+
f"Debug [{stamp}]"
|
263
|
+
f" \u2013 Widgets: {len(widgets)}"
|
264
|
+
f" \u2013 {self._traceMallocRef} Memory: {mem[0]:n}"
|
265
|
+
f" \u2013 Peak: {mem[1]:n}"
|
266
|
+
), 6000)
|
267
|
+
return
|
268
|
+
|
226
269
|
# END Class GuiMainStatus
|
novelwriter/gui/theme.py
CHANGED
@@ -7,7 +7,7 @@ Created: 2019-05-18 [0.1.3] GuiTheme
|
|
7
7
|
Created: 2019-11-08 [0.4] GuiIcons
|
8
8
|
|
9
9
|
This file is a part of novelWriter
|
10
|
-
Copyright 2018–
|
10
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
11
11
|
|
12
12
|
This program is free software: you can redistribute it and/or modify
|
13
13
|
it under the terms of the GNU General Public License as published by
|
@@ -133,6 +133,7 @@ class GuiTheme:
|
|
133
133
|
self.getToggleIcon = self.iconCache.getToggleIcon
|
134
134
|
self.loadDecoration = self.iconCache.loadDecoration
|
135
135
|
self.getHeaderDecoration = self.iconCache.getHeaderDecoration
|
136
|
+
self.getHeaderDecorationNarrow = self.iconCache.getHeaderDecorationNarrow
|
136
137
|
|
137
138
|
# Extract Other Info
|
138
139
|
self.guiDPI = qApp.primaryScreen().logicalDotsPerInchX()
|
@@ -459,13 +460,13 @@ class GuiIcons:
|
|
459
460
|
"search_regex", "search_word",
|
460
461
|
|
461
462
|
# Format Icons
|
462
|
-
"fmt_bold", "
|
463
|
-
"fmt_superscript", "fmt_underline",
|
463
|
+
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_strike", "fmt_strike-md",
|
464
|
+
"fmt_subscript", "fmt_superscript", "fmt_underline",
|
464
465
|
|
465
466
|
# General Button Icons
|
466
467
|
"add", "backward", "bookmark", "browse", "checked", "close", "cross", "down", "edit",
|
467
|
-
"export", "forward", "maximise", "menu", "minimise", "noncheckable", "
|
468
|
-
"
|
468
|
+
"export", "forward", "maximise", "menu", "minimise", "noncheckable", "panel", "refresh",
|
469
|
+
"remove", "revert", "search_replace", "search", "settings", "unchecked", "up", "view",
|
469
470
|
|
470
471
|
# Switches
|
471
472
|
"sticky-on", "sticky-off",
|
@@ -473,12 +474,13 @@ class GuiIcons:
|
|
473
474
|
|
474
475
|
# Decorations
|
475
476
|
"deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4", "deco_doc_more",
|
477
|
+
"deco_doc_h0_n", "deco_doc_h1_n", "deco_doc_h2_n", "deco_doc_h3_n", "deco_doc_h4_n",
|
478
|
+
"deco_doc_nt_n",
|
476
479
|
}
|
477
480
|
|
478
481
|
TOGGLE_ICON_KEYS = {
|
479
|
-
"sticky":
|
480
|
-
"bullet":
|
481
|
-
"fmt_mode": ("fmt_mode-sc", "fmt_mode-md"),
|
482
|
+
"sticky": ("sticky-on", "sticky-off"),
|
483
|
+
"bullet": ("bullet-on", "bullet-off"),
|
482
484
|
}
|
483
485
|
|
484
486
|
IMAGE_MAP = {
|
@@ -493,6 +495,7 @@ class GuiIcons:
|
|
493
495
|
self._qIcons: dict[str, QIcon] = {}
|
494
496
|
self._themeMap: dict[str, Path] = {}
|
495
497
|
self._headerDec: list[QPixmap] = []
|
498
|
+
self._headerDecNarrow: list[QPixmap] = []
|
496
499
|
|
497
500
|
# Icon Theme Path
|
498
501
|
self._confName = "icons.conf"
|
@@ -580,6 +583,7 @@ class GuiIcons:
|
|
580
583
|
self._qIcons[iconKey] = qIcon
|
581
584
|
|
582
585
|
self._headerDec = []
|
586
|
+
self._headerDecNarrow = []
|
583
587
|
|
584
588
|
return True
|
585
589
|
|
@@ -680,6 +684,20 @@ class GuiIcons:
|
|
680
684
|
]
|
681
685
|
return self._headerDec[minmax(hLevel, 0, 4)]
|
682
686
|
|
687
|
+
def getHeaderDecorationNarrow(self, hLevel: int) -> QPixmap:
|
688
|
+
"""Get the narrow decoration for a specific header level."""
|
689
|
+
if not self._headerDecNarrow:
|
690
|
+
iPx = self.mainTheme.baseIconSize
|
691
|
+
self._headerDecNarrow = [
|
692
|
+
self.loadDecoration("deco_doc_h0_n", h=iPx),
|
693
|
+
self.loadDecoration("deco_doc_h1_n", h=iPx),
|
694
|
+
self.loadDecoration("deco_doc_h2_n", h=iPx),
|
695
|
+
self.loadDecoration("deco_doc_h3_n", h=iPx),
|
696
|
+
self.loadDecoration("deco_doc_h4_n", h=iPx),
|
697
|
+
self.loadDecoration("deco_doc_nt_n", h=iPx),
|
698
|
+
]
|
699
|
+
return self._headerDecNarrow[minmax(hLevel, 0, 5)]
|
700
|
+
|
683
701
|
##
|
684
702
|
# Internal Functions
|
685
703
|
##
|