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
novelwriter/config.py CHANGED
@@ -22,7 +22,7 @@ General Public License for more details.
22
22
 
23
23
  You should have received a copy of the GNU General Public License
24
24
  along with this program. If not, see <https://www.gnu.org/licenses/>.
25
- """
25
+ """ # noqa
26
26
  from __future__ import annotations
27
27
 
28
28
  import json
@@ -45,6 +45,7 @@ from novelwriter.common import (
45
45
  formatTimeStamp, processDialogSymbols, simplified
46
46
  )
47
47
  from novelwriter.constants import nwFiles, nwQuotes, nwUnicode
48
+ from novelwriter.enum import nwTheme
48
49
  from novelwriter.error import formatException, logException
49
50
 
50
51
  if TYPE_CHECKING:
@@ -55,13 +56,20 @@ if TYPE_CHECKING:
55
56
 
56
57
  logger = logging.getLogger(__name__)
57
58
 
58
- DEF_GUI = "default"
59
- DEF_SYNTAX = "default_light"
59
+ DEF_GUI_DARK = "default_dark"
60
+ DEF_GUI_LIGHT = "default_light"
60
61
  DEF_ICONS = "material_rounded_normal"
61
62
  DEF_TREECOL = "theme"
62
63
 
63
64
 
64
65
  class Config:
66
+ """User Config.
67
+
68
+ The main user config. The state of the config is stored in the
69
+ novelwriter.conf file between sessions. Most of the settings can be
70
+ modified by the user in the Preferences dialog, but some just record
71
+ various states of the GUI.
72
+ """
65
73
 
66
74
  __slots__ = (
67
75
  "_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
@@ -69,22 +77,23 @@ class Config:
69
77
  "_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
70
78
  "_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
71
79
  "appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
72
- "autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine",
73
- "dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
80
+ "autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "darkTheme",
81
+ "dialogLine", "dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
74
82
  "doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
75
83
  "fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
76
- "fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme",
77
- "hasEnchant", "hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
78
- "iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
79
- "lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
80
- "nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
81
- "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap",
82
- "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx",
83
- "searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces",
84
- "showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle",
85
- "tabWidth", "textFont", "textMargin", "textWidth", "useCharCount", "userIdleTime",
86
- "verPyQtString", "verPyQtValue", "verPyString", "verQtString", "verQtValue",
87
- "viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize",
84
+ "fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "hasEnchant", "hideFocusFooter",
85
+ "hideHScroll", "hideVScroll", "highlightEmph", "hostName", "iconColDocs", "iconColTree",
86
+ "iconTheme", "incNotesWCount", "isDebug", "kernelVer", "lastNotes", "lightTheme",
87
+ "lineHighlight", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak",
88
+ "narratorDialog", "nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows",
89
+ "outlinePanePos", "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop",
90
+ "searchMatchCap", "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord",
91
+ "searchRegEx", "searchWord", "showEditToolBar", "showFullPath", "showLineEndings",
92
+ "showMultiSpaces", "showSessionTime", "showTabsNSpaces", "showViewerPanel",
93
+ "spellLanguage", "stopWhenIdle", "tabWidth", "textFont", "textMargin", "textWidth",
94
+ "themeMode", "useCharCount", "userIdleTime", "verPyQtString", "verPyQtValue",
95
+ "verPyString", "verQtString", "verQtValue", "viewComments", "viewNotes", "viewPanePos",
96
+ "viewSynopsis", "welcomeWinSize",
88
97
  )
89
98
 
90
99
  LANG_NW = 1
@@ -153,14 +162,15 @@ class Config:
153
162
 
154
163
  # General GUI Settings
155
164
  self.guiLocale = self._qLocale.name()
156
- self.guiTheme = DEF_GUI # GUI theme
157
- self.guiSyntax = DEF_SYNTAX # Syntax theme
158
- self.guiFont = QFont() # Main GUI font
159
- self.hideVScroll = False # Hide vertical scroll bars on main widgets
160
- self.hideHScroll = False # Hide horizontal scroll bars on main widgets
161
- self.lastNotes = "0x0" # The latest release notes that have been shown
162
- self.nativeFont = True # Use native font dialog
163
- self.useCharCount = False # Use character count as primary count
165
+ self.lightTheme = DEF_GUI_LIGHT # Light GUI theme
166
+ self.darkTheme = DEF_GUI_DARK # Dark GUI theme
167
+ self.themeMode = nwTheme.AUTO # Colour theme mode
168
+ self.guiFont = QFont() # Main GUI font
169
+ self.hideVScroll = False # Hide vertical scroll bars on main widgets
170
+ self.hideHScroll = False # Hide horizontal scroll bars on main widgets
171
+ self.lastNotes = "0x0" # The latest release notes that have been shown
172
+ self.nativeFont = True # Use native font dialog
173
+ self.useCharCount = False # Use character count as primary count
164
174
 
