novelWriter 2.3rc1__py3-none-any.whl → 2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
  2. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/RECORD +119 -109
  3. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/WHEEL +1 -1
  4. novelWriter-2.4.dist-info/entry_points.txt +2 -0
  5. novelwriter/__init__.py +17 -10
  6. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  7. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  8. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  9. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  10. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  11. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  12. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  13. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  16. novelwriter/assets/i18n/project_nl_NL.json +11 -0
  17. novelwriter/assets/i18n/project_pt_BR.json +11 -0
  18. novelwriter/assets/icons/none.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
  21. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
  22. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
  23. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
  24. novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
  25. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  26. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  27. novelwriter/assets/icons/typicons_light/icons.conf +4 -0
  28. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
  29. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
  30. novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
  31. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
  32. novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
  33. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  34. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  35. novelwriter/assets/manual.pdf +0 -0
  36. novelwriter/assets/sample.zip +0 -0
  37. novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
  38. novelwriter/assets/syntax/default_dark.conf +1 -0
  39. novelwriter/assets/syntax/default_light.conf +1 -0
  40. novelwriter/assets/syntax/grey_dark.conf +1 -0
  41. novelwriter/assets/syntax/grey_light.conf +1 -0
  42. novelwriter/assets/syntax/light_owl.conf +1 -0
  43. novelwriter/assets/syntax/night_owl.conf +1 -0
  44. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  45. novelwriter/assets/syntax/solarized_light.conf +1 -0
  46. novelwriter/assets/syntax/tango.conf +23 -0
  47. novelwriter/assets/syntax/tomorrow.conf +1 -0
  48. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  49. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  50. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  51. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  52. novelwriter/assets/text/credits_en.htm +25 -23
  53. novelwriter/assets/themes/cyberpunk_night.conf +29 -0
  54. novelwriter/common.py +12 -4
  55. novelwriter/config.py +47 -16
  56. novelwriter/constants.py +5 -6
  57. novelwriter/core/buildsettings.py +64 -44
  58. novelwriter/core/coretools.py +97 -13
  59. novelwriter/core/docbuild.py +74 -7
  60. novelwriter/core/document.py +24 -3
  61. novelwriter/core/index.py +31 -112
  62. novelwriter/core/project.py +11 -15
  63. novelwriter/core/projectxml.py +3 -2
  64. novelwriter/core/sessions.py +2 -2
  65. novelwriter/core/spellcheck.py +3 -3
  66. novelwriter/core/status.py +6 -5
  67. novelwriter/core/storage.py +16 -6
  68. novelwriter/core/tohtml.py +22 -25
  69. novelwriter/core/tokenizer.py +417 -237
  70. novelwriter/core/tomd.py +17 -8
  71. novelwriter/core/toodt.py +386 -351
  72. novelwriter/core/tree.py +8 -8
  73. novelwriter/dialogs/about.py +10 -12
  74. novelwriter/dialogs/docmerge.py +17 -14
  75. novelwriter/dialogs/docsplit.py +20 -19
  76. novelwriter/dialogs/editlabel.py +5 -4
  77. novelwriter/dialogs/preferences.py +32 -40
  78. novelwriter/dialogs/projectsettings.py +31 -28
  79. novelwriter/dialogs/quotes.py +10 -9
  80. novelwriter/dialogs/wordlist.py +18 -15
  81. novelwriter/enum.py +17 -14
  82. novelwriter/error.py +14 -12
  83. novelwriter/extensions/circularprogress.py +12 -8
  84. novelwriter/extensions/configlayout.py +23 -3
  85. novelwriter/extensions/modified.py +51 -2
  86. novelwriter/extensions/pagedsidebar.py +16 -14
  87. novelwriter/extensions/simpleprogress.py +3 -1
  88. novelwriter/extensions/statusled.py +3 -1
  89. novelwriter/extensions/switch.py +10 -9
  90. novelwriter/extensions/switchbox.py +14 -13
  91. novelwriter/extensions/versioninfo.py +1 -1
  92. novelwriter/gui/doceditor.py +433 -496
  93. novelwriter/gui/dochighlight.py +54 -33
  94. novelwriter/gui/docviewer.py +162 -175
  95. novelwriter/gui/docviewerpanel.py +20 -37
  96. novelwriter/gui/editordocument.py +15 -4
  97. novelwriter/gui/itemdetails.py +51 -54
  98. novelwriter/gui/mainmenu.py +37 -17
  99. novelwriter/gui/noveltree.py +31 -37
  100. novelwriter/gui/outline.py +120 -98
  101. novelwriter/gui/projtree.py +114 -112
  102. novelwriter/gui/search.py +362 -0
  103. novelwriter/gui/sidebar.py +36 -45
  104. novelwriter/gui/statusbar.py +14 -14
  105. novelwriter/gui/theme.py +116 -34
  106. novelwriter/guimain.py +216 -207
  107. novelwriter/shared.py +31 -6
  108. novelwriter/text/counting.py +138 -0
  109. novelwriter/tools/dictionaries.py +15 -14
  110. novelwriter/tools/lipsum.py +20 -17
  111. novelwriter/tools/manusbuild.py +43 -35
  112. novelwriter/tools/manuscript.py +381 -104
  113. novelwriter/tools/manussettings.py +263 -125
  114. novelwriter/tools/noveldetails.py +21 -19
  115. novelwriter/tools/welcome.py +59 -57
  116. novelwriter/tools/writingstats.py +61 -55
  117. novelwriter/types.py +90 -0
  118. novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
  119. novelwriter/core/__init__.py +0 -3
  120. novelwriter/dialogs/__init__.py +0 -3
  121. novelwriter/extensions/__init__.py +0 -3
  122. novelwriter/gui/__init__.py +0 -3
  123. novelwriter/tools/__init__.py +0 -3
  124. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
  125. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
