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
@@ -29,7 +29,7 @@ import logging
|
|
29
29
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
30
30
|
from PyQt5.QtGui import QCloseEvent, QColor
|
31
31
|
from PyQt5.QtWidgets import (
|
32
|
-
QAbstractItemView, QApplication, QColorDialog,
|
32
|
+
QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
|
33
33
|
QHBoxLayout, QLineEdit, QMenu, QStackedWidget, QToolButton, QTreeWidget,
|
34
34
|
QTreeWidgetItem, QVBoxLayout, QWidget
|
35
35
|
)
|
@@ -40,7 +40,7 @@ from novelwriter.constants import nwLabels, trConst
|
|
40
40
|
from novelwriter.core.status import NWStatus, StatusEntry
|
41
41
|
from novelwriter.enum import nwStatusShape
|
42
42
|
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
|
43
|
-
from novelwriter.extensions.modified import NComboBox, NIconToolButton
|
43
|
+
from novelwriter.extensions.modified import NComboBox, NDialog, NIconToolButton
|
44
44
|
from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
45
45
|
from novelwriter.extensions.switch import NSwitch
|
46
46
|
from novelwriter.types import (
|
@@ -51,14 +51,14 @@ from novelwriter.types import (
|
|
51
51
|
logger = logging.getLogger(__name__)
|
52
52
|
|
53
53
|
|
54
|
-
class GuiProjectSettings(
|
54
|
+
class GuiProjectSettings(NDialog):
|
55
55
|
|
56
56
|
PAGE_SETTINGS = 0
|
57
57
|
PAGE_STATUS = 1
|
58
58
|
PAGE_IMPORT = 2
|
59
59
|
PAGE_REPLACE = 3
|
60
60
|
|
61
|
-
newProjectSettingsReady = pyqtSignal(
|
61
|
+
newProjectSettingsReady = pyqtSignal()
|
62
62
|
|
63
63
|
def __init__(self, parent: QWidget, gotoPage: int = PAGE_SETTINGS) -> None:
|
64
64
|
super().__init__(parent=parent)
|
@@ -76,8 +76,8 @@ class GuiProjectSettings(QDialog):
|
|
76
76
|
|
77
77
|
# Title
|
78
78
|
self.titleLabel = NColourLabel(
|
79
|
-
self.tr("Project Settings"), SHARED.theme.helpText,
|
80
|
-
|
79
|
+
self.tr("Project Settings"), self, color=SHARED.theme.helpText,
|
80
|
+
scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
|
81
81
|
)
|
82
82
|
|
83
83
|
# SideBar
|
@@ -92,7 +92,7 @@ class GuiProjectSettings(QDialog):
|
|
92
92
|
# Buttons
|
93
93
|
self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogCancel, self)
|
94
94
|
self.buttonBox.accepted.connect(self._doSave)
|
95
|
-
self.buttonBox.rejected.connect(self.
|
95
|
+
self.buttonBox.rejected.connect(self.reject)
|
96
96
|
|
97
97
|
# Content
|
98
98
|
SHARED.project.countStatus()
|
@@ -147,7 +147,7 @@ class GuiProjectSettings(QDialog):
|
|
147
147
|
"""Capture the user closing the window and save settings."""
|
148
148
|
self._saveSettings()
|
149
149
|
event.accept()
|
150
|
-
self.
|
150
|
+
self.softDelete()
|
151
151
|
return
|
152
152
|
|
153
153
|
##
|
@@ -175,7 +175,7 @@ class GuiProjectSettings(QDialog):
|
|
175
175
|
projAuthor = self.settingsPage.projAuthor.text()
|
176
176
|
projLang = self.settingsPage.projLang.currentData()
|
177
177
|
spellLang = self.settingsPage.spellLang.currentData()
|
178
|
-
doBackup = not self.settingsPage.
|
178
|
+
doBackup = not self.settingsPage.noBackup.isChecked()
|
179
179
|
|
180
180
|
project.data.setName(projName)
|
181
181
|
project.data.setAuthor(projAuthor)
|
@@ -183,23 +183,19 @@ class GuiProjectSettings(QDialog):
|
|
183
183
|
project.data.setSpellLang(spellLang)
|
184
184
|
project.setProjectLang(projLang)
|
185
185
|
|
186
|
-
rebuildTrees = False
|
187
|
-
|
188
186
|
if self.statusPage.changed:
|
189
187
|
logger.debug("Updating status labels")
|
190
188
|
project.data.itemStatus.update(self.statusPage.getNewList())
|
191
|
-
rebuildTrees = True
|
192
189
|
|
193
190
|
if self.importPage.changed:
|
194
191
|
logger.debug("Updating importance labels")
|
195
192
|
project.data.itemImport.update(self.importPage.getNewList())
|
196
|
-
rebuildTrees = True
|
197
193
|
|
198
194
|
if self.replacePage.changed:
|
199
195
|
logger.debug("Updating auto-replace settings")
|
200
196
|
project.data.setAutoReplace(self.replacePage.getNewList())
|
201
197
|
|
202
|
-
self.newProjectSettingsReady.emit(
|
198
|
+
self.newProjectSettingsReady.emit()
|
203
199
|
QApplication.processEvents()
|
204
200
|
self.close()
|
205
201
|
|
@@ -289,10 +285,10 @@ class _SettingsPage(NScrollableForm):
|
|
289
285
|
self.spellLang.setCurrentIndex(idx)
|
290
286
|
|
291
287
|
# Backup on Close
|
292
|
-
self.
|
293
|
-
self.
|
288
|
+
self.noBackup = NSwitch(self)
|
289
|
+
self.noBackup.setChecked(not data.doBackup)
|
294
290
|
self.addRow(
|
295
|
-
self.tr("Disable backup on close"), self.
|
291
|
+
self.tr("Disable backup on close"), self.noBackup,
|
296
292
|
self.tr("Overrides main preferences.")
|
297
293
|
)
|
298
294
|
|
@@ -345,7 +341,7 @@ class _StatusPage(NFixedPage):
|
|
345
341
|
|
346
342
|
# Title
|
347
343
|
self.pageTitle = NColourLabel(
|
348
|
-
pageLabel, SHARED.theme.helpText,
|
344
|
+
pageLabel, self, color=SHARED.theme.helpText,
|
349
345
|
scale=NColourLabel.HEADER_SCALE
|
350
346
|
)
|
351
347
|
|
@@ -637,8 +633,8 @@ class _ReplacePage(NFixedPage):
|
|
637
633
|
|
638
634
|
# Title
|
639
635
|
self.pageTitle = NColourLabel(
|
640
|
-
self.tr("Text Auto-Replace for Preview and Build"),
|
641
|
-
SHARED.theme.helpText,
|
636
|
+
self.tr("Text Auto-Replace for Preview and Build"), self,
|
637
|
+
color=SHARED.theme.helpText, scale=NColourLabel.HEADER_SCALE
|
642
638
|
)
|
643
639
|
|
644
640
|
# List Box
|
novelwriter/dialogs/quotes.py
CHANGED
@@ -28,18 +28,22 @@ import logging
|
|
28
28
|
from PyQt5.QtCore import QSize, pyqtSlot
|
29
29
|
from PyQt5.QtGui import QFontMetrics
|
30
30
|
from PyQt5.QtWidgets import (
|
31
|
-
|
31
|
+
QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
|
32
32
|
QListWidgetItem, QVBoxLayout, QWidget
|
33
33
|
)
|
34
34
|
|
35
35
|
from novelwriter import CONFIG
|
36
36
|
from novelwriter.constants import nwQuotes, trConst
|
37
|
-
from novelwriter.
|
37
|
+
from novelwriter.extensions.modified import NDialog
|
38
|
+
from novelwriter.types import (
|
39
|
+
QtAccepted, QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk,
|
40
|
+
QtUserRole
|
41
|
+
)
|
38
42
|
|
39
43
|
logger = logging.getLogger(__name__)
|
40
44
|
|
41
45
|
|
42
|
-
class GuiQuoteSelect(
|
46
|
+
class GuiQuoteSelect(NDialog):
|
43
47
|
|
44
48
|
_selected = ""
|
45
49
|
|
@@ -126,8 +130,8 @@ class GuiQuoteSelect(QDialog):
|
|
126
130
|
cls = GuiQuoteSelect(parent, current=current)
|
127
131
|
cls.exec()
|
128
132
|
quote = cls._selected
|
129
|
-
accepted = cls.result() ==
|
130
|
-
cls.
|
133
|
+
accepted = cls.result() == QtAccepted
|
134
|
+
cls.softDelete()
|
131
135
|
return quote, accepted
|
132
136
|
|
133
137
|
##
|
novelwriter/dialogs/wordlist.py
CHANGED
@@ -30,7 +30,7 @@ from pathlib import Path
|
|
30
30
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
31
31
|
from PyQt5.QtGui import QCloseEvent
|
32
32
|
from PyQt5.QtWidgets import (
|
33
|
-
QAbstractItemView, QApplication,
|
33
|
+
QAbstractItemView, QApplication, QDialogButtonBox, QFileDialog,
|
34
34
|
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout, QWidget
|
35
35
|
)
|
36
36
|
|
@@ -38,13 +38,13 @@ from novelwriter import CONFIG, SHARED
|
|
38
38
|
from novelwriter.common import formatFileFilter
|
39
39
|
from novelwriter.core.spellcheck import UserDictionary
|
40
40
|
from novelwriter.extensions.configlayout import NColourLabel
|
41
|
-
from novelwriter.extensions.modified import NIconToolButton
|
41
|
+
from novelwriter.extensions.modified import NDialog, NIconToolButton
|
42
42
|
from novelwriter.types import QtDialogClose, QtDialogSave
|
43
43
|
|
44
44
|
logger = logging.getLogger(__name__)
|
45
45
|
|
46
46
|
|
47
|
-
class GuiWordList(
|
47
|
+
class GuiWordList(NDialog):
|
48
48
|
|
49
49
|
newWordListReady = pyqtSignal()
|
50
50
|
|
@@ -69,7 +69,7 @@ class GuiWordList(QDialog):
|
|
69
69
|
|
70
70
|
# Header
|
71
71
|
self.headLabel = NColourLabel(
|
72
|
-
self.tr("Project Word List"), SHARED.theme.helpText,
|
72
|
+
self.tr("Project Word List"), self, color=SHARED.theme.helpText,
|
73
73
|
scale=NColourLabel.HEADER_SCALE
|
74
74
|
)
|
75
75
|
|
@@ -109,7 +109,7 @@ class GuiWordList(QDialog):
|
|
109
109
|
# Buttons
|
110
110
|
self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogClose, self)
|
111
111
|
self.buttonBox.accepted.connect(self._doSave)
|
112
|
-
self.buttonBox.rejected.connect(self.
|
112
|
+
self.buttonBox.rejected.connect(self.reject)
|
113
113
|
|
114
114
|
# Assemble
|
115
115
|
self.outerBox = QVBoxLayout()
|
@@ -140,7 +140,7 @@ class GuiWordList(QDialog):
|
|
140
140
|
"""Capture the close event and perform cleanup."""
|
141
141
|
self._saveGuiSettings()
|
142
142
|
event.accept()
|
143
|
-
self.
|
143
|
+
self.softDelete()
|
144
144
|
return
|
145
145
|
|
146
146
|
##
|
novelwriter/enum.py
CHANGED
@@ -148,12 +148,11 @@ class nwView(Enum):
|
|
148
148
|
SEARCH = 4
|
149
149
|
|
150
150
|
|
151
|
-
class
|
151
|
+
class nwFocus(Enum):
|
152
152
|
|
153
|
-
TREE
|
154
|
-
|
155
|
-
|
156
|
-
OUTLINE = 4
|
153
|
+
TREE = 1
|
154
|
+
DOCUMENT = 2
|
155
|
+
OUTLINE = 3
|
157
156
|
|
158
157
|
|
159
158
|
class nwOutline(Enum):
|
@@ -203,7 +203,7 @@ class NScrollableForm(QScrollArea):
|
|
203
203
|
|
204
204
|
if helpText:
|
205
205
|
qHelp = NColourLabel(
|
206
|
-
str(helpText), color=self._helpCol,
|
206
|
+
str(helpText), self, color=self._helpCol,
|
207
207
|
scale=self._fontScale, wrap=True, indent=self._indent
|
208
208
|
)
|
209
209
|
labelBox = QVBoxLayout()
|
@@ -252,11 +252,20 @@ class NColourLabel(QLabel):
|
|
252
252
|
HELP_SCALE = DEFAULT_SCALE
|
253
253
|
HEADER_SCALE = 1.25
|
254
254
|
|
255
|
-
|
256
|
-
|
257
|
-
|
255
|
+
_state = None
|
256
|
+
|
257
|
+
def __init__(
|
258
|
+
self, text: str, parent: QWidget, *,
|
259
|
+
color: QColor | None = None, faded: QColor | None = None,
|
260
|
+
scale: float = HELP_SCALE, wrap: bool = False, indent: int = 0,
|
261
|
+
bold: bool = False
|
262
|
+
) -> None:
|
258
263
|
super().__init__(text, parent=parent)
|
259
264
|
|
265
|
+
default = self.palette().windowText().color()
|
266
|
+
self._color = color or default
|
267
|
+
self._faded = faded or default
|
268
|
+
|
260
269
|
font = self.font()
|
261
270
|
font.setPointSizeF(scale*font.pointSizeF())
|
262
271
|
font.setWeight(QFont.Weight.Bold if bold else QFont.Weight.Normal)
|
@@ -268,7 +277,32 @@ class NColourLabel(QLabel):
|
|
268
277
|
self.setFont(font)
|
269
278
|
self.setIndent(indent)
|
270
279
|
self.setWordWrap(wrap)
|
280
|
+
self.setColorState(True)
|
281
|
+
|
282
|
+
return
|
283
|
+
|
284
|
+
def setTextColors(self, *, color: QColor | None = None, faded: QColor | None = None) -> None:
|
285
|
+
"""Set or update the text colours."""
|
286
|
+
self._color = color or self._color
|
287
|
+
self._faded = faded or self._faded
|
288
|
+
self._refeshTextColor()
|
289
|
+
return
|
290
|
+
|
291
|
+
def setColorState(self, state: bool) -> None:
|
292
|
+
"""Change the colour state."""
|
293
|
+
if self._state is not state:
|
294
|
+
self._state = state
|
295
|
+
self._refeshTextColor()
|
296
|
+
return
|
271
297
|
|
298
|
+
def _refeshTextColor(self) -> None:
|
299
|
+
"""Refresh the colour of the text on the label."""
|
300
|
+
palette = self.palette()
|
301
|
+
palette.setColor(
|
302
|
+
QPalette.ColorRole.WindowText,
|
303
|
+
self._color if self._state else self._faded,
|
304
|
+
)
|
305
|
+
self.setPalette(palette)
|
272
306
|
return
|
273
307
|
|
274
308
|
|
@@ -30,7 +30,7 @@ from __future__ import annotations
|
|
30
30
|
from enum import Enum
|
31
31
|
from typing import TYPE_CHECKING
|
32
32
|
|
33
|
-
from PyQt5.QtCore import QSize, Qt
|
33
|
+
from PyQt5.QtCore import QSize, Qt, pyqtSlot
|
34
34
|
from PyQt5.QtGui import QWheelEvent
|
35
35
|
from PyQt5.QtWidgets import (
|
36
36
|
QApplication, QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton,
|
@@ -43,7 +43,26 @@ if TYPE_CHECKING: # pragma: no cover
|
|
43
43
|
from novelwriter.guimain import GuiMain
|
44
44
|
|
45
45
|
|
46
|
-
class
|
46
|
+
class NDialog(QDialog):
|
47
|
+
|
48
|
+
def softDelete(self) -> None:
|
49
|
+
"""Since calling deleteLater is sometimes not safe from Python,
|
50
|
+
as the C++ object can be deleted before the Python process is
|
51
|
+
done with the object, we instead set the dialog's parent to None
|
52
|
+
so that it gets garbage collected when it runs out of scope.
|
53
|
+
"""
|
54
|
+
self.setParent(None) # type: ignore
|
55
|
+
return
|
56
|
+
|
57
|
+
@pyqtSlot()
|
58
|
+
def reject(self) -> None:
|
59
|
+
"""Overload the reject slot and also call close."""
|
60
|
+
super().reject()
|
61
|
+
self.close()
|
62
|
+
return
|
63
|
+
|
64
|
+
|
65
|
+
class NToolDialog(NDialog):
|
47
66
|
|
48
67
|
def __init__(self, parent: GuiMain) -> None:
|
49
68
|
super().__init__(parent=parent)
|
@@ -62,7 +81,7 @@ class NToolDialog(QDialog):
|
|
62
81
|
return
|
63
82
|
|
64
83
|
|
65
|
-
class NNonBlockingDialog(
|
84
|
+
class NNonBlockingDialog(NDialog):
|
66
85
|
|
67
86
|
def __init__(self, parent: QWidget | None = None) -> None:
|
68
87
|
super().__init__(parent=parent)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
"""
|
2
|
-
novelWriter – Custom Widget: Progress
|
3
|
-
|
2
|
+
novelWriter – Custom Widget: Progress Bars
|
3
|
+
==========================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2023-06-07 [2.1b1]
|
6
|
+
Created: 2023-06-07 [2.1b1] NProgressCircle
|
7
|
+
Created: 2023-06-09 [2.1b1] NProgressSimple
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
10
|
Copyright 2018–2024, Veronica Berglyd Olsen
|
@@ -101,3 +102,25 @@ class NProgressCircle(QProgressBar):
|
|
101
102
|
painter.setPen(self._tColor)
|
102
103
|
painter.drawText(self._cRect, QtAlignCenter, self._text or f"{progress:.1f} %")
|
103
104
|
return
|
105
|
+
|
106
|
+
|
107
|
+
class NProgressSimple(QProgressBar):
|
108
|
+
"""Extension: Simple Progress Widget
|
109
|
+
|
110
|
+
A custom widget that paints a plain bar with no other styling.
|
111
|
+
"""
|
112
|
+
|
113
|
+
def __init__(self, parent: QWidget) -> None:
|
114
|
+
super().__init__(parent=parent)
|
115
|
+
return
|
116
|
+
|
117
|
+
def paintEvent(self, event: QPaintEvent) -> None:
|
118
|
+
"""Custom painter for the progress bar."""
|
119
|
+
if (value := self.value()) > 0:
|
120
|
+
progress = ceil(self.width()*float(value)/self.maximum())
|
121
|
+
painter = QPainter(self)
|
122
|
+
painter.setRenderHint(QtPaintAnitAlias, True)
|
123
|
+
painter.setPen(self.palette().highlight().color())
|
124
|
+
painter.setBrush(self.palette().highlight())
|
125
|
+
painter.drawRect(0, 0, progress, self.height())
|
126
|
+
return
|
@@ -25,44 +25,56 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
-
from typing import Literal
|
29
|
-
|
30
28
|
from PyQt5.QtGui import QColor, QPainter, QPaintEvent
|
31
29
|
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
32
30
|
|
33
|
-
from novelwriter
|
31
|
+
from novelwriter import CONFIG
|
32
|
+
from novelwriter.enum import nwTrinary
|
33
|
+
from novelwriter.types import QtBlack, QtPaintAnitAlias
|
34
34
|
|
35
35
|
logger = logging.getLogger(__name__)
|
36
36
|
|
37
37
|
|
38
38
|
class StatusLED(QAbstractButton):
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
__slots__ = (
|
41
|
+
"_neutral", "_postitve", "_negative", "_color", "_state", "_bPx"
|
42
|
+
)
|
43
43
|
|
44
|
-
def __init__(self,
|
45
|
-
sW: int, sH: int, parent: QWidget | None = None) -> None:
|
44
|
+
def __init__(self, sW: int, sH: int, parent: QWidget | None = None) -> None:
|
46
45
|
super().__init__(parent=parent)
|
47
|
-
|
48
|
-
self.
|
49
|
-
self.
|
50
|
-
self.
|
51
|
-
self.
|
52
|
-
|
46
|
+
self._neutral = QtBlack
|
47
|
+
self._postitve = QtBlack
|
48
|
+
self._negative = QtBlack
|
49
|
+
self._color = QtBlack
|
50
|
+
self._state = nwTrinary.NEUTRAL
|
51
|
+
self._bPx = CONFIG.pxInt(1)
|
53
52
|
self.setFixedWidth(sW)
|
54
53
|
self.setFixedHeight(sH)
|
54
|
+
return
|
55
55
|
|
56
|
+
@property
|
57
|
+
def state(self) -> nwTrinary:
|
58
|
+
"""The current state of the LED."""
|
59
|
+
return self._state
|
60
|
+
|
61
|
+
def setColors(self, neutral: QColor, positive: QColor, negative: QColor) -> None:
|
62
|
+
"""Set the three colours for the status values."""
|
63
|
+
self._neutral = neutral
|
64
|
+
self._postitve = positive
|
65
|
+
self._negative = negative
|
66
|
+
self.setState(self._state)
|
56
67
|
return
|
57
68
|
|
58
|
-
def setState(self, state:
|
69
|
+
def setState(self, state: nwTrinary) -> None:
|
59
70
|
"""Set the colour state."""
|
60
|
-
if state ==
|
61
|
-
self.
|
62
|
-
elif state ==
|
63
|
-
self.
|
71
|
+
if state == nwTrinary.POSITIVE:
|
72
|
+
self._color = self._postitve
|
73
|
+
elif state == nwTrinary.NEGATIVE:
|
74
|
+
self._color = self._negative
|
64
75
|
else:
|
65
|
-
self.
|
76
|
+
self._color = self._neutral
|
77
|
+
self._state = state
|
66
78
|
self.update()
|
67
79
|
return
|
68
80
|
|
@@ -70,8 +82,12 @@ class StatusLED(QAbstractButton):
|
|
70
82
|
"""Draw the LED."""
|
71
83
|
painter = QPainter(self)
|
72
84
|
painter.setRenderHint(QtPaintAnitAlias, True)
|
73
|
-
painter.setPen(self.palette().
|
74
|
-
painter.setBrush(self.
|
85
|
+
painter.setPen(self.palette().windowText().color())
|
86
|
+
painter.setBrush(self._color)
|
75
87
|
painter.setOpacity(1.0)
|
76
|
-
painter.drawEllipse(
|
88
|
+
painter.drawEllipse(
|
89
|
+
self._bPx, self._bPx,
|
90
|
+
self.width() - 2*self._bPx,
|
91
|
+
self.height() - 2*self._bPx
|
92
|
+
)
|
77
93
|
return
|
novelwriter/gui/doceditor.py
CHANGED
@@ -55,6 +55,7 @@ from novelwriter.common import minmax, transferCase
|
|
55
55
|
from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
|
56
56
|
from novelwriter.core.document import NWDocument
|
57
57
|
from novelwriter.enum import nwComment, nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary
|
58
|
+
from novelwriter.extensions.configlayout import NColourLabel
|
58
59
|
from novelwriter.extensions.eventfilters import WheelEventFilter
|
59
60
|
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton
|
60
61
|
from novelwriter.gui.dochighlight import BLOCK_META, BLOCK_TITLE
|
@@ -64,7 +65,7 @@ from novelwriter.text.counting import standardCounter
|
|
64
65
|
from novelwriter.tools.lipsum import GuiLipsum
|
65
66
|
from novelwriter.types import (
|
66
67
|
QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop,
|
67
|
-
QtAlignRight, QtKeepAnchor, QtModCtrl,
|
68
|
+
QtAlignRight, QtKeepAnchor, QtModCtrl, QtModNone, QtModShift, QtMouseLeft,
|
68
69
|
QtMoveAnchor, QtMoveLeft, QtMoveRight
|
69
70
|
)
|
70
71
|
|
@@ -210,6 +211,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
210
211
|
# Function Mapping
|
211
212
|
self.closeSearch = self.docSearch.closeSearch
|
212
213
|
self.searchVisible = self.docSearch.isVisible
|
214
|
+
self.changeFocusState = self.docHeader.changeFocusState
|
213
215
|
|
214
216
|
# Finalise
|
215
217
|
self.updateSyntaxColours()
|
@@ -436,11 +438,6 @@ class GuiDocEditor(QPlainTextEdit):
|
|
436
438
|
|
437
439
|
return True
|
438
440
|
|
439
|
-
def updateTagHighLighting(self) -> None:
|
440
|
-
"""Rerun the syntax highlighter on all meta data lines."""
|
441
|
-
self._qDocument.syntaxHighlighter.rehighlightByType(BLOCK_META)
|
442
|
-
return
|
443
|
-
|
444
441
|
def replaceText(self, text: str) -> None:
|
445
442
|
"""Replace the text of the current document with the provided
|
446
443
|
text. This also clears undo history.
|
@@ -956,7 +953,7 @@ class GuiDocEditor(QPlainTextEdit):
|
|
956
953
|
super().keyPressEvent(event)
|
957
954
|
nPos = self.cursorRect().topLeft().y()
|
958
955
|
kMod = event.modifiers()
|
959
|
-
okMod = kMod in (
|
956
|
+
okMod = kMod in (QtModNone, QtModShift)
|
960
957
|
okKey = event.key() not in self.MOVE_KEYS
|
961
958
|
if nPos != cPos and okMod and okKey:
|
962
959
|
mPos = CONFIG.autoScrollPos*0.01 * self.viewport().height()
|
@@ -1034,6 +1031,13 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1034
1031
|
self.beginSearch()
|
1035
1032
|
return
|
1036
1033
|
|
1034
|
+
@pyqtSlot(list, list)
|
1035
|
+
def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
|
1036
|
+
"""Tags have changed, so just in case we rehighlight them."""
|
1037
|
+
if updated or deleted:
|
1038
|
+
self._qDocument.syntaxHighlighter.rehighlightByType(BLOCK_META)
|
1039
|
+
return
|
1040
|
+
|
1037
1041
|
##
|
1038
1042
|
# Private Slots
|
1039
1043
|
##
|
@@ -1922,8 +1926,6 @@ class GuiDocEditor(QPlainTextEdit):
|
|
1922
1926
|
).format(tag)):
|
1923
1927
|
itemClass = nwKeyWords.KEY_CLASS.get(tBits[0], nwItemClass.NO_CLASS)
|
1924
1928
|
self.requestNewNoteCreation.emit(tag, itemClass)
|
1925
|
-
QApplication.processEvents()
|
1926
|
-
self._qDocument.syntaxHighlighter.rehighlightBlock(block)
|
1927
1929
|
|
1928
1930
|
return nwTrinary.POSITIVE if exist else nwTrinary.NEGATIVE
|
1929
1931
|
|
@@ -2030,6 +2032,9 @@ class GuiDocEditor(QPlainTextEdit):
|
|
2030
2032
|
cursor.movePosition(QtMoveLeft, QtKeepAnchor, nDelete)
|
2031
2033
|
cursor.insertText(tInsert)
|
2032
2034
|
|
2035
|
+
# Re-highlight, since the auto-replace sometimes interferes with it
|
2036
|
+
self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
|
2037
|
+
|
2033
2038
|
return
|
2034
2039
|
|
2035
2040
|
@staticmethod
|
@@ -2782,8 +2787,7 @@ class GuiDocEditHeader(QWidget):
|
|
2782
2787
|
self.setAutoFillBackground(True)
|
2783
2788
|
|
2784
2789
|
# Title Label
|
2785
|
-
self.itemTitle =
|
2786
|
-
self.itemTitle.setIndent(0)
|
2790
|
+
self.itemTitle = NColourLabel("", self, faded=SHARED.theme.fadedText)
|
2787
2791
|
self.itemTitle.setMargin(0)
|
2788
2792
|
self.itemTitle.setContentsMargins(0, 0, 0, 0)
|
2789
2793
|
self.itemTitle.setAutoFillBackground(True)
|
@@ -2915,10 +2919,15 @@ class GuiDocEditHeader(QWidget):
|
|
2915
2919
|
palette.setColor(QPalette.ColorRole.Window, SHARED.theme.colBack)
|
2916
2920
|
palette.setColor(QPalette.ColorRole.WindowText, SHARED.theme.colText)
|
2917
2921
|
palette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
|
2918
|
-
|
2919
2922
|
self.setPalette(palette)
|
2920
|
-
self.itemTitle.
|
2923
|
+
self.itemTitle.setTextColors(
|
2924
|
+
color=palette.windowText().color(), faded=SHARED.theme.fadedText
|
2925
|
+
)
|
2926
|
+
return
|
2921
2927
|
|
2928
|
+
def changeFocusState(self, state: bool) -> None:
|
2929
|
+
"""Toggle focus state."""
|
2930
|
+
self.itemTitle.setColorState(state)
|
2922
2931
|
return
|
2923
2932
|
|
2924
2933
|
def setHandle(self, tHandle: str) -> None:
|