novelWriter 2.7.4__py3-none-any.whl → 2.8b1__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.
Files changed (196) hide show
  1. novelwriter/__init__.py +8 -7
  2. novelwriter/assets/icons/font_awesome.icons +22 -4
  3. novelwriter/assets/icons/material_filled_normal.icons +20 -2
  4. novelwriter/assets/icons/material_filled_thin.icons +20 -2
  5. novelwriter/assets/icons/material_rounded_normal.icons +20 -2
  6. novelwriter/assets/icons/material_rounded_thin.icons +20 -2
  7. novelwriter/assets/icons/material_sharp_normal.icons +20 -2
  8. novelwriter/assets/icons/material_sharp_thin.icons +20 -2
  9. novelwriter/assets/icons/remix_filled.icons +20 -2
  10. novelwriter/assets/icons/remix_outline.icons +20 -2
  11. novelwriter/assets/images/welcome.webp +0 -0
  12. novelwriter/assets/manual.pdf +0 -0
  13. novelwriter/assets/manual_fr.pdf +0 -0
  14. novelwriter/assets/sample.zip +0 -0
  15. novelwriter/assets/text/credits_en.htm +61 -11
  16. novelwriter/assets/themes/aura.conf +97 -0
  17. novelwriter/assets/themes/aura_bright.conf +95 -0
  18. novelwriter/assets/themes/aura_soft.conf +97 -0
  19. novelwriter/assets/themes/b2t_garden_dark.conf +97 -0
  20. novelwriter/assets/themes/b2t_garden_light.conf +97 -0
  21. novelwriter/assets/themes/b2t_suburb_dark.conf +97 -0
  22. novelwriter/assets/themes/b2t_suburb_light.conf +97 -0
  23. novelwriter/assets/themes/b4t_classic_o_dark.conf +97 -0
  24. novelwriter/assets/themes/b4t_classic_o_light.conf +97 -0
  25. novelwriter/assets/themes/b4t_modern_c_dark.conf +97 -0
  26. novelwriter/assets/themes/b4t_modern_c_light.conf +97 -0
  27. novelwriter/assets/themes/blue_streak_dark.conf +97 -0
  28. novelwriter/assets/themes/blue_streak_light.conf +97 -0
  29. novelwriter/assets/themes/castle_day.conf +95 -0
  30. novelwriter/assets/themes/castle_night.conf +95 -0
  31. novelwriter/assets/themes/catppuccin_latte.conf +97 -0
  32. novelwriter/assets/themes/catppuccin_mocha.conf +97 -0
  33. novelwriter/assets/themes/chalky_soil.conf +95 -0
  34. novelwriter/assets/themes/chernozem.conf +95 -0
  35. novelwriter/assets/themes/cyberpunk_night.conf +88 -40
  36. novelwriter/assets/themes/default_dark.conf +89 -41
  37. novelwriter/assets/themes/default_light.conf +89 -41
  38. novelwriter/assets/themes/dracula.conf +91 -42
  39. novelwriter/assets/themes/espresso.conf +97 -0
  40. novelwriter/assets/themes/everforest_dark.conf +97 -0
  41. novelwriter/assets/themes/everforest_light.conf +97 -0
  42. novelwriter/assets/themes/floral_daydream.conf +95 -0
  43. novelwriter/assets/themes/floral_midnight.conf +95 -0
  44. novelwriter/assets/themes/full_moon.conf +95 -0
  45. novelwriter/assets/themes/grey_dark.conf +97 -0
  46. novelwriter/assets/themes/grey_light.conf +97 -0
  47. novelwriter/assets/themes/horizon_dark.conf +97 -0
  48. novelwriter/assets/themes/horizon_light.conf +97 -0
  49. novelwriter/assets/themes/jewel_case_dark.conf +95 -0
  50. novelwriter/assets/themes/jewel_case_light.conf +95 -0
  51. novelwriter/assets/themes/lcars.conf +97 -0
  52. novelwriter/assets/themes/light_owl.conf +117 -0
  53. novelwriter/assets/themes/new_moon.conf +97 -0
  54. novelwriter/assets/themes/night_owl.conf +117 -0
  55. novelwriter/assets/themes/noctis.conf +129 -0
  56. novelwriter/assets/themes/noctis_lux.conf +129 -0
  57. novelwriter/assets/themes/nord.conf +97 -0
  58. novelwriter/assets/themes/nordlicht.conf +95 -0
  59. novelwriter/assets/themes/otium_dark.conf +95 -0
  60. novelwriter/assets/themes/otium_light.conf +95 -0
  61. novelwriter/assets/themes/paragon.conf +96 -0
  62. novelwriter/assets/themes/primer_light.conf +97 -0
  63. novelwriter/assets/themes/primer_night.conf +97 -0
  64. novelwriter/assets/themes/rose_pine.conf +97 -0
  65. novelwriter/assets/themes/rose_pine_dawn.conf +97 -0
  66. novelwriter/assets/themes/ruby_day.conf +95 -0
  67. novelwriter/assets/themes/ruby_night.conf +95 -0
  68. novelwriter/assets/themes/selenium_dark.conf +95 -0
  69. novelwriter/assets/themes/selenium_light.conf +95 -0
  70. novelwriter/assets/themes/sepia_dark.conf +95 -0
  71. novelwriter/assets/themes/sepia_light.conf +95 -0
  72. novelwriter/assets/themes/snazzy.conf +102 -40
  73. novelwriter/assets/themes/solarized_dark.conf +108 -40
  74. novelwriter/assets/themes/solarized_light.conf +108 -40
  75. novelwriter/assets/themes/sultana_light.conf +95 -0
  76. novelwriter/assets/themes/sultana_night.conf +95 -0
  77. novelwriter/assets/themes/tango_dark.conf +111 -0
  78. novelwriter/assets/themes/tango_light.conf +111 -0
  79. novelwriter/assets/themes/tomorrow.conf +117 -0
  80. novelwriter/assets/themes/tomorrow_night.conf +117 -0
  81. novelwriter/assets/themes/tomorrow_night_blue.conf +117 -0
  82. novelwriter/assets/themes/tomorrow_night_bright.conf +117 -0
  83. novelwriter/assets/themes/tomorrow_night_eighties.conf +117 -0
  84. novelwriter/assets/themes/vivid_black_green.conf +97 -0
  85. novelwriter/assets/themes/vivid_black_red.conf +97 -0
  86. novelwriter/assets/themes/vivid_white_green.conf +97 -0
  87. novelwriter/assets/themes/vivid_white_red.conf +97 -0
  88. novelwriter/assets/themes/warpgate.conf +96 -0
  89. novelwriter/assets/themes/waterlily_dark.conf +95 -0
  90. novelwriter/assets/themes/waterlily_light.conf +95 -0
  91. novelwriter/common.py +47 -17
  92. novelwriter/config.py +57 -62
  93. novelwriter/constants.py +32 -6
  94. novelwriter/core/buildsettings.py +3 -23
  95. novelwriter/core/coretools.py +21 -25
  96. novelwriter/core/docbuild.py +4 -9
  97. novelwriter/core/document.py +2 -6
  98. novelwriter/core/index.py +33 -53
  99. novelwriter/core/indexdata.py +17 -22
  100. novelwriter/core/item.py +11 -35
  101. novelwriter/core/itemmodel.py +5 -21
  102. novelwriter/core/novelmodel.py +3 -7
  103. novelwriter/core/options.py +3 -4
  104. novelwriter/core/project.py +31 -21
  105. novelwriter/core/projectdata.py +2 -21
  106. novelwriter/core/projectxml.py +13 -21
  107. novelwriter/core/sessions.py +2 -4
  108. novelwriter/core/spellcheck.py +12 -13
  109. novelwriter/core/status.py +27 -20
  110. novelwriter/core/storage.py +5 -10
  111. novelwriter/core/tree.py +6 -15
  112. novelwriter/dialogs/about.py +9 -10
  113. novelwriter/dialogs/docmerge.py +17 -14
  114. novelwriter/dialogs/docsplit.py +18 -14
  115. novelwriter/dialogs/editlabel.py +15 -9
  116. novelwriter/dialogs/preferences.py +69 -68
  117. novelwriter/dialogs/projectsettings.py +88 -67
  118. novelwriter/dialogs/quotes.py +15 -10
  119. novelwriter/dialogs/wordlist.py +18 -21
  120. novelwriter/enum.py +75 -30
  121. novelwriter/error.py +6 -11
  122. novelwriter/extensions/configlayout.py +8 -34
  123. novelwriter/extensions/eventfilters.py +3 -3
  124. novelwriter/extensions/modified.py +87 -32
  125. novelwriter/extensions/novelselector.py +13 -12
  126. novelwriter/extensions/pagedsidebar.py +10 -18
  127. novelwriter/extensions/progressbars.py +5 -11
  128. novelwriter/extensions/statusled.py +3 -6
  129. novelwriter/extensions/switch.py +8 -11
  130. novelwriter/extensions/switchbox.py +2 -11
  131. novelwriter/extensions/versioninfo.py +6 -7
  132. novelwriter/formats/shared.py +10 -2
  133. novelwriter/formats/todocx.py +15 -37
  134. novelwriter/formats/tohtml.py +52 -61
  135. novelwriter/formats/tokenizer.py +33 -64
  136. novelwriter/formats/tomarkdown.py +4 -11
  137. novelwriter/formats/toodt.py +12 -71
  138. novelwriter/formats/toqdoc.py +11 -21
  139. novelwriter/formats/toraw.py +2 -6
  140. novelwriter/gui/doceditor.py +207 -245
  141. novelwriter/gui/dochighlight.py +142 -101
  142. novelwriter/gui/docviewer.py +53 -84
  143. novelwriter/gui/docviewerpanel.py +18 -41
  144. novelwriter/gui/editordocument.py +12 -17
  145. novelwriter/gui/itemdetails.py +5 -14
  146. novelwriter/gui/mainmenu.py +24 -32
  147. novelwriter/gui/noveltree.py +13 -51
  148. novelwriter/gui/outline.py +20 -61
  149. novelwriter/gui/projtree.py +40 -96
  150. novelwriter/gui/search.py +9 -24
  151. novelwriter/gui/sidebar.py +54 -22
  152. novelwriter/gui/statusbar.py +7 -22
  153. novelwriter/gui/theme.py +482 -368
  154. novelwriter/guimain.py +87 -101
  155. novelwriter/shared.py +79 -48
  156. novelwriter/splash.py +9 -5
  157. novelwriter/text/comments.py +1 -1
  158. novelwriter/text/counting.py +9 -5
  159. novelwriter/text/patterns.py +20 -15
  160. novelwriter/tools/dictionaries.py +18 -16
  161. novelwriter/tools/lipsum.py +15 -17
  162. novelwriter/tools/manusbuild.py +25 -45
  163. novelwriter/tools/manuscript.py +94 -95
  164. novelwriter/tools/manussettings.py +149 -104
  165. novelwriter/tools/noveldetails.py +10 -24
  166. novelwriter/tools/welcome.py +24 -72
  167. novelwriter/tools/writingstats.py +17 -26
  168. novelwriter/types.py +25 -13
  169. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/METADATA +7 -7
  170. novelwriter-2.8b1.dist-info/RECORD +212 -0
  171. novelwriter/assets/images/welcome-dark.jpg +0 -0
  172. novelwriter/assets/images/welcome-light.jpg +0 -0
  173. novelwriter/assets/syntax/cyberpunk_night.conf +0 -28
  174. novelwriter/assets/syntax/default_dark.conf +0 -42
  175. novelwriter/assets/syntax/default_light.conf +0 -42
  176. novelwriter/assets/syntax/dracula.conf +0 -44
  177. novelwriter/assets/syntax/grey_dark.conf +0 -29
  178. novelwriter/assets/syntax/grey_light.conf +0 -29
  179. novelwriter/assets/syntax/light_owl.conf +0 -49
  180. novelwriter/assets/syntax/night_owl.conf +0 -49
  181. novelwriter/assets/syntax/snazzy.conf +0 -42
  182. novelwriter/assets/syntax/solarized_dark.conf +0 -29
  183. novelwriter/assets/syntax/solarized_light.conf +0 -29
  184. novelwriter/assets/syntax/tango.conf +0 -39
  185. novelwriter/assets/syntax/tomorrow.conf +0 -49
  186. novelwriter/assets/syntax/tomorrow_night.conf +0 -49
  187. novelwriter/assets/syntax/tomorrow_night_blue.conf +0 -49
  188. novelwriter/assets/syntax/tomorrow_night_bright.conf +0 -49
  189. novelwriter/assets/syntax/tomorrow_night_eighties.conf +0 -49
  190. novelwriter/assets/themes/default.conf +0 -3
  191. novelwriter-2.7.4.dist-info/RECORD +0 -163
  192. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
  193. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
  194. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
  195. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
  196. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,7 @@ General Public License for more details.
