novelWriter 2.2rc1__py3-none-any.whl → 2.3__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.2rc1.dist-info → novelWriter-2.3.dist-info}/METADATA +1 -1
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/RECORD +149 -132
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/WHEEL +1 -1
- novelWriter-2.3.dist-info/entry_points.txt +2 -0
- novelwriter/__init__.py +11 -6
- 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_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_de_DE.json +1 -0
- novelwriter/assets/i18n/project_en_US.json +1 -0
- novelwriter/assets/i18n/project_es_419.json +11 -0
- novelwriter/assets/i18n/project_fr_FR.json +11 -0
- novelwriter/assets/i18n/project_it_IT.json +11 -0
- novelwriter/assets/i18n/project_ja_JP.json +2 -1
- novelwriter/assets/i18n/project_nb_NO.json +1 -0
- novelwriter/assets/i18n/project_nl_NL.json +11 -0
- novelwriter/assets/i18n/project_pt_BR.json +11 -0
- novelwriter/assets/i18n/project_zh_CN.json +11 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +11 -2
- novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-list.svg +9 -0
- novelwriter/assets/icons/typicons_light/icons.conf +11 -2
- novelwriter/assets/icons/typicons_light/mixed_document-new.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-list.svg +9 -0
- novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
- novelwriter/assets/images/novelwriter-text-light.svg +4 -0
- novelwriter/assets/images/welcome-dark.jpg +0 -0
- novelwriter/assets/images/welcome-light.jpg +0 -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 +4 -2
- novelwriter/assets/themes/cyberpunk_night.conf +29 -0
- novelwriter/assets/themes/default_dark.conf +2 -2
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +64 -66
- novelwriter/config.py +39 -44
- novelwriter/constants.py +39 -17
- novelwriter/core/buildsettings.py +8 -8
- novelwriter/core/coretools.py +198 -157
- novelwriter/core/docbuild.py +7 -4
- novelwriter/core/document.py +7 -7
- novelwriter/core/index.py +90 -57
- novelwriter/core/item.py +23 -5
- novelwriter/core/options.py +11 -10
- novelwriter/core/project.py +73 -47
- novelwriter/core/projectdata.py +3 -16
- novelwriter/core/projectxml.py +14 -42
- novelwriter/core/sessions.py +4 -3
- novelwriter/core/spellcheck.py +6 -4
- novelwriter/core/status.py +5 -4
- novelwriter/core/storage.py +183 -141
- novelwriter/core/tohtml.py +6 -4
- novelwriter/core/tokenizer.py +110 -83
- novelwriter/core/tomd.py +2 -2
- novelwriter/core/toodt.py +41 -31
- novelwriter/core/tree.py +5 -4
- novelwriter/dialogs/about.py +88 -179
- novelwriter/dialogs/docmerge.py +30 -20
- novelwriter/dialogs/docsplit.py +33 -22
- novelwriter/dialogs/editlabel.py +20 -8
- novelwriter/dialogs/preferences.py +562 -725
- novelwriter/dialogs/{projsettings.py → projectsettings.py} +301 -270
- novelwriter/dialogs/quotes.py +47 -36
- novelwriter/dialogs/wordlist.py +128 -59
- novelwriter/enum.py +25 -22
- novelwriter/error.py +2 -2
- novelwriter/extensions/circularprogress.py +12 -12
- novelwriter/extensions/configlayout.py +185 -146
- novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
- novelwriter/extensions/modified.py +81 -0
- novelwriter/extensions/novelselector.py +27 -13
- novelwriter/extensions/pagedsidebar.py +15 -20
- novelwriter/extensions/simpleprogress.py +8 -9
- novelwriter/extensions/statusled.py +9 -9
- novelwriter/extensions/switch.py +32 -64
- novelwriter/extensions/switchbox.py +2 -7
- novelwriter/extensions/versioninfo.py +153 -0
- novelwriter/gui/doceditor.py +250 -214
- novelwriter/gui/dochighlight.py +66 -94
- novelwriter/gui/docviewer.py +71 -98
- novelwriter/gui/docviewerpanel.py +140 -47
- novelwriter/gui/editordocument.py +3 -3
- novelwriter/gui/itemdetails.py +9 -9
- novelwriter/gui/mainmenu.py +47 -47
- novelwriter/gui/noveltree.py +53 -61
- novelwriter/gui/outline.py +100 -76
- novelwriter/gui/projtree.py +246 -112
- novelwriter/gui/sidebar.py +9 -8
- novelwriter/gui/statusbar.py +49 -7
- novelwriter/gui/theme.py +74 -76
- novelwriter/guimain.py +175 -330
- novelwriter/shared.py +68 -30
- novelwriter/tools/dictionaries.py +7 -8
- novelwriter/tools/lipsum.py +34 -28
- novelwriter/tools/manusbuild.py +3 -4
- novelwriter/tools/manuscript.py +25 -32
- novelwriter/tools/manussettings.py +194 -225
- novelwriter/tools/noveldetails.py +525 -0
- novelwriter/tools/welcome.py +819 -0
- novelwriter/tools/writingstats.py +26 -13
- novelWriter-2.2rc1.dist-info/entry_points.txt +0 -5
- novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
- novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
- novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
- novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
- novelwriter/assets/images/wizard-back.jpg +0 -0
- novelwriter/assets/text/gplv3_en.htm +0 -641
- novelwriter/assets/text/release_notes.htm +0 -17
- novelwriter/dialogs/projdetails.py +0 -525
- novelwriter/dialogs/projload.py +0 -298
- novelwriter/dialogs/updates.py +0 -182
- novelwriter/extensions/pageddialog.py +0 -130
- novelwriter/tools/projwizard.py +0 -478
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,13 @@ novelWriter – Custom Widget: Config Layout
|
|
3
3
|
==========================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2020-05-03 [0.4.5]
|
6
|
+
Created: 2020-05-03 [0.4.5] NColourLabel
|
7
|
+
Created: 2024-01-08 [2.3b1] NScrollableForm
|
8
|
+
Created: 2024-01-26 [2.3b1] NScrollablePage
|
9
|
+
Created: 2024-01-26 [2.3b1] NFixedPage
|
7
10
|
|
8
11
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
12
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
13
|
|
11
14
|
This program is free software: you can redistribute it and/or modify
|
12
15
|
it under the terms of the GNU General Public License as published by
|
@@ -23,210 +26,246 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
26
|
"""
|
24
27
|
from __future__ import annotations
|
25
28
|
|
26
|
-
from PyQt5.QtGui import QColor, QPalette
|
29
|
+
from PyQt5.QtGui import QColor, QFont, QPalette
|
27
30
|
from PyQt5.QtCore import Qt
|
28
31
|
from PyQt5.QtWidgets import (
|
29
|
-
QAbstractButton,
|
32
|
+
QAbstractButton, QFrame, QHBoxLayout, QLabel, QLayout, QScrollArea,
|
30
33
|
QVBoxLayout, QWidget
|
31
34
|
)
|
32
35
|
|
33
36
|
from novelwriter import CONFIG
|
34
37
|
|
35
|
-
|
38
|
+
DEFAULT_SCALE = 0.9
|
39
|
+
RIGHT_TOP = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop
|
40
|
+
LEFT_TOP = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
|
36
41
|
|
37
42
|
|
38
|
-
class
|
43
|
+
class NFixedPage(QFrame):
|
44
|
+
"""Extension: Fixed Page Widget
|
39
45
|
|
40
|
-
|
41
|
-
|
46
|
+
A custom widget that holds a layout. This is just a wrapper around a
|
47
|
+
QFrame that sets the same frame style as the other Page widgets.
|
48
|
+
"""
|
42
49
|
|
43
|
-
|
44
|
-
|
45
|
-
self.
|
46
|
-
self.
|
50
|
+
def __init__(self, parent: QWidget) -> None:
|
51
|
+
super().__init__(parent=parent)
|
52
|
+
self.setFrameShadow(QFrame.Shadow.Sunken)
|
53
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
54
|
+
return
|
47
55
|
|
48
|
-
|
49
|
-
|
50
|
-
self.
|
51
|
-
|
56
|
+
def setCentralLayout(self, layout: QLayout) -> None:
|
57
|
+
"""Set a layout as the central object."""
|
58
|
+
self.setLayout(layout)
|
59
|
+
return
|
52
60
|
|
61
|
+
def setCentralWidget(self, widget: QWidget) -> None:
|
62
|
+
"""Set a layout as the central object."""
|
63
|
+
layout = QHBoxLayout()
|
64
|
+
layout.addWidget(widget)
|
65
|
+
self.setLayout(layout)
|
53
66
|
return
|
54
67
|
|
55
|
-
|
56
|
-
# Getters and Setters
|
57
|
-
##
|
68
|
+
# END Class NFixedPage
|
58
69
|
|
59
|
-
def setHelpTextStyle(self, color: QColor | list | tuple,
|
60
|
-
fontScale: float = FONT_SCALE) -> None:
|
61
|
-
"""Set the text color for the help text."""
|
62
|
-
if isinstance(color, QColor):
|
63
|
-
self._helpCol = color
|
64
|
-
else:
|
65
|
-
self._helpCol = QColor(*color)
|
66
|
-
self._fontScale = fontScale
|
67
|
-
return
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
class NScrollablePage(QScrollArea):
|
72
|
+
"""Extension: Scrollable Page Widget
|
73
|
+
|
74
|
+
A custom widget that holds a layout within a scrollable area.
|
75
|
+
"""
|
76
|
+
|
77
|
+
def __init__(self, parent: QWidget) -> None:
|
78
|
+
super().__init__(parent=parent)
|
79
|
+
self._widget = QWidget(self)
|
80
|
+
self.setWidget(self._widget)
|
81
|
+
self.setWidgetResizable(True)
|
82
|
+
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
83
|
+
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
84
|
+
self.setFrameShadow(QFrame.Shadow.Sunken)
|
85
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
75
86
|
return
|
76
87
|
|
77
|
-
def
|
78
|
-
"""Set the
|
79
|
-
|
80
|
-
self._itemMap[row](0).setText(text)
|
88
|
+
def setCentralLayout(self, layout: QLayout) -> None:
|
89
|
+
"""Set the central layout of the scroll page."""
|
90
|
+
self._widget.setLayout(layout)
|
81
91
|
return
|
82
92
|
|
83
|
-
|
84
|
-
# Class Methods
|
85
|
-
##
|
93
|
+
# END Class NScrollablePage
|
86
94
|
|
87
|
-
def addGroupLabel(self, label: str) -> None:
|
88
|
-
"""Add a text label to separate groups of settings."""
|
89
|
-
hM = CONFIG.pxInt(4)
|
90
|
-
qLabel = QLabel("<b>%s</b>" % label)
|
91
|
-
qLabel.setContentsMargins(0, hM, 0, hM)
|
92
|
-
self.addWidget(qLabel, self._nextRow, 0, 1, 2, Qt.AlignLeft)
|
93
|
-
self.setRowStretch(self._nextRow, 0)
|
94
|
-
self.setRowStretch(self._nextRow + 1, 1)
|
95
|
-
self._nextRow += 1
|
96
|
-
return
|
97
95
|
|
98
|
-
|
99
|
-
|
100
|
-
"""Add a label and a widget as a new row of the grid."""
|
101
|
-
wSp = CONFIG.pxInt(8)
|
102
|
-
qLabel = QLabel(label)
|
103
|
-
qLabel.setIndent(wSp)
|
104
|
-
qLabel.setBuddy(widget)
|
96
|
+
class NScrollableForm(QScrollArea):
|
97
|
+
"""Extension: Scrollable Form Widget
|
105
98
|
|
106
|
-
|
107
|
-
|
108
|
-
qHelp = NHelpLabel(str(helpText), self._helpCol, self._fontScale)
|
109
|
-
qHelp.setIndent(wSp)
|
110
|
-
labelBox = QVBoxLayout()
|
111
|
-
labelBox.addWidget(qLabel)
|
112
|
-
labelBox.addWidget(qHelp)
|
113
|
-
labelBox.setSpacing(0)
|
114
|
-
labelBox.addStretch(1)
|
115
|
-
self.addLayout(labelBox, self._nextRow, 0, 1, 1, Qt.AlignLeft | Qt.AlignTop)
|
116
|
-
else:
|
117
|
-
self.addWidget(qLabel, self._nextRow, 0, 1, 1, Qt.AlignLeft | Qt.AlignTop)
|
99
|
+
A custom widget that creates a form within a scrollable area.
|
100
|
+
"""
|
118
101
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
102
|
+
def __init__(self, parent: QWidget) -> None:
|
103
|
+
super().__init__(parent=parent)
|
104
|
+
self._helpCol = QColor(0, 0, 0)
|
105
|
+
self._fontScale = DEFAULT_SCALE
|
106
|
+
self._first = True
|
107
|
+
self._indent = CONFIG.pxInt(12)
|
125
108
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
controlBox.addWidget(button, 0, Qt.AlignVCenter)
|
130
|
-
controlBox.setSpacing(wSp)
|
131
|
-
self.addLayout(controlBox, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignTop)
|
109
|
+
self._sections: dict[int, QLabel] = {}
|
110
|
+
self._editable: dict[str, NColourLabel] = {}
|
111
|
+
self._index: dict[str, QWidget] = {}
|
132
112
|
|
133
|
-
|
134
|
-
|
135
|
-
qLayout = QHBoxLayout()
|
136
|
-
qLayout.addWidget(widget)
|
137
|
-
self.addLayout(qLayout, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignTop)
|
138
|
-
else:
|
139
|
-
self.addWidget(widget, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignTop)
|
113
|
+
self._layout = QVBoxLayout()
|
114
|
+
self._layout.setSpacing(CONFIG.pxInt(12))
|
140
115
|
|
141
|
-
self.
|
142
|
-
self.
|
116
|
+
self._widget = QWidget(self)
|
117
|
+
self._widget.setLayout(self._layout)
|
143
118
|
|
144
|
-
self.
|
145
|
-
self.
|
119
|
+
self.setWidget(self._widget)
|
120
|
+
self.setWidgetResizable(True)
|
121
|
+
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
122
|
+
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
123
|
+
self.setFrameShadow(QFrame.Shadow.Sunken)
|
124
|
+
self.setFrameShape(QFrame.Shape.StyledPanel)
|
146
125
|
|
147
|
-
return
|
126
|
+
return
|
148
127
|
|
149
|
-
|
128
|
+
##
|
129
|
+
# Properties
|
130
|
+
##
|
150
131
|
|
132
|
+
@property
|
133
|
+
def labels(self) -> list[str]:
|
134
|
+
return list(self._index.keys())
|
151
135
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
"""
|
136
|
+
##
|
137
|
+
# Setters
|
138
|
+
##
|
156
139
|
|
157
|
-
def
|
158
|
-
|
159
|
-
self.
|
140
|
+
def setHelpTextStyle(self, color: QColor, scale: float = DEFAULT_SCALE) -> None:
|
141
|
+
"""Set the text color for the help text."""
|
142
|
+
self._helpCol = color
|
143
|
+
self._fontScale = scale
|
144
|
+
return
|
160
145
|
|
161
|
-
|
162
|
-
|
163
|
-
self.
|
164
|
-
|
146
|
+
def setHelpText(self, key: str, text: str) -> None:
|
147
|
+
"""Set the text for the help label."""
|
148
|
+
if qHelp := self._editable.get(key):
|
149
|
+
qHelp.setText(text)
|
150
|
+
return
|
165
151
|
|
152
|
+
def setRowIndent(self, indent: int) -> None:
|
153
|
+
"""Set the indentation of each row."""
|
154
|
+
self._indent = max(indent, 0)
|
166
155
|
return
|
167
156
|
|
168
157
|
##
|
169
158
|
# Methods
|
170
159
|
##
|
171
160
|
|
172
|
-
def
|
161
|
+
def scrollToSection(self, identifier: int) -> None:
|
162
|
+
"""Scroll to the requested section identifier."""
|
163
|
+
if identifier in self._sections:
|
164
|
+
yPos = self._sections[identifier].pos().y() - CONFIG.pxInt(8)
|
165
|
+
self.verticalScrollBar().setValue(yPos)
|
166
|
+
return
|
167
|
+
|
168
|
+
def scrollToLabel(self, label: str) -> None:
|
169
|
+
"""Scroll to the requested label."""
|
170
|
+
if label in self._index:
|
171
|
+
yPos = self._index[label].pos().y() - CONFIG.pxInt(8)
|
172
|
+
self.verticalScrollBar().setValue(yPos)
|
173
|
+
return
|
174
|
+
|
175
|
+
def addGroupLabel(self, label: str, identifier: int | None = None) -> None:
|
173
176
|
"""Add a text label to separate groups of settings."""
|
174
177
|
hM = CONFIG.pxInt(4)
|
175
|
-
qLabel = QLabel("<b
|
178
|
+
qLabel = QLabel(f"<b>{label}</b>", self)
|
176
179
|
qLabel.setContentsMargins(0, hM, 0, hM)
|
177
|
-
|
178
|
-
|
179
|
-
self.
|
180
|
-
self.
|
180
|
+
if not self._first:
|
181
|
+
self._layout.addSpacing(5*hM)
|
182
|
+
self._layout.addWidget(qLabel)
|
183
|
+
self._first = False
|
184
|
+
if identifier is not None:
|
185
|
+
self._sections[identifier] = qLabel
|
181
186
|
return
|
182
187
|
|
183
|
-
def addRow(self, label: str, widget: QWidget
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
if isinstance(widget, QLineEdit):
|
191
|
-
qLayout = QHBoxLayout()
|
192
|
-
qLayout.addWidget(widget)
|
193
|
-
self.addLayout(qLayout, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignTop)
|
194
|
-
else:
|
195
|
-
self.addWidget(widget, self._nextRow, 1, 1, 1, Qt.AlignRight | Qt.AlignTop)
|
188
|
+
def addRow(self, label: str, widget: QWidget, helpText: str = "", unit: str | None = None,
|
189
|
+
button: QWidget | None = None, editable: str | None = None,
|
190
|
+
stretch: tuple[int, int] = (1, 0)) -> None:
|
191
|
+
"""Add a label and a widget as a new row of the form."""
|
192
|
+
row = QHBoxLayout()
|
193
|
+
row.setSpacing(CONFIG.pxInt(12))
|
196
194
|
|
195
|
+
qLabel = QLabel(label, self)
|
196
|
+
qLabel.setIndent(self._indent)
|
197
197
|
qLabel.setBuddy(widget)
|
198
198
|
|
199
|
-
|
200
|
-
|
201
|
-
|
199
|
+
if helpText:
|
200
|
+
qHelp = NColourLabel(
|
201
|
+
str(helpText), color=self._helpCol, parent=self,
|
202
|
+
scale=self._fontScale, wrap=True, indent=self._indent
|
203
|
+
)
|
204
|
+
labelBox = QVBoxLayout()
|
205
|
+
labelBox.addWidget(qLabel, 0)
|
206
|
+
labelBox.addWidget(qHelp, 1)
|
207
|
+
labelBox.setSpacing(0)
|
208
|
+
row.addLayout(labelBox, stretch[0])
|
209
|
+
if editable:
|
210
|
+
self._editable[editable] = qHelp
|
211
|
+
else:
|
212
|
+
row.addWidget(qLabel, stretch[0])
|
202
213
|
|
214
|
+
if isinstance(unit, str):
|
215
|
+
box = QHBoxLayout()
|
216
|
+
box.addWidget(widget, 1)
|
217
|
+
box.addWidget(QLabel(unit, self), 0)
|
218
|
+
row.addLayout(box, stretch[1])
|
219
|
+
elif isinstance(button, QAbstractButton):
|
220
|
+
box = QHBoxLayout()
|
221
|
+
box.addWidget(widget, 1)
|
222
|
+
box.addWidget(button, 0)
|
223
|
+
row.addLayout(box, stretch[1])
|
224
|
+
else:
|
225
|
+
row.addWidget(widget, stretch[1])
|
226
|
+
|
227
|
+
self._layout.addLayout(row)
|
228
|
+
self._index[label.strip()] = widget
|
229
|
+
self._first = False
|
230
|
+
|
231
|
+
return
|
232
|
+
|
233
|
+
def finalise(self) -> None:
|
234
|
+
"""Finalise the layout when the form is built."""
|
235
|
+
self._layout.addSpacing(CONFIG.pxInt(20))
|
236
|
+
self._layout.addStretch(1)
|
203
237
|
return
|
204
238
|
|
205
|
-
# END Class
|
239
|
+
# END Class NScrollableForm
|
206
240
|
|
207
241
|
|
208
|
-
class
|
242
|
+
class NColourLabel(QLabel):
|
243
|
+
"""Extension: A Coloured Label
|
209
244
|
|
210
|
-
|
211
|
-
|
212
|
-
|
245
|
+
A custom widget that draws a label in a specific colour, and
|
246
|
+
optionally at a specific size, and word wrapped.
|
247
|
+
"""
|
213
248
|
|
214
|
-
|
215
|
-
|
216
|
-
else:
|
217
|
-
qCol = QColor(*color)
|
249
|
+
HELP_SCALE = DEFAULT_SCALE
|
250
|
+
HEADER_SCALE = 1.25
|
218
251
|
|
219
|
-
|
220
|
-
|
221
|
-
|
252
|
+
def __init__(self, text: str, color: QColor | None = None, parent: QWidget | None = None,
|
253
|
+
scale: float = HELP_SCALE, wrap: bool = False, indent: int = 0,
|
254
|
+
bold: bool = False) -> None:
|
255
|
+
super().__init__(text, parent=parent)
|
222
256
|
|
223
|
-
|
224
|
-
|
225
|
-
|
257
|
+
font = self.font()
|
258
|
+
font.setPointSizeF(scale*font.pointSizeF())
|
259
|
+
font.setWeight(QFont.Weight.Bold if bold else QFont.Weight.Normal)
|
260
|
+
if color:
|
261
|
+
colour = self.palette()
|
262
|
+
colour.setColor(QPalette.WindowText, color)
|
263
|
+
self.setPalette(colour)
|
226
264
|
|
227
|
-
self.
|
228
|
-
self.
|
265
|
+
self.setFont(font)
|
266
|
+
self.setIndent(indent)
|
267
|
+
self.setWordWrap(wrap)
|
229
268
|
|
230
269
|
return
|
231
270
|
|
232
|
-
# END Class
|
271
|
+
# END Class NColourLabel
|
@@ -1,12 +1,13 @@
|
|
1
1
|
"""
|
2
|
-
novelWriter – Custom
|
3
|
-
|
2
|
+
novelWriter – Custom Objects: Event Filters
|
3
|
+
===========================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2023-08-31 [2.1rc1]
|
6
|
+
Created: 2023-08-31 [2.1rc1] WheelEventFilter
|
7
|
+
Created: 2023-11-28 [2.2] StatusTipFilter
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
10
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
11
|
|
11
12
|
This program is free software: you can redistribute it and/or modify
|
12
13
|
it under the terms of the GNU General Public License as published by
|
@@ -23,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
24
|
"""
|
24
25
|
from __future__ import annotations
|
25
26
|
|
26
|
-
from PyQt5.QtGui import QWheelEvent
|
27
|
+
from PyQt5.QtGui import QStatusTipEvent, QWheelEvent
|
27
28
|
from PyQt5.QtCore import QEvent, QObject
|
28
29
|
from PyQt5.QtWidgets import QWidget
|
29
30
|
|
@@ -63,3 +64,12 @@ class WheelEventFilter(QObject):
|
|
63
64
|
return False
|
64
65
|
|
65
66
|
# END Class WheelEventFilter
|
67
|
+
|
68
|
+
|
69
|
+
class StatusTipFilter(QObject):
|
70
|
+
|
71
|
+
def eventFilter(self, obj: QObject, event: QEvent) -> bool:
|
72
|
+
"""Filter out status tip events on menus."""
|
73
|
+
return True if isinstance(event, QStatusTipEvent) else super().eventFilter(obj, event)
|
74
|
+
|
75
|
+
# END Class StatusTipFilter
|
@@ -0,0 +1,81 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Custom Widget: Modified Widgets
|
3
|
+
=============================================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2024-02-01 [2.3b1] NComboBox
|
7
|
+
Created: 2024-02-01 [2.3b1] NSpinBox
|
8
|
+
Created: 2024-02-01 [2.3b1] NDoubleSpinBox
|
9
|
+
|
10
|
+
This file is a part of novelWriter
|
11
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
12
|
+
|
13
|
+
This program is free software: you can redistribute it and/or modify
|
14
|
+
it under the terms of the GNU General Public License as published by
|
15
|
+
the Free Software Foundation, either version 3 of the License, or
|
16
|
+
(at your option) any later version.
|
17
|
+
|
18
|
+
This program is distributed in the hope that it will be useful, but
|
19
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
20
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
21
|
+
General Public License for more details.
|
22
|
+
|
23
|
+
You should have received a copy of the GNU General Public License
|
24
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
25
|
+
"""
|
26
|
+
from __future__ import annotations
|
27
|
+
|
28
|
+
from PyQt5.QtCore import Qt
|
29
|
+
from PyQt5.QtGui import QWheelEvent
|
30
|
+
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QWidget
|
31
|
+
|
32
|
+
|
33
|
+
class NComboBox(QComboBox):
|
34
|
+
|
35
|
+
def __init__(self, parent: QWidget | None = None) -> None:
|
36
|
+
super().__init__(parent=parent)
|
37
|
+
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
38
|
+
return
|
39
|
+
|
40
|
+
def wheelEvent(self, event: QWheelEvent) -> None:
|
41
|
+
if self.hasFocus():
|
42
|
+
super().wheelEvent(event)
|
43
|
+
else:
|
44
|
+
event.ignore()
|
45
|
+
return
|
46
|
+
|
47
|
+
# END Class NComboBox
|
48
|
+
|
49
|
+
|
50
|
+
class NSpinBox(QSpinBox):
|
51
|
+
|
52
|
+
def __init__(self, parent: QWidget | None = None) -> None:
|
53
|
+
super().__init__(parent=parent)
|
54
|
+
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
55
|
+
return
|
56
|
+
|
57
|
+
def wheelEvent(self, event: QWheelEvent) -> None:
|
58
|
+
if self.hasFocus():
|
59
|
+
super().wheelEvent(event)
|
60
|
+
else:
|
61
|
+
event.ignore()
|
62
|
+
return
|
63
|
+
|
64
|
+
# END Class NSpinBox
|
65
|
+
|
66
|
+
|
67
|
+
class NDoubleSpinBox(QDoubleSpinBox):
|
68
|
+
|
69
|
+
def __init__(self, parent: QWidget | None = None) -> None:
|
70
|
+
super().__init__(parent=parent)
|
71
|
+
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
72
|
+
return
|
73
|
+
|
74
|
+
def wheelEvent(self, event: QWheelEvent) -> None:
|
75
|
+
if self.hasFocus():
|
76
|
+
super().wheelEvent(event)
|
77
|
+
else:
|
78
|
+
event.ignore()
|
79
|
+
return
|
80
|
+
|
81
|
+
# END Class NDoubleSpinBox
|
@@ -3,10 +3,10 @@ novelWriter – Custom Widget: Novel Selector
|
|
3
3
|
===========================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2022-11-17 [2.0]
|
6
|
+
Created: 2022-11-17 [2.0] NovelSelector
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright 2018–
|
9
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -43,6 +43,8 @@ class NovelSelector(QComboBox):
|
|
43
43
|
super().__init__(parent=parent)
|
44
44
|
self._blockSignal = False
|
45
45
|
self._firstHandle = None
|
46
|
+
self._includeAll = False
|
47
|
+
self._listFormat = None
|
46
48
|
self.currentIndexChanged.connect(self._indexChanged)
|
47
49
|
return
|
48
50
|
|
@@ -64,17 +66,29 @@ class NovelSelector(QComboBox):
|
|
64
66
|
|
65
67
|
def setHandle(self, tHandle: str | None, blockSignal: bool = True) -> None:
|
66
68
|
"""Set the currently selected handle."""
|
67
|
-
self.
|
68
|
-
|
69
|
-
index = self.count() - 1
|
70
|
-
else:
|
71
|
-
index = self.findData(tHandle)
|
72
|
-
if index >= 0:
|
69
|
+
if (index := self.findData(tHandle) if tHandle else (self.count() - 1)) >= 0:
|
70
|
+
self._blockSignal = blockSignal
|
73
71
|
self.setCurrentIndex(index)
|
74
|
-
|
72
|
+
self._blockSignal = False
|
73
|
+
return
|
74
|
+
|
75
|
+
def setIncludeAll(self, value: bool) -> None:
|
76
|
+
"""Set flag to add an "All Novel Folders" option."""
|
77
|
+
self._includeAll = value
|
78
|
+
return
|
79
|
+
|
80
|
+
def setListFormat(self, value: str | None) -> None:
|
81
|
+
"""Set a format string for the list entries."""
|
82
|
+
if value is None or "{0}" in value:
|
83
|
+
self._listFormat = value
|
75
84
|
return
|
76
85
|
|
77
|
-
|
86
|
+
##
|
87
|
+
# Public Slots
|
88
|
+
##
|
89
|
+
|
90
|
+
@pyqtSlot()
|
91
|
+
def refreshNovelList(self) -> None:
|
78
92
|
"""Rebuild the list of novel items."""
|
79
93
|
self._blockSignal = True
|
80
94
|
self._firstHandle = None
|
@@ -83,8 +97,8 @@ class NovelSelector(QComboBox):
|
|
83
97
|
icon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
|
84
98
|
handle = self.currentData()
|
85
99
|
for tHandle, nwItem in SHARED.project.tree.iterRoots(nwItemClass.NOVEL):
|
86
|
-
if
|
87
|
-
name =
|
100
|
+
if self._listFormat:
|
101
|
+
name = self._listFormat.format(nwItem.itemName)
|
88
102
|
self.addItem(name, tHandle)
|
89
103
|
else:
|
90
104
|
name = nwItem.itemName
|
@@ -92,7 +106,7 @@ class NovelSelector(QComboBox):
|
|
92
106
|
if self._firstHandle is None:
|
93
107
|
self._firstHandle = tHandle
|
94
108
|
|
95
|
-
if
|
109
|
+
if self._includeAll:
|
96
110
|
self.insertSeparator(self.count())
|
97
111
|
self.addItem(icon, self.tr("All Novel Folders"), "")
|
98
112
|
|