novelWriter 2.6b1__py3-none-any.whl → 2.6rc1__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 (114) hide show
  1. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/METADATA +4 -4
  2. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/RECORD +114 -98
  3. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +50 -11
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
  16. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  17. novelwriter/assets/i18n/project_de_DE.json +2 -2
  18. novelwriter/assets/i18n/project_ru_RU.json +11 -0
  19. novelwriter/assets/icons/typicons_dark/icons.conf +7 -0
  20. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  21. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  22. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  23. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  24. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  25. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  26. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  27. novelwriter/assets/icons/typicons_light/icons.conf +7 -0
  28. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  29. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  30. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  31. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  32. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  33. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  34. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  35. novelwriter/assets/manual.pdf +0 -0
  36. novelwriter/assets/sample.zip +0 -0
  37. novelwriter/assets/text/credits_en.htm +1 -0
  38. novelwriter/common.py +38 -3
  39. novelwriter/config.py +19 -13
  40. novelwriter/constants.py +60 -45
  41. novelwriter/core/buildsettings.py +1 -1
  42. novelwriter/core/coretools.py +112 -126
  43. novelwriter/core/docbuild.py +4 -3
  44. novelwriter/core/document.py +1 -1
  45. novelwriter/core/index.py +10 -20
  46. novelwriter/core/item.py +40 -7
  47. novelwriter/core/itemmodel.py +518 -0
  48. novelwriter/core/options.py +1 -1
  49. novelwriter/core/project.py +68 -90
  50. novelwriter/core/projectdata.py +8 -2
  51. novelwriter/core/projectxml.py +1 -1
  52. novelwriter/core/sessions.py +1 -1
  53. novelwriter/core/spellcheck.py +1 -1
  54. novelwriter/core/status.py +24 -8
  55. novelwriter/core/storage.py +1 -1
  56. novelwriter/core/tree.py +269 -288
  57. novelwriter/dialogs/about.py +1 -1
  58. novelwriter/dialogs/docmerge.py +8 -18
  59. novelwriter/dialogs/docsplit.py +1 -1
  60. novelwriter/dialogs/editlabel.py +1 -1
  61. novelwriter/dialogs/preferences.py +4 -4
  62. novelwriter/dialogs/projectsettings.py +148 -98
  63. novelwriter/dialogs/quotes.py +1 -1
  64. novelwriter/dialogs/wordlist.py +11 -10
  65. novelwriter/enum.py +8 -1
  66. novelwriter/error.py +2 -2
  67. novelwriter/extensions/configlayout.py +7 -5
  68. novelwriter/extensions/eventfilters.py +1 -1
  69. novelwriter/extensions/modified.py +17 -5
  70. novelwriter/extensions/novelselector.py +1 -1
  71. novelwriter/extensions/pagedsidebar.py +4 -4
  72. novelwriter/extensions/progressbars.py +4 -4
  73. novelwriter/extensions/statusled.py +3 -3
  74. novelwriter/extensions/switch.py +3 -3
  75. novelwriter/extensions/switchbox.py +1 -1
  76. novelwriter/extensions/versioninfo.py +1 -1
  77. novelwriter/formats/shared.py +1 -1
  78. novelwriter/formats/todocx.py +35 -39
  79. novelwriter/formats/tohtml.py +15 -16
  80. novelwriter/formats/tokenizer.py +26 -22
  81. novelwriter/formats/tomarkdown.py +1 -1
  82. novelwriter/formats/toodt.py +54 -125
  83. novelwriter/formats/toqdoc.py +93 -45
  84. novelwriter/formats/toraw.py +1 -1
  85. novelwriter/gui/doceditor.py +233 -220
  86. novelwriter/gui/dochighlight.py +1 -1
  87. novelwriter/gui/docviewer.py +39 -10
  88. novelwriter/gui/docviewerpanel.py +15 -23
  89. novelwriter/gui/editordocument.py +1 -1
  90. novelwriter/gui/itemdetails.py +20 -27
  91. novelwriter/gui/mainmenu.py +14 -9
  92. novelwriter/gui/noveltree.py +13 -13
  93. novelwriter/gui/outline.py +18 -20
  94. novelwriter/gui/projtree.py +545 -1201
  95. novelwriter/gui/search.py +11 -19
  96. novelwriter/gui/sidebar.py +1 -1
  97. novelwriter/gui/statusbar.py +20 -3
  98. novelwriter/gui/theme.py +8 -4
  99. novelwriter/guimain.py +60 -48
  100. novelwriter/shared.py +53 -24
  101. novelwriter/text/counting.py +1 -1
  102. novelwriter/text/patterns.py +18 -6
  103. novelwriter/tools/dictionaries.py +1 -1
  104. novelwriter/tools/lipsum.py +1 -1
  105. novelwriter/tools/manusbuild.py +14 -12
  106. novelwriter/tools/manuscript.py +7 -7
  107. novelwriter/tools/manussettings.py +43 -53
  108. novelwriter/tools/noveldetails.py +1 -1
  109. novelwriter/tools/welcome.py +1 -1
  110. novelwriter/tools/writingstats.py +1 -1
  111. novelwriter/types.py +9 -3
  112. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/LICENSE.md +0 -0
  113. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/entry_points.txt +0 -0
  114. {novelWriter-2.6b1.dist-info → novelWriter-2.6rc1.dist-info}/top_level.txt +0 -0