21
21
 
22
22
  You should have received a copy of the GNU General Public License
23
23
  along with this program. If not, see <https://www.gnu.org/licenses/>.
24
- """
24
+ """ # noqa
25
25
  from __future__ import annotations
26
26
 
27
27
  import csv
@@ -33,21 +33,21 @@ from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
33
33
  from PyQt6.QtGui import QCloseEvent, QColor
34
34
  from PyQt6.QtWidgets import (
35
35
  QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
36
- QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget,
37
- QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
36
+ QFileDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
37
+ QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
38
38
  )
39
39
 
40
40
  from novelwriter import CONFIG, SHARED
41
41
  from novelwriter.common import formatFileFilter, qtAddAction, qtLambda, simplified
42
42
  from novelwriter.constants import nwLabels, trConst
43
- from novelwriter.core.status import NWStatus, StatusEntry
44
- from novelwriter.enum import nwStatusShape
43
+ from novelwriter.core.status import CUSTOM_COL, NWStatus, StatusEntry
44
+ from novelwriter.enum import nwStandardButton, nwStatusShape
45
45
  from novelwriter.extensions.configlayout import NColorLabel, NFixedPage, NScrollableForm
46
46
  from novelwriter.extensions.modified import NComboBox, NDialog, NIconToolButton