165
175
  # Icons
166
176
  self.iconTheme = DEF_ICONS # Icons theme
@@ -178,8 +188,8 @@ class Config:
178
188
  # Project Settings
179
189
  self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
180
190
  self.autoSaveDoc = 30 # Interval for auto-saving document, in seconds
181
- self.emphLabels = True # Add emphasis to H1 and H2 item labels
182
- self.backupOnClose = False # Flag for running automatic backups
191
+ self.emphLabels = False # Add emphasis to H1 and H2 item labels
192
+ self.backupOnClose = True # Flag for running automatic backups
183
193
  self.askBeforeBackup = True # Flag for asking before running automatic backup
184
194
  self.askBeforeExit = True # Flag for asking before exiting the app
185
195
 
@@ -189,6 +199,7 @@ class Config:
189
199
  self.textMargin = 40 # Editor/viewer text margin
190
200
  self.tabWidth = 40 # Editor tabulator width
191
201
  self.cursorWidth = 1 # Editor cursor width
202
+ self.lineHighlight = False # Highlight current line in editor
192
203
 
193
204
  self.focusWidth = 800 # Focus Mode text width
194
205
  self.hideFocusFooter = False # Hide document footer in Focus Mode
@@ -198,7 +209,7 @@ class Config:
198
209
  self.doJustify = False # Justify text
199
210
  self.showTabsNSpaces = False # Show tabs and spaces in editor
200
211
  self.showLineEndings = False # Show line endings in editor
201
- self.showMultiSpaces = True # Highlight multiple spaces in the text
212
+ self.showMultiSpaces = False # Highlight multiple spaces in the text
202
213
 
203
214
  self.doReplace = True # Enable auto-replace as you type
204
215
  self.doReplaceSQuote = True # Smart single quotes
@@ -206,7 +217,7 @@ class Config:
206
217
  self.doReplaceDash = True # Replace multiple hyphens with dashes
207
218
  self.doReplaceDots = True # Replace three dots with ellipsis
208
219
 
209
- self.autoScroll = False # Typewriter-like scrolling
220
+ self.autoScroll = True # Typewriter-like scrolling
210
221
  self.autoScrollPos = 30 # Start point for typewriter-like scrolling
211
222
  self.scrollPastEnd = True # Scroll past end of document, and centre cursor
212
223
 
@@ -245,6 +256,7 @@ class Config:
245
256
  self.showSessionTime = True # Show the session time in the status bar
246
257
  self.viewComments = True # Comments are shown in the viewer
247
258
  self.viewSynopsis = True # Synopsis is shown in the viewer
259
+ self.viewNotes = True # Notes are shown in the viewer
248
260
 
249
261
  # Search Box States
250
262
  self.searchCase = False
@@ -295,8 +307,6 @@ class Config:
295
307
  # Packages
296
308
  self.hasEnchant = False # The pyenchant package
297
309
 
298
- return
299
-
300
310
  ##
301
311
  # Properties
302
312
  ##
@@ -345,7 +355,6 @@ class Config:
345
355
  def setLastAuthor(self, value: str) -> None:
346
356
  """Set tle last used author name."""
347
357
  self._lastAuthor = simplified(value)
348
- return
349
358
 
350
359
  def setMainWinSize(self, width: int, height: int) -> None:
351
360
  """Set the size of the main window, but only if the change is
@@ -357,17 +366,14 @@ class Config:
357
366
  self.mainWinSize[0] = width
358
367
  if abs(self.mainWinSize[1] - height) > 5:
359
368
  self.mainWinSize[1] = height
360
- return
361
369
 
362
370
  def setWelcomeWinSize(self, width: int, height: int) -> None:
363
371
  """Set the size of the Preferences dialog window."""
364
372
  self.welcomeWinSize = [width, height]
365
- return
366
373
 
367
374
  def setPreferencesWinSize(self, width: int, height: int) -> None:
368
375
  """Set the size of the Preferences dialog window."""
369
376
  self.prefsWinSize = [width, height]
370
- return
371
377
 
372
378
  def setLastPath(self, key: str, path: str | Path) -> None:
373
379
  """Set the last used path. Only the folder is saved, so if the