@@ -26,8 +26,8 @@ from __future__ import annotations
26
26
  import math
27
27
  import logging
28
28
 
29
+ from PyQt5.QtCore import pyqtSlot
29
30
  from PyQt5.QtGui import QCloseEvent
30
- from PyQt5.QtCore import QSize, Qt, pyqtSlot
31
31
  from PyQt5.QtWidgets import (
32
32
  QAbstractItemView, QDialog, QDialogButtonBox, QFormLayout, QGridLayout,
33
33
  QHBoxLayout, QLabel, QSpinBox, QStackedWidget, QTreeWidget,
@@ -37,10 +37,11 @@ from PyQt5.QtWidgets import (
37
37
  from novelwriter import CONFIG, SHARED
38
38
  from novelwriter.common import formatTime, numberToRoman
39
39
  from novelwriter.constants import nwUnicode
40
- from novelwriter.extensions.switch import NSwitch
41
40
  from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage
42
- from novelwriter.extensions.pagedsidebar import NPagedSideBar
43
41
  from novelwriter.extensions.novelselector import NovelSelector
42
+ from novelwriter.extensions.pagedsidebar import NPagedSideBar
43
+ from novelwriter.extensions.switch import NSwitch
44
+ from novelwriter.types import QtAlignRight, QtDecoration, QtDialogClose
44
45
 
45
46
  logger = logging.getLogger(__name__)
46
47
 
@@ -94,7 +95,7 @@ class GuiNovelDetails(QDialog):
94
95
  self.mainStack.addWidget(self.contentsPage)
95
96
 
96
97
  # Buttons
97
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
98
+ self.buttonBox = QDialogButtonBox(QtDialogClose, self)
98
99
  self.buttonBox.rejected.connect(self.close)
99
100
 
100
101
  # Assemble
@@ -216,7 +217,7 @@ class _OverviewPage(NScrollablePage):
216
217
  self.projForm.addRow("<b>{0}</b>".format(self.tr("Editing Time")), self.projEditTime)
217
218
  self.projForm.addRow("<b>{0}</b>".format(self.tr("Word Count")), self.projWords)
218
219
  self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Novels")), self.projNovels)
219
- self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes ")), self.projNotes)
220
+ self.projForm.addRow("<b>\u2026 {0}</b>".format(self.tr("In Notes")), self.projNotes)
220
221
  self.projForm.setContentsMargins(mPx, 0, 0, 0)
221
222
  self.projForm.setHorizontalSpacing(hPx)
222
223
  self.projForm.setVerticalSpacing(vPx)
@@ -309,7 +310,8 @@ class _ContentsPage(NFixedPage):
309
310
  self._data = []
310
311
  self._currentRoot = None
311
312
 
312
- iPx = SHARED.theme.baseIconSize
313
+ iPx = SHARED.theme.baseIconHeight
314
+ iSz = SHARED.theme.baseIconSize
313
315
  hPx = CONFIG.pxInt(12)
314
316
  vPx = CONFIG.pxInt(4)
315
317
  options = SHARED.project.options
@@ -322,7 +324,7 @@ class _ContentsPage(NFixedPage):
322
324
 
323
325
  # Contents Tree
324
326
  self.tocTree = QTreeWidget(self)
325
- self.tocTree.setIconSize(QSize(iPx, iPx))
327
+ self.tocTree.setIconSize(iSz)
326
328
  self.tocTree.setIndentation(0)
327
329
  self.tocTree.setColumnCount(6)
328
330
  self.tocTree.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
@@ -337,10 +339,10 @@ class _ContentsPage(NFixedPage):
337
339
 
338
340
  treeHeadItem = self.tocTree.headerItem()
339
341
  if treeHeadItem:
340
- treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignmentFlag.AlignRight)
341
- treeHeadItem.setTextAlignment(self.C_PAGES, Qt.AlignmentFlag.AlignRight)
342
- treeHeadItem.setTextAlignment(self.C_PAGE, Qt.AlignmentFlag.AlignRight)
343
- treeHeadItem.setTextAlignment(self.C_PROG, Qt.AlignmentFlag.AlignRight)
342
+ treeHeadItem.setTextAlignment(self.C_WORDS, QtAlignRight)
343
+ treeHeadItem.setTextAlignment(self.C_PAGES, QtAlignRight)
344
+ treeHeadItem.setTextAlignment(self.C_PAGE, QtAlignRight)
345
+ treeHeadItem.setTextAlignment(self.C_PROG, QtAlignRight)
344
346
 
345
347
  treeHeader = self.tocTree.header()
346
348
  treeHeader.setStretchLastSection(True)
@@ -364,7 +366,7 @@ class _ContentsPage(NFixedPage):
364
366
  countFrom = options.getInt("GuiNovelDetails", "countFrom", 1)
365
367
  clearDouble = options.getBool("GuiNovelDetails", "clearDouble", True)
366
368
 
367
- self.wpLabel = QLabel(self.tr("Words per page"))
369
+ self.wpLabel = QLabel(self.tr("Words per page"), self)
368
370
 
369
371
  self.wpValue = QSpinBox(self)
370
372
  self.wpValue.setMinimum(10)
@@ -373,7 +375,7 @@ class _ContentsPage(NFixedPage):
373
375
  self.wpValue.setValue(wordsPerPage)
374
376
  self.wpValue.valueChanged.connect(self._populateTree)
375
377
 
376
- self.poLabel = QLabel(self.tr("First page offset"))
378
+ self.poLabel = QLabel(self.tr("First page offset"), self)
377
379
 
378
380
  self.poValue = QSpinBox(self)
379
381
  self.poValue.setMinimum(1)
@@ -382,7 +384,7 @@ class _ContentsPage(NFixedPage):
382
384
  self.poValue.setValue(countFrom)
383
385
  self.poValue.valueChanged.connect(self._populateTree)
384
386
 
385
- self.dblLabel = QLabel(self.tr("Chapters on odd pages"))
387
+ self.dblLabel = QLabel(self.tr("Chapters on odd pages"), self)
386
388
 
387
389
  self.dblValue = NSwitch(self, height=iPx)
388
390
  self.dblValue.setChecked(clearDouble)
@@ -483,17 +485,17 @@ class _ContentsPage(NFixedPage):
483
485
  if tTitle.strip() == "":
484
486
  tTitle = self.tr("Untitled")
485
487
 
486
- newItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
488
+ newItem.setData(self.C_TITLE, QtDecoration, hDec)
487
489
  newItem.setText(self.C_TITLE, tTitle)
488
490
  newItem.setText(self.C_WORDS, f"{wCount:n}")
489
491
  newItem.setText(self.C_PAGES, f"{pCount:n}")
490
492
  newItem.setText(self.C_PAGE, progPage)
491
493
  newItem.setText(self.C_PROG, progText)
492
494
 
493
- newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
494
- newItem.setTextAlignment(self.C_PAGES, Qt.AlignRight)
495
- newItem.setTextAlignment(self.C_PAGE, Qt.AlignRight)
496
- newItem.setTextAlignment(self.C_PROG, Qt.AlignRight)
495
+ newItem.setTextAlignment(self.C_WORDS, QtAlignRight)
496
+ newItem.setTextAlignment(self.C_PAGES, QtAlignRight)
497
+ newItem.setTextAlignment(self.C_PAGE, QtAlignRight)
498
+ newItem.setTextAlignment(self.C_PROG, QtAlignRight)
497
499
 
498
500
  # Make pages and titles/partitions stand out
499
501
  if tLevel < 2:
@@ -25,33 +25,35 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from pathlib import Path
29
28
  from datetime import datetime
29
+ from pathlib import Path
30
30
 
31
- from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPaintEvent, QPainter, QPen
32
31
  from PyQt5.QtCore import (
33
32
  QAbstractListModel, QEvent, QModelIndex, QObject, QPoint, QSize, Qt,
34
33
  pyqtSignal, pyqtSlot
35
34
  )
35
+ from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPaintEvent, QPainter, QPen
36
36
  from PyQt5.QtWidgets import (
37
- QAction, QDialog, QFileDialog, QFormLayout, QHBoxLayout, QLabel, QLineEdit,
38
- QListView, QMenu, QPushButton, QScrollArea, QShortcut, QStackedWidget,
39
- QStyle, QStyleOptionViewItem, QStyledItemDelegate, QToolButton,
40
- QVBoxLayout, QWidget, qApp
37
+ QAction, QApplication, QDialog, QFileDialog, QFormLayout, QHBoxLayout,
38
+ QLabel, QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut,
39
+ QStackedWidget, QStyleOptionViewItem, QStyledItemDelegate, QVBoxLayout,
40
+ QWidget
41
41
  )
42
42
 
43
43
  from novelwriter import CONFIG, SHARED
44
- from novelwriter.enum import nwItemClass
45
- from novelwriter.common import formatInt, makeFileNameSafe
44
+ from novelwriter.common import cssCol, formatInt, makeFileNameSafe
46
45
  from novelwriter.constants import nwFiles
47
46
  from novelwriter.core.coretools import ProjectBuilder
47
+ from novelwriter.enum import nwItemClass
48
+ from novelwriter.extensions.configlayout import NWrappedWidgetBox
49
+ from novelwriter.extensions.modified import NIconToolButton, NSpinBox
48
50
  from novelwriter.extensions.switch import NSwitch
49
- from novelwriter.extensions.modified import NSpinBox
50
51
  from novelwriter.extensions.versioninfo import VersionInfoWidget
52
+ from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtSelected
51
53
 
52
54
  logger = logging.getLogger(__name__)
53
55
 
54
- PANEL_ALPHA = 0.7
56
+ PANEL_ALPHA = 178
55
57
 
56
58
 
57
59
  class GuiWelcome(QDialog):
@@ -74,8 +76,9 @@ class GuiWelcome(QDialog):
74
76
  hD = CONFIG.pxInt(36)
75
77
  hE = CONFIG.pxInt(48)
76
78
  hF = CONFIG.pxInt(128)
77
- self._hPx = CONFIG.pxInt(600)
79
+ btnIconSize = SHARED.theme.buttonIconSize
78
80
 
81
+ self._hPx = CONFIG.pxInt(600)
79
82
  self.resize(*CONFIG.welcomeWinSize)
80
83
 
81
84
  # Elements
@@ -108,26 +111,32 @@ class GuiWelcome(QDialog):
108
111
 
109
112
  self.btnList = QPushButton(self.tr("List"), self)
110
113
  self.btnList.setIcon(SHARED.theme.getIcon("list"))
114
+ self.btnList.setIconSize(btnIconSize)
111
115
  self.btnList.clicked.connect(self._showOpenProjectPage)
112
116
 
113
117
  self.btnNew = QPushButton(self.tr("New"), self)
114
118
  self.btnNew.setIcon(SHARED.theme.getIcon("add"))
119
+ self.btnNew.setIconSize(btnIconSize)
115
120
  self.btnNew.clicked.connect(self._showNewProjectPage)
116
121
 
117
122
  self.btnBrowse = QPushButton(self.tr("Browse"), self)
118
123
  self.btnBrowse.setIcon(SHARED.theme.getIcon("browse"))
124
+ self.btnBrowse.setIconSize(btnIconSize)
119
125
  self.btnBrowse.clicked.connect(self._browseForProject)
120
126
 
121
127
  self.btnCancel = QPushButton(self.tr("Cancel"), self)
122
128
  self.btnCancel.setIcon(SHARED.theme.getIcon("cross"))
129
+ self.btnCancel.setIconSize(btnIconSize)
123
130
  self.btnCancel.clicked.connect(self.close)
124
131
 
125
132
  self.btnCreate = QPushButton(self.tr("Create"), self)
126
133
  self.btnCreate.setIcon(SHARED.theme.getIcon("star"))
134
+ self.btnCreate.setIconSize(btnIconSize)
127
135
  self.btnCreate.clicked.connect(self.tabNew.createNewProject)
128
136
 
129
137
  self.btnOpen = QPushButton(self.tr("Open"), self)
130
138
  self.btnOpen.setIcon(SHARED.theme.getIcon("open"))
139
+ self.btnOpen.setIconSize(btnIconSize)
131
140
  self.btnOpen.clicked.connect(self._openSelectedItem)
132
141
 
133
142
  self.btnBox = QHBoxLayout()
@@ -152,10 +161,8 @@ class GuiWelcome(QDialog):
152
161
  self.innerBox.addSpacing(hB)
153
162
  self.innerBox.addLayout(self.btnBox)
154
163
 
155
- topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
156
-
157
164
  self.outerBox = QHBoxLayout()
158
- self.outerBox.addWidget(self.nwLogo, 3, topRight)
165
+ self.outerBox.addWidget(self.nwLogo, 3, QtAlignRightTop)
159
166
  self.outerBox.addLayout(self.innerBox, 9)
160
167
  self.outerBox.setContentsMargins(hF, hE, hC, hE)
161
168
 
@@ -305,12 +312,12 @@ class _OpenProjectPage(QWidget):
305
312
 
306
313
  self._selectFirstItem()
307
314
 
308
- baseCol = self.palette().base().color()
309
- self.setStyleSheet((
310
- "QListView {{border: none; background: rgba({r},{g},{b},{a});}} "
311
- "QLineEdit {{border: none; background: rgba({r},{g},{b},{a}); padding: {m}px;}} "
312
- ).format(r=baseCol.red(), g=baseCol.green(), b=baseCol.blue(),
313
- a=PANEL_ALPHA, m=CONFIG.pxInt(4)))
315
+ mPx = CONFIG.pxInt(4)
316
+ baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
317
+ self.setStyleSheet(
318
+ f"QListView {{border: none; background: {baseCol};}} "
319
+ f"QLineEdit {{border: none; background: {baseCol}; padding: {mPx}px;}} "
320
+ )
314
321
 
315
322
  return
316
323
 
@@ -370,7 +377,7 @@ class _OpenProjectPage(QWidget):
370
377
  action.triggered.connect(self.openSelectedItem)
371
378
  action = ctxMenu.addAction(self.tr("Remove Project"))
372
379
  action.triggered.connect(self._deleteSelectedItem)
373
- ctxMenu.exec_(self.mapToGlobal(pos))
380
+ ctxMenu.exec(self.mapToGlobal(pos))
374
381
  ctxMenu.deleteLater()
375
382
  return
376
383
 
@@ -404,11 +411,11 @@ class _ProjectListItem(QStyledItemDelegate):
404
411
  self._pPx = (mPx//2, 3*mPx//2, iPx + mPx, mPx, mPx + tPx) # Painter coordinates
405
412
  self._hPx = 2*mPx + tPx + fPx # Fixed height
406
413
 
407
- self._tFont = qApp.font()
414
+ self._tFont = QApplication.font()
408
415
  self._tFont.setPointSizeF(1.2*fPt)
409
416
  self._tFont.setWeight(QFont.Weight.Bold)
410
417
 
411
- self._dFont = qApp.font()
418
+ self._dFont = QApplication.font()
412
419
  self._dFont.setPointSizeF(fPt)
413
420
  self._dPen = QPen(SHARED.theme.helpText)
414
421
 
@@ -424,9 +431,9 @@ class _ProjectListItem(QStyledItemDelegate):
424
431
  ix, iy, x, y1, y2 = self._pPx
425
432
 
426
433
  painter.save()
427
- if opt.state & QStyle.StateFlag.State_Selected == QStyle.StateFlag.State_Selected:
434
+ if opt.state & QtSelected == QtSelected:
428
435
  painter.setOpacity(0.25)
429
- painter.fillRect(rect, qApp.palette().highlight())
436
+ painter.fillRect(rect, QApplication.palette().highlight())
430
437
  painter.setOpacity(1.0)
431
438
 
432
439
  painter.drawPixmap(ix, rect.top() + iy, self._icon)
@@ -455,7 +462,7 @@ class _ProjectListModel(QAbstractListModel):
455
462
  opened = self.tr("Last Opened")
456
463
  records = sorted(CONFIG.recentProjects.listEntries(), key=lambda x: x[3], reverse=True)
457
464
  for path, title, count, time in records:
458
- when = datetime.fromtimestamp(time).strftime("%x")
465
+ when = CONFIG.localDate(datetime.fromtimestamp(time))
459
466
  data.append((title, path, f"{opened}: {when}, {words}: {formatInt(count)}"))
460
467
  self._data = data
461
468
  return
@@ -517,11 +524,11 @@ class _NewProjectPage(QWidget):
517
524
  # Styles
518
525
  # ======
519
526
 
520
- baseCol = self.palette().base().color()
521
- self.setStyleSheet((
522
- "QScrollArea {{border: none; background: rgba({r},{g},{b},{a});}} "
523
- "_NewProjectForm {{border: none; background: rgba({r},{g},{b},{a});}} "
524
- ).format(r=baseCol.red(), g=baseCol.green(), b=baseCol.blue(), a=PANEL_ALPHA))
527
+ baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA)
528
+ self.setStyleSheet(
529
+ f"QScrollArea {{border: none; background: {baseCol};}} "
530
+ f"_NewProjectForm {{border: none; background: {baseCol};}} "
531
+ )
525
532
 
526
533
  return
527
534
 
@@ -553,11 +560,12 @@ class _NewProjectForm(QWidget):
553
560
  def __init__(self, parent: QWidget) -> None:
554
561
  super().__init__(parent=parent)
555
562
 
556
- self._basePath = CONFIG.lastPath()
563
+ self._basePath = CONFIG.homePath()
557
564
  self._fillMode = self.FILL_BLANK
558
565
  self._copyPath = None
559
566
 
560
- iPx = SHARED.theme.baseIconSize
567
+ iPx = SHARED.theme.baseIconHeight
568
+ iSz = SHARED.theme.baseIconSize
561
569
  sPx = CONFIG.pxInt(16)
562
570
 
563
571
  # Project Settings
@@ -578,8 +586,7 @@ class _NewProjectForm(QWidget):
578
586
  self.projPath = QLineEdit(self)
579
587
  self.projPath.setReadOnly(True)
580
588
 
581
- self.browsePath = QToolButton(self)
582
- self.browsePath.setIcon(SHARED.theme.getIcon("browse"))
589
+ self.browsePath = NIconToolButton(self, iSz, "browse")
583
590
  self.browsePath.clicked.connect(self._doBrowse)
584
591
 
585
592
  self.pathBox = QHBoxLayout()
@@ -590,8 +597,7 @@ class _NewProjectForm(QWidget):
590
597
  self.projFill = QLineEdit(self)
591
598
  self.projFill.setReadOnly(True)
592
599
 
593
- self.browseFill = QToolButton(self)
594
- self.browseFill.setIcon(SHARED.theme.getIcon("add_document"))
600
+ self.browseFill = NIconToolButton(self, iSz, "add_document")
595
601
 
596
602
  self.fillMenu = _PopLeftDirectionMenu(self.browseFill)
597
603
 
@@ -608,7 +614,6 @@ class _NewProjectForm(QWidget):
608
614
  self.fillCopy.triggered.connect(self._setFillCopy)
609
615
 
610
616
  self.browseFill.setMenu(self.fillMenu)
611
- self.browseFill.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
612
617
 
613
618
  self.fillBox = QHBoxLayout()
614
619
  self.fillBox.addWidget(self.projFill)
@@ -616,7 +621,7 @@ class _NewProjectForm(QWidget):
616
621
 
617
622
  # Project Form
618
623
  self.projectForm = QFormLayout()
619
- self.projectForm.setAlignment(Qt.AlignmentFlag.AlignLeft)
624
+ self.projectForm.setAlignment(QtAlignLeft)
620
625
  self.projectForm.addRow(self.tr("Project Name"), self.projName)
621
626
  self.projectForm.addRow(self.tr("Author"), self.projAuthor)
622
627
  self.projectForm.addRow(self.tr("Project Path"), self.pathBox)
@@ -627,23 +632,21 @@ class _NewProjectForm(QWidget):
627
632
 
628
633
  self.numChapters = NSpinBox(self)
629
634
  self.numChapters.setRange(0, 200)
630
- self.numChapters.setValue(5)
635
+ self.numChapters.setValue(0)
631
636
  self.numChapters.setToolTip(self.tr("Set to 0 to only add scenes"))
632
637
 
633
- self.chapterBox = QHBoxLayout()
634
- self.chapterBox.addWidget(QLabel(self.tr("Add")))
635
- self.chapterBox.addWidget(self.numChapters)
636
- self.chapterBox.addWidget(QLabel(self.tr("chapter documents")))
638
+ self.chapterBox = NWrappedWidgetBox(
639
+ self.tr("Add {0} chapter documents"), self.numChapters
640
+ )
637
641
  self.chapterBox.addStretch(1)
638
642
 
639
643
  self.numScenes = NSpinBox(self)
640
644
  self.numScenes.setRange(0, 200)
641
- self.numScenes.setValue(5)
645
+ self.numScenes.setValue(0)
642
646
 
643
- self.sceneBox = QHBoxLayout()
644
- self.sceneBox.addWidget(QLabel(self.tr("Add")))
645
- self.sceneBox.addWidget(self.numScenes)
646
- self.sceneBox.addWidget(QLabel(self.tr("scene documents (to each chapter)")))
647
+ self.sceneBox = NWrappedWidgetBox(
648
+ self.tr("Add {0} scene documents (to each chapter)"), self.numScenes
649
+ )
647
650
  self.sceneBox.addStretch(1)
648
651
 
649
652
  self.novelForm = QVBoxLayout()
@@ -669,7 +672,7 @@ class _NewProjectForm(QWidget):
669
672
  self.addNotes.setChecked(False)
670
673
 
671
674
  self.notesForm = QFormLayout()
672
- self.notesForm.setAlignment(Qt.AlignmentFlag.AlignLeft)
675
+ self.notesForm.setAlignment(QtAlignLeft)
673
676
  self.notesForm.addRow(self.tr("Add a folder for plot notes"), self.addPlot)
674
677
  self.notesForm.addRow(self.tr("Add a folder for character notes"), self.addChar)
675
678
  self.notesForm.addRow(self.tr("Add a folder for location notes"), self.addWorld)
@@ -679,10 +682,10 @@ class _NewProjectForm(QWidget):
679
682
  # ========
680
683
 
681
684
  self.extraBox = QVBoxLayout()
682
- self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes"))))
685
+ self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes")), self))
683
686
  self.extraBox.addLayout(self.novelForm)
684
687
  self.extraBox.addSpacing(sPx)
685
- self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes"))))
688
+ self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes")), self))
686
689
  self.extraBox.addLayout(self.notesForm)
687
690
  self.extraBox.setContentsMargins(0, 0, 0, 0)
688
691
 
@@ -691,7 +694,7 @@ class _NewProjectForm(QWidget):
691
694
  self.extraWidget.setContentsMargins(0, 0, 0, 0)
692
695
 
693
696
  self.formBox = QVBoxLayout()
694
- self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project"))))
697
+ self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project")), self))
695
698
  self.formBox.addLayout(self.projectForm)
696
699
  self.formBox.addSpacing(sPx)
697
700
  self.formBox.addWidget(self.extraWidget)
@@ -735,11 +738,10 @@ class _NewProjectForm(QWidget):
735
738
  """Select a project folder."""
736
739
  if projDir := QFileDialog.getExistingDirectory(
737
740
  self, self.tr("Select Project Folder"),
738
- str(self._basePath), options=QFileDialog.ShowDirsOnly
741
+ str(self._basePath), options=QFileDialog.Option.ShowDirsOnly
739
742
  ):
740
743
  self._basePath = Path(projDir)
741
744
  self._updateProjPath()
742
- CONFIG.setLastPath(self._basePath)
743
745
  return
744
746
 
745
747
  @pyqtSlot()
@@ -750,7 +752,7 @@ class _NewProjectForm(QWidget):
750
752
  return
751
753
 
752
754
  @pyqtSlot()
753
- def _syncSwitches(self):
755
+ def _syncSwitches(self) -> None:
754
756
  """Check if the add notes option should also be switched off."""
755
757
  addPlot = self.addPlot.isChecked()
756
758
  addChar = self.addChar.isChecked()
@@ -810,7 +812,7 @@ class _PopLeftDirectionMenu(QMenu):
810
812
 
811
813
  def event(self, event: QEvent) -> bool:
812
814
  """Overload the show event and move the menu popup location."""
813
- if event.type() == QEvent.Show:
815
+ if event.type() == QEvent.Type.Show:
814
816
  if isinstance(parent := self.parent(), QWidget):
815
817
  offset = QPoint(parent.width() - self.width(), parent.height())
816
818
  self.move(parent.mapToGlobal(offset))