47
47
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
48
48
  from novelwriter.extensions.switch import NSwitch
49
49
  from novelwriter.types import (
50
- QtDialogCancel, QtDialogSave, QtSizeMinimum, QtSizeMinimumExpanding,
50
+ QtRoleAccept, QtRoleReject, QtSizeMinimum, QtSizeMinimumExpanding,
51
51
  QtUserRole
52
52
  )
53
53
 
@@ -55,6 +55,7 @@ logger = logging.getLogger(__name__)
55
55
 
56
56
 
57
57
  class GuiProjectSettings(NDialog):
58
+ """GUI: Project Settings DIalog."""
58
59
 
59
60
  PAGE_SETTINGS = 0
60
61
  PAGE_STATUS = 1
@@ -94,9 +95,15 @@ class GuiProjectSettings(NDialog):
94
95
  self.sidebar.buttonClicked.connect(self._sidebarClicked)
95
96
 
96
97
  # Buttons
97
- self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogCancel, self)
98
- self.buttonBox.accepted.connect(self._doSave)
99
- self.buttonBox.rejected.connect(self.reject)
98
+ self.btnSave = SHARED.theme.getStandardButton(nwStandardButton.SAVE, self)
99
+ self.btnSave.clicked.connect(self._doSave)
100
+
101
+ self.btnCancel = SHARED.theme.getStandardButton(nwStandardButton.CANCEL, self)
102
+ self.btnCancel.clicked.connect(self.reject)
103
+
104
+ self.btnBox = QDialogButtonBox(self)
105
+ self.btnBox.addButton(self.btnSave, QtRoleAccept)
106
+ self.btnBox.addButton(self.btnCancel, QtRoleReject)
100
107
 
101
108
  # Content
102
109
  SHARED.project.countStatus()
@@ -125,7 +132,7 @@ class GuiProjectSettings(NDialog):
125
132
  self.outerBox = QVBoxLayout()
126
133
  self.outerBox.addLayout(self.topBox)
127
134
  self.outerBox.addLayout(self.mainBox)
128
- self.outerBox.addWidget(self.buttonBox)
135
+ self.outerBox.addWidget(self.btnBox)
129
136
  self.outerBox.setSpacing(8)
130
137
 
131
138
  self.setLayout(self.outerBox)
@@ -137,11 +144,8 @@ class GuiProjectSettings(NDialog):
137
144
 
