novelWriter 2.4b1__py3-none-any.whl → 2.4rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/METADATA +5 -6
  2. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/RECORD +62 -66
  3. novelwriter/__init__.py +5 -5
  4. novelwriter/assets/icons/none.svg +4 -0
  5. novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
  6. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  7. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  8. novelwriter/assets/icons/typicons_light/icons.conf +2 -2
  9. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  10. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  11. novelwriter/assets/manual.pdf +0 -0
  12. novelwriter/assets/sample.zip +0 -0
  13. novelwriter/common.py +6 -1
  14. novelwriter/config.py +8 -4
  15. novelwriter/core/coretools.py +21 -22
  16. novelwriter/core/status.py +3 -2
  17. novelwriter/core/toodt.py +332 -355
  18. novelwriter/dialogs/about.py +9 -11
  19. novelwriter/dialogs/docmerge.py +17 -14
  20. novelwriter/dialogs/docsplit.py +14 -12
  21. novelwriter/dialogs/editlabel.py +5 -4
  22. novelwriter/dialogs/preferences.py +28 -33
  23. novelwriter/dialogs/projectsettings.py +29 -26
  24. novelwriter/dialogs/quotes.py +10 -9
  25. novelwriter/dialogs/wordlist.py +15 -12
  26. novelwriter/error.py +13 -11
  27. novelwriter/extensions/circularprogress.py +12 -8
  28. novelwriter/extensions/configlayout.py +1 -3
  29. novelwriter/extensions/modified.py +33 -2
  30. novelwriter/extensions/pagedsidebar.py +16 -14
  31. novelwriter/extensions/simpleprogress.py +3 -1
  32. novelwriter/extensions/statusled.py +3 -1
  33. novelwriter/extensions/switch.py +10 -9
  34. novelwriter/extensions/switchbox.py +14 -13
  35. novelwriter/gui/doceditor.py +182 -225
  36. novelwriter/gui/dochighlight.py +4 -4
  37. novelwriter/gui/docviewer.py +53 -57
  38. novelwriter/gui/docviewerpanel.py +16 -13
  39. novelwriter/gui/editordocument.py +4 -4
  40. novelwriter/gui/itemdetails.py +45 -48
  41. novelwriter/gui/noveltree.py +22 -20
  42. novelwriter/gui/outline.py +87 -88
  43. novelwriter/gui/projtree.py +31 -29
  44. novelwriter/gui/search.py +75 -29
  45. novelwriter/gui/sidebar.py +24 -28
  46. novelwriter/gui/statusbar.py +14 -14
  47. novelwriter/gui/theme.py +47 -35
  48. novelwriter/guimain.py +35 -31
  49. novelwriter/shared.py +5 -5
  50. novelwriter/tools/dictionaries.py +13 -12
  51. novelwriter/tools/lipsum.py +20 -17
  52. novelwriter/tools/manusbuild.py +35 -27
  53. novelwriter/tools/manuscript.py +68 -73
  54. novelwriter/tools/manussettings.py +68 -73
  55. novelwriter/tools/noveldetails.py +20 -18
  56. novelwriter/tools/welcome.py +47 -43
  57. novelwriter/tools/writingstats.py +61 -55
  58. novelwriter/types.py +90 -0
  59. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
  60. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
  61. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
  62. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
  63. novelwriter/core/__init__.py +0 -3
  64. novelwriter/dialogs/__init__.py +0 -3
  65. novelwriter/extensions/__init__.py +0 -3
  66. novelwriter/gui/__init__.py +0 -3
  67. novelwriter/text/__init__.py +0 -3
  68. novelwriter/tools/__init__.py +0 -3
  69. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/LICENSE.md +0 -0
  70. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/WHEEL +0 -0
  71. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/entry_points.txt +0 -0
  72. {novelWriter-2.4b1.dist-info → novelWriter-2.4rc1.dist-info}/top_level.txt +0 -0
@@ -26,16 +26,16 @@ from __future__ import annotations
26
26
  import logging
27
27
 
28
28
  from PyQt5.QtGui import QCloseEvent, QColor
29
- from PyQt5.QtCore import Qt
30
29
  from PyQt5.QtWidgets import (
31
30
  QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
32
31
  QWidget
33
32
  )
34
33
 
35
34
  from novelwriter import CONFIG, SHARED
36
- from novelwriter.common import readTextFile
35
+ from novelwriter.common import cssCol, readTextFile
37
36
  from novelwriter.extensions.configlayout import NColourLabel
38
37
  from novelwriter.extensions.versioninfo import VersionInfoWidget