@@ -64,6 +64,10 @@ font = nw_font.svg
64
64
  forward = typ_chevron-right.svg
65
65
  import = mixed_import.svg
66
66
  list = typ_th-list.svg
67
+ margin_bottom = mixed_margin-bottom.svg
68
+ margin_left = mixed_margin-left.svg
69
+ margin_right = mixed_margin-right.svg
70
+ margin_top = mixed_margin-top.svg
67
71
  maximise = typ_arrow-maximise.svg
68
72
  menu = typ_th-dot-menu.svg
69
73
  minimise = typ_arrow-minimise.svg
@@ -94,6 +98,8 @@ search_regex = nw_search-regex.svg
94
98
  search_replace = mixed_search-replace.svg
95
99
  search_word = nw_search-word.svg
96
100
  settings = typ_cog.svg
101
+ size_height = mixed_size-height.svg
102
+ size_width = mixed_size-width.svg
97
103
  star = typ_star.svg
98
104
  status_idle = typ_media-pause-grey.svg
99
105
  status_lang = typ_globe-grey.svg
@@ -102,6 +108,7 @@ status_stats = typ_chart-bar-grey.svg
102
108
  status_time = typ_stopwatch-grey.svg
103
109
  sticky-off = typ_pin-outline.svg
104
110
  sticky-on = typ_pin.svg
111
+ toolbar = nw_toolbar.svg
105
112
  unchecked = mixed_input-unchecked.svg
106
113
  unfold-hide = typ_unfold-hidden.svg
107
114
  unfold-show = typ_unfold-visible.svg
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <rect x="2" y="18" width="20" height="4" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
5
+ <path d="m18.414 8.5959c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <rect x="2" y="2" width="4" height="20" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
5
+ <path d="m15.404 18.5c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <rect x="18" y="2" width="4" height="20" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
5
+ <path d="m8.5959 18.5c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <rect x="2" y="2" width="20" height="4" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
5
+ <path d="m18.414 15.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <path d="m18.414 10.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
5
+ <path d="m18.414 13.596c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
4
+ <path d="m13.596 18.414c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
5
+ <path d="m10.404 18.414c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
6
+ </svg>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="8" y="2" width="8" height="8" rx="1" ry="1" fill="none" stroke="#4271ae" stroke-linecap="round" stroke-width="2"/>
4
+ <rect x="8" y="14" width="8" height="8" rx="1" ry="1" fill="none" stroke="#4271ae" stroke-linecap="round" stroke-width="2"/>
5
+ </svg>
Binary file
Binary file
@@ -35,6 +35,7 @@ translators for the languages currently available:</p>
35
35
  <li><b>Norwegian:</b> Veronica Berglyd Olsen (vkbo)</li>