138
145
  logger.debug("Ready: GuiProjectSettings")
139
146
 
140
- return
141
-
142
147
  def __del__(self) -> None: # pragma: no cover
143
148
  logger.debug("Delete: GuiProjectSettings")
144
- return
145
149
 
146
150
  ##
147
151
  # Events
@@ -152,7 +156,6 @@ class GuiProjectSettings(NDialog):
152
156
  self._saveSettings()
153
157
  event.accept()
154
158
  self.softDelete()
155
- return
156
159
 
157
160
  ##
158
161
  # Private Slots
@@ -169,7 +172,6 @@ class GuiProjectSettings(NDialog):
169
172
  self.mainStack.setCurrentWidget(self.importPage)
170
173
  elif pageId == self.PAGE_REPLACE:
171
174
  self.mainStack.setCurrentWidget(self.replacePage)
172
- return
173
175
 
174
176
  @pyqtSlot()
175
177
  def _doSave(self) -> None:
@@ -203,8 +205,6 @@ class GuiProjectSettings(NDialog):
203
205
  QApplication.processEvents()
204
206
  self.close()
205
207
 
206
- return
207
-
208
208
  ##
209
209
  # Internal Functions
210
210
  ##
@@ -223,8 +223,6 @@ class GuiProjectSettings(NDialog):
223
223
  options.setValue("GuiProjectSettings", "importColW", importColW)
224
224
  options.setValue("GuiProjectSettings", "replaceColW", replaceColW)
225
225
 
226
- return
227
-
228
226
 
229
227
  class _SettingsPage(NScrollableForm):
230
228
 
@@ -295,8 +293,6 @@ class _SettingsPage(NScrollableForm):
295
293
 
296
294
  self.finalise()
297
295
 
298
- return
299
-
300
296
 
301
297
  class _StatusPage(NFixedPage):
302
298
 
@@ -326,6 +322,7 @@ class _StatusPage(NFixedPage):
326
322
  self._changed = False
327
323
  self._color = QColor(100, 100, 100)
328
324
  self._shape = nwStatusShape.SQUARE
325
+ self._theme = CUSTOM_COL
329
326
  self._icons = {}
330
327
 
331
328
  self._iPx = SHARED.theme.baseIconHeight
@@ -359,36 +356,51 @@ class _StatusPage(NFixedPage):
359
356
  self._addItem(key, StatusEntry.duplicate(entry))
360
357
 
361
358
  # List Controls
362
- self.addButton = NIconToolButton(self, iSz, "add", "green")
359
+ self.addButton = NIconToolButton(self, iSz, "add", "add")
363
360
  self.addButton.setToolTip(self.tr("Add Label"))
364
361
  self.addButton.clicked.connect(self._onItemCreate)
365
362
 
366
- self.delButton = NIconToolButton(self, iSz, "remove", "red")
363
+ self.delButton = NIconToolButton(self, iSz, "remove", "remove")
367
364
  self.delButton.setToolTip(self.tr("Delete Label"))
368
365
  self.delButton.clicked.connect(self._onItemDelete)
369
366
 
370
- self.upButton = NIconToolButton(self, iSz, "chevron_up", "blue")
367
+ self.upButton = NIconToolButton(self, iSz, "chevron_up", "action")
371
368
  self.upButton.setToolTip(self.tr("Move Up"))
372
369
  self.upButton.clicked.connect(qtLambda(self._moveItem, -1))
373
370
 
374
- self.downButton = NIconToolButton(self, iSz, "chevron_down", "blue")
371
+ self.downButton = NIconToolButton(self, iSz, "chevron_down", "action")
375
372
  self.downButton.setToolTip(self.tr("Move Down"))
376
373
  self.downButton.clicked.connect(qtLambda(self._moveItem, 1))
377
374
 
378
- self.importButton = NIconToolButton(self, iSz, "import", "green")
375
+ self.importButton = NIconToolButton(self, iSz, "import", "apply")
379
376
  self.importButton.setToolTip(self.tr("Import Labels"))
380
377
  self.importButton.clicked.connect(self._importLabels)
381
378
 
382
- self.exportButton = NIconToolButton(self, iSz, "export", "blue")
379
+ self.exportButton = NIconToolButton(self, iSz, "export", "action")
383
380
  self.exportButton.setToolTip(self.tr("Export Labels"))
384
381
  self.exportButton.clicked.connect(self._exportLabels)
385
382
 
386
383
  # Edit Form
387
- self.labelText = QLineEdit(self)
388
- self.labelText.setMaxLength(40)
389
- self.labelText.setPlaceholderText(self.tr("Select item to edit"))
390
- self.labelText.setEnabled(False)
391
- self.labelText.textEdited.connect(self._onNameEdit)
384
+ self.editName = QLineEdit(self)
385
+ self.editName.setMaxLength(40)
386
+ self.editName.setPlaceholderText(self.tr("Select item to edit"))
387
+ self.editName.setEnabled(False)
388
+ self.editName.textEdited.connect(self._onNameEdit)
389
+
390
+ self.labelName = QLabel(self.tr("Label"), self)
391
+ self.labelName.setBuddy(self.editName)
392
+
393
+ # Icon Colours
394
+ self.iconColor = NComboBox(self)
395
+ self.iconColor.setMinimumWidth(200)
396
+ self.iconColor.setEnabled(False)
397
+ self.iconColor.addItem(self.tr("Custom"), CUSTOM_COL)
398
+ for key, label in nwLabels.THEME_COLORS.items():
399
+ self.iconColor.addItem(trConst(label), key)
400
+ self.iconColor.currentIndexChanged.connect(self._onThemeSelect)
401
+
402
+ self.labelColor = QLabel(self.tr("Colour"), self)
403
+ self.labelColor.setBuddy(self.iconColor)
392
404
 