38
+ from novelwriter.types import QtAlignRightTop, QtDialogClose
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -70,7 +70,7 @@ class GuiAbout(QDialog):
70
70
 
71
71
  self.nwLicence = QLabel(self.tr("This application is licenced under {0}").format(
72
72
  "<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a>"
73
- ))
73
+ ), self)
74
74
  self.nwLicence.setOpenExternalLinks(True)
75
75
 
76
76
  # Credits
@@ -84,7 +84,7 @@ class GuiAbout(QDialog):
84
84
  self.txtCredits.setViewportMargins(0, hA, hA, 0)
85
85
 
86
86
  # Buttons
87
- self.btnBox = QDialogButtonBox(QDialogButtonBox.Close, self)
87
+ self.btnBox = QDialogButtonBox(QtDialogClose, self)
88
88
  self.btnBox.rejected.connect(self.close)
89
89
 
90
90
  # Assemble
@@ -100,10 +100,8 @@ class GuiAbout(QDialog):
100
100
  self.innerBox.addSpacing(hB)
101
101
  self.innerBox.addWidget(self.btnBox)
102
102
 
103
- topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
104
-
105
103
  self.outerBox = QHBoxLayout()
106
- self.outerBox.addWidget(self.nwLogo, 0, topRight)
104
+ self.outerBox.addWidget(self.nwLogo, 0, QtAlignRightTop)
107
105
  self.outerBox.addLayout(self.innerBox, 1)
108
106
 
109
107
  self.setLayout(self.outerBox)
@@ -149,10 +147,10 @@ class GuiAbout(QDialog):
149
147
 
150
148
  def _setStyleSheet(self) -> None:
151
149
  """Set stylesheet for all browser tabs."""
152
- baseCol = self.palette().window().color()
153
- self.txtCredits.setStyleSheet((
154
- "QTextBrowser {{border: none; background: rgb({r},{g},{b});}} "
155
- ).format(r=baseCol.red(), g=baseCol.green(), b=baseCol.blue()))
150
+ baseCol = cssCol(self.palette().window().color())
151
+ self.txtCredits.setStyleSheet(
152
+ f"QTextBrowser {{border: none; background: {baseCol};}} "
153
+ )
156
154
  return
157
155
 
158
156
  # END Class GuiAbout
@@ -26,8 +26,8 @@ from __future__ import annotations
26
26
 
27
27
  import logging
28
28
 
29
+ from PyQt5.QtCore import Qt, pyqtSlot
29
30
  from PyQt5.QtGui import QCloseEvent
30
- from PyQt5.QtCore import Qt, QSize, pyqtSlot
31
31
  from PyQt5.QtWidgets import (
32
32
  QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel,
33
33
  QListWidget, QListWidgetItem, QVBoxLayout, QWidget
@@ -36,13 +36,14 @@ from PyQt5.QtWidgets import (
36
36
  from novelwriter import CONFIG, SHARED
37
37
  from novelwriter.extensions.switch import NSwitch
38
38
  from novelwriter.extensions.configlayout import NColourLabel
39
+ from novelwriter.types import QtDialogCancel, QtDialogOk, QtDialogReset, QtUserRole
39
40
 
40
41
  logger = logging.getLogger(__name__)
41
42
 
42
43
 
43
44
  class GuiDocMerge(QDialog):
44
45
 
45
- D_HANDLE = Qt.ItemDataRole.UserRole
46
+ D_HANDLE = QtUserRole
46
47
 
47
48
  def __init__(self, parent: QWidget, sHandle: str, itemList: list[str]) -> None:
48
49
  super().__init__(parent=parent)
@@ -53,27 +54,29 @@ class GuiDocMerge(QDialog):
53
54
 
54
55
  self._data = {}
55
56
 
56
- self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
57
+ self.headLabel = QLabel(self.tr("Documents to Merge"), self)
58
+ self.headLabel.setFont(SHARED.theme.guiFontB)
57
59
  self.helpLabel = NColourLabel(
58
60
  self.tr("Drag and drop items to change the order, or uncheck to exclude."),
59
61
  SHARED.theme.helpText, parent=self, wrap=True
60
62
  )
61
63
 
62
- iPx = SHARED.theme.baseIconSize
64
+ iPx = SHARED.theme.baseIconHeight
65
+ iSz = SHARED.theme.baseIconSize
63
66
  hSp = CONFIG.pxInt(12)
64
67
  vSp = CONFIG.pxInt(8)
65
68
  bSp = CONFIG.pxInt(12)
66
69
 
67
- self.listBox = QListWidget()
68
- self.listBox.setIconSize(QSize(iPx, iPx))
70
+ self.listBox = QListWidget(self)
71
+ self.listBox.setIconSize(iSz)
69
72
  self.listBox.setMinimumWidth(CONFIG.pxInt(400))
70
73
  self.listBox.setMinimumHeight(CONFIG.pxInt(180))
71
- self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows)
72
- self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
73
- self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
74
+ self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
75
+ self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
76
+ self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
74
77
 
75
78
  # Merge Options
76
- self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
79
+ self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self)
77
80
  self.trashSwitch = NSwitch(self, height=iPx)