@@ -379,12 +385,10 @@ class Config:
379
385
  path = path.parent
380
386
  if path.is_dir():
381
387
  self._recentPaths.setPath(key, path)
382
- return
383
388
 
384
389
  def setBackupPath(self, path: Path | str) -> None:
385
390
  """Set the current backup path."""
386
391
  self._backupPath = checkPath(path, self._backPath)
387
- return
388
392
 
389
393
  def setGuiFont(self, value: QFont | str | None) -> None:
390
394
  """Update the GUI's font style from settings."""
@@ -403,9 +407,8 @@ class Config:
403
407
  else:
404
408
  font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
405
409
  self.guiFont = fontMatcher(font)
406
- logger.debug("GUI font set to: %s", describeFont(font))
410
+ logger.debug("Main font set to: %s", describeFont(font))
407
411
  QApplication.setFont(self.guiFont)
408
- return
409
412
 
410
413
  def setTextFont(self, value: QFont | str | None) -> None:
411
414
  """Set the text font if it exists. If it doesn't, or is None,
@@ -431,14 +434,13 @@ class Config:
431
434
  font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
432
435
  self.textFont = fontMatcher(font)
433
436
  logger.debug("Text font set to: %s", describeFont(self.textFont))
434
- return
435
437
 
436
438
  ##
437
439
  # Methods
438
440
  ##
439
441
 
440
442
  def homePath(self) -> Path:
441
- """The user's home folder."""
443
+ """Return the user's home folder."""
442
444
  return self._homePath
443
445
 
444
446
  def dataPath(self, target: str | None = None) -> Path:
@@ -520,7 +522,6 @@ class Config:
520
522
  """Send a message to the splash screen."""
521
523
  if self._splash:
522
524
  self._splash.showStatus(message)
523
- return
524
525
 
525
526
  ##
526
527
  # Config Actions
@@ -551,11 +552,10 @@ class Config:
551
552
  self._confPath.mkdir(exist_ok=True)
552
553
  self._dataPath.mkdir(exist_ok=True)
553
554
 
554
- # Also create the syntax, themes and icons folders if possible
555
+ # Also create the themes and icons folders if possible
555
556
  if self._dataPath.is_dir():
556
557
  (self._dataPath / "cache").mkdir(exist_ok=True)
557
558
  (self._dataPath / "icons").mkdir(exist_ok=True)
558
- (self._dataPath / "syntax").mkdir(exist_ok=True)
559
559
  (self._dataPath / "themes").mkdir(exist_ok=True)
560
560
 
561
561
  self._recentPaths.loadCache()
@@ -564,8 +564,6 @@ class Config:
564
564
 
565
565
  logger.debug("Config instance initialised")
566
566
 
567
- return
568
-
569
567
  def initLocalisation(self, nwApp: QApplication) -> None:
570
568
  """Initialise the localisation of the GUI."""
571
569
  self.splashMessage("Loading localisation ...")
@@ -593,8 +591,6 @@ class Config:
593
591
  nwApp.installTranslator(qTrans)
594
592
  self._qtTrans[lngFile] = qTrans
595
593
 
596
- return
597
-
598
594
  def loadConfig(self, splash: NSplashScreen | None = None) -> bool:
599
595
  """Load preferences from file and replace default settings."""
600
596
  self._splash = splash
@@ -626,8 +622,9 @@ class Config:
626
622
  # Main
627
623
  sec = "Main"
628
624
  self.setGuiFont(conf.rdStr(sec, "font", ""))
629
- self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
630
- self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
625
+ self.lightTheme = conf.rdStr(sec, "lighttheme", self.lightTheme)
626
+ self.darkTheme = conf.rdStr(sec, "darktheme", self.darkTheme)
627
+ self.themeMode = conf.rdEnum(sec, "thememode", self.themeMode)
631
628
  self.iconTheme = conf.rdStr(sec, "icons", self.iconTheme)
632
629
  self.iconColTree = conf.rdStr(sec, "iconcoltree", self.iconColTree)