393
405
  buttonStyle = (
394
406
  "QToolButton {padding: 0 4px;} "
@@ -425,6 +437,9 @@ class _StatusPage(NFixedPage):
425
437
  self.shapeButton.setStyleSheet(buttonStyle)
426
438
  self.shapeButton.setEnabled(False)
427
439
 
440
+ self.labelShape = QLabel(self.tr("Shape"), self)
441
+ self.labelShape.setBuddy(self.iconColor)
442
+
428
443
  # Assemble
429
444
  self.listControls = QVBoxLayout()
430
445
  self.listControls.addWidget(self.addButton)
@@ -435,10 +450,15 @@ class _StatusPage(NFixedPage):
435
450
  self.listControls.addWidget(self.importButton)
436
451
  self.listControls.addWidget(self.exportButton)
437
452
 
438
- self.editBox = QHBoxLayout()
439
- self.editBox.addWidget(self.labelText, 1)
440
- self.editBox.addWidget(self.colorButton, 0)
441
- self.editBox.addWidget(self.shapeButton, 0)
453
+ self.editBox = QGridLayout()
454
+ self.editBox.addWidget(self.labelName, 0, 0)
455
+ self.editBox.addWidget(self.editName, 0, 1, 1, 5)
456
+ self.editBox.addWidget(self.labelColor, 1, 0)
457
+ self.editBox.addWidget(self.iconColor, 1, 1)
458
+ self.editBox.addWidget(self.colorButton, 1, 2)
459
+ self.editBox.addWidget(self.labelShape, 1, 3)
460
+ self.editBox.addWidget(self.shapeButton, 1, 4)
461
+ self.editBox.setColumnStretch(5, 1)
442
462
 
443
463
  self.innerBox = QGridLayout()
444
464
  self.innerBox.addWidget(self.listBox, 0, 0)
@@ -454,8 +474,6 @@ class _StatusPage(NFixedPage):
454
474
  self.setCentralLayout(self.outerBox)
455
475
  self._setButtonIcons()
456
476
 
457
- return
458
-
459
477
  @property
460
478
  def changed(self) -> bool:
461
479
  """The user changed these settings."""
@@ -494,16 +512,22 @@ class _StatusPage(NFixedPage):
494
512
  entry.name = name
495
513
  item.setText(self.C_LABEL, name)
496
514
  self._changed = True
497
- return
515
+
516
+ @pyqtSlot(int)
517
+ def _onThemeSelect(self, index: int) -> None:
518
+ """Update the colour handling on theme selection change."""
519
+ self._theme = str(self.iconColor.currentData())
520
+ self._setButtonIcons()
521
+ self._updateIcon()
498
522
 
499
523
  @pyqtSlot()
500
524
  def _onColorSelect(self) -> None:
501
525
  """Open a dialog to select the status icon colour."""
502
526
  if (color := QColorDialog.getColor(self._color, self, self.trSelColor)).isValid():
503
527
  self._color = color
528
+ self._theme = CUSTOM_COL
504
529
  self._setButtonIcons()
505
530
  self._updateIcon()
506
- return
507
531
 
508
532
  @pyqtSlot()
509
533
  def _onItemCreate(self) -> None:
@@ -511,9 +535,9 @@ class _StatusPage(NFixedPage):
511
535
  color = QColor(100, 100, 100)
512
536
  shape = nwStatusShape.SQUARE
513
537
  icon = NWStatus.createIcon(self._iPx, color, shape)
514
- self._addItem(None, StatusEntry(self.tr("New Item"), color, shape, icon, 0))
538
+ theme = str(self.iconColor.currentData())
539
+ self._addItem(None, StatusEntry(self.tr("New Item"), color, theme, shape, icon, 0))
515
540
  self._changed = True
516
- return
517
541
 
518
542
  @pyqtSlot()
519
543
  def _onItemDelete(self) -> None:
@@ -526,7 +550,6 @@ class _StatusPage(NFixedPage):
526
550
  else:
527
551
  self.listBox.takeTopLevelItem(iRow)
528
552
  self._changed = True
529
- return
530
553
 
531
554
  @pyqtSlot()
532
555
  def _onSelectionChanged(self) -> None:
@@ -537,25 +560,28 @@ class _StatusPage(NFixedPage):
537
560
  entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
538
561
  self._color = entry.color
539
562
  self._shape = entry.shape
563
+ self._theme = entry.theme
540
564
  self._setButtonIcons()
541
565
 
542
- self.labelText.setText(entry.name)
543
- self.labelText.selectAll()
544
- self.labelText.setFocus()
566
+ self.editName.setText(entry.name)
567
+ self.editName.selectAll()
568
+ self.editName.setFocus()
545
569
 
546
- self.labelText.setEnabled(True)
570
+ self.editName.setEnabled(True)
571
+ self.iconColor.setEnabled(True)
547
572
  self.colorButton.setEnabled(True)
548
573
  self.shapeButton.setEnabled(True)
549
574
  else:
550
575
  self._color = QColor(100, 100, 100)
551
576
  self._shape = nwStatusShape.SQUARE
577
+ self._theme = CUSTOM_COL
552
578
  self._setButtonIcons()
553
- self.labelText.setText("")
579
+ self.editName.setText("")
554
580
 
555
- self.labelText.setEnabled(False)
581
+ self.editName.setEnabled(False)
582
+ self.iconColor.setEnabled(False)
556
583
  self.colorButton.setEnabled(False)
557
584
  self.shapeButton.setEnabled(False)
558
- return
559
585
 
560
586
  @pyqtSlot()
561
587
  def _importLabels(self) -> None:
@@ -592,7 +618,6 @@ class _StatusPage(NFixedPage):
592
618
  writer.writerow([entry.shape.name, entry.color.name(), entry.name])
593
619
  except Exception as exc:
594
620
  SHARED.error("Could not write file.", exc=exc)
595
- return
596
621
 
597
622
  ##
598
623
  # Internal Functions
@@ -603,19 +628,18 @@ class _StatusPage(NFixedPage):
603
628
  self._shape = shape
604
629
  self._setButtonIcons()
605
630
  self._updateIcon()
606
- return
607
631
 
608
632
  def _updateIcon(self) -> None:
609
633
  """Apply changes made to a status icon."""
610
634
  if item := self._getSelectedItem():
611
- icon = NWStatus.createIcon(self._iPx, self._color, self._shape)
635
+ icon = NWStatus.createIcon(self._iPx, self._pickColor(), self._shape)
612
636
  entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
613
637
  entry.color = self._color
614
638
  entry.shape = self._shape
639
+ entry.theme = self._theme
615
640
  entry.icon = icon
616
641
  item.setIcon(self.C_LABEL, icon)
617
642
  self._changed = True
618
- return
619
643
 
620
644
  def _addItem(self, key: str | None, entry: StatusEntry) -> None:
621
645
  """Add a status item to the list."""
@@ -626,7 +650,6 @@ class _StatusPage(NFixedPage):
626
650
  item.setData(self.C_DATA, self.D_KEY, key)
627
651
  item.setData(self.C_DATA, self.D_ENTRY, entry)
628
652
  self.listBox.addTopLevelItem(item)
629
- return
630
653
 
631
654
  def _moveItem(self, step: int) -> None:
632
655
  """Move and item up or down step."""
@@ -639,7 +662,6 @@ class _StatusPage(NFixedPage):
639
662
  self.listBox.clearSelection()
640
663
  cItem.setSelected(True)
641
664
  self._changed = True
642
- return
643
665
 
644
666
  def _getSelectedItem(self) -> QTreeWidgetItem | None:
645
667
  """Get the currently selected item."""
@@ -658,10 +680,16 @@ class _StatusPage(NFixedPage):
658
680
 
659
681
  def _setButtonIcons(self) -> None:
660
682
  """Set the colour of the colour button."""
661
- icon = NWStatus.createIcon(self._iPx, self._color, nwStatusShape.SQUARE)
683
+ icon = NWStatus.createIcon(self._iPx, self._pickColor(), nwStatusShape.SQUARE)
684
+ self.iconColor.setCurrentData(self._theme, CUSTOM_COL)
662
685
  self.colorButton.setIcon(icon)
663
686
  self.shapeButton.setIcon(self._icons[self._shape])
664
- return
687
+
688
+ def _pickColor(self) -> QColor:
689
+ """Get the correct colour value based on selections."""
690
+ if self._theme == CUSTOM_COL:
691
+ return self._color
692
+ return SHARED.theme.getBaseColor(self._theme)
665
693
 
666
694
 
667
695
  class _ReplacePage(NFixedPage):
@@ -701,10 +729,10 @@ class _ReplacePage(NFixedPage):
701
729
  self.listBox.setSortingEnabled(True)
702
730
 
703
731
  # List Controls
704
- self.addButton = NIconToolButton(self, iSz, "add", "green")
732
+ self.addButton = NIconToolButton(self, iSz, "add", "add")
705
733
  self.addButton.clicked.connect(self._onEntryCreated)
706
734
 
707
- self.delButton = NIconToolButton(self, iSz, "remove", "red")
735
+ self.delButton = NIconToolButton(self, iSz, "remove", "remove")
708
736
  self.delButton.clicked.connect(self._onEntryDeleted)
709
737
 
710
738
  # Edit Form
@@ -743,8 +771,6 @@ class _ReplacePage(NFixedPage):
743
771
 
744
772
  self.setCentralLayout(self.outerBox)
745
773
 
746
- return
747
-
748
774
  @property
749
775
  def changed(self) -> bool:
750
776
  """The user changed these settings."""
@@ -777,7 +803,6 @@ class _ReplacePage(NFixedPage):
777
803
  if (item := self._getSelectedItem()) and (key := self._stripKey(text)):
778
804
  item.setText(self.C_KEY, f"<{key}>")
779
805
  self._changed = True
780
- return
781
806
 
782
807
  @pyqtSlot(str)
783
808
  def _onValueEdit(self, text: str) -> None:
@@ -785,7 +810,6 @@ class _ReplacePage(NFixedPage):
785
810
  if item := self._getSelectedItem():
786
811
  item.setText(self.C_REPL, text)
787
812
  self._changed = True
788
- return
789
813
 
790
814
  @pyqtSlot()
791
815
  def _onSelectionChanged(self) -> None:
@@ -804,14 +828,12 @@ class _ReplacePage(NFixedPage):
804
828
  self.editValue.setText("")
805
829
  self.editKey.setEnabled(False)
806
830
  self.editValue.setEnabled(False)
807
- return
808
831
 
809
832
  @pyqtSlot()
810
833
  def _onEntryCreated(self) -> None:
811
834
  """Add a new list entry."""
812
835
  key = f"<keyword{self.listBox.topLevelItemCount() + 1:d}>"
813
836
  self.listBox.addTopLevelItem(QTreeWidgetItem([key, ""]))
814
- return
815
837
 
816
838
  @pyqtSlot()
817
839
  def _onEntryDeleted(self) -> None:
@@ -819,7 +841,6 @@ class _ReplacePage(NFixedPage):
819
841
  if item := self._getSelectedItem():
820
842
  self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(item))
