novelWriter 2.3.1__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 (119) hide show
  1. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
  2. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/RECORD +114 -107
  3. novelwriter/__init__.py +17 -10
  4. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  5. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  6. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  7. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  8. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  9. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  10. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  11. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  12. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  13. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  14. novelwriter/assets/icons/none.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
  16. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
  17. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
  18. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
  19. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
  21. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  22. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  23. novelwriter/assets/icons/typicons_light/icons.conf +4 -0
  24. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
  25. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
  26. novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
  27. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
  28. novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
  29. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  30. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  31. novelwriter/assets/manual.pdf +0 -0
  32. novelwriter/assets/sample.zip +0 -0
  33. novelwriter/assets/syntax/default_dark.conf +1 -0
  34. novelwriter/assets/syntax/default_light.conf +1 -0
  35. novelwriter/assets/syntax/grey_dark.conf +1 -0
  36. novelwriter/assets/syntax/grey_light.conf +1 -0
  37. novelwriter/assets/syntax/light_owl.conf +1 -0
  38. novelwriter/assets/syntax/night_owl.conf +1 -0
  39. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  40. novelwriter/assets/syntax/solarized_light.conf +1 -0
  41. novelwriter/assets/syntax/tomorrow.conf +1 -0
  42. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  43. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  44. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  45. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  46. novelwriter/assets/text/credits_en.htm +25 -23
  47. novelwriter/common.py +12 -4
  48. novelwriter/config.py +47 -16
  49. novelwriter/constants.py +5 -6
  50. novelwriter/core/buildsettings.py +64 -44
  51. novelwriter/core/coretools.py +97 -13
  52. novelwriter/core/docbuild.py +74 -7
  53. novelwriter/core/document.py +24 -3
  54. novelwriter/core/index.py +31 -112
  55. novelwriter/core/project.py +10 -15
  56. novelwriter/core/projectxml.py +1 -1
  57. novelwriter/core/sessions.py +2 -2
  58. novelwriter/core/spellcheck.py +3 -3
  59. novelwriter/core/status.py +6 -5
  60. novelwriter/core/storage.py +8 -2
  61. novelwriter/core/tohtml.py +22 -25
  62. novelwriter/core/tokenizer.py +417 -233
  63. novelwriter/core/tomd.py +17 -8
  64. novelwriter/core/toodt.py +386 -351
  65. novelwriter/core/tree.py +8 -8
  66. novelwriter/dialogs/about.py +9 -11
  67. novelwriter/dialogs/docmerge.py +17 -14
  68. novelwriter/dialogs/docsplit.py +20 -19
  69. novelwriter/dialogs/editlabel.py +5 -4
  70. novelwriter/dialogs/preferences.py +32 -40
  71. novelwriter/dialogs/projectsettings.py +31 -28
  72. novelwriter/dialogs/quotes.py +10 -9
  73. novelwriter/dialogs/wordlist.py +17 -14
  74. novelwriter/enum.py +17 -14
  75. novelwriter/error.py +14 -12
  76. novelwriter/extensions/circularprogress.py +12 -8
  77. novelwriter/extensions/configlayout.py +1 -3
  78. novelwriter/extensions/modified.py +51 -2
  79. novelwriter/extensions/pagedsidebar.py +16 -14
  80. novelwriter/extensions/simpleprogress.py +3 -1
  81. novelwriter/extensions/statusled.py +3 -1
  82. novelwriter/extensions/switch.py +10 -9
  83. novelwriter/extensions/switchbox.py +14 -13
  84. novelwriter/extensions/versioninfo.py +1 -1
  85. novelwriter/gui/doceditor.py +433 -496
  86. novelwriter/gui/dochighlight.py +54 -33
  87. novelwriter/gui/docviewer.py +162 -175
  88. novelwriter/gui/docviewerpanel.py +20 -37
  89. novelwriter/gui/editordocument.py +15 -4
  90. novelwriter/gui/itemdetails.py +51 -54
  91. novelwriter/gui/mainmenu.py +37 -16
  92. novelwriter/gui/noveltree.py +31 -37
  93. novelwriter/gui/outline.py +120 -98
  94. novelwriter/gui/projtree.py +61 -67
  95. novelwriter/gui/search.py +362 -0
  96. novelwriter/gui/sidebar.py +36 -45
  97. novelwriter/gui/statusbar.py +14 -14
  98. novelwriter/gui/theme.py +107 -32
  99. novelwriter/guimain.py +209 -202
  100. novelwriter/shared.py +31 -6
  101. novelwriter/text/counting.py +138 -0
  102. novelwriter/tools/dictionaries.py +15 -14
  103. novelwriter/tools/lipsum.py +20 -17
  104. novelwriter/tools/manusbuild.py +43 -35
  105. novelwriter/tools/manuscript.py +381 -104
  106. novelwriter/tools/manussettings.py +262 -125
  107. novelwriter/tools/noveldetails.py +20 -18
  108. novelwriter/tools/welcome.py +52 -49
  109. novelwriter/tools/writingstats.py +61 -55
  110. novelwriter/types.py +90 -0
  111. novelwriter/core/__init__.py +0 -3
  112. novelwriter/dialogs/__init__.py +0 -3
  113. novelwriter/extensions/__init__.py +0 -3
  114. novelwriter/gui/__init__.py +0 -3
  115. novelwriter/tools/__init__.py +0 -3
  116. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
  117. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/WHEEL +0 -0
  118. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/entry_points.txt +0 -0
  119. {novelWriter-2.3.1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
@@ -32,6 +32,8 @@ from PyQt5.QtWidgets import (
32
32
  QStyleOptionToolButton, QToolBar, QToolButton, QWidget
33
33
  )
34
34
 
35
+ from novelwriter.types import QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen
36
+
35
37
 
36
38
  class NPagedSideBar(QToolBar):
37
39
  """Extensions: Paged Side Bar
@@ -54,10 +56,10 @@ class NPagedSideBar(QToolBar):
54
56
  self._group.buttonClicked.connect(self._buttonClicked)
55
57
 
56
58
  self.setMovable(False)
57
- self.setOrientation(Qt.Vertical)
59
+ self.setOrientation(Qt.Orientation.Vertical)
58
60
 
59
61
  stretch = QWidget(self)
60
- stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
62
+ stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
61
63
  self._stretchAction = self.addWidget(stretch)
62
64
 
63
65
  return
@@ -117,13 +119,13 @@ class _NPagedToolButton(QToolButton):
117
119
  def __init__(self, parent: QWidget) -> None:
118
120
  super().__init__(parent=parent)
119
121
 
120
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
122
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
121
123
  self.setCheckable(True)
122
124
 
123
125
  fH = self.fontMetrics().height()
124
126
  self._bH = round(fH * 1.7)
125
127
  self._tM = (self._bH - fH)//2
126
- self._lM = 3*self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
128
+ self._lM = 3*self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
127
129
  self._cR = self._lM//2
128
130
  self._aH = 2*fH//7
129
131
  self.setFixedHeight(self._bH)
@@ -143,15 +145,15 @@ class _NPagedToolButton(QToolButton):
143
145
  opt.initFrom(self)
144
146
 
145
147
  paint = QPainter(self)
146
- paint.setRenderHint(QPainter.Antialiasing, True)
147
- paint.setPen(Qt.NoPen)
148
- paint.setBrush(Qt.NoBrush)
148
+ paint.setRenderHint(QtPaintAnitAlias, True)
149
+ paint.setPen(QtNoPen)
150
+ paint.setBrush(QtNoBrush)
149
151
 
150
152
  width = self.width()
151
153
  height = self.height()
152
154
  palette = self.palette()
153
155
 
154
- if opt.state & QStyle.State_MouseOver == QStyle.State_MouseOver:
156
+ if opt.state & QtMouseOver == QtMouseOver:
155
157
  backCol = palette.base()
156
158
  paint.setBrush(backCol)
157
159
  paint.setOpacity(0.75)
@@ -171,7 +173,7 @@ class _NPagedToolButton(QToolButton):
171
173
 
172
174
  paint.setPen(textCol)
173
175
  paint.setOpacity(1.0)
174
- paint.drawText(QRectF(self._lM, self._tM, tW, tH), Qt.AlignLeft, self.text())
176
+ paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
175
177
 
176
178
  tC = self.height()//2
177
179
  tW = self.width() - self._aH - self._lM
@@ -195,12 +197,12 @@ class _NPagedToolLabel(QLabel):
195
197
  def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
196
198
  super().__init__(parent=parent)
197
199
 
198
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
200
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
199
201
 
200
202
  fH = self.fontMetrics().height()
201
203
  self._bH = round(fH * 1.7)
202
204
  self._tM = (self._bH - fH)//2
203
- self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
205
+ self._lM = self.style().pixelMetric(QStyle.PixelMetric.PM_ButtonMargin)//2
204
206
  self.setFixedHeight(self._bH)
205
207
 
206
208
  self._textCol = textColor or self.palette().text().color()
@@ -212,8 +214,8 @@ class _NPagedToolLabel(QLabel):
212
214
  label that matches the button style.
213
215
  """
214
216
  paint = QPainter(self)
215
- paint.setRenderHint(QPainter.Antialiasing, True)
216
- paint.setPen(Qt.NoPen)
217
+ paint.setRenderHint(QtPaintAnitAlias, True)
218
+ paint.setPen(QtNoPen)
217
219
 
218
220
  width = self.width()
219
221
  height = self.height()
@@ -223,7 +225,7 @@ class _NPagedToolLabel(QLabel):
223
225
 
224
226
  paint.setPen(self._textCol)
225
227
  paint.setOpacity(1.0)
226
- paint.drawText(QRectF(self._lM, self._tM, tW, tH), Qt.AlignLeft, self.text())
228
+ paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
227
229
 
228
230
  return
229
231
 
@@ -28,6 +28,8 @@ from math import ceil
28
28
  from PyQt5.QtGui import QPaintEvent, QPainter
29
29
  from PyQt5.QtWidgets import QProgressBar, QWidget
30
30
 
31
+ from novelwriter.types import QtPaintAnitAlias
32
+
31
33
 
32
34
  class NProgressSimple(QProgressBar):
33
35
  """Extension: Simple Progress Widget
@@ -44,7 +46,7 @@ class NProgressSimple(QProgressBar):
44
46
  if (value := self.value()) > 0:
45
47
  progress = ceil(self.width()*float(value)/self.maximum())
46
48
  painter = QPainter(self)
47
- painter.setRenderHint(QPainter.Antialiasing, True)
49
+ painter.setRenderHint(QtPaintAnitAlias, True)
48
50
  painter.setPen(self.palette().highlight().color())
49
51
  painter.setBrush(self.palette().highlight())
50
52
  painter.drawRect(0, 0, progress, self.height())
@@ -30,6 +30,8 @@ from typing import Literal
30
30
  from PyQt5.QtGui import QColor, QPaintEvent, QPainter
31
31
  from PyQt5.QtWidgets import QAbstractButton, QWidget
32
32
 
33
+ from novelwriter.types import QtPaintAnitAlias
34
+
33
35
  logger = logging.getLogger(__name__)
34
36
 
35
37
 
@@ -67,7 +69,7 @@ class StatusLED(QAbstractButton):
67
69
  def paintEvent(self, event: QPaintEvent) -> None:
68
70
  """Draw the LED."""
69
71
  painter = QPainter(self)
70
- painter.setRenderHint(QPainter.Antialiasing, True)
72
+ painter.setRenderHint(QtPaintAnitAlias, True)
71
73
  painter.setPen(self.palette().dark().color())
72
74
  painter.setBrush(self._theCol)
73
75
  painter.setOpacity(1.0)
@@ -27,25 +27,26 @@ from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
27
27
  from PyQt5.QtCore import QEvent, QPropertyAnimation, Qt, pyqtProperty
28
28
  from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
29
29
 
30
- from novelwriter import CONFIG
30
+ from novelwriter import CONFIG, SHARED
31
+ from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen
31
32
 
32
33
 
33
34
  class NSwitch(QAbstractButton):
34
35
 
35
36
  __slots__ = ("_xW", "_xH", "_xR", "_rB", "_rH", "_rR", "_offset")
36
37
 
37
- def __init__(self, parent: QWidget | None = None, height: int = 0) -> None:
38
+ def __init__(self, parent: QWidget, height: int = 0) -> None:
38
39
  super().__init__(parent=parent)
39
40
 
40
- self._xH = height or CONFIG.pxInt(20)
41
+ self._xH = height or SHARED.theme.baseButtonHeight
41
42
  self._xW = 2*self._xH
42
43
  self._xR = int(self._xH*0.5)
43
- self._rB = int(CONFIG.guiScale*2)
44
+ self._rB = CONFIG.pxInt(2)
44
45
  self._rH = self._xH - 2*self._rB
45
46
  self._rR = self._xR - self._rB
46
47
 
47
48
  self.setCheckable(True)
48
- self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
49
+ self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
49
50
  self.setFixedWidth(self._xW)
50
51
  self.setFixedHeight(self._xH)
51
52
  self._offset = self._xR
@@ -89,8 +90,8 @@ class NSwitch(QAbstractButton):
89
90
  def paintEvent(self, event: QPaintEvent) -> None:
90
91
  """Drawing the switch itself."""
91
92
  painter = QPainter(self)
92
- painter.setRenderHint(QPainter.Antialiasing, True)
93
- painter.setPen(Qt.NoPen)
93
+ painter.setRenderHint(QtPaintAnitAlias, True)
94
+ painter.setPen(QtNoPen)
94
95
 
95
96
  palette = self.palette()
96
97
  if self.isChecked():
@@ -119,7 +120,7 @@ class NSwitch(QAbstractButton):
119
120
  def mouseReleaseEvent(self, event: QMouseEvent) -> None:
120
121
  """Animate the switch on mouse release."""
121
122
  super().mouseReleaseEvent(event)
122
- if event.button() == Qt.LeftButton:
123
+ if event.button() == QtMouseLeft:
123
124
  anim = QPropertyAnimation(self, b"offset", self)
124
125
  anim.setDuration(120)
125
126
  anim.setStartValue(self._offset)
@@ -129,7 +130,7 @@ class NSwitch(QAbstractButton):
129
130
 
130
131
  def enterEvent(self, event: QEvent) -> None:
131
132
  """Change the cursor when hovering the button."""
132
- self.setCursor(Qt.PointingHandCursor)
133
+ self.setCursor(Qt.CursorShape.PointingHandCursor)
133
134
  super().enterEvent(event)
134
135
  return
135
136
 
@@ -24,10 +24,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
24
24
  from __future__ import annotations
25
25
 
26
26
  from PyQt5.QtGui import QIcon
27
- from PyQt5.QtCore import Qt, pyqtSignal
27
+ from PyQt5.QtCore import pyqtSignal
28
28
  from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
29
29
 
30
30
  from novelwriter.extensions.switch import NSwitch
31
+ from novelwriter.types import QtAlignLeft, QtAlignRight, QtAlignRightMiddle
31
32
 
32
33
 
33
34
  class NSwitchBox(QScrollArea):
@@ -57,8 +58,8 @@ class NSwitchBox(QScrollArea):
57
58
  self._content = QGridLayout()
58
59
  self._content.setColumnStretch(1, 1)
59
60
 
60
- self._widget = QWidget()
61
- self._widget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
61
+ self._widget = QWidget(self)
62
+ self._widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum)
62
63
  self._widget.setLayout(self._content)
63
64
 
64
65
  self.setWidgetResizable(True)
@@ -68,29 +69,29 @@ class NSwitchBox(QScrollArea):
68
69
 
69
70
  def addLabel(self, text: str) -> None:
70
71
  """Add a header label to the content box."""
71
- label = QLabel(text)
72
+ label = QLabel(text, self)
72
73
  font = label.font()
73
74
  font.setBold(True)
74
75
  label.setFont(font)
75
- self._content.addWidget(label, self._index, 0, 1, 3, Qt.AlignLeft)
76
+ self._content.addWidget(label, self._index, 0, 1, 3, QtAlignLeft)
76
77
  self._widgets.append(label)
77
78
  self._bumpIndex()
78
79
  return
79
80
 
80
81
  def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None:
81
82
  """Add an item to the content box."""
82
- icon = QLabel("")
83
- icon.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
83
+ icon = QLabel("", self)
84
+ icon.setAlignment(QtAlignRightMiddle)
84
85
  icon.setPixmap(qIcon.pixmap(self._sIcon, self._sIcon))
85
- self._content.addWidget(icon, self._index, 0, Qt.AlignLeft)
86
+ self._content.addWidget(icon, self._index, 0, QtAlignLeft)
86
87
 
87
- label = QLabel(text)
88
- self._content.addWidget(label, self._index, 1, Qt.AlignLeft)
88
+ label = QLabel(text, self)
89
+ self._content.addWidget(label, self._index, 1, QtAlignLeft)
89
90
 
90
91
  switch = NSwitch(self, height=self._hSwitch)
91
92
  switch.setChecked(default)
92
93
  switch.toggled.connect(lambda state: self._emitSwitchSignal(identifier, state))
93
- self._content.addWidget(switch, self._index, 2, Qt.AlignRight)
94
+ self._content.addWidget(switch, self._index, 2, QtAlignRight)
94
95
 
95
96
  self._widgets.append(switch)
96
97
  self._bumpIndex()
@@ -99,9 +100,9 @@ class NSwitchBox(QScrollArea):
99
100
 
100
101
  def addSeparator(self) -> None:
101
102
  """Add a blank entry in the content box."""
102
- spacer = QWidget()
103
+ spacer = QWidget(self)
103
104
  spacer.setFixedHeight(int(0.5*self._sIcon))
104
- self._content.addWidget(spacer, self._index, 0, 1, 3, Qt.AlignLeft)
105
+ self._content.addWidget(spacer, self._index, 0, 1, 3, QtAlignLeft)
105
106
  self._widgets.append(spacer)
106
107
  self._bumpIndex()
107
108
  return
@@ -57,7 +57,7 @@ class VersionInfoWidget(QWidget):
57
57
  # Labels
58
58
  self._lblInfo = QLabel("{0} {1} \u2013 {2} {3} \u2013 {4}".format(
59
59
  self.tr("Version"), formatVersion(__version__),
60
- self.tr("Released on"), datetime.strptime(__date__, "%Y-%m-%d").strftime("%x"),
60
+ self.tr("Released on"), CONFIG.localDate(datetime.strptime(__date__, "%Y-%m-%d")),
61
61
  "<a href='#notes'>{0}</a>".format(self.tr("Release Notes")),
62
62
  ), self)
63
63
  self._lblInfo.linkActivated.connect(self._processLink)