novelWriter 2.4b1__py3-none-any.whl → 2.4rc1__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.4b1.dist-info → novelWriter-2.4rc1.dist-info}/METADATA +5 -6
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/RECORD +62 -66
- novelwriter/__init__.py +5 -5
- novelwriter/assets/icons/none.svg +4 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
- 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 +2 -2
- 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/common.py +6 -1
- novelwriter/config.py +8 -4
- novelwriter/core/coretools.py +21 -22
- novelwriter/core/status.py +3 -2
- novelwriter/core/toodt.py +332 -355
- novelwriter/dialogs/about.py +9 -11
- novelwriter/dialogs/docmerge.py +17 -14
- novelwriter/dialogs/docsplit.py +14 -12
- novelwriter/dialogs/editlabel.py +5 -4
- novelwriter/dialogs/preferences.py +28 -33
- novelwriter/dialogs/projectsettings.py +29 -26
- novelwriter/dialogs/quotes.py +10 -9
- novelwriter/dialogs/wordlist.py +15 -12
- novelwriter/error.py +13 -11
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +1 -3
- novelwriter/extensions/modified.py +33 -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/gui/doceditor.py +182 -225
- novelwriter/gui/dochighlight.py +4 -4
- novelwriter/gui/docviewer.py +53 -57
- novelwriter/gui/docviewerpanel.py +16 -13
- novelwriter/gui/editordocument.py +4 -4
- novelwriter/gui/itemdetails.py +45 -48
- novelwriter/gui/noveltree.py +22 -20
- novelwriter/gui/outline.py +87 -88
- novelwriter/gui/projtree.py +31 -29
- novelwriter/gui/search.py +75 -29
- novelwriter/gui/sidebar.py +24 -28
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +47 -35
- novelwriter/guimain.py +35 -31
- novelwriter/shared.py +5 -5
- novelwriter/tools/dictionaries.py +13 -12
- novelwriter/tools/lipsum.py +20 -17
- novelwriter/tools/manusbuild.py +35 -27
- novelwriter/tools/manuscript.py +68 -73
- novelwriter/tools/manussettings.py +68 -73
- novelwriter/tools/noveldetails.py +20 -18
- novelwriter/tools/welcome.py +47 -43
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
- 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/text/__init__.py +0 -3
- novelwriter/tools/__init__.py +0 -3
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/WHEEL +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/top_level.txt +0 -0
novelwriter/dialogs/wordlist.py
CHANGED
@@ -28,17 +28,19 @@ import logging
|
|
28
28
|
from typing import TYPE_CHECKING
|
29
29
|
from pathlib import Path
|
30
30
|
|
31
|
-
from PyQt5.QtGui import QCloseEvent
|
32
31
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
32
|
+
from PyQt5.QtGui import QCloseEvent
|
33
33
|
from PyQt5.QtWidgets import (
|
34
|
-
QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog,
|
35
|
-
QLineEdit, QListWidget,
|
34
|
+
QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog,
|
35
|
+
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED
|
39
39
|
from novelwriter.common import formatFileFilter
|
40
40
|
from novelwriter.core.spellcheck import UserDictionary
|
41
41
|
from novelwriter.extensions.configlayout import NColourLabel
|
42
|
+
from novelwriter.extensions.modified import NIconToolButton
|
43
|
+
from novelwriter.types import QtDialogClose, QtDialogSave
|
42
44
|
|
43
45
|
if TYPE_CHECKING: # pragma: no cover
|
44
46
|
from novelwriter.guimain import GuiMain
|
@@ -57,6 +59,7 @@ class GuiWordList(QDialog):
|
|
57
59
|
self.setObjectName("GuiWordList")
|
58
60
|
self.setWindowTitle(self.tr("Project Word List"))
|
59
61
|
|
62
|
+
iSz = SHARED.theme.baseIconSize
|
60
63
|
mS = CONFIG.pxInt(250)
|
61
64
|
wW = CONFIG.pxInt(320)
|
62
65
|
wH = CONFIG.pxInt(340)
|
@@ -74,11 +77,11 @@ class GuiWordList(QDialog):
|
|
74
77
|
scale=NColourLabel.HEADER_SCALE
|
75
78
|
)
|
76
79
|
|
77
|
-
self.importButton =
|
80
|
+
self.importButton = NIconToolButton(self, iSz, "import")
|
78
81
|
self.importButton.setToolTip(self.tr("Import words from text file"))
|
79
82
|
self.importButton.clicked.connect(self._importWords)
|
80
83
|
|
81
|
-
self.exportButton =
|
84
|
+
self.exportButton = NIconToolButton(self, iSz, "export")
|
82
85
|
self.exportButton.setToolTip(self.tr("Export words to text file"))
|
83
86
|
self.exportButton.clicked.connect(self._exportWords)
|
84
87
|
|
@@ -89,17 +92,17 @@ class GuiWordList(QDialog):
|
|
89
92
|
|
90
93
|
# List Box
|
91
94
|
self.listBox = QListWidget(self)
|
92
|
-
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
|
95
|
+
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
|
93
96
|
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
94
97
|
self.listBox.setSortingEnabled(True)
|
95
98
|
|
96
99
|
# Add/Remove Form
|
97
100
|
self.newEntry = QLineEdit(self)
|
98
101
|
|
99
|
-
self.addButton =
|
102
|
+
self.addButton = NIconToolButton(self, iSz, "add")
|
100
103
|
self.addButton.clicked.connect(self._doAdd)
|
101
104
|
|
102
|
-
self.delButton =
|
105
|
+
self.delButton = NIconToolButton(self, iSz, "remove")
|
103
106
|
self.delButton.clicked.connect(self._doDelete)
|
104
107
|
|
105
108
|
self.editBox = QHBoxLayout()
|
@@ -108,7 +111,7 @@ class GuiWordList(QDialog):
|
|
108
111
|
self.editBox.addWidget(self.delButton, 0)
|
109
112
|
|
110
113
|
# Buttons
|
111
|
-
self.buttonBox = QDialogButtonBox(
|
114
|
+
self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogClose, self)
|
112
115
|
self.buttonBox.accepted.connect(self._doSave)
|
113
116
|
self.buttonBox.rejected.connect(self.close)
|
114
117
|
|
@@ -155,7 +158,7 @@ class GuiWordList(QDialog):
|
|
155
158
|
self.newEntry.setText("")
|
156
159
|
self.listBox.clearSelection()
|
157
160
|
self._addWord(word)
|
158
|
-
if items := self.listBox.findItems(word, Qt.MatchExactly):
|
161
|
+
if items := self.listBox.findItems(word, Qt.MatchFlag.MatchExactly):
|
159
162
|
self.listBox.setCurrentItem(items[0])
|
160
163
|
self.listBox.scrollToItem(items[0], QAbstractItemView.ScrollHint.PositionAtCenter)
|
161
164
|
return
|
@@ -175,7 +178,7 @@ class GuiWordList(QDialog):
|
|
175
178
|
userDict.add(word)
|
176
179
|
userDict.save()
|
177
180
|
self.newWordListReady.emit()
|
178
|
-
|
181
|
+
QApplication.processEvents()
|
179
182
|
self.close()
|
180
183
|
return
|
181
184
|
|
@@ -242,7 +245,7 @@ class GuiWordList(QDialog):
|
|
242
245
|
|
243
246
|
def _addWord(self, word: str) -> None:
|
244
247
|
"""Add a single word to the list."""
|
245
|
-
if word and not self.listBox.findItems(word, Qt.MatchExactly):
|
248
|
+
if word and not self.listBox.findItems(word, Qt.MatchFlag.MatchExactly):
|
246
249
|
self.listBox.addItem(word)
|
247
250
|
self._changed = True
|
248
251
|
return
|
novelwriter/error.py
CHANGED
@@ -29,11 +29,11 @@ import logging
|
|
29
29
|
|
30
30
|
from typing import TYPE_CHECKING
|
31
31
|
|
32
|
-
from PyQt5.QtGui import QFont, QFontDatabase
|
33
32
|
from PyQt5.QtCore import Qt, pyqtSlot
|
33
|
+
from PyQt5.QtGui import QFont, QFontDatabase
|
34
34
|
from PyQt5.QtWidgets import (
|
35
|
-
|
36
|
-
QDialogButtonBox
|
35
|
+
QApplication, QWidget, QDialog, QGridLayout, QStyle, QPlainTextEdit,
|
36
|
+
QLabel, QDialogButtonBox
|
37
37
|
)
|
38
38
|
|
39
39
|
if TYPE_CHECKING: # pragma: no cover
|
@@ -74,7 +74,9 @@ class NWErrorMessage(QDialog):
|
|
74
74
|
# Widgets
|
75
75
|
self.msgIcon = QLabel()
|
76
76
|
self.msgIcon.setPixmap(
|
77
|
-
|
77
|
+
QApplication.style().standardIcon(
|
78
|
+
QStyle.StandardPixmap.SP_MessageBoxCritical
|
79
|
+
).pixmap(64, 64)
|
78
80
|
)
|
79
81
|
self.msgHead = QLabel()
|
80
82
|
self.msgHead.setOpenExternalLinks(True)
|
@@ -88,13 +90,13 @@ class NWErrorMessage(QDialog):
|
|
88
90
|
self.msgBody.setFont(font)
|
89
91
|
self.msgBody.setReadOnly(True)
|
90
92
|
|
91
|
-
self.btnBox = QDialogButtonBox(QDialogButtonBox.Close)
|
93
|
+
self.btnBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
|
92
94
|
self.btnBox.rejected.connect(self._doClose)
|
93
95
|
|
94
96
|
# Assemble
|
95
97
|
self.mainBox = QGridLayout()
|
96
|
-
self.mainBox.addWidget(self.msgIcon, 0, 0, 2, 1, Qt.AlignTop)
|
97
|
-
self.mainBox.addWidget(self.msgHead, 0, 1, 1, 1, Qt.AlignTop)
|
98
|
+
self.mainBox.addWidget(self.msgIcon, 0, 0, 2, 1, Qt.AlignmentFlag.AlignTop)
|
99
|
+
self.mainBox.addWidget(self.msgHead, 0, 1, 1, 1, Qt.AlignmentFlag.AlignTop)
|
98
100
|
self.mainBox.addWidget(self.msgBody, 1, 1, 1, 1)
|
99
101
|
self.mainBox.addWidget(self.btnBox, 2, 0, 1, 2)
|
100
102
|
self.mainBox.setSpacing(16)
|
@@ -179,14 +181,14 @@ class NWErrorMessage(QDialog):
|
|
179
181
|
def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackType) -> None:
|
180
182
|
"""Function to catch unhandled global exceptions."""
|
181
183
|
from traceback import print_tb
|
182
|
-
from PyQt5.QtWidgets import
|
184
|
+
from PyQt5.QtWidgets import QApplication
|
183
185
|
|
184
186
|
logger.critical("%s: %s", exType.__name__, str(exValue))
|
185
187
|
print_tb(exTrace)
|
186
188
|
|
187
189
|
try:
|
188
190
|
nwGUI = None
|
189
|
-
for qWin in
|
191
|
+
for qWin in QApplication.topLevelWidgets():
|
190
192
|
if qWin.objectName() == "GuiMain":
|
191
193
|
nwGUI = qWin
|
192
194
|
break
|
@@ -197,7 +199,7 @@ def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackTyp
|
|
197
199
|
|
198
200
|
errMsg = NWErrorMessage(nwGUI)
|
199
201
|
errMsg.setMessage(exType, exValue, exTrace)
|
200
|
-
errMsg.
|
202
|
+
errMsg.exec()
|
201
203
|
|
202
204
|
try:
|
203
205
|
# Try a controlled shutdown
|
@@ -209,7 +211,7 @@ def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackTyp
|
|
209
211
|
logger.critical("Could not close the project before exiting")
|
210
212
|
logger.critical(formatException(exc))
|
211
213
|
|
212
|
-
|
214
|
+
QApplication.exit(1)
|
213
215
|
|
214
216
|
except Exception as exc:
|
215
217
|
logger.critical(formatException(exc))
|
@@ -25,10 +25,14 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
from math import ceil
|
27
27
|
|
28
|
+
from PyQt5.QtCore import QRect
|
28
29
|
from PyQt5.QtGui import QBrush, QColor, QPaintEvent, QPainter, QPen
|
29
|
-
from PyQt5.QtCore import QRect, Qt
|
30
30
|
from PyQt5.QtWidgets import QProgressBar, QSizePolicy, QWidget
|
31
31
|
|
32
|
+
from novelwriter.types import (
|
33
|
+
QtPaintAnitAlias, QtAlignCenter, QtRoundCap, QtSolidLine, QtTransparent
|
34
|
+
)
|
35
|
+
|
32
36
|
|
33
37
|
class NProgressCircle(QProgressBar):
|
34
38
|
"""Extension: Circular Progress Widget
|
@@ -48,14 +52,14 @@ class NProgressCircle(QProgressBar):
|
|
48
52
|
self._point = point
|
49
53
|
self._dRect = QRect(0, 0, size, size)
|
50
54
|
self._cRect = QRect(point, point, size - 2*point, size - 2*point)
|
51
|
-
self._dPen = QPen(
|
52
|
-
self._dBrush = QBrush(
|
55
|
+
self._dPen = QPen(QtTransparent)
|
56
|
+
self._dBrush = QBrush(QtTransparent)
|
53
57
|
self.setColours(
|
54
58
|
track=self.palette().alternateBase().color(),
|
55
59
|
bar=self.palette().highlight().color(),
|
56
60
|
text=self.palette().text().color()
|
57
61
|
)
|
58
|
-
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
62
|
+
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
59
63
|
self.setFixedWidth(size)
|
60
64
|
self.setFixedHeight(size)
|
61
65
|
return
|
@@ -67,9 +71,9 @@ class NProgressCircle(QProgressBar):
|
|
67
71
|
self._dPen = QPen(back)
|
68
72
|
self._dBrush = QBrush(back)
|
69
73
|
if isinstance(bar, QColor):
|
70
|
-
self._cPen = QPen(QBrush(bar), self._point,
|
74
|
+
self._cPen = QPen(QBrush(bar), self._point, QtSolidLine, QtRoundCap)
|
71
75
|
if isinstance(track, QColor):
|
72
|
-
self._bPen = QPen(QBrush(track), self._point,
|
76
|
+
self._bPen = QPen(QBrush(track), self._point, QtSolidLine, QtRoundCap)
|
73
77
|
if isinstance(text, QColor):
|
74
78
|
self._tColor = text
|
75
79
|
return
|
@@ -85,7 +89,7 @@ class NProgressCircle(QProgressBar):
|
|
85
89
|
progress = 100.0*self.value()/self.maximum()
|
86
90
|
angle = ceil(16*3.6*progress)
|
87
91
|
painter = QPainter(self)
|
88
|
-
painter.setRenderHint(
|
92
|
+
painter.setRenderHint(QtPaintAnitAlias, True)
|
89
93
|
painter.setPen(self._dPen)
|
90
94
|
painter.setBrush(self._dBrush)
|
91
95
|
painter.drawEllipse(self._dRect)
|
@@ -94,7 +98,7 @@ class NProgressCircle(QProgressBar):
|
|
94
98
|
painter.setPen(self._cPen)
|
95
99
|
painter.drawArc(self._cRect, 90*16, -angle)
|
96
100
|
painter.setPen(self._tColor)
|
97
|
-
painter.drawText(self._cRect,
|
101
|
+
painter.drawText(self._cRect, QtAlignCenter, self._text or f"{progress:.1f} %")
|
98
102
|
return
|
99
103
|
|
100
104
|
# END Class NProgressCircle
|
@@ -37,8 +37,6 @@ from PyQt5.QtWidgets import (
|
|
37
37
|
from novelwriter import CONFIG
|
38
38
|
|
39
39
|
DEFAULT_SCALE = 0.9
|
40
|
-
RIGHT_TOP = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop
|
41
|
-
LEFT_TOP = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
|
42
40
|
|
43
41
|
|
44
42
|
class NFixedPage(QFrame):
|
@@ -260,7 +258,7 @@ class NColourLabel(QLabel):
|
|
260
258
|
font.setWeight(QFont.Weight.Bold if bold else QFont.Weight.Normal)
|
261
259
|
if color:
|
262
260
|
colour = self.palette()
|
263
|
-
colour.setColor(QPalette.WindowText, color)
|
261
|
+
colour.setColor(QPalette.ColorRole.WindowText, color)
|
264
262
|
self.setPalette(colour)
|
265
263
|
|
266
264
|
self.setFont(font)
|
@@ -29,6 +29,8 @@ from PyQt5.QtCore import QSize, Qt
|
|
29
29
|
from PyQt5.QtGui import QWheelEvent
|
30
30
|
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
|
31
31
|
|
32
|
+
from novelwriter import SHARED
|
33
|
+
|
32
34
|
|
33
35
|
class NComboBox(QComboBox):
|
34
36
|
|
@@ -89,11 +91,40 @@ class NDoubleSpinBox(QDoubleSpinBox):
|
|
89
91
|
|
90
92
|
class NIconToolButton(QToolButton):
|
91
93
|
|
92
|
-
def __init__(self, parent: QWidget, iconSize:
|
94
|
+
def __init__(self, parent: QWidget, iconSize: QSize, icon: str | None = None) -> None:
|
93
95
|
super().__init__(parent=parent)
|
94
96
|
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
95
|
-
self.setIconSize(
|
97
|
+
self.setIconSize(iconSize)
|
96
98
|
self.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
99
|
+
if icon:
|
100
|
+
self.setThemeIcon(icon)
|
101
|
+
return
|
102
|
+
|
103
|
+
def setThemeIcon(self, iconKey: str) -> None:
|
104
|
+
"""Set an icon from the current theme."""
|
105
|
+
self.setIcon(SHARED.theme.getIcon(iconKey))
|
97
106
|
return
|
98
107
|
|
99
108
|
# END Class NIconToolButton
|
109
|
+
|
110
|
+
|
111
|
+
class NIconToggleButton(QToolButton):
|
112
|
+
|
113
|
+
def __init__(self, parent: QWidget, iconSize: QSize, icon: str | None = None) -> None:
|
114
|
+
super().__init__(parent=parent)
|
115
|
+
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
|
116
|
+
self.setIconSize(iconSize)
|
117
|
+
self.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
118
|
+
self.setCheckable(True)
|
119
|
+
self.setStyleSheet("border: none; background: transparent;")
|
120
|
+
if icon:
|
121
|
+
self.setThemeIcon(icon)
|
122
|
+
return
|
123
|
+
|
124
|
+
def setThemeIcon(self, iconKey: str) -> None:
|
125
|
+
"""Set an icon from the current theme."""
|
126
|
+
iconSize = self.iconSize()
|
127
|
+
self.setIcon(SHARED.theme.getToggleIcon(iconKey, (iconSize.width(), iconSize.height())))
|
128
|
+
return
|
129
|
+
|
130
|
+
# END Class NUnfoldButton
|
@@ -32,6 +32,8 @@ from PyQt5.QtWidgets import (
|
|
32
32
|
QStyleOptionToolButton, QToolBar, QToolButton, QWidget
|
33
33
|
)
|
34
34
|
|
35
|
+
from novelwriter.types import QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen
|
36
|
+
|
35
37
|
|
36
38
|
class NPagedSideBar(QToolBar):
|
37
39
|
"""Extensions: Paged Side Bar
|
@@ -54,10 +56,10 @@ class NPagedSideBar(QToolBar):
|
|
54
56
|
self._group.buttonClicked.connect(self._buttonClicked)
|
55
57
|
|
56
58
|
self.setMovable(False)
|
57
|
-
self.setOrientation(Qt.Vertical)
|
59
|
+
self.setOrientation(Qt.Orientation.Vertical)
|
58
60
|
|
59
61
|
stretch = QWidget(self)
|
60
|
-
stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
62
|
+
stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
61
63
|
self._stretchAction = self.addWidget(stretch)
|
62
64
|
|
63
65
|
return
|
@@ -117,13 +119,13 @@ class _NPagedToolButton(QToolButton):
|
|
117
119
|
def __init__(self, parent: QWidget) -> None:
|
118
120
|
super().__init__(parent=parent)
|
119
121
|
|
120
|
-
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
122
|
+
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
121
123
|
self.setCheckable(True)
|
122
124
|
|
123
125
|
fH = self.fontMetrics().height()
|
124
126
|
self._bH = round(fH * 1.7)
|
125
127
|
self._tM = (self._bH - fH)//2
|
126
|
-
self._lM = 3*self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
|
128
|
+
self._lM = 3*self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
|
127
129
|
self._cR = self._lM//2
|
128
130
|
self._aH = 2*fH//7
|
129
131
|
self.setFixedHeight(self._bH)
|
@@ -143,15 +145,15 @@ class _NPagedToolButton(QToolButton):
|
|
143
145
|
opt.initFrom(self)
|
144
146
|
|
145
147
|
paint = QPainter(self)
|
146
|
-
paint.setRenderHint(
|
147
|
-
paint.setPen(
|
148
|
-
paint.setBrush(
|
148
|
+
paint.setRenderHint(QtPaintAnitAlias, True)
|
149
|
+
paint.setPen(QtNoPen)
|
150
|
+
paint.setBrush(QtNoBrush)
|
149
151
|
|
150
152
|
width = self.width()
|
151
153
|
height = self.height()
|
152
154
|
palette = self.palette()
|
153
155
|
|
154
|
-
if opt.state &
|
156
|
+
if opt.state & QtMouseOver == QtMouseOver:
|
155
157
|
backCol = palette.base()
|
156
158
|
paint.setBrush(backCol)
|
157
159
|
paint.setOpacity(0.75)
|
@@ -171,7 +173,7 @@ class _NPagedToolButton(QToolButton):
|
|
171
173
|
|
172
174
|
paint.setPen(textCol)
|
173
175
|
paint.setOpacity(1.0)
|
174
|
-
paint.drawText(QRectF(self._lM, self._tM, tW, tH),
|
176
|
+
paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
|
175
177
|
|
176
178
|
tC = self.height()//2
|
177
179
|
tW = self.width() - self._aH - self._lM
|
@@ -195,12 +197,12 @@ class _NPagedToolLabel(QLabel):
|
|
195
197
|
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
|
196
198
|
super().__init__(parent=parent)
|
197
199
|
|
198
|
-
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
200
|
+
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
199
201
|
|
200
202
|
fH = self.fontMetrics().height()
|
201
203
|
self._bH = round(fH * 1.7)
|
202
204
|
self._tM = (self._bH - fH)//2
|
203
|
-
self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
|
205
|
+
self._lM = self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
|
204
206
|
self.setFixedHeight(self._bH)
|
205
207
|
|
206
208
|
self._textCol = textColor or self.palette().text().color()
|
@@ -212,8 +214,8 @@ class _NPagedToolLabel(QLabel):
|
|
212
214
|
label that matches the button style.
|
213
215
|
"""
|
214
216
|
paint = QPainter(self)
|
215
|
-
paint.setRenderHint(
|
216
|
-
paint.setPen(
|
217
|
+
paint.setRenderHint(QtPaintAnitAlias, True)
|
218
|
+
paint.setPen(QtNoPen)
|
217
219
|
|
218
220
|
width = self.width()
|
219
221
|
height = self.height()
|
@@ -223,7 +225,7 @@ class _NPagedToolLabel(QLabel):
|
|
223
225
|
|
224
226
|
paint.setPen(self._textCol)
|
225
227
|
paint.setOpacity(1.0)
|
226
|
-
paint.drawText(QRectF(self._lM, self._tM, tW, tH),
|
228
|
+
paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
|
227
229
|
|
228
230
|
return
|
229
231
|
|
@@ -28,6 +28,8 @@ from math import ceil
|
|
28
28
|
from PyQt5.QtGui import QPaintEvent, QPainter
|
29
29
|
from PyQt5.QtWidgets import QProgressBar, QWidget
|
30
30
|
|
31
|
+
from novelwriter.types import QtPaintAnitAlias
|
32
|
+
|
31
33
|
|
32
34
|
class NProgressSimple(QProgressBar):
|
33
35
|
"""Extension: Simple Progress Widget
|
@@ -44,7 +46,7 @@ class NProgressSimple(QProgressBar):
|
|
44
46
|
if (value := self.value()) > 0:
|
45
47
|
progress = ceil(self.width()*float(value)/self.maximum())
|
46
48
|
painter = QPainter(self)
|
47
|
-
painter.setRenderHint(
|
49
|
+
painter.setRenderHint(QtPaintAnitAlias, True)
|
48
50
|
painter.setPen(self.palette().highlight().color())
|
49
51
|
painter.setBrush(self.palette().highlight())
|
50
52
|
painter.drawRect(0, 0, progress, self.height())
|
@@ -30,6 +30,8 @@ from typing import Literal
|
|
30
30
|
from PyQt5.QtGui import QColor, QPaintEvent, QPainter
|
31
31
|
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
32
32
|
|
33
|
+
from novelwriter.types import QtPaintAnitAlias
|
34
|
+
|
33
35
|
logger = logging.getLogger(__name__)
|
34
36
|
|
35
37
|
|
@@ -67,7 +69,7 @@ class StatusLED(QAbstractButton):
|
|
67
69
|
def paintEvent(self, event: QPaintEvent) -> None:
|
68
70
|
"""Draw the LED."""
|
69
71
|
painter = QPainter(self)
|
70
|
-
painter.setRenderHint(
|
72
|
+
painter.setRenderHint(QtPaintAnitAlias, True)
|
71
73
|
painter.setPen(self.palette().dark().color())
|
72
74
|
painter.setBrush(self._theCol)
|
73
75
|
painter.setOpacity(1.0)
|
novelwriter/extensions/switch.py
CHANGED
@@ -27,25 +27,26 @@ from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
|
27
27
|
from PyQt5.QtCore import QEvent, QPropertyAnimation, Qt, pyqtProperty
|
28
28
|
from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
|
29
29
|
|
30
|
-
from novelwriter import CONFIG
|
30
|
+
from novelwriter import CONFIG, SHARED
|
31
|
+
from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen
|
31
32
|
|
32
33
|
|
33
34
|
class NSwitch(QAbstractButton):
|
34
35
|
|
35
36
|
__slots__ = ("_xW", "_xH", "_xR", "_rB", "_rH", "_rR", "_offset")
|
36
37
|
|
37
|
-
def __init__(self, parent: QWidget
|
38
|
+
def __init__(self, parent: QWidget, height: int = 0) -> None:
|
38
39
|
super().__init__(parent=parent)
|
39
40
|
|
40
|
-
self._xH = height or
|
41
|
+
self._xH = height or SHARED.theme.baseButtonHeight
|
41
42
|
self._xW = 2*self._xH
|
42
43
|
self._xR = int(self._xH*0.5)
|
43
|
-
self._rB =
|
44
|
+
self._rB = CONFIG.pxInt(2)
|
44
45
|
self._rH = self._xH - 2*self._rB
|
45
46
|
self._rR = self._xR - self._rB
|
46
47
|
|
47
48
|
self.setCheckable(True)
|
48
|
-
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
49
|
+
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
49
50
|
self.setFixedWidth(self._xW)
|
50
51
|
self.setFixedHeight(self._xH)
|
51
52
|
self._offset = self._xR
|
@@ -89,8 +90,8 @@ class NSwitch(QAbstractButton):
|
|
89
90
|
def paintEvent(self, event: QPaintEvent) -> None:
|
90
91
|
"""Drawing the switch itself."""
|
91
92
|
painter = QPainter(self)
|
92
|
-
painter.setRenderHint(
|
93
|
-
painter.setPen(
|
93
|
+
painter.setRenderHint(QtPaintAnitAlias, True)
|
94
|
+
painter.setPen(QtNoPen)
|
94
95
|
|
95
96
|
palette = self.palette()
|
96
97
|
if self.isChecked():
|
@@ -119,7 +120,7 @@ class NSwitch(QAbstractButton):
|
|
119
120
|
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
|
120
121
|
"""Animate the switch on mouse release."""
|
121
122
|
super().mouseReleaseEvent(event)
|
122
|
-
if event.button() ==
|
123
|
+
if event.button() == QtMouseLeft:
|
123
124
|
anim = QPropertyAnimation(self, b"offset", self)
|
124
125
|
anim.setDuration(120)
|
125
126
|
anim.setStartValue(self._offset)
|
@@ -129,7 +130,7 @@ class NSwitch(QAbstractButton):
|
|
129
130
|
|
130
131
|
def enterEvent(self, event: QEvent) -> None:
|
131
132
|
"""Change the cursor when hovering the button."""
|
132
|
-
self.setCursor(Qt.PointingHandCursor)
|
133
|
+
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
133
134
|
super().enterEvent(event)
|
134
135
|
return
|
135
136
|
|
@@ -24,10 +24,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
24
24
|
from __future__ import annotations
|
25
25
|
|
26
26
|
from PyQt5.QtGui import QIcon
|
27
|
-
from PyQt5.QtCore import
|
27
|
+
from PyQt5.QtCore import pyqtSignal
|
28
28
|
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
|
29
29
|
|
30
30
|
from novelwriter.extensions.switch import NSwitch
|
31
|
+
from novelwriter.types import QtAlignLeft, QtAlignRight, QtAlignRightMiddle
|
31
32
|
|
32
33
|
|
33
34
|
class NSwitchBox(QScrollArea):
|
@@ -57,8 +58,8 @@ class NSwitchBox(QScrollArea):
|
|
57
58
|
self._content = QGridLayout()
|
58
59
|
self._content.setColumnStretch(1, 1)
|
59
60
|
|
60
|
-
self._widget = QWidget()
|
61
|
-
self._widget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
|
61
|
+
self._widget = QWidget(self)
|
62
|
+
self._widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum)
|
62
63
|
self._widget.setLayout(self._content)
|
63
64
|
|
64
65
|
self.setWidgetResizable(True)
|
@@ -68,29 +69,29 @@ class NSwitchBox(QScrollArea):
|
|
68
69
|
|
69
70
|
def addLabel(self, text: str) -> None:
|
70
71
|
"""Add a header label to the content box."""
|
71
|
-
label = QLabel(text)
|
72
|
+
label = QLabel(text, self)
|
72
73
|
font = label.font()
|
73
74
|
font.setBold(True)
|
74
75
|
label.setFont(font)
|
75
|
-
self._content.addWidget(label, self._index, 0, 1, 3,
|
76
|
+
self._content.addWidget(label, self._index, 0, 1, 3, QtAlignLeft)
|
76
77
|
self._widgets.append(label)
|
77
78
|
self._bumpIndex()
|
78
79
|
return
|
79
80
|
|
80
81
|
def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None:
|
81
82
|
"""Add an item to the content box."""
|
82
|
-
icon = QLabel("")
|
83
|
-
icon.setAlignment(
|
83
|
+
icon = QLabel("", self)
|
84
|
+
icon.setAlignment(QtAlignRightMiddle)
|
84
85
|
icon.setPixmap(qIcon.pixmap(self._sIcon, self._sIcon))
|
85
|
-
self._content.addWidget(icon, self._index, 0,
|
86
|
+
self._content.addWidget(icon, self._index, 0, QtAlignLeft)
|
86
87
|
|
87
|
-
label = QLabel(text)
|
88
|
-
self._content.addWidget(label, self._index, 1,
|
88
|
+
label = QLabel(text, self)
|
89
|
+
self._content.addWidget(label, self._index, 1, QtAlignLeft)
|
89
90
|
|
90
91
|
switch = NSwitch(self, height=self._hSwitch)
|
91
92
|
switch.setChecked(default)
|
92
93
|
switch.toggled.connect(lambda state: self._emitSwitchSignal(identifier, state))
|
93
|
-
self._content.addWidget(switch, self._index, 2,
|
94
|
+
self._content.addWidget(switch, self._index, 2, QtAlignRight)
|
94
95
|
|
95
96
|
self._widgets.append(switch)
|
96
97
|
self._bumpIndex()
|
@@ -99,9 +100,9 @@ class NSwitchBox(QScrollArea):
|
|
99
100
|
|
100
101
|
def addSeparator(self) -> None:
|
101
102
|
"""Add a blank entry in the content box."""
|
102
|
-
spacer = QWidget()
|
103
|
+
spacer = QWidget(self)
|
103
104
|
spacer.setFixedHeight(int(0.5*self._sIcon))
|
104
|
-
self._content.addWidget(spacer, self._index, 0, 1, 3,
|
105
|
+
self._content.addWidget(spacer, self._index, 0, 1, 3, QtAlignLeft)
|
105
106
|
self._widgets.append(spacer)
|
106
107
|
self._bumpIndex()
|
107
108
|
return
|