821
843
  self._changed = True
822
- return
823
844
 
824
845
  ##
825
846
  # Internal Functions
@@ -20,7 +20,7 @@ General Public License for more details.
20
20
 
21
21
  You should have received a copy of the GNU General Public License
22
22
  along with this program. If not, see <https://www.gnu.org/licenses/>.
23
- """
23
+ """ # noqa
24
24
  from __future__ import annotations
25
25
 
26
26
  import logging
@@ -32,10 +32,12 @@ from PyQt6.QtWidgets import (
32
32
  QListWidgetItem, QVBoxLayout, QWidget
33
33
  )
34
34
 
35
+ from novelwriter import SHARED
35
36
  from novelwriter.constants import nwQuotes, trConst
37
+ from novelwriter.enum import nwStandardButton
36
38
  from novelwriter.extensions.modified import NDialog
37
39
  from novelwriter.types import (
38
- QtAccepted, QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk,
40
+ QtAccepted, QtAlignCenter, QtAlignTop, QtRoleAccept, QtRoleReject,
39
41
  QtUserRole
40
42
  )
41
43
 
@@ -43,6 +45,7 @@ logger = logging.getLogger(__name__)
43
45
 
44
46
 
45
47
  class GuiQuoteSelect(NDialog):
48
+ """GUI: Quote Selector Dialog."""
46
49
 