36
36
  <li><b>Polish:</b> Anna Maria Polak (Nauthiz)</li>
37
37
  <li><b>Portuguese:</b> Bruno Meneguello (bkmeneguello)</li>
38
+ <li><b>Russian:</b> Konstantin Tan (k1kimosha)</li>
38
39
  <li><b>Simplified Chinese:</b> Qianzhi Long (longqzh)</li>
39
40
  </ul>
40
41
 
novelwriter/common.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-05-12 [0.1.0]
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
@@ -37,8 +37,8 @@ from typing import TYPE_CHECKING, Any, Literal, TypeVar
37
37
  from urllib.parse import urljoin
38
38
  from urllib.request import pathname2url
39
39
 
40
- from PyQt5.QtCore import QCoreApplication, QUrl
41
- from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontInfo
40
+ from PyQt5.QtCore import QCoreApplication, QMimeData, QUrl
41
+ from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo
42
42
 
43
43
  from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
44
44
  from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
@@ -434,6 +434,30 @@ def describeFont(font: QFont) -> str:
434
434
  return "Error"
435
435
 
436
436
 
437
+ def fontMatcher(font: QFont) -> QFont:
438
+ """Make sure the font is the correct family, if possible. This
439
+ ensures that Qt doesn't re-use another font under the hood. The
440
+ default Qt5 font matching algorithm doesn't handle well changing
441
+ application fonts at runtime.
442
+ """
443
+ info = QFontInfo(font)
444
+ if (famRequest := font.family()) != (famActual := info.family()):
445
+ logger.warning("Font mismatch: Requested '%s', but got '%s'", famRequest, famActual)
446
+ db = QFontDatabase()
447
+ if famRequest in db.families():
448
+ styleRequest, sizeRequest = font.styleName(), font.pointSize()
449
+ logger.info("Lookup: %s, %s, %d pt", famRequest, styleRequest, sizeRequest)
450
+ temp = db.font(famRequest, styleRequest, sizeRequest)
451
+ temp.setPointSize(sizeRequest) # Make sure it isn't changed
452
+ famFound, styleFound, sizeFound = temp.family(), temp.styleName(), temp.pointSize()
453
+ if famFound == famRequest:
454
+ logger.info("Found: %s, %s, %d pt", famFound, styleFound, sizeFound)
455
+ return temp
456
+ logger.warning("Could not find a font match in the font database")
457
+ logger.warning("If you just changed font, you may need to restart the application")
458
+ return font
459
+
460
+
437
461
  def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable:
438
462
  """A replacement for Python lambdas that works for Qt slots."""
439
463
  def wrapper(*a_: Any) -> None:
@@ -441,6 +465,17 @@ def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable:
441
465
  return wrapper
442
466
 
443
467
 
468
+ def encodeMimeHandles(mimeData: QMimeData, handles: list[str]) -> None:
469
+ """Encode handles into a mime data object."""
470
+ mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles))
471
+ return
472
+
473
+
474
+ def decodeMimeHandles(mimeData: QMimeData) -> list[str]:
475
+ """Decode and split a mime data object with handles."""
476
+ return mimeData.data(nwConst.MIME_HANDLE).data().decode().split("|")
477
+
478
+
444
479
  ##
445
480
  # Encoder Functions
446
481
  ##
novelwriter/config.py CHANGED
@@ -8,7 +8,7 @@ Created: 2022-11-09 [2.0rc2] RecentProjects
8
8
  Created: 2024-06-16 [2.5rc1] RecentPaths
9
9
 
10
10
  This file is a part of novelWriter
11
- Copyright 2018–2024, Veronica Berglyd Olsen
11
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
12
12
 
13
13
  This program is free software: you can redistribute it and/or modify
14
14
  it under the terms of the GNU General Public License as published by
