novelWriter 2.3rc1__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.3rc1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/RECORD +119 -109
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/WHEEL +1 -1
- novelWriter-2.4.dist-info/entry_points.txt +2 -0
- 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/i18n/project_nl_NL.json +11 -0
- novelwriter/assets/i18n/project_pt_BR.json +11 -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/cyberpunk_night.conf +26 -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/tango.conf +23 -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/assets/themes/cyberpunk_night.conf +29 -0
- 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 +11 -15
- novelwriter/core/projectxml.py +3 -2
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/spellcheck.py +3 -3
- novelwriter/core/status.py +6 -5
- novelwriter/core/storage.py +16 -6
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +417 -237
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +386 -351
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/about.py +10 -12
- 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 +18 -15
- novelwriter/enum.py +17 -14
- novelwriter/error.py +14 -12
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +23 -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 -17
- novelwriter/gui/noveltree.py +31 -37
- novelwriter/gui/outline.py +120 -98
- novelwriter/gui/projtree.py +114 -112
- novelwriter/gui/search.py +362 -0
- novelwriter/gui/sidebar.py +36 -45
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +116 -34
- novelwriter/guimain.py +216 -207
- 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 +263 -125
- novelwriter/tools/noveldetails.py +21 -19
- novelwriter/tools/welcome.py +59 -57
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
- 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.3rc1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3rc1.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()
|
@@ -230,7 +231,6 @@ class GuiMainMenu(QMenuBar):
|
|
230
231
|
|
231
232
|
# Document > Import From File
|
232
233
|
self.aImportFile = self.docuMenu.addAction(self.tr("Import Text from File"))
|
233
|
-
self.aImportFile.setShortcut("Ctrl+Shift+I")
|
234
234
|
self.aImportFile.triggered.connect(lambda: self.mainGui.importDocument())
|
235
235
|
|
236
236
|
return
|
@@ -672,6 +672,12 @@ class GuiMainMenu(QMenuBar):
|
|
672
672
|
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
|
673
673
|
)
|
674
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
|
+
|
675
681
|
# Shortcode Superscript
|
676
682
|
self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript"))
|
677
683
|
self.aScSuper.triggered.connect(
|
@@ -687,29 +693,29 @@ class GuiMainMenu(QMenuBar):
|
|
687
693
|
# Format > Separator
|
688
694
|
self.fmtMenu.addSeparator()
|
689
695
|
|
690
|
-
# Format >
|
691
|
-
self.aFmtHead1 = self.fmtMenu.addAction(self.tr("
|
696
|
+
# Format > Heading 1 (Partition)
|
697
|
+
self.aFmtHead1 = self.fmtMenu.addAction(self.tr("Heading 1 (Partition)"))
|
692
698
|
self.aFmtHead1.setShortcut("Ctrl+1")
|
693
699
|
self.aFmtHead1.triggered.connect(
|
694
700
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1)
|
695
701
|
)
|
696
702
|
|
697
|
-
# Format >
|
698
|
-
self.aFmtHead2 = self.fmtMenu.addAction(self.tr("
|
703
|
+
# Format > Heading 2 (Chapter)
|
704
|
+
self.aFmtHead2 = self.fmtMenu.addAction(self.tr("Heading 2 (Chapter)"))
|
699
705
|
self.aFmtHead2.setShortcut("Ctrl+2")
|
700
706
|
self.aFmtHead2.triggered.connect(
|
701
707
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2)
|
702
708
|
)
|
703
709
|
|
704
|
-
# Format >
|
705
|
-
self.aFmtHead3 = self.fmtMenu.addAction(self.tr("
|
710
|
+
# Format > Heading 3 (Scene)
|
711
|
+
self.aFmtHead3 = self.fmtMenu.addAction(self.tr("Heading 3 (Scene)"))
|
706
712
|
self.aFmtHead3.setShortcut("Ctrl+3")
|
707
713
|
self.aFmtHead3.triggered.connect(
|
708
714
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3)
|
709
715
|
)
|
710
716
|
|
711
|
-
# Format >
|
712
|
-
self.aFmtHead4 = self.fmtMenu.addAction(self.tr("
|
717
|
+
# Format > Heading 4 (Section)
|
718
|
+
self.aFmtHead4 = self.fmtMenu.addAction(self.tr("Heading 4 (Section)"))
|
713
719
|
self.aFmtHead4.setShortcut("Ctrl+4")
|
714
720
|
self.aFmtHead4.triggered.connect(
|
715
721
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4)
|
@@ -730,6 +736,12 @@ class GuiMainMenu(QMenuBar):
|
|
730
736
|
lambda: self.requestDocAction.emit(nwDocAction.BLOCK_UNN)
|
731
737
|
)
|
732
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
|
+
|
733
745
|
# Format > Separator
|
734
746
|
self.fmtMenu.addSeparator()
|
735
747
|
|
@@ -798,14 +810,14 @@ class GuiMainMenu(QMenuBar):
|
|
798
810
|
# Format > Separator
|
799
811
|
self.fmtMenu.addSeparator()
|
800
812
|
|
801
|
-
# Format > Replace Single Quotes
|
802
|
-
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"))
|
803
815
|
self.aFmtReplSng.triggered.connect(
|
804
816
|
lambda: self.requestDocAction.emit(nwDocAction.REPL_SNG)
|
805
817
|
)
|
806
818
|
|
807
|
-
# Format > Replace Double Quotes
|
808
|
-
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"))
|
809
821
|
self.aFmtReplDbl.triggered.connect(
|
810
822
|
lambda: self.requestDocAction.emit(nwDocAction.REPL_DBL)
|
811
823
|
)
|
@@ -850,6 +862,14 @@ class GuiMainMenu(QMenuBar):
|
|
850
862
|
self.aReplaceNext.setShortcut("Ctrl+Shift+1")
|
851
863
|
self.aReplaceNext.triggered.connect(lambda: self.mainGui.docEditor.replaceNext())
|
852
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
|
+
|
853
873
|
return
|
854
874
|
|
855
875
|
def _buildToolsMenu(self) -> None:
|