633
630
  self.iconColDocs = conf.rdBool(sec, "iconcoldocs", self.iconColDocs)
@@ -665,6 +662,7 @@ class Config:
665
662
  self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
666
663
  self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
667
664
  self.cursorWidth = conf.rdInt(sec, "cursorwidth", self.cursorWidth)
665
+ self.lineHighlight = conf.rdBool(sec, "linehighlight", self.lineHighlight)
668
666
  self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth)
669
667
  self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
670
668
  self.doJustify = conf.rdBool(sec, "justify", self.doJustify)
@@ -708,6 +706,7 @@ class Config:
708
706
  self.showSessionTime = conf.rdBool(sec, "showsessiontime", self.showSessionTime)
709
707
  self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
710
708
  self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
709
+ self.viewNotes = conf.rdBool(sec, "viewnotes", self.viewNotes)
711
710
  self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
712
711
  self.searchWord = conf.rdBool(sec, "searchword", self.searchWord)
713
712
  self.searchRegEx = conf.rdBool(sec, "searchregex", self.searchRegEx)
@@ -721,7 +720,7 @@ class Config:
721
720
  # Check Values
722
721
  # ============
723
722
 
724
- self._prepareFont(self.guiFont, "GUI")
723
+ self._prepareFont(self.guiFont, "main")
725
724
  self._prepareFont(self.textFont, "document")
726
725
 
727
726
  # If we're using straight quotes, disable auto-replace
@@ -751,8 +750,9 @@ class Config:
751
750
 