@@ -40,7 +40,10 @@ from PyQt5.QtCore import (
40
40
  from PyQt5.QtGui import QFont, QFontDatabase
41
41
  from PyQt5.QtWidgets import QApplication
42
42
 
43
- from novelwriter.common import NWConfigParser, checkInt, checkPath, describeFont, formatTimeStamp
43
+ from novelwriter.common import (
44
+ NWConfigParser, checkInt, checkPath, describeFont, fontMatcher,
45
+ formatTimeStamp
46
+ )
44
47
  from novelwriter.constants import nwFiles, nwUnicode
45
48
  from novelwriter.error import formatException, logException
46
49
 
@@ -191,6 +194,7 @@ class Config:
191
194
  # State
192
195
  self.showViewerPanel = True # The panel for the viewer is visible
193
196
  self.showEditToolBar = False # The document editor toolbar visibility
197
+ self.showSessionTime = True # Show the session time in the status bar
194
198
  self.viewComments = True # Comments are shown in the viewer
195
199
  self.viewSynopsis = True # Synopsis is shown in the viewer
196
200
 
@@ -369,10 +373,11 @@ class Config:
369
373
  def setGuiFont(self, value: QFont | str | None) -> None:
370
374
  """Update the GUI's font style from settings."""
371
375
  if isinstance(value, QFont):
372
- self.guiFont = value
376
+ self.guiFont = fontMatcher(value)
373
377
  elif value and isinstance(value, str):
374
- self.guiFont = QFont()
375
- self.guiFont.fromString(value)
378
+ font = QFont()
379
+ font.fromString(value)
380
+ self.guiFont = fontMatcher(font)
376
381
  else:
377
382
  font = QFont()
378
383
  fontDB = QFontDatabase()
@@ -382,11 +387,9 @@ class Config:
382
387
  font.setPointSize(10)
383
388
  else:
384
389
  font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
385
- self.guiFont = font
390
+ self.guiFont = fontMatcher(font)
386
391
  logger.debug("GUI font set to: %s", describeFont(font))
387
-
388
392
  QApplication.setFont(self.guiFont)
389
-
390
393
  return
391
394
 
392
395
  def setTextFont(self, value: QFont | str | None) -> None:
@@ -394,10 +397,11 @@ class Config:
394
397
  set to default font.
395
398
  """
396
399
  if isinstance(value, QFont):
397
- self.textFont = value
400
+ self.textFont = fontMatcher(value)
398
401
  elif value and isinstance(value, str):
399
- self.textFont = QFont()
400
- self.textFont.fromString(value)
402
+ font = QFont()
403
+ font.fromString(value)
404
+ self.textFont = fontMatcher(font)
401
405
  else:
402
406
  fontDB = QFontDatabase()
403
407
  fontFam = fontDB.families()
@@ -411,8 +415,8 @@ class Config:
411
415
  font.setPointSize(12)
412
416
  else:
413
417
  font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
414
- self.textFont = font
415
- logger.debug("Text font set to: %s", describeFont(font))
418
+ self.textFont = fontMatcher(font)
419
+ logger.debug("Text font set to: %s", describeFont(self.textFont))
416
420
  return
417
421
 
418
422
  ##
@@ -671,6 +675,7 @@ class Config:
671
675
  sec = "State"
672
676
  self.showViewerPanel = conf.rdBool(sec, "showviewerpanel", self.showViewerPanel)
673
677
  self.showEditToolBar = conf.rdBool(sec, "showedittoolbar", self.showEditToolBar)
678
+ self.showSessionTime = conf.rdBool(sec, "showsessiontime", self.showSessionTime)
674
679
  self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
675
680
  self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
676
681
  self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
@@ -781,6 +786,7 @@ class Config:
781
786
  conf["State"] = {
782
787
  "showviewerpanel": str(self.showViewerPanel),
783
788
  "showedittoolbar": str(self.showEditToolBar),
789
+ "showsessiontime": str(self.showSessionTime),
784
790
  "viewcomments": str(self.viewComments),
785
791
  "viewsynopsis": str(self.viewSynopsis),
786
792
  "searchcase": str(self.searchCase),
novelwriter/constants.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-04-28 [0.0.1]
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
@@ -53,6 +53,9 @@ class nwConst:
53
53
  # Requests
54
54
  USER_AGENT = "Mozilla/5.0 (compatible; novelWriter (Python))"
55
55
 
56
+ # Mime Types
57
+ MIME_HANDLE = "text/vnd.novelwriter.handle"
58
+
56
59
  # Gui Settings
57
60
  STATUS_MSG_TIMEOUT = 15000 # milliseconds
58
61
  MAX_SEARCH_RESULT = 1000
@@ -105,6 +108,9 @@ class nwStyles:
105
108
  H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
106
109
  H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
107
110
 
111
+ T_NORMAL = 1.0
112
+ T_SMALL = 0.8
113
+
108
114
  T_LABEL = {
109
115
  "H0": QT_TRANSLATE_NOOP("Constant", "Title"),
110
116
  "H1": QT_TRANSLATE_NOOP("Constant", "Heading 1 (Partition)"),
@@ -115,15 +121,15 @@ class nwStyles:
115
121
  "SP": QT_TRANSLATE_NOOP("Constant", "Scene Separator"),
116
122
  }
117
123
  T_MARGIN = {
118
- "H0": (1.42, 0.50), # Title margins
119
- "H1": (1.42, 0.50), # Heading 1 margins
120
- "H2": (1.67, 0.50), # Heading 2 margins
121
- "H3": (1.17, 0.50), # Heading 3 margins
122
- "H4": (1.17, 0.50), # Heading 4 margins
123
- "TT": (0.00, 0.58), # Text margins
124
- "SP": (1.17, 1.17), # Separator margins
125
- "MT": (0.00, 0.58), # Meta margins
126
- "FT": (1.42, 0.47), # Footnote margins
124
+ "H0": (1.50, 0.60), # Title margins (top, bottom)
125
+ "H1": (1.50, 0.60), # Heading 1 margins (top, bottom)
126
+ "H2": (1.50, 0.60), # Heading 2 margins (top, bottom)
127
+ "H3": (1.20, 0.60), # Heading 3 margins (top, bottom)
128
+ "H4": (1.20, 0.60), # Heading 4 margins (top, bottom)
129
+ "TT": (0.00, 0.60), # Text margins (top, bottom)
130
+ "SP": (1.20, 1.20), # Separator margins (top, bottom)
131
+ "MT": (0.00, 0.60), # Meta margins (top, bottom)
132
+ "FT": (1.40, 0.40), # Footnote margins (left, bottom)
127
133
  }
128
134
 
129
135
 
@@ -201,7 +207,7 @@ class nwLists:
201
207
 
202
208
  class nwStats:
203
209
 
204
- CHARS_ALL = "allChars"
210
+ CHARS = "allChars"
205
211
  CHARS_TEXT = "textChars"
206
212
  CHARS_TITLE = "titleChars"
207
213
  PARAGRAPHS = "paragraphCount"
@@ -209,14 +215,14 @@ class nwStats:
209
215
  WCHARS_ALL = "allWordChars"
210
216
  WCHARS_TEXT = "textWordChars"
211
217
  WCHARS_TITLE = "titleWordChars"
212
- WORDS_ALL = "allWords"
218
+ WORDS = "allWords"
213
219
  WORDS_TEXT = "textWords"
214
220
  WORDS_TITLE = "titleWords"
215
221
 
216
222
  # Note: The order here affects the order of menu entries
217
223
  ALL_FIELDS = [
218
- WORDS_ALL, WORDS_TEXT, WORDS_TITLE,
219
- CHARS_ALL, CHARS_TEXT, CHARS_TITLE,
224
+ WORDS, WORDS_TEXT, WORDS_TITLE,
225
+ CHARS, CHARS_TEXT, CHARS_TITLE,
220
226
  WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
221
227
  PARAGRAPHS, TITLES,
222
228
  ]
@@ -268,6 +274,10 @@ class nwLabels:
268
274
  "doc_h4": QT_TRANSLATE_NOOP("Constant", "Novel Section"),
269
275
  "note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
270
276
  }
277
+ ACTIVE_NAME = {
278
+ "checked": QT_TRANSLATE_NOOP("Constant", "Active"),
279
+ "unchecked": QT_TRANSLATE_NOOP("Constant", "Inactive"),
280
+ }
271
281
  KEY_NAME = {
272
282
  nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
273
283
  nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
@@ -319,17 +329,17 @@ class nwLabels:
319
329
  nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
320
330
  }
321
331
  STATS_NAME = {
322
- nwStats.CHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters"),
323
- nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text"),
324
- nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings"),
325
- nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Constant", "Paragraphs"),
326
- nwStats.TITLES: QT_TRANSLATE_NOOP("Constant", "Headings"),
327
- nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters, No Spaces"),
328
- nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text, No Spaces"),
329
- nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings, No Spaces"),
330
- nwStats.WORDS_ALL: QT_TRANSLATE_NOOP("Constant", "Words"),
331
- nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Constant", "Words in Text"),
332
- nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Constant", "Words in Headings"),
332
+ nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
333
+ nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text"),
334
+ nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings"),
335
+ nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Stats", "Paragraphs"),
336
+ nwStats.TITLES: QT_TRANSLATE_NOOP("Stats", "Headings"),
337
+ nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Stats", "Characters, No Spaces"),
338
+ nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text, No Spaces"),
339
+ nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings, No Spaces"),
340
+ nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words"),
341
+ nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in Text"),
342
+ nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in Headings"),
333
343
  }
334
344
  BUILD_FMT = {
335
345
  nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
@@ -356,32 +366,32 @@ class nwLabels:
356
366
  nwBuildFmt.J_NWD: ".json",
357
367
  }
358
368
  SHAPES_PLAIN = {
359
- nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
360
- nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
361
- nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
362
- nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
363
- nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
364
- nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
365
- nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
366
- nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
369
+ nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Shape", "Square"),
370
+ nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Shape", "Triangle"),
371
+ nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Shape", "Nabla"),
372
+ nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Shape", "Diamond"),
373
+ nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Shape", "Pentagon"),
374
+ nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Shape", "Hexagon"),
375
+ nwStatusShape.STAR: QT_TRANSLATE_NOOP("Shape", "Star"),
376
+ nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Shape", "Pacman"),
367
377
  }
368
378
  SHAPES_CIRCLE = {
369
- nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
370
- nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
371
- nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
372
- nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
379
+ nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Shape", "1/4 Circle"),
380
+ nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Shape", "Half Circle"),
381
+ nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Shape", "3/4 Circle"),
382
+ nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Shape", "Full Circle"),
373
383
  }
374
384
  SHAPES_BARS = {
375
- nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
376
- nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
377
- nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
378
- nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
385
+ nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Shape", "1 Bar"),
386
+ nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Shape", "2 Bars"),
387
+ nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Shape", "3 Bars"),
388
+ nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Shape", "4 Bars"),
379
389
  }
380
390
  SHAPES_BLOCKS = {
381
- nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
382
- nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
383
- nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
384
- nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
391
+ nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Shape", "1 Block"),
392
+ nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Shape", "2 Blocks"),
393
+ nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Shape", "3 Blocks"),
394
+ nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Shape", "4 Blocks"),
385
395
  }
386
396
  FILE_FILTERS = {
387
397
  "*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
@@ -542,6 +552,11 @@ class nwUnicode:
542
552
  U_LTRI = "\u25c0" # Left-pointing triangle
543
553
  U_LTRIS = "\u25c2" # Left-pointing triangle, small
544
554
 
555
+ # Special
556
+ U_UNKN = "\ufffd" # Unknown character
557
+ U_NAC1 = "\ufffe" # Not a character
558
+ U_NAC2 = "\uffff" # Not a character
559
+
545
560
  # HTML Equivalents
546
561
  # ================
547
562
 
@@ -7,7 +7,7 @@ Created: 2023-02-14 [2.1b1] BuildSettings
7
7
  Created: 2023-05-22 [2.1b1] BuildCollection
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2024, Veronica Berglyd Olsen
10
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by