78
81
 
79
82
  self.optBox = QGridLayout()
@@ -83,11 +86,11 @@ class GuiDocMerge(QDialog):
83
86
  self.optBox.setColumnStretch(2, 1)
84
87
 
85
88
  # Buttons
86
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
89
+ self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
87
90
  self.buttonBox.accepted.connect(self.accept)
88
91
  self.buttonBox.rejected.connect(self.reject)
89
92
 
90
- self.resetButton = self.buttonBox.addButton(QDialogButtonBox.Reset)
93
+ self.resetButton = self.buttonBox.addButton(QtDialogReset)
91
94
  self.resetButton.clicked.connect(self._resetList)
92
95
 
93
96
  # Assemble
@@ -119,7 +122,7 @@ class GuiDocMerge(QDialog):
119
122
  finalItems = []
120
123
  for i in range(self.listBox.count()):
121
124
  item = self.listBox.item(i)
122
- if item is not None and item.checkState() == Qt.Checked:
125
+ if item is not None and item.checkState() == Qt.CheckState.Checked:
123
126
  finalItems.append(item.data(self.D_HANDLE))
124
127
 
125
128
  self._data["moveToTrash"] = self.trashSwitch.isChecked()
@@ -174,7 +177,7 @@ class GuiDocMerge(QDialog):
174
177
  newItem.setIcon(itemIcon)
175
178
  newItem.setText(nwItem.itemName)
176
179
  newItem.setData(self.D_HANDLE, tHandle)
177
- newItem.setCheckState(Qt.Checked)
180
+ newItem.setCheckState(Qt.CheckState.Checked)
178
181
 
179
182
  self.listBox.addItem(newItem)
180
183
 
@@ -26,8 +26,8 @@ from __future__ import annotations
26
26
 
27
27
  import logging
28
28
 
29
+ from PyQt5.QtCore import pyqtSlot
29
30
  from PyQt5.QtGui import QCloseEvent