752
751
  conf["Main"] = {
753
752
  "font": self.guiFont.toString(),
754
- "theme": str(self.guiTheme),
755
- "syntax": str(self.guiSyntax),
753
+ "lighttheme": str(self.lightTheme),
754
+ "darktheme": str(self.darkTheme),
755
+ "thememode": self.themeMode.name,
756
756
  "icons": str(self.iconTheme),
757
757
  "iconcoltree": str(self.iconColTree),
758
758
  "iconcoldocs": str(self.iconColDocs),
@@ -790,6 +790,7 @@ class Config:
790
790
  "margin": str(self.textMargin),
791
791
  "tabwidth": str(self.tabWidth),
792
792
  "cursorwidth": str(self.cursorWidth),
793
+ "lineHighlight": str(self.lineHighlight),
793
794
  "focuswidth": str(self.focusWidth),
794
795
  "hidefocusfooter": str(self.hideFocusFooter),
795
796
  "justify": str(self.doJustify),
@@ -833,6 +834,7 @@ class Config:
833
834
  "showsessiontime": str(self.showSessionTime),
834
835
  "viewcomments": str(self.viewComments),
835
836
  "viewsynopsis": str(self.viewSynopsis),
837
+ "viewnotes": str(self.viewNotes),
836
838
  "searchcase": str(self.searchCase),
837
839
  "searchword": str(self.searchWord),
838
840
  "searchregex": str(self.searchRegEx),
@@ -862,7 +864,6 @@ class Config:
862
864
  def finishStartup(self) -> None:
863
865
  """Call after startup is complete."""
864
866
  self._splash = None
865
- return
866
867
 
867
868
  ##
868
869
  # Internal Functions
@@ -884,7 +885,6 @@ class Config:
884
885
  else:
885
886
  self.hasEnchant = True
886
887
  logger.debug("Checking package 'pyenchant': OK")
887
- return
888
888
 
889
889
  def _prepareFont(self, font: QFont, kind: str) -> None:
890
890
  """Check Unicode availability in font. This also initialises any
@@ -895,16 +895,15 @@ class Config:
895
895
  for char in nwUnicode.UI_SYMBOLS:
896
896
  if not metrics.inFont(char): # type: ignore
897
897
  logger.warning("No glyph U+%04x in font", ord(char)) # pragma: no cover
898
- return
899
898
 
900
899
 
901
900
  class RecentProjects:
901
+ """A record of recently opened projects."""
902
902
 
903
903
  def __init__(self, config: Config) -> None:
904
904
  self._conf = config
905
905
  self._data: dict[str, dict[str, str | int]] = {}
906
906
  self._map: dict[str, str] = {}
907
- return
908
907
 
909
908
  def loadCache(self) -> bool:
910
909
  """Load the cache file for recent projects."""
@@ -966,14 +965,12 @@ class RecentProjects:
966
965
  self.saveCache()
967
966
  except Exception:
968
967
  pass
969
- return
970
968
 
971
969
  def remove(self, path: str | Path) -> None:
972
970
  """Try to remove a path from the recent projects cache."""
973
971
  if self._data.pop(str(path), None) is not None:
974
972
  logger.debug("Removed recent: %s", path)
975
973
  self.saveCache()
976
- return
977
974
 
978
975
  def _setEntry(
979
976
  self, puuid: str, path: str, title: str, words: int, chars: int, saved: int
@@ -988,24 +985,22 @@ class RecentProjects:
988
985
  }
989
986
  if puuid:
990
987
  self._map[puuid] = path
991
- return
992
988
 
993
989
 
994
990
  class RecentPaths:
991
+ """A record of recently used file paths."""
995
992
 
996
993
  KEYS: Final[list[str]] = ["default", "project", "import", "outline", "stats"]
997
994
 
998
995
  def __init__(self, config: Config) -> None:
999
996
  self._conf = config
1000
997
  self._data = {}
1001
- return
1002
998
 
1003
999
  def setPath(self, key: str, path: Path | str) -> None:
1004
1000
  """Set a path for a given key, and save the cache."""
1005
1001
  if key in self.KEYS:
1006
1002
  self._data[key] = str(path)
1007
1003
  self.saveCache()
1008
- return
1009
1004
 
1010
1005
  def getPath(self, key: str) -> str | None:
1011
1006
  """Get a path for a given key, or return None."""
novelwriter/constants.py CHANGED
@@ -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
  from typing import Final
@@ -28,21 +28,23 @@ from typing import Final
28
28
  from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
29
29
 
30
30
  from novelwriter.enum import (
31
- nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
31
+ nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape,
32
+ nwTheme
32
33
  )
33
34
 
34
35
 
35
36
  def trConst(text: str) -> str:
36
- """Wrapper function for locally translating constants."""
37
+ """Translate a constant."""
37
38
  return QCoreApplication.translate("Constant", text)
38
39
 
39
40
 
40
41
  def trStats(text: str) -> str:
41
- """Wrapper function for locally translating stats constants."""
42
+ """Translate a stats constants."""
42
43
  return QCoreApplication.translate("Stats", text)
43
44
 
44
45
 
45
46
  class nwConst:
47
+ """Various Constants."""
46
48
 
47
49
  # Date and Time Formats
48
50
  FMT_TSTAMP = "%Y-%m-%d %H:%M:%S" # Default format
@@ -69,6 +71,7 @@ class nwConst:
69
71
 
70
72
 
71
73
  class nwRegEx:
74
+ """Common RegExes."""
72
75
 
73
76
  URL = r"https?://(?:www\.|(?!www))[\w/()@:%_\+-.~#?&=]+"
74
77
  WORDS = r"\b[^\s\-\+\/–—\[\]:]+\b"
@@ -76,11 +79,13 @@ class nwRegEx:
76
79
  FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
77
80
  FMT_EB = r"(?<![\w\\])(\*{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
78
81
  FMT_ST = r"(?<![\w\\])(~{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
82
+ FMT_HL = r"(?<![\w\\])(={2})(?![\s=])(.+?)(?<![\s\\])(\1)(?!\w)"
79
83
  FMT_SC = r"(?i)(?<!\\)(\[(?:b|/b|i|/i|s|/s|u|/u|m|/m|sup|/sup|sub|/sub|br)\])"
80
84
  FMT_SV = r"(?i)(?<!\\)(\[(?:footnote|field):)(.+?)(?<!\\)(\])"
81
85
 
82
86
 
83
87
  class nwShortcode:
88
+ """Document ShortCodes."""
84
89
 
85
90
  BOLD_O = "[b]"
86
91
  BOLD_C = "[/b]"
@@ -110,6 +115,7 @@ class nwShortcode:
110
115
 
111
116
 
112
117
  class nwStyles:
118
+ """Style Settings for Headings."""
113
119
 
114
120
  H_VALID = ("H0", "H1", "H2", "H3", "H4")
115
121
  H_LEVEL: Final[dict[str, int]] = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
@@ -141,6 +147,7 @@ class nwStyles:
141
147
 
142
148
 
143
149
  class nwFiles:
150
+ """novelWriter Files."""
144
151
 
145
152
  # Config Files
146
153
  CONF_FILE = "novelwriter.conf"
@@ -161,6 +168,7 @@ class nwFiles:
161
168
 
162
169
 
163
170
  class nwKeyWords:
171
+ """Meta Data KeyWord Constants."""
164
172
 
165
173
  TAG_KEY = "@tag"
166
174
  POV_KEY = "@pov"
@@ -208,6 +216,7 @@ class nwKeyWords:
208
216
 
209
217
 
210
218
  class nwLists:
219
+ """Various Lists."""
211
220
 
212
221
  USER_CLASSES: Final[list[nwItemClass]] = [
213
222
  nwItemClass.CHARACTER,
@@ -221,6 +230,7 @@ class nwLists:
221
230
 
222
231
 
223
232
  class nwStats:
233
+ """Text Statistics."""
224
234
 
225
235
  CHARS = "allChars"
226
236
  CHARS_TEXT = "textChars"
@@ -244,6 +254,7 @@ class nwStats:
244
254
 
245
255
 
246
256
  class nwLabels:
257
+ """Various Common GUI Labels."""
247
258
 
248
259
  CLASS_NAME: Final[dict[nwItemClass, str]] = {
249
260
  nwItemClass.NO_CLASS: QT_TRANSLATE_NOOP("Constant", "None"),
@@ -446,20 +457,31 @@ class nwLabels:
446
457
  "Custom": (-1.0, -1.0),
447
458
  }
448
459
  THEME_COLORS: Final[dict[str, str]] = {
449
- "theme": QT_TRANSLATE_NOOP("Constant", "Theme Colours"),
450
460
  "default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"),
461
+ "base": QT_TRANSLATE_NOOP("Constant", "Background Colour"),
451
462
  "faded": QT_TRANSLATE_NOOP("Constant", "Faded Colour"),
452
463
  "red": QT_TRANSLATE_NOOP("Constant", "Red"),
453
464
  "orange": QT_TRANSLATE_NOOP("Constant", "Orange"),
454
465
  "yellow": QT_TRANSLATE_NOOP("Constant", "Yellow"),
455
466
  "green": QT_TRANSLATE_NOOP("Constant", "Green"),
456
- "aqua": QT_TRANSLATE_NOOP("Constant", "Aqua"),
467
+ "cyan": QT_TRANSLATE_NOOP("Constant", "Cyan"),
457
468
  "blue": QT_TRANSLATE_NOOP("Constant", "Blue"),
458
469
  "purple": QT_TRANSLATE_NOOP("Constant", "Purple"),
459
470
  }
471
+ THEME_MODE_ICON: Final[dict[nwTheme, str]] = {
472
+ nwTheme.AUTO: "theme_auto",
473
+ nwTheme.LIGHT: "theme_light",
474
+ nwTheme.DARK: "theme_dark",
475
+ }
476
+ THEME_MODE_LABEL: Final[dict[nwTheme, str]] = {
477
+ nwTheme.AUTO: QT_TRANSLATE_NOOP("Constant", "System Theme"),
478
+ nwTheme.LIGHT: QT_TRANSLATE_NOOP("Constant", "Light Theme"),
479
+ nwTheme.DARK: QT_TRANSLATE_NOOP("Constant", "Dark Theme"),
480
+ }
460
481
 
461
482
 
462
483
  class nwHeadFmt:
484
+ """Manuscript Header Formats."""
463
485
 
464
486
  BR = "{BR}"
465
487
  TITLE = "{Title}"
@@ -486,8 +508,10 @@ class nwHeadFmt:
486
508
 
487
509
  class nwQuotes:
488
510
  """Allowed quotation marks.
511
+
489
512
  Source: https://en.wikipedia.org/wiki/Quotation_mark
490
513
  """
514
+
491
515
  SYMBOLS: Final[dict[str, str]] = {
492
516
  "\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
493
517
  "\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
@@ -529,6 +553,7 @@ class nwQuotes:
529
553
 
530
554
  class nwUnicode:
531
555
  """Supported unicode character constants and their HTML equivalents."""
556
+
532
557
  # Unicode Constants
533
558
  # =================
534
559
 
@@ -660,6 +685,7 @@ class nwUnicode:
660
685
 
661
686
 
662
687
  class nwHtmlUnicode:
688
+ """Unicode to HTML Map."""
663
689
 
664
690
  U_TO_H: Final[dict[str, str]] = {
665
691
  # Quotes