47
50
  _selected = ""
48
51
 
@@ -90,9 +93,15 @@ class GuiQuoteSelect(NDialog):
90
93
  self.listBox.setMinimumHeight(150)
91
94
 
92
95
  # Buttons
93
- self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
94
- self.buttonBox.accepted.connect(self.accept)
95
- self.buttonBox.rejected.connect(self.reject)
96
+ self.btnOk = SHARED.theme.getStandardButton(nwStandardButton.OK, self)
97
+ self.btnOk.clicked.connect(self.accept)
98
+
99
+ self.btnCancel = SHARED.theme.getStandardButton(nwStandardButton.CANCEL, self)
100
+ self.btnCancel.clicked.connect(self.reject)
101
+
102
+ self.btnBox = QDialogButtonBox(self)
103
+ self.btnBox.addButton(self.btnOk, QtRoleAccept)
104
+ self.btnBox.addButton(self.btnCancel, QtRoleReject)
96
105
 
97
106
  # Assemble
98
107
  self.labelBox.addWidget(self.previewLabel, 0, QtAlignTop)
@@ -102,17 +111,14 @@ class GuiQuoteSelect(NDialog):
102
111
  self.innerBox.addWidget(self.listBox)
103
112
 
104
113
  self.outerBox.addLayout(self.innerBox)
105
- self.outerBox.addWidget(self.buttonBox)
114
+ self.outerBox.addWidget(self.btnBox)
106
115
 
107
116
  self.setLayout(self.outerBox)
108
117
 
109
118
  logger.debug("Ready: GuiQuoteSelect")
110
119
 
111
- return
112
-
113
120
  def __del__(self) -> None: # pragma: no cover
114
121
  logger.debug("Delete: GuiQuoteSelect")
115
- return
116
122
 
117
123
  @property
118
124
  def selectedQuote(self) -> str:
@@ -140,4 +146,3 @@ class GuiQuoteSelect(NDialog):
140
146
  quote = items[0].data(self.D_KEY)
141
147
  self.previewLabel.setText(quote)
142
148
  self._selected = quote
143
- return
@@ -20,7 +20,7 @@ General Public License for more details.
20
20
 
21
21
  You should have received a copy of the GNU General Public License
22
22
  along with this program. If not, see <https://www.gnu.org/licenses/>.
23
- """
23
+ """ # noqa
24
24
  from __future__ import annotations
25
25
 
26
26
  import logging
@@ -37,9 +37,10 @@ from PyQt6.QtWidgets import (
37
37
  from novelwriter import CONFIG, SHARED
38
38
  from novelwriter.common import formatFileFilter
39
39
  from novelwriter.core.spellcheck import UserDictionary
40
+ from novelwriter.enum import nwStandardButton
40
41
  from novelwriter.extensions.configlayout import NColorLabel
41
42
  from novelwriter.extensions.modified import NDialog, NIconToolButton
42
- from novelwriter.types import QtDialogClose, QtDialogSave
43
+ from novelwriter.types import QtRoleAccept, QtRoleDestruct
43
44
 
44
45
  if TYPE_CHECKING:
45
46
  from PyQt6.QtGui import QCloseEvent
@@ -48,6 +49,7 @@ logger = logging.getLogger(__name__)
48
49
 
49
50
 
50
51
  class GuiWordList(NDialog):
52
+ """GUI: User Dictionary Edit Tool."""
51
53
 
52
54
  newWordListReady = pyqtSignal()
53
55
 
@@ -73,11 +75,11 @@ class GuiWordList(NDialog):
73
75
  scale=NColorLabel.HEADER_SCALE
74
76
  )
75
77
 
76
- self.importButton = NIconToolButton(self, iSz, "import", "green")
78
+ self.importButton = NIconToolButton(self, iSz, "import", "apply")
77
79
  self.importButton.setToolTip(self.tr("Import words from text file"))
78
80
  self.importButton.clicked.connect(self._importWords)
79
81
 
