novelWriter 2.3.1__py3-none-any.whl → 2.4__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.4.dist-info}/METADATA +5 -6
- {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/RECORD +114 -107
- novelwriter/__init__.py +17 -10
- 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_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/icons/none.svg +4 -0
- 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_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_dark/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
- 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_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/icons/typicons_light/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -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 +25 -23
- novelwriter/common.py +12 -4
- novelwriter/config.py +47 -16
- novelwriter/constants.py +5 -6
- novelwriter/core/buildsettings.py +64 -44
- novelwriter/core/coretools.py +97 -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/projectxml.py +1 -1
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/spellcheck.py +3 -3
- novelwriter/core/status.py +6 -5
- novelwriter/core/storage.py +8 -2
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +417 -233
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +386 -351
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/about.py +9 -11
- novelwriter/dialogs/docmerge.py +17 -14
- novelwriter/dialogs/docsplit.py +20 -19
- novelwriter/dialogs/editlabel.py +5 -4
- novelwriter/dialogs/preferences.py +32 -40
- novelwriter/dialogs/projectsettings.py +31 -28
- novelwriter/dialogs/quotes.py +10 -9
- novelwriter/dialogs/wordlist.py +17 -14
- novelwriter/enum.py +17 -14
- novelwriter/error.py +14 -12
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +1 -3
- novelwriter/extensions/modified.py +51 -2
- novelwriter/extensions/pagedsidebar.py +16 -14
- novelwriter/extensions/simpleprogress.py +3 -1
- novelwriter/extensions/statusled.py +3 -1
- novelwriter/extensions/switch.py +10 -9
- novelwriter/extensions/switchbox.py +14 -13
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/gui/doceditor.py +433 -496
- novelwriter/gui/dochighlight.py +54 -33
- novelwriter/gui/docviewer.py +162 -175
- novelwriter/gui/docviewerpanel.py +20 -37
- novelwriter/gui/editordocument.py +15 -4
- novelwriter/gui/itemdetails.py +51 -54
- novelwriter/gui/mainmenu.py +37 -16
- novelwriter/gui/noveltree.py +31 -37
- novelwriter/gui/outline.py +120 -98
- novelwriter/gui/projtree.py +61 -67
- novelwriter/gui/search.py +362 -0
- novelwriter/gui/sidebar.py +36 -45
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +107 -32
- novelwriter/guimain.py +209 -202
- novelwriter/shared.py +31 -6
- novelwriter/text/counting.py +138 -0
- novelwriter/tools/dictionaries.py +15 -14
- novelwriter/tools/lipsum.py +20 -17
- novelwriter/tools/manusbuild.py +43 -35
- novelwriter/tools/manuscript.py +381 -104
- novelwriter/tools/manussettings.py +262 -125
- novelwriter/tools/noveldetails.py +20 -18
- novelwriter/tools/welcome.py +52 -49
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelwriter/core/__init__.py +0 -3
- novelwriter/dialogs/__init__.py +0 -3
- novelwriter/extensions/__init__.py +0 -3
- novelwriter/gui/__init__.py +0 -3
- novelwriter/tools/__init__.py +0 -3
- {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/WHEEL +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
@@ -27,17 +27,20 @@ import logging
|
|
27
27
|
|
28
28
|
from enum import Enum
|
29
29
|
|
30
|
-
from PyQt5.QtCore import QModelIndex,
|
30
|
+
from PyQt5.QtCore import QModelIndex, Qt, pyqtSignal, pyqtSlot
|
31
31
|
from PyQt5.QtWidgets import (
|
32
32
|
QAbstractItemView, QFrame, QHeaderView, QMenu, QTabWidget, QToolButton,
|
33
33
|
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
34
34
|
)
|
35
35
|
|
36
36
|
from novelwriter import CONFIG, SHARED
|
37
|
-
from novelwriter.enum import nwDocMode, nwItemClass
|
38
37
|
from novelwriter.common import checkInt
|
39
38
|
from novelwriter.constants import nwHeaders, nwLabels, nwLists, trConst
|
40
39
|
from novelwriter.core.index import IndexHeading, IndexItem
|
40
|
+
from novelwriter.enum import nwDocMode, nwItemClass
|
41
|
+
from novelwriter.extensions.modified import NIconToolButton
|
42
|
+
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
|
43
|
+
from novelwriter.types import QtDecoration, QtUserRole
|
41
44
|
|
42
45
|
logger = logging.getLogger(__name__)
|
43
46
|
|
@@ -54,7 +57,7 @@ class GuiDocViewerPanel(QWidget):
|
|
54
57
|
|
55
58
|
self._lastHandle = None
|
56
59
|
|
57
|
-
|
60
|
+
iSz = SHARED.theme.baseIconSize
|
58
61
|
|
59
62
|
self.tabBackRefs = _ViewPanelBackRefs(self)
|
60
63
|
|
@@ -64,8 +67,7 @@ class GuiDocViewerPanel(QWidget):
|
|
64
67
|
self.aInactive.setCheckable(True)
|
65
68
|
self.aInactive.toggled.connect(self._toggleHideInactive)
|
66
69
|
|
67
|
-
self.optsButton =
|
68
|
-
self.optsButton.setIconSize(QSize(iPx, iPx))
|
70
|
+
self.optsButton = NIconToolButton(self, iSz)
|
69
71
|
self.optsButton.setMenu(self.optsMenu)
|
70
72
|
self.optsButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
71
73
|
|
@@ -99,35 +101,14 @@ class GuiDocViewerPanel(QWidget):
|
|
99
101
|
|
100
102
|
def updateTheme(self, updateTabs: bool = True) -> None:
|
101
103
|
"""Update theme elements."""
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
hPx = CONFIG.pxInt(8)
|
106
|
-
hCol = qPalette.highlight().color()
|
107
|
-
fCol = qPalette.text().color()
|
108
|
-
|
109
|
-
buttonStyle = (
|
110
|
-
"QToolButton {{padding: {0}px; margin: 0 0 {1}px 0; border: none; "
|
111
|
-
"background: transparent;}} "
|
112
|
-
"QToolButton:hover {{border: none; background: rgba({2}, {3}, {4}, 0.2);}} "
|
113
|
-
"QToolButton::menu-indicator {{image: none;}} "
|
114
|
-
).format(mPx, mPx, fCol.red(), fCol.green(), fCol.blue())
|
115
|
-
self.optsButton.setIcon(SHARED.theme.getIcon("menu"))
|
116
|
-
self.optsButton.setStyleSheet(buttonStyle)
|
117
|
-
|
118
|
-
styleSheet = (
|
119
|
-
"QTabWidget::pane {{border: 0;}} "
|
120
|
-
"QTabWidget QTabBar::tab {{border: 0; padding: {0}px {1}px;}} "
|
121
|
-
"QTabWidget QTabBar::tab:selected {{color: rgb({2}, {3}, {4});}} "
|
122
|
-
).format(vPx, hPx, hCol.red(), hCol.green(), hCol.blue())
|
123
|
-
self.mainTabs.setStyleSheet(styleSheet)
|
104
|
+
self.optsButton.setThemeIcon("menu")
|
105
|
+
self.optsButton.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON))
|
106
|
+
self.mainTabs.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_FLAT_TABS))
|
124
107
|
self.updateHandle(self._lastHandle)
|
125
|
-
|
126
108
|
if updateTabs:
|
127
109
|
self.tabBackRefs.updateTheme()
|
128
110
|
for tab in self.kwTabs.values():
|
129
111
|
tab.updateTheme()
|
130
|
-
|
131
112
|
return
|
132
113
|
|
133
114
|
def openProjectTasks(self) -> None:
|
@@ -252,7 +233,7 @@ class _ViewPanelBackRefs(QTreeWidget):
|
|
252
233
|
C_VIEW = 2
|
253
234
|
C_TITLE = 3
|
254
235
|
|
255
|
-
D_HANDLE =
|
236
|
+
D_HANDLE = QtUserRole
|
256
237
|
|
257
238
|
def __init__(self, parent: GuiDocViewerPanel) -> None:
|
258
239
|
super().__init__(parent=parent)
|
@@ -260,13 +241,14 @@ class _ViewPanelBackRefs(QTreeWidget):
|
|
260
241
|
self._parent = parent
|
261
242
|
self._treeMap: dict[str, QTreeWidgetItem] = {}
|
262
243
|
|
263
|
-
iPx = SHARED.theme.
|
244
|
+
iPx = SHARED.theme.baseIconHeight
|
245
|
+
iSz = SHARED.theme.baseIconSize
|
264
246
|
cMg = CONFIG.pxInt(6)
|
265
247
|
|
266
248
|
self.setHeaderLabels([self.tr("Document"), "", "", self.tr("First Heading")])
|
267
249
|
self.setIndentation(0)
|
268
250
|
self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
269
|
-
self.setIconSize(
|
251
|
+
self.setIconSize(iSz)
|
270
252
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
271
253
|
|
272
254
|
# Set Header Sizes
|
@@ -368,7 +350,7 @@ class _ViewPanelBackRefs(QTreeWidget):
|
|
368
350
|
trItem.setToolTip(self.C_DOC, nwItem.itemName)
|
369
351
|
trItem.setIcon(self.C_EDIT, self._editIcon)
|
370
352
|
trItem.setIcon(self.C_VIEW, self._viewIcon)
|
371
|
-
trItem.setData(self.C_TITLE,
|
353
|
+
trItem.setData(self.C_TITLE, QtDecoration, hDec)
|
372
354
|
trItem.setText(self.C_TITLE, hItem.title)
|
373
355
|
trItem.setToolTip(self.C_TITLE, hItem.title)
|
374
356
|
trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
|
@@ -393,7 +375,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
393
375
|
C_TITLE = 5
|
394
376
|
C_SHORT = 6
|
395
377
|
|
396
|
-
D_TAG =
|
378
|
+
D_TAG = QtUserRole
|
397
379
|
|
398
380
|
def __init__(self, parent: GuiDocViewerPanel, itemClass: nwItemClass) -> None:
|
399
381
|
super().__init__(parent=parent)
|
@@ -402,7 +384,8 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
402
384
|
self._class = itemClass
|
403
385
|
self._treeMap: dict[str, QTreeWidgetItem] = {}
|
404
386
|
|
405
|
-
iPx = SHARED.theme.
|
387
|
+
iPx = SHARED.theme.baseIconHeight
|
388
|
+
iSz = SHARED.theme.baseIconSize
|
406
389
|
cMg = CONFIG.pxInt(6)
|
407
390
|
|
408
391
|
self.setHeaderLabels([
|
@@ -410,7 +393,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
410
393
|
self.tr("Heading"), self.tr("Short Description")
|
411
394
|
])
|
412
395
|
self.setIndentation(0)
|
413
|
-
self.setIconSize(
|
396
|
+
self.setIconSize(iSz)
|
414
397
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
415
398
|
self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
416
399
|
self.setExpandsOnDoubleClick(False)
|
@@ -486,7 +469,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
|
486
469
|
trItem.setIcon(self.C_DOC, docIcon)
|
487
470
|
trItem.setText(self.C_DOC, nwItem.itemName)
|
488
471
|
trItem.setToolTip(self.C_DOC, nwItem.itemName)
|
489
|
-
trItem.setData(self.C_TITLE,
|
472
|
+
trItem.setData(self.C_TITLE, QtDecoration, hDec)
|
490
473
|
trItem.setText(self.C_TITLE, hItem.title)
|
491
474
|
trItem.setToolTip(self.C_TITLE, hItem.title)
|
492
475
|
trItem.setText(self.C_SHORT, hItem.synopsis)
|
@@ -25,13 +25,14 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
+
from collections.abc import Iterable
|
28
29
|
from time import time
|
29
30
|
|
30
|
-
from PyQt5.QtGui import QTextCursor, QTextDocument
|
31
|
+
from PyQt5.QtGui import QTextBlock, QTextCursor, QTextDocument
|
31
32
|
from PyQt5.QtCore import QObject, pyqtSlot
|
32
|
-
from PyQt5.QtWidgets import
|
33
|
-
from novelwriter import SHARED
|
33
|
+
from PyQt5.QtWidgets import QApplication, QPlainTextDocumentLayout
|
34
34
|
|
35
|
+
from novelwriter import SHARED
|
35
36
|
from novelwriter.gui.dochighlight import GuiDocHighlighter, TextBlockData
|
36
37
|
|
37
38
|
logger = logging.getLogger(__name__)
|
@@ -85,7 +86,7 @@ class GuiTextDocument(QTextDocument):
|
|
85
86
|
self.setUndoRedoEnabled(True)
|
86
87
|
self.blockSignals(False)
|
87
88
|
self._syntax.rehighlight()
|
88
|
-
|
89
|
+
QApplication.processEvents()
|
89
90
|
|
90
91
|
tEnd = time()
|
91
92
|
|
@@ -113,6 +114,16 @@ class GuiTextDocument(QTextDocument):
|
|
113
114
|
return word, cPos, cLen, SHARED.spelling.suggestWords(word)
|
114
115
|
return "", -1, -1, []
|
115
116
|
|
117
|
+
def iterBlockByType(self, cType: int, maxCount: int = 1000) -> Iterable[QTextBlock]:
|
118
|
+
"""Iterate over all text blocks of a given type."""
|
119
|
+
count = 0
|
120
|
+
for i in range(self.blockCount()):
|
121
|
+
block = self.findBlockByNumber(i)
|
122
|
+
if count < maxCount and block.isValid() and block.userState() & cType > 0:
|
123
|
+
count += 1
|
124
|
+
yield block
|
125
|
+
return None
|
126
|
+
|
116
127
|
##
|
117
128
|
# Public Slots
|
118
129
|
##
|
novelwriter/gui/itemdetails.py
CHANGED
@@ -25,30 +25,27 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
-
from
|
29
|
-
|
30
|
-
from PyQt5.QtGui import QFont
|
31
|
-
from PyQt5.QtCore import Qt, pyqtSlot
|
28
|
+
from PyQt5.QtCore import pyqtSlot
|
32
29
|
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
|
33
30
|
|
34
31
|
from novelwriter import CONFIG, SHARED
|
35
32
|
from novelwriter.constants import trConst, nwLabels
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
from novelwriter.types import (
|
34
|
+
QtAlignLeft, QtAlignLeftBase, QtAlignRight, QtAlignRightBase, QtAlignRightMiddle
|
35
|
+
)
|
39
36
|
|
40
37
|
logger = logging.getLogger(__name__)
|
41
38
|
|
42
39
|
|
43
40
|
class GuiItemDetails(QWidget):
|
44
41
|
|
45
|
-
def __init__(self,
|
46
|
-
super().__init__(parent=
|
42
|
+
def __init__(self, parent: QWidget) -> None:
|
43
|
+
super().__init__(parent=parent)
|
47
44
|
|
48
45
|
logger.debug("Create: GuiItemDetails")
|
49
46
|
|
50
47
|
# Internal Variables
|
51
|
-
self.
|
48
|
+
self._handle = None
|
52
49
|
|
53
50
|
# Sizes
|
54
51
|
hSp = CONFIG.pxInt(6)
|
@@ -56,89 +53,89 @@ class GuiItemDetails(QWidget):
|
|
56
53
|
mPx = CONFIG.pxInt(6)
|
57
54
|
fPt = SHARED.theme.fontPointSize
|
58
55
|
|
59
|
-
fntLabel =
|
56
|
+
fntLabel = self.font()
|
60
57
|
fntLabel.setBold(True)
|
61
58
|
fntLabel.setPointSizeF(0.9*fPt)
|
62
59
|
|
63
|
-
fntValue =
|
60
|
+
fntValue = self.font()
|
64
61
|
fntValue.setPointSizeF(0.9*fPt)
|
65
62
|
|
66
63
|
# Label
|
67
|
-
self.labelName = QLabel(self.tr("Label"))
|
64
|
+
self.labelName = QLabel(self.tr("Label"), self)
|
68
65
|
self.labelName.setFont(fntLabel)
|
69
|
-
self.labelName.setAlignment(
|
66
|
+
self.labelName.setAlignment(QtAlignLeftBase)
|
70
67
|
|
71
|
-
self.labelIcon = QLabel("")
|
72
|
-
self.labelIcon.setAlignment(
|
68
|
+
self.labelIcon = QLabel("", self)
|
69
|
+
self.labelIcon.setAlignment(QtAlignRightBase)
|
73
70
|
|
74
|
-
self.labelData = QLabel("")
|
71
|
+
self.labelData = QLabel("", self)
|
75
72
|
self.labelData.setFont(fntValue)
|
76
|
-
self.labelData.setAlignment(
|
73
|
+
self.labelData.setAlignment(QtAlignLeftBase)
|
77
74
|
self.labelData.setWordWrap(True)
|
78
75
|
|
79
76
|
# Status
|
80
|
-
self.statusName = QLabel(self.tr("Status"))
|
77
|
+
self.statusName = QLabel(self.tr("Status"), self)
|
81
78
|
self.statusName.setFont(fntLabel)
|
82
|
-
self.statusName.setAlignment(
|
79
|
+
self.statusName.setAlignment(QtAlignLeft)
|
83
80
|
|
84
|
-
self.statusIcon = QLabel("")
|
85
|
-
self.statusIcon.setAlignment(
|
81
|
+
self.statusIcon = QLabel("", self)
|
82
|
+
self.statusIcon.setAlignment(QtAlignRightMiddle)
|
86
83
|
|
87
|
-
self.statusData = QLabel("")
|
84
|
+
self.statusData = QLabel("", self)
|
88
85
|
self.statusData.setFont(fntValue)
|
89
|
-
self.statusData.setAlignment(
|
86
|
+
self.statusData.setAlignment(QtAlignLeft)
|
90
87
|
|
91
88
|
# Class
|
92
|
-
self.className = QLabel(self.tr("Class"))
|
89
|
+
self.className = QLabel(self.tr("Class"), self)
|
93
90
|
self.className.setFont(fntLabel)
|
94
|
-
self.className.setAlignment(
|
91
|
+
self.className.setAlignment(QtAlignLeft)
|
95
92
|
|
96
|
-
self.classIcon = QLabel("")
|
97
|
-
self.classIcon.setAlignment(
|
93
|
+
self.classIcon = QLabel("", self)
|
94
|
+
self.classIcon.setAlignment(QtAlignRightMiddle)
|
98
95
|
|
99
|
-
self.classData = QLabel("")
|
96
|
+
self.classData = QLabel("", self)
|
100
97
|
self.classData.setFont(fntValue)
|
101
|
-
self.classData.setAlignment(
|
98
|
+
self.classData.setAlignment(QtAlignLeft)
|
102
99
|
|
103
100
|
# Layout
|
104
|
-
self.usageName = QLabel(self.tr("Usage"))
|
101
|
+
self.usageName = QLabel(self.tr("Usage"), self)
|
105
102
|
self.usageName.setFont(fntLabel)
|
106
|
-
self.usageName.setAlignment(
|
103
|
+
self.usageName.setAlignment(QtAlignLeft)
|
107
104
|
|
108
|
-
self.usageIcon = QLabel("")
|
109
|
-
self.usageIcon.setAlignment(
|
105
|
+
self.usageIcon = QLabel("", self)
|
106
|
+
self.usageIcon.setAlignment(QtAlignRightMiddle)
|
110
107
|
|
111
|
-
self.usageData = QLabel("")
|
108
|
+
self.usageData = QLabel("", self)
|
112
109
|
self.usageData.setFont(fntValue)
|
113
|
-
self.usageData.setAlignment(
|
110
|
+
self.usageData.setAlignment(QtAlignLeft)
|
114
111
|
self.usageData.setWordWrap(True)
|
115
112
|
|
116
113
|
# Character Count
|
117
|
-
self.cCountName = QLabel(" "+self.tr("Characters"))
|
114
|
+
self.cCountName = QLabel(" "+self.tr("Characters"), self)
|
118
115
|
self.cCountName.setFont(fntLabel)
|
119
|
-
self.cCountName.setAlignment(
|
116
|
+
self.cCountName.setAlignment(QtAlignRight)
|
120
117
|
|
121
|
-
self.cCountData = QLabel("")
|
118
|
+
self.cCountData = QLabel("", self)
|
122
119
|
self.cCountData.setFont(fntValue)
|
123
|
-
self.cCountData.setAlignment(
|
120
|
+
self.cCountData.setAlignment(QtAlignRight)
|
124
121
|
|
125
122
|
# Word Count
|
126
|
-
self.wCountName = QLabel(" "+self.tr("Words"))
|
123
|
+
self.wCountName = QLabel(" "+self.tr("Words"), self)
|
127
124
|
self.wCountName.setFont(fntLabel)
|
128
|
-
self.wCountName.setAlignment(
|
125
|
+
self.wCountName.setAlignment(QtAlignRight)
|
129
126
|
|
130
|
-
self.wCountData = QLabel("")
|
127
|
+
self.wCountData = QLabel("", self)
|
131
128
|
self.wCountData.setFont(fntValue)
|
132
|
-
self.wCountData.setAlignment(
|
129
|
+
self.wCountData.setAlignment(QtAlignRight)
|
133
130
|
|
134
131
|
# Paragraph Count
|
135
|
-
self.pCountName = QLabel(" "+self.tr("Paragraphs"))
|
132
|
+
self.pCountName = QLabel(" "+self.tr("Paragraphs"), self)
|
136
133
|
self.pCountName.setFont(fntLabel)
|
137
|
-
self.pCountName.setAlignment(
|
134
|
+
self.pCountName.setAlignment(QtAlignRight)
|
138
135
|
|
139
|
-
self.pCountData = QLabel("")
|
136
|
+
self.pCountData = QLabel("", self)
|
140
137
|
self.pCountData.setFont(fntValue)
|
141
|
-
self.pCountData.setAlignment(
|
138
|
+
self.pCountData.setAlignment(QtAlignRight)
|
142
139
|
|
143
140
|
# Assemble
|
144
141
|
self.mainBox = QGridLayout(self)
|
@@ -194,7 +191,7 @@ class GuiItemDetails(QWidget):
|
|
194
191
|
|
195
192
|
def clearDetails(self) -> None:
|
196
193
|
"""Clear all the data values."""
|
197
|
-
self.
|
194
|
+
self._handle = None
|
198
195
|
self.labelIcon.clear()
|
199
196
|
self.labelData.clear()
|
200
197
|
self.statusIcon.clear()
|
@@ -210,11 +207,11 @@ class GuiItemDetails(QWidget):
|
|
210
207
|
|
211
208
|
def refreshDetails(self) -> None:
|
212
209
|
"""Reload the content of the details panel."""
|
213
|
-
self.updateViewBox(self.
|
210
|
+
self.updateViewBox(self._handle)
|
214
211
|
|
215
212
|
def updateTheme(self) -> None:
|
216
213
|
"""Update theme elements."""
|
217
|
-
self.updateViewBox(self.
|
214
|
+
self.updateViewBox(self._handle)
|
218
215
|
return
|
219
216
|
|
220
217
|
##
|
@@ -233,8 +230,8 @@ class GuiItemDetails(QWidget):
|
|
233
230
|
self.clearDetails()
|
234
231
|
return
|
235
232
|
|
236
|
-
self.
|
237
|
-
iPx = int(round(0.
|
233
|
+
self._handle = tHandle
|
234
|
+
iPx = int(round(0.9*SHARED.theme.baseIconHeight))
|
238
235
|
|
239
236
|
# Label
|
240
237
|
# =====
|
@@ -295,7 +292,7 @@ class GuiItemDetails(QWidget):
|
|
295
292
|
"""Update the counts if the handle is the same as the one we're
|
296
293
|
already showing. Otherwise, do nothing.
|
297
294
|
"""
|
298
|
-
if tHandle == self.
|
295
|
+
if tHandle == self._handle:
|
299
296
|
self.cCountData.setText(f"{cC:n}")
|
300
297
|
self.wCountData.setText(f"{wC:n}")
|
301
298
|
self.pCountData.setText(f"{pC:n}")
|
novelwriter/gui/mainmenu.py
CHANGED
@@ -33,9 +33,9 @@ from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
|
|
33
33
|
from PyQt5.QtWidgets import QMenuBar, QAction
|
34
34
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
|
-
from novelwriter.enum import nwDocAction, nwDocInsert, nwWidget
|
37
36
|
from novelwriter.common import openExternalPath
|
38
37
|
from novelwriter.constants import nwConst, trConst, nwKeyWords, nwLabels, nwUnicode
|
38
|
+
from novelwriter.enum import nwDocAction, nwDocInsert, nwView, nwWidget
|
39
39
|
from novelwriter.extensions.eventfilters import StatusTipFilter
|
40
40
|
|
41
41
|
if TYPE_CHECKING: # pragma: no cover
|
@@ -55,6 +55,7 @@ class GuiMainMenu(QMenuBar):
|
|
55
55
|
requestDocInsertText = pyqtSignal(str)
|
56
56
|
requestDocKeyWordInsert = pyqtSignal(str)
|
57
57
|
requestFocusChange = pyqtSignal(nwWidget)
|
58
|
+
requestViewChange = pyqtSignal(nwView)
|
58
59
|
|
59
60
|
def __init__(self, mainGui: GuiMain) -> None:
|
60
61
|
super().__init__(parent=mainGui)
|
@@ -196,12 +197,12 @@ class GuiMainMenu(QMenuBar):
|
|
196
197
|
# Document > Open
|
197
198
|
self.aOpenDoc = self.docuMenu.addAction(self.tr("Open Document"))
|
198
199
|
self.aOpenDoc.setShortcut("Ctrl+O")
|
199
|
-
self.aOpenDoc.triggered.connect(
|
200
|
+
self.aOpenDoc.triggered.connect(self.mainGui.openSelectedItem)
|
200
201
|
|
201
202
|
# Document > Save
|
202
203
|
self.aSaveDoc = self.docuMenu.addAction(self.tr("Save Document"))
|
203
204
|
self.aSaveDoc.setShortcut("Ctrl+S")
|
204
|
-
self.aSaveDoc.triggered.connect(
|
205
|
+
self.aSaveDoc.triggered.connect(self.mainGui.saveDocument)
|
205
206
|
|
206
207
|
# Document > Close
|
207
208
|
self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document"))
|
@@ -219,7 +220,7 @@ class GuiMainMenu(QMenuBar):
|
|
219
220
|
# Document > Close Preview
|
220
221
|
self.aCloseView = self.docuMenu.addAction(self.tr("Close Document View"))
|
221
222
|
self.aCloseView.setShortcut("Ctrl+Shift+R")
|
222
|
-
self.aCloseView.triggered.connect(
|
223
|
+
self.aCloseView.triggered.connect(self.mainGui.closeDocViewer)
|
223
224
|
|
224
225
|
# Document > Separator
|
225
226
|
self.docuMenu.addSeparator()
|
@@ -671,6 +672,12 @@ class GuiMainMenu(QMenuBar):
|
|
671
672
|
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
|
672
673
|
)
|
673
674
|
|
675
|
+
# Shortcode Mark
|
676
|
+
self.aScMark = self.mShortcodes.addAction(self.tr("Highlight"))
|
677
|
+
self.aScMark.triggered.connect(
|
678
|
+
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
|
679
|
+
)
|
680
|
+
|
674
681
|
# Shortcode Superscript
|
675
682
|
self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript"))
|
676
683
|
self.aScSuper.triggered.connect(
|
@@ -686,29 +693,29 @@ class GuiMainMenu(QMenuBar):
|
|
686
693
|
# Format > Separator
|
687
694
|
self.fmtMenu.addSeparator()
|
688
695
|
|
689
|
-
# Format >
|
690
|
-
self.aFmtHead1 = self.fmtMenu.addAction(self.tr("
|
696
|
+
# Format > Heading 1 (Partition)
|
697
|
+
self.aFmtHead1 = self.fmtMenu.addAction(self.tr("Heading 1 (Partition)"))
|
691
698
|
self.aFmtHead1.setShortcut("Ctrl+1")
|
692
699
|
self.aFmtHead1.triggered.connect(
|
693
700
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1)
|
694
701
|
)
|
695
702
|
|
696
|
-
# Format >
|
697
|
-
self.aFmtHead2 = self.fmtMenu.addAction(self.tr("
|
703
|
+
# Format > Heading 2 (Chapter)
|
704
|
+
self.aFmtHead2 = self.fmtMenu.addAction(self.tr("Heading 2 (Chapter)"))
|
698
705
|
self.aFmtHead2.setShortcut("Ctrl+2")
|
699
706
|
self.aFmtHead2.triggered.connect(
|
700
707
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2)
|
701
708
|
)
|
702
709
|
|
703
|
-
# Format >
|
704
|
-
self.aFmtHead3 = self.fmtMenu.addAction(self.tr("
|
710
|
+
# Format > Heading 3 (Scene)
|
711
|
+
self.aFmtHead3 = self.fmtMenu.addAction(self.tr("Heading 3 (Scene)"))
|
705
712
|
self.aFmtHead3.setShortcut("Ctrl+3")
|
706
713
|
self.aFmtHead3.triggered.connect(
|
707
714
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3)
|
708
715
|
)
|
709
716
|
|
710
|
-
# Format >
|
711
|
-
self.aFmtHead4 = self.fmtMenu.addAction(self.tr("
|
717
|
+
# Format > Heading 4 (Section)
|
718
|
+
self.aFmtHead4 = self.fmtMenu.addAction(self.tr("Heading 4 (Section)"))
|
712
719
|
self.aFmtHead4.setShortcut("Ctrl+4")
|
713
720
|
self.aFmtHead4.triggered.connect(
|
714
721
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4)
|
@@ -729,6 +736,12 @@ class GuiMainMenu(QMenuBar):
|
|
729
736
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN)
|
730
737
|
)
|
731
738
|
|
739
|
+
# Format > Alternative Scene
|
740
|
+
self.aFmtHardSc = self.fmtMenu.addAction(self.tr("Alternative Scene"))
|
741
|
+
self.aFmtHardSc.triggered.connect(
|
742
|
+
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_HSC)
|
743
|
+
)
|
744
|
+
|
732
745
|
# Format > Separator
|
733
746
|
self.fmtMenu.addSeparator()
|
734
747
|
|
@@ -797,14 +810,14 @@ class GuiMainMenu(QMenuBar):
|
|
797
810
|
# Format > Separator
|
798
811
|
self.fmtMenu.addSeparator()
|
799
812
|
|
800
|
-
# Format > Replace Single Quotes
|
801
|
-
self.aFmtReplSng = self.fmtMenu.addAction(self.tr("
|
813
|
+
# Format > Replace Straight Single Quotes
|
814
|
+
self.aFmtReplSng = self.fmtMenu.addAction(self.tr("Replace Straight Single Quotes"))
|
802
815
|
self.aFmtReplSng.triggered.connect(
|
803
816
|
lambda: self.requestDocAction.emit(nwDocAction.REPL_SNG)
|
804
817
|
)
|
805
818
|
|
806
|
-
# Format > Replace Double Quotes
|
807
|
-
self.aFmtReplDbl = self.fmtMenu.addAction(self.tr("
|
819
|
+
# Format > Replace Straight Double Quotes
|
820
|
+
self.aFmtReplDbl = self.fmtMenu.addAction(self.tr("Replace Straight Double Quotes"))
|
808
821
|
self.aFmtReplDbl.triggered.connect(
|
809
822
|
lambda: self.requestDocAction.emit(nwDocAction.REPL_DBL)
|
810
823
|
)
|
@@ -849,6 +862,14 @@ class GuiMainMenu(QMenuBar):
|
|
849
862
|
self.aReplaceNext.setShortcut("Ctrl+Shift+1")
|
850
863
|
self.aReplaceNext.triggered.connect(lambda: self.mainGui.docEditor.replaceNext())
|
851
864
|
|
865
|
+
# Search > Separator
|
866
|
+
self.srcMenu.addSeparator()
|
867
|
+
|
868
|
+
# Search > Find in Project
|
869
|
+
self.aFindProj = self.srcMenu.addAction(self.tr("Find in Project"))
|
870
|
+
self.aFindProj.setShortcut("Ctrl+Shift+F")
|
871
|
+
self.aFindProj.triggered.connect(lambda: self.requestViewChange.emit(nwView.SEARCH))
|
872
|
+
|
852
873
|
return
|
853
874
|
|
854
875
|
def _buildToolsMenu(self) -> None:
|