30
- from PyQt5.QtCore import Qt, pyqtSlot
31
31
  from PyQt5.QtWidgets import (
32
32
  QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout,
33
33
  QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget
@@ -36,15 +36,16 @@ from PyQt5.QtWidgets import (
36
36
  from novelwriter import CONFIG, SHARED
37
37
  from novelwriter.extensions.switch import NSwitch
38
38
  from novelwriter.extensions.configlayout import NColourLabel
39
+ from novelwriter.types import QtDialogCancel, QtDialogOk, QtUserRole
39
40
 
40
41
  logger = logging.getLogger(__name__)
41
42
 
42
43
 
43
44
  class GuiDocSplit(QDialog):
44
45
 
45
- LINE_ROLE = Qt.ItemDataRole.UserRole
46
- LEVEL_ROLE = Qt.ItemDataRole.UserRole + 1
47
- LABEL_ROLE = Qt.ItemDataRole.UserRole + 2
46
+ LINE_ROLE = QtUserRole
47
+ LEVEL_ROLE = QtUserRole + 1
48
+ LABEL_ROLE = QtUserRole + 2
48
49
 
49
50
  def __init__(self, parent: QWidget, sHandle: str) -> None:
50
51
  super().__init__(parent=parent)
@@ -57,14 +58,15 @@ class GuiDocSplit(QDialog):
57
58
 
58
59
  self.setWindowTitle(self.tr("Split Document"))
59
60
 
60
- self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document Headings")))
61
+ self.headLabel = QLabel(self.tr("Document Headings"), self)
62
+ self.headLabel.setFont(SHARED.theme.guiFontB)
61
63
  self.helpLabel = NColourLabel(
62
64
  self.tr("Select the maximum level to split into files."),
63
65
  SHARED.theme.helpText, parent=self, wrap=True
64
66
  )
65
67
 
66
68
  # Values
67
- iPx = SHARED.theme.baseIconSize
69
+ iPx = SHARED.theme.baseIconHeight
68
70
  hSp = CONFIG.pxInt(12)
69
71
  vSp = CONFIG.pxInt(8)
70
72
  bSp = CONFIG.pxInt(12)
@@ -75,8 +77,8 @@ class GuiDocSplit(QDialog):
75
77
  docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
76
78
 
77
79
  # Heading Selection
78
- self.listBox = QListWidget()
79
- self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
80
+ self.listBox = QListWidget(self)
81
+ self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
80
82
  self.listBox.setMinimumWidth(CONFIG.pxInt(400))
81
83
  self.listBox.setMinimumHeight(CONFIG.pxInt(180))
82
84
 
@@ -91,15 +93,15 @@ class GuiDocSplit(QDialog):
91
93
  self.splitLevel.currentIndexChanged.connect(self._reloadList)
92
94
 
93
95
  # Split Options
94
- self.folderLabel = QLabel(self.tr("Split into a new folder"))
96
+ self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
95
97
  self.folderSwitch = NSwitch(self, height=iPx)
96
98
  self.folderSwitch.setChecked(intoFolder)
97
99
 
98
- self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"))
100
+ self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
99
101
  self.hierarchySwitch = NSwitch(self, height=iPx)
100
102
  self.hierarchySwitch.setChecked(docHierarchy)
101
103
 
102
- self.trashLabel = QLabel(self.tr("Move split document to Trash"))
104
+ self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
103
105
  self.trashSwitch = NSwitch(self, height=iPx)
104
106
 
105
107
  self.optBox = QGridLayout()
@@ -114,7 +116,7 @@ class GuiDocSplit(QDialog):
114
116
  self.optBox.setColumnStretch(3, 1)
115
117
 
116
118
  # Buttons
117
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
119
+ self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
118
120
  self.buttonBox.accepted.connect(self.accept)
119
121
  self.buttonBox.rejected.connect(self.reject)
120
122
 
@@ -31,6 +31,7 @@ from PyQt5.QtWidgets import (
31
31
  )
32
32
 
33
33
  from novelwriter import CONFIG
34
+ from novelwriter.types import QtDialogCancel, QtDialogOk
34
35
 
35
36
  logger = logging.getLogger(__name__)
36
37
 
@@ -55,13 +56,13 @@ class GuiEditLabel(QDialog):
55
56
  self.labelValue.selectAll()
56
57
 
57
58
  # Buttons
58
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
59
+ self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
59
60
  self.buttonBox.accepted.connect(self.accept)
60
61
  self.buttonBox.rejected.connect(self.reject)
61
62
 
62
63
  # Assemble
63
64
  self.innerBox = QHBoxLayout()
64
- self.innerBox.addWidget(QLabel(self.tr("Label")), 0)
65
+ self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
65
66
  self.innerBox.addWidget(self.labelValue, 1)
66
67
  self.innerBox.setSpacing(mSp)
67
68
 
@@ -88,9 +89,9 @@ class GuiEditLabel(QDialog):
88
89
  def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
89
90
  """Pop the dialog and return the result."""
90
91
  cls = GuiEditLabel(parent, text=text)
91
- cls.exec_()
92
+ cls.exec()
92
93
  label = cls.itemLabel
93
- accepted = cls.result() == QDialog.Accepted
94
+ accepted = cls.result() == QDialog.DialogCode.Accepted
94
95
  cls.deleteLater()
95
96
  return label, accepted
96
97
 
@@ -26,21 +26,25 @@ from __future__ import annotations
26
26
 
27
27
  import logging
28
28
 
29
- from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
30
29
  from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
30
+ from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
31
31
  from PyQt5.QtWidgets import (
32
- QAbstractButton, QCompleter, QDialog, QDialogButtonBox, QFileDialog,
33
- QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QToolButton, QVBoxLayout,
34
- QWidget, qApp
32
+ QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox,
33
+ QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout,
34
+ QWidget
35
35
  )
36
36
 
37
37
  from novelwriter import CONFIG, SHARED
38
38
  from novelwriter.constants import nwConst, nwUnicode
39
39
  from novelwriter.dialogs.quotes import GuiQuoteSelect
40
- from novelwriter.extensions.switch import NSwitch
41
- from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
42
40
  from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
41
+ from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox
43
42
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
43
+ from novelwriter.extensions.switch import NSwitch
44
+ from novelwriter.types import (
45
+ QtAlignCenter, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept,
46
+ QtRoleApply, QtRoleReject
47
+ )
44
48
 
45
49
  logger = logging.getLogger(__name__)
46
50
 
@@ -83,11 +87,7 @@ class GuiPreferences(QDialog):
83
87
  self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
84
88
 
85
89
  # Buttons
86
- self.buttonBox = QDialogButtonBox(
87
- QDialogButtonBox.StandardButton.Apply
88
- | QDialogButtonBox.StandardButton.Save
89
- | QDialogButtonBox.StandardButton.Close
90
- )
90
+ self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self)
91
91
  self.buttonBox.clicked.connect(self._dialogButtonClicked)
92
92
 
93
93
  # Assemble
@@ -132,8 +132,8 @@ class GuiPreferences(QDialog):
132
132
  def buildForm(self) -> None:
133
133
  """Build the settings form."""
134
134
  section = 0
135
+ iSz = SHARED.theme.baseIconSize
135
136
  minWidth = CONFIG.pxInt(200)
136
- mIcon = SHARED.theme.getIcon("more")
137
137
 
138
138
  # Label
139
139
  self.sidebar.addLabel(self.tr("General"))
@@ -175,8 +175,7 @@ class GuiPreferences(QDialog):
175
175
  self.guiFont.setReadOnly(True)
176
176
  self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
177
177
  self.guiFont.setText(CONFIG.guiFont)
178
- self.guiFontButton = QToolButton(self)
179
- self.guiFontButton.setIcon(mIcon)
178
+ self.guiFontButton = NIconToolButton(self, iSz, "more")
180
179
  self.guiFontButton.clicked.connect(self._selectGuiFont)
181
180
  self.mainForm.addRow(
182
181
  self.tr("Application font family"), self.guiFont,
@@ -236,8 +235,7 @@ class GuiPreferences(QDialog):
236
235
  self.textFont.setReadOnly(True)
237
236
  self.textFont.setMinimumWidth(CONFIG.pxInt(162))
238
237
  self.textFont.setText(CONFIG.textFont)
239
- self.textFontButton = QToolButton(self)
240
- self.textFontButton.setIcon(mIcon)
238
+ self.textFontButton = NIconToolButton(self, iSz, "more")
241
239
  self.textFontButton.clicked.connect(self._selectTextFont)
242
240
  self.mainForm.addRow(
243
241
  self.tr("Document font family"), self.textFont,
@@ -320,6 +318,7 @@ class GuiPreferences(QDialog):
320
318
  # Backup Path
321
319
  self.backupPath = CONFIG.backupPath()
322
320
  self.backupGetPath = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Browse"), self)
321
+ self.backupGetPath.setIconSize(iSz)
323
322
  self.backupGetPath.clicked.connect(self._backupFolder)
324
323
  self.mainForm.addRow(
325
324
  self.tr("Backup storage location"), self.backupGetPath,
@@ -675,10 +674,9 @@ class GuiPreferences(QDialog):
675
674
  self.quoteSym["SO"].setMaxLength(1)
676
675
  self.quoteSym["SO"].setReadOnly(True)
677
676
  self.quoteSym["SO"].setFixedWidth(qWidth)
678
- self.quoteSym["SO"].setAlignment(Qt.AlignCenter)
677
+ self.quoteSym["SO"].setAlignment(QtAlignCenter)
679
678
  self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
680
- self.btnSingleStyleO = QToolButton(self)
681
- self.btnSingleStyleO.setIcon(mIcon)
679
+ self.btnSingleStyleO = NIconToolButton(self, iSz, "more")
682
680
  self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
683
681
  self.mainForm.addRow(
684
682
  self.tr("Single quote open style"), self.quoteSym["SO"],
@@ -690,10 +688,9 @@ class GuiPreferences(QDialog):
690
688
  self.quoteSym["SC"].setMaxLength(1)
691
689
  self.quoteSym["SC"].setReadOnly(True)
692
690
  self.quoteSym["SC"].setFixedWidth(qWidth)
693
- self.quoteSym["SC"].setAlignment(Qt.AlignCenter)
691
+ self.quoteSym["SC"].setAlignment(QtAlignCenter)
694
692
  self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
695
- self.btnSingleStyleC = QToolButton(self)
696
- self.btnSingleStyleC.setIcon(mIcon)
693
+ self.btnSingleStyleC = NIconToolButton(self, iSz, "more")
697
694
  self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
698
695
  self.mainForm.addRow(
699
696
  self.tr("Single quote close style"), self.quoteSym["SC"],
@@ -706,10 +703,9 @@ class GuiPreferences(QDialog):
706
703
  self.quoteSym["DO"].setMaxLength(1)
707
704
  self.quoteSym["DO"].setReadOnly(True)
708
705
  self.quoteSym["DO"].setFixedWidth(qWidth)
709
- self.quoteSym["DO"].setAlignment(Qt.AlignCenter)
706
+ self.quoteSym["DO"].setAlignment(QtAlignCenter)
710
707
  self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
711
- self.btnDoubleStyleO = QToolButton(self)
712
- self.btnDoubleStyleO.setIcon(mIcon)
708
+ self.btnDoubleStyleO = NIconToolButton(self, iSz, "more")
713
709
  self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
714
710
  self.mainForm.addRow(
715
711
  self.tr("Double quote open style"), self.quoteSym["DO"],
@@ -721,10 +717,9 @@ class GuiPreferences(QDialog):
721
717
  self.quoteSym["DC"].setMaxLength(1)
722
718
  self.quoteSym["DC"].setReadOnly(True)
723
719
  self.quoteSym["DC"].setFixedWidth(qWidth)
724
- self.quoteSym["DC"].setAlignment(Qt.AlignCenter)
720
+ self.quoteSym["DC"].setAlignment(QtAlignCenter)
725
721
  self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
726
- self.btnDoubleStyleC = QToolButton(self)
727
- self.btnDoubleStyleC.setIcon(mIcon)
722
+ self.btnDoubleStyleC = NIconToolButton(self, iSz, "more")
728
723
  self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
729
724
  self.mainForm.addRow(
730
725
  self.tr("Double quote close style"), self.quoteSym["DC"],
@@ -746,7 +741,7 @@ class GuiPreferences(QDialog):
746
741
  logger.debug("Close: GuiPreferences")
747
742
  self._saveWindowSize()
748
743
  event.accept()
749
- qApp.processEvents()
744
+ QApplication.processEvents()
750
745
  self.done(nwConst.DLG_FINISHED)
751
746
  self.deleteLater()
752
747
  return
@@ -766,12 +761,12 @@ class GuiPreferences(QDialog):
766
761
  def _dialogButtonClicked(self, button: QAbstractButton) -> None:
767
762
  """Handle button clicks from the dialog button box."""
768
763
  role = self.buttonBox.buttonRole(button)
769
- if role == QDialogButtonBox.ButtonRole.ApplyRole:
764
+ if role == QtRoleApply:
770
765
  self._saveValues()
771
- elif role == QDialogButtonBox.ButtonRole.AcceptRole:
766
+ elif role == QtRoleAccept:
772
767
  self._saveValues()
773
768
  self.close()
774
- elif role == QDialogButtonBox.ButtonRole.RejectRole:
769
+ elif role == QtRoleReject:
775
770
  self.close()
776
771
  return
777
772
 
@@ -816,7 +811,7 @@ class GuiPreferences(QDialog):
816
811
  """Open a dialog to select the backup folder."""
817
812
  if path := QFileDialog.getExistingDirectory(
818
813
  self, self.tr("Backup Directory"), str(self.backupPath) or "",
819
- options=QFileDialog.ShowDirsOnly
814
+ options=QFileDialog.Option.ShowDirsOnly
820
815
  ):
821
816
  self.backupPath = path
822
817
  self.mainForm.setHelpText("backupPath", self.tr("Path: {0}").format(path))
@@ -26,20 +26,21 @@ from __future__ import annotations
26
26
 
27
27
  import logging
28
28
 
29
- from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
30
29
  from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
30
+ from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
31
31
  from PyQt5.QtWidgets import (
32
- QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout, QLineEdit,
33
- QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
34
- QWidget, qApp
32
+ QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout,
33
+ QLineEdit, QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem,
34
+ QVBoxLayout, QWidget
35
35
  )
36
36
 
37
37
  from novelwriter import CONFIG, SHARED
38
38
  from novelwriter.common import simplified
39
- from novelwriter.extensions.switch import NSwitch
40
- from novelwriter.extensions.modified import NComboBox
41
39
  from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
40
+ from novelwriter.extensions.modified import NComboBox, NIconToolButton
42
41
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
42
+ from novelwriter.extensions.switch import NSwitch
43
+ from novelwriter.types import QtDialogCancel, QtDialogSave, QtUserRole
43
44
 
44
45
  logger = logging.getLogger(__name__)
45
46
 
@@ -83,9 +84,7 @@ class GuiProjectSettings(QDialog):
83
84
  self.sidebar.buttonClicked.connect(self._sidebarClicked)
84
85
 
85
86
  # Buttons
86
- self.buttonBox = QDialogButtonBox(
87
- QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel
88
- )
87
+ self.buttonBox = QDialogButtonBox(QtDialogSave | QtDialogCancel, self)
89
88
  self.buttonBox.accepted.connect(self._doSave)
90
89
  self.buttonBox.rejected.connect(self.close)
91
90
 
@@ -195,7 +194,7 @@ class GuiProjectSettings(QDialog):
195
194
  project.data.setAutoReplace(newList)
196
195
 
197
196
  self.newProjectSettingsReady.emit(rebuildTrees)
198
- qApp.processEvents()
197
+ QApplication.processEvents()
199
198
  self.close()
200
199
 
201
200
  return
@@ -305,9 +304,9 @@ class _StatusPage(NFixedPage):
305
304
  COL_LABEL = 0
306
305
  COL_USAGE = 1
307
306
 
308
- KEY_ROLE = Qt.ItemDataRole.UserRole
309
- COL_ROLE = Qt.ItemDataRole.UserRole + 1
310
- NUM_ROLE = Qt.ItemDataRole.UserRole + 2
307
+ KEY_ROLE = QtUserRole
308
+ COL_ROLE = QtUserRole + 1
309
+ NUM_ROLE = QtUserRole + 2
311
310
 
312
311
  def __init__(self, parent: QWidget, isStatus: bool) -> None:
313
312
  super().__init__(parent=parent)
@@ -329,7 +328,9 @@ class _StatusPage(NFixedPage):
329
328
  self._colDeleted = []
330
329
  self._selColour = QColor(100, 100, 100)
331
330
 
332
- self.iPx = SHARED.theme.baseIconSize
331
+ self.iPx = SHARED.theme.baseIconHeight
332
+ iSz = SHARED.theme.baseIconSize
333
+ bSz = SHARED.theme.buttonIconSize
333
334
 
334
335
  # Title
335
336
  self.pageTitle = NColourLabel(
@@ -348,16 +349,16 @@ class _StatusPage(NFixedPage):
348
349
  self._addItem(key, entry["name"], entry["cols"], entry["count"])
349
350
 
350
351
  # List Controls
351
- self.addButton = QPushButton(SHARED.theme.getIcon("add"), "", self)
352
+ self.addButton = NIconToolButton(self, iSz, "add")
352
353
  self.addButton.clicked.connect(self._newItem)
353
354
 
354
- self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "", self)
355
+ self.delButton = NIconToolButton(self, iSz, "remove")
355
356
  self.delButton.clicked.connect(self._delItem)
356
357
 
357
- self.upButton = QPushButton(SHARED.theme.getIcon("up"), "", self)
358
+ self.upButton = NIconToolButton(self, iSz, "up")
358
359
  self.upButton.clicked.connect(lambda: self._moveItem(-1))
359
360
 
360
- self.dnButton = QPushButton(SHARED.theme.getIcon("down"), "", self)
361
+ self.dnButton = NIconToolButton(self, iSz, "down")
361
362
  self.dnButton.clicked.connect(lambda: self._moveItem(1))
362
363
 
363
364
  # Edit Form
@@ -368,12 +369,12 @@ class _StatusPage(NFixedPage):
368
369
 
369
370
  self.colPixmap = QPixmap(self.iPx, self.iPx)
370
371
  self.colPixmap.fill(QColor(100, 100, 100))
371
- self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"))
372
- self.colButton.setIconSize(self.colPixmap.rect().size())
372
+ self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"), self)
373
+ self.colButton.setIconSize(bSz)
373
374
  self.colButton.setEnabled(False)
374
375
  self.colButton.clicked.connect(self._selectColour)
375
376
 
376
- self.saveButton = QPushButton(self.tr("Save"))
377
+ self.saveButton = QPushButton(self.tr("Save"), self)
377
378
  self.saveButton.setEnabled(False)
378
379
  self.saveButton.clicked.connect(self._saveItem)
379
380
 
@@ -589,6 +590,8 @@ class _ReplacePage(NFixedPage):
589
590
 
590
591
  self._changed = False
591
592
 
593
+ iSz = SHARED.theme.baseIconSize
594
+
592
595
  wCol0 = CONFIG.pxInt(
593
596
  SHARED.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
594
597
  )
@@ -600,7 +603,7 @@ class _ReplacePage(NFixedPage):
600
603
  )
601
604
 
602
605
  # List Box
603
- self.listBox = QTreeWidget()
606
+ self.listBox = QTreeWidget(self)
604
607
  self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
605
608
  self.listBox.setColumnWidth(self.COL_KEY, wCol0)
606
609
  self.listBox.setIndentation(0)
@@ -610,14 +613,14 @@ class _ReplacePage(NFixedPage):
610
613
  newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
611
614
  self.listBox.addTopLevelItem(newItem)
612
615
 
613
- self.listBox.sortByColumn(self.COL_KEY, Qt.AscendingOrder)
616
+ self.listBox.sortByColumn(self.COL_KEY, Qt.SortOrder.AscendingOrder)
614
617
  self.listBox.setSortingEnabled(True)
615
618
 
616
619
  # List Controls
617
- self.addButton = QPushButton(SHARED.theme.getIcon("add"), "")
620
+ self.addButton = NIconToolButton(self, iSz, "add")
618
621
  self.addButton.clicked.connect(self._addEntry)
619
622
 
620
- self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "")
623
+ self.delButton = NIconToolButton(self, iSz, "remove")
621
624
  self.delButton.clicked.connect(self._delEntry)
622
625
 
623
626
  # Edit Form
@@ -630,7 +633,7 @@ class _ReplacePage(NFixedPage):
630
633
  self.editValue.setEnabled(False)
631
634
  self.editValue.setMaxLength(80)
632
635
 
633
- self.saveButton = QPushButton(self.tr("Save"))
636
+ self.saveButton = QPushButton(self.tr("Save"), self)
634
637
  self.saveButton.clicked.connect(self._saveEntry)
635
638
 
636
639
  # Assemble
@@ -26,7 +26,7 @@ from __future__ import annotations
26
26
  import logging
27
27
 
28
28
  from PyQt5.QtGui import QFontMetrics
29
- from PyQt5.QtCore import QSize, Qt, pyqtSlot
29
+ from PyQt5.QtCore import QSize, pyqtSlot
30
30
  from PyQt5.QtWidgets import (
31
31
  QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
32
32
  QListWidgetItem, QVBoxLayout, QWidget
@@ -34,6 +34,7 @@ from PyQt5.QtWidgets import (
34
34
 
35
35
  from novelwriter import CONFIG
36
36
  from novelwriter.constants import trConst, nwQuotes
37
+ from novelwriter.types import QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk, QtUserRole
37
38
 
38
39
  logger = logging.getLogger(__name__)
39
40
 
@@ -42,7 +43,7 @@ class GuiQuoteSelect(QDialog):
42
43
 
43
44
  _selected = ""
44
45
 
45
- D_KEY = Qt.ItemDataRole.UserRole
46
+ D_KEY = QtUserRole
46
47
 
47
48
  def __init__(self, parent: QWidget, current: str = '"') -> None:
48
49
  super().__init__(parent=parent)
@@ -65,14 +66,14 @@ class GuiQuoteSelect(QDialog):
65
66
  lblFont.setPointSizeF(4*lblFont.pointSizeF())
66
67
 
67
68
  # Preview Label
68
- self.previewLabel = QLabel(current)
69
+ self.previewLabel = QLabel(current, self)
69
70
  self.previewLabel.setFont(lblFont)
70
71
  self.previewLabel.setFixedSize(QSize(pxW, pxH))
71
- self.previewLabel.setAlignment(Qt.AlignCenter)
72
- self.previewLabel.setFrameStyle(QFrame.Box | QFrame.Plain)
72
+ self.previewLabel.setAlignment(QtAlignCenter)
73
+ self.previewLabel.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain)
73
74
 
74
75
  # Quote Symbols
75
- self.listBox = QListWidget()
76
+ self.listBox = QListWidget(self)
76
77
  self.listBox.itemSelectionChanged.connect(self._selectedSymbol)
77
78
 
78
79
  minSize = 100
@@ -89,12 +90,12 @@ class GuiQuoteSelect(QDialog):
89
90
  self.listBox.setMinimumHeight(CONFIG.pxInt(150))
90
91
 
91
92
  # Buttons
92
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
93
+ self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
93
94
  self.buttonBox.accepted.connect(self.accept)
94
95
  self.buttonBox.rejected.connect(self.reject)
95
96
 
96
97
  # Assemble
97
- self.labelBox.addWidget(self.previewLabel, 0, Qt.AlignTop)
98
+ self.labelBox.addWidget(self.previewLabel, 0, QtAlignTop)
98
99
  self.labelBox.addStretch(1)
99
100
 
100
101
  self.innerBox.addLayout(self.labelBox)
@@ -122,7 +123,7 @@ class GuiQuoteSelect(QDialog):
122
123
  def getQuote(cls, parent: QWidget, current: str = "") -> tuple[str, bool]:
123
124
  """Pop the dialog and return the result."""
124
125
  cls = GuiQuoteSelect(parent, current=current)
125
- cls.exec_()
126
+ cls.exec()
126
127
  quote = cls._selected
127
128
  accepted = cls.result() == QDialog.DialogCode.Accepted
128
129
  cls.deleteLater()