80
- self.exportButton = NIconToolButton(self, iSz, "export", "blue")
82
+ self.exportButton = NIconToolButton(self, iSz, "export", "action")
81
83
  self.exportButton.setToolTip(self.tr("Export words to text file"))
82
84
  self.exportButton.clicked.connect(self._exportWords)
83
85
 
@@ -95,11 +97,11 @@ class GuiWordList(NDialog):
95
97
  # Add/Remove Form
96
98
  self.newEntry = QLineEdit(self)
97
99
 
98
- self.addButton = NIconToolButton(self, iSz, "add", "green")
100
+ self.addButton = NIconToolButton(self, iSz, "add", "add")
99
101
  self.addButton.setToolTip(self.tr("Add Word"))
100
102
  self.addButton.clicked.connect(self._doAdd)
101
103
 
102
- self.delButton = NIconToolButton(self, iSz, "remove", "red")
104
+ self.delButton = NIconToolButton(self, iSz, "remove", "remove")
103
105
  self.delButton.setToolTip(self.tr("Remove Word"))
104
106
  self.delButton.clicked.connect(self._doDelete)
105
107
 
@@ -109,9 +111,15 @@ class GuiWordList(NDialog):
109
111
  self.editBox.addWidget(self.delButton, 0)
110
112
 
111
113
  # Buttons
112
- self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogClose, self)
113
- self.buttonBox.accepted.connect(self._doSave)
114
- self.buttonBox.rejected.connect(self.reject)
114
+ self.btnSave = SHARED.theme.getStandardButton(nwStandardButton.SAVE, self)
115
+ self.btnSave.clicked.connect(self._doSave)
116
+
117
+ self.btnClose = SHARED.theme.getStandardButton(nwStandardButton.CLOSE, self)
118
+ self.btnClose.clicked.connect(self.reject)
119
+
120
+ self.btnBox = QDialogButtonBox(self)
121
+ self.btnBox.addButton(self.btnSave, QtRoleAccept)
122
+ self.btnBox.addButton(self.btnClose, QtRoleDestruct)
115
123
 
116
124
  # Assemble
117
125
  self.outerBox = QVBoxLayout()
@@ -119,7 +127,7 @@ class GuiWordList(NDialog):
119
127
  self.outerBox.addWidget(self.listBox, 1)
120
128
  self.outerBox.addLayout(self.editBox, 0)
121
129
  self.outerBox.addSpacing(12)
122
- self.outerBox.addWidget(self.buttonBox, 0)
130
+ self.outerBox.addWidget(self.btnBox, 0)
123
131
  self.outerBox.setSpacing(4)
124
132
 
125
133
  self.setLayout(self.outerBox)
@@ -128,11 +136,8 @@ class GuiWordList(NDialog):
128
136
 
129
137
  logger.debug("Ready: GuiWordList")
130
138
 
131
- return
132
-
133
139
  def __del__(self) -> None: # pragma: no cover
134
140
  logger.debug("Delete: GuiWordList")
135
- return
136
141
 
137
142
  ##
138
143
  # Events
@@ -143,7 +148,6 @@ class GuiWordList(NDialog):
143
148
  self._saveGuiSettings()
144
149
  event.accept()
145
150
  self.softDelete()
146
- return
147
151
 
148
152
  ##
149
153
  # Private Slots
@@ -159,14 +163,12 @@ class GuiWordList(NDialog):
159
163
  if items := self.listBox.findItems(word, Qt.MatchFlag.MatchExactly):
160
164
  self.listBox.setCurrentItem(items[0])
161
165
  self.listBox.scrollToItem(items[0], QAbstractItemView.ScrollHint.PositionAtCenter)
162
- return
163
166
 
164
167
  @pyqtSlot()
165
168
  def _doDelete(self) -> None:
166
169
  """Delete the selected items."""
167
170
  for item in self.listBox.selectedItems():
168
171
  self.listBox.takeItem(self.listBox.row(item))
169
- return
170
172
 
171
173
  @pyqtSlot()
172
174
  def _doSave(self) -> None:
@@ -178,7 +180,6 @@ class GuiWordList(NDialog):
178
180
  self.newWordListReady.emit()
179
181
  QApplication.processEvents()
180
182
  self.close()
181
- return
182
183
 
183
184
  @pyqtSlot()
184
185
  def _importWords(self) -> None:
@@ -213,7 +214,6 @@ class GuiWordList(NDialog):
213
214
  fo.write("\n".join(self._listWords()))
214
215
  except Exception as exc:
215
216
  SHARED.error("Could not write file.", exc=exc)
216
- return
217
217
 
218
218
  ##
219
219
  # Internal Functions
@@ -226,7 +226,6 @@ class GuiWordList(NDialog):
226
226
  self.listBox.clear()
227
227
  for word in userDict:
228
228
  self.listBox.addItem(word)
229
- return
230
229
 
231
230
  def _saveGuiSettings(self) -> None:
232
231
  """Save GUI settings."""
@@ -234,14 +233,12 @@ class GuiWordList(NDialog):
234
233
  pOptions = SHARED.project.options
235
234
  pOptions.setValue("GuiWordList", "winWidth", self.width())
236
235
  pOptions.setValue("GuiWordList", "winHeight", self.height())
237
- return
238
236
 
239
237
  def _addWord(self, word: str) -> None:
240
238
  """Add a single word to the list."""
241
239
  if word and not self.listBox.findItems(word, Qt.MatchFlag.MatchExactly):
242
240
  self.listBox.addItem(word)
243
241
  self._changed = True
244
- return
245
242
 
246
243
  def _listWords(self) -> list[str]:
247
244
  """List all words in the list box."""