novelWriter 2.6.3__py3-none-any.whl → 2.7rc1__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 (325) hide show
  1. novelwriter/__init__.py +98 -75
  2. novelwriter/assets/i18n/project_en_GB.json +2 -0
  3. novelwriter/assets/icons/font_awesome.icons +109 -0
  4. novelwriter/assets/icons/material_filled_bold.icons +109 -0
  5. novelwriter/assets/icons/material_filled_normal.icons +109 -0
  6. novelwriter/assets/icons/material_filled_thin.icons +109 -0
  7. novelwriter/assets/icons/material_rounded_bold.icons +109 -0
  8. novelwriter/assets/icons/material_rounded_normal.icons +109 -0
  9. novelwriter/assets/icons/material_rounded_thin.icons +109 -0
  10. novelwriter/assets/icons/remix_filled.icons +109 -0
  11. novelwriter/assets/icons/remix_outline.icons +109 -0
  12. novelwriter/assets/images/splash.png +0 -0
  13. novelwriter/assets/manual.pdf +0 -0
  14. novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
  15. novelwriter/assets/sample.zip +0 -0
  16. novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
  17. novelwriter/assets/syntax/snazzy.conf +3 -3
  18. novelwriter/assets/text/credits_en.htm +6 -6
  19. novelwriter/assets/themes/cyberpunk_night.conf +23 -7
  20. novelwriter/assets/themes/default_dark.conf +20 -4
  21. novelwriter/assets/themes/default_light.conf +21 -5
  22. novelwriter/assets/themes/dracula.conf +20 -4
  23. novelwriter/assets/themes/snazzy.conf +48 -0
  24. novelwriter/assets/themes/solarized_dark.conf +24 -8
  25. novelwriter/assets/themes/solarized_light.conf +22 -6
  26. novelwriter/common.py +43 -27
  27. novelwriter/config.py +201 -139
  28. novelwriter/constants.py +67 -36
  29. novelwriter/core/buildsettings.py +25 -16
  30. novelwriter/core/coretools.py +52 -41
  31. novelwriter/core/docbuild.py +20 -13
  32. novelwriter/core/document.py +2 -2
  33. novelwriter/core/index.py +166 -432
  34. novelwriter/core/indexdata.py +406 -0
  35. novelwriter/core/item.py +50 -32
  36. novelwriter/core/itemmodel.py +43 -38
  37. novelwriter/core/novelmodel.py +225 -0
  38. novelwriter/core/options.py +1 -1
  39. novelwriter/core/project.py +24 -25
  40. novelwriter/core/projectdata.py +47 -29
  41. novelwriter/core/projectxml.py +18 -8
  42. novelwriter/core/sessions.py +32 -15
  43. novelwriter/core/spellcheck.py +4 -3
  44. novelwriter/core/status.py +12 -15
  45. novelwriter/core/storage.py +1 -1
  46. novelwriter/core/tree.py +55 -13
  47. novelwriter/dialogs/about.py +19 -22
  48. novelwriter/dialogs/docmerge.py +23 -24
  49. novelwriter/dialogs/docsplit.py +26 -26
  50. novelwriter/dialogs/editlabel.py +19 -20
  51. novelwriter/dialogs/preferences.py +143 -69
  52. novelwriter/dialogs/projectsettings.py +51 -54
  53. novelwriter/dialogs/quotes.py +14 -19
  54. novelwriter/dialogs/wordlist.py +25 -30
  55. novelwriter/enum.py +8 -0
  56. novelwriter/error.py +16 -16
  57. novelwriter/extensions/configlayout.py +24 -20
  58. novelwriter/extensions/eventfilters.py +9 -5
  59. novelwriter/extensions/modified.py +34 -15
  60. novelwriter/extensions/novelselector.py +18 -5
  61. novelwriter/extensions/pagedsidebar.py +39 -49
  62. novelwriter/extensions/progressbars.py +10 -8
  63. novelwriter/extensions/statusled.py +6 -13
  64. novelwriter/extensions/switch.py +31 -41
  65. novelwriter/extensions/switchbox.py +8 -3
  66. novelwriter/extensions/versioninfo.py +4 -4
  67. novelwriter/formats/shared.py +1 -1
  68. novelwriter/formats/todocx.py +14 -10
  69. novelwriter/formats/tohtml.py +7 -5
  70. novelwriter/formats/tokenizer.py +37 -33
  71. novelwriter/formats/tomarkdown.py +6 -2
  72. novelwriter/formats/toodt.py +27 -22
  73. novelwriter/formats/toqdoc.py +19 -14
  74. novelwriter/formats/toraw.py +6 -2
  75. novelwriter/gui/doceditor.py +314 -305
  76. novelwriter/gui/dochighlight.py +46 -45
  77. novelwriter/gui/docviewer.py +102 -104
  78. novelwriter/gui/docviewerpanel.py +47 -51
  79. novelwriter/gui/editordocument.py +8 -5
  80. novelwriter/gui/itemdetails.py +11 -14
  81. novelwriter/gui/mainmenu.py +146 -145
  82. novelwriter/gui/noveltree.py +246 -406
  83. novelwriter/gui/outline.py +141 -72
  84. novelwriter/gui/projtree.py +139 -132
  85. novelwriter/gui/search.py +34 -31
  86. novelwriter/gui/sidebar.py +13 -18
  87. novelwriter/gui/statusbar.py +27 -21
  88. novelwriter/gui/theme.py +554 -436
  89. novelwriter/guimain.py +56 -38
  90. novelwriter/shared.py +32 -23
  91. novelwriter/splash.py +74 -0
  92. novelwriter/text/comments.py +70 -0
  93. novelwriter/text/patterns.py +4 -4
  94. novelwriter/tools/dictionaries.py +20 -29
  95. novelwriter/tools/lipsum.py +18 -18
  96. novelwriter/tools/manusbuild.py +39 -42
  97. novelwriter/tools/manuscript.py +102 -115
  98. novelwriter/tools/manussettings.py +116 -96
  99. novelwriter/tools/noveldetails.py +60 -72
  100. novelwriter/tools/welcome.py +57 -75
  101. novelwriter/tools/writingstats.py +112 -102
  102. novelwriter/types.py +5 -7
  103. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/METADATA +6 -6
  104. novelwriter-2.7rc1.dist-info/RECORD +162 -0
  105. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/WHEEL +1 -1
  106. novelWriter-2.6.3.dist-info/RECORD +0 -363
  107. novelwriter/assets/icons/typicons_dark/README.md +0 -29
  108. novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
  109. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
  110. novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
  111. novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
  112. novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
  113. novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
  114. novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
  115. novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
  116. novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
  117. novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
  118. novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
  119. novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
  120. novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
  121. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
  122. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
  123. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
  124. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
  125. novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
  126. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
  127. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
  128. novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
  129. novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
  130. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
  131. novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
  132. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
  133. novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
  134. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
  135. novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
  136. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
  137. novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
  138. novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
  139. novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
  140. novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
  141. novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
  142. novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
  143. novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
  144. novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
  145. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
  146. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
  147. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
  148. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
  149. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
  150. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
  151. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
  152. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
  153. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
  154. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
  155. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
  156. novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
  157. novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
  158. novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
  159. novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
  160. novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
  161. novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
  162. novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
  163. novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
  164. novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
  165. novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
  166. novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
  167. novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
  168. novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
  169. novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
  170. novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
  171. novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
  172. novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
  173. novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
  174. novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
  175. novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
  176. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
  177. novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
  178. novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
  179. novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
  180. novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
  181. novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
  182. novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
  183. novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
  184. novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
  185. novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
  186. novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
  187. novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
  188. novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
  189. novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
  190. novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
  191. novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
  192. novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
  193. novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
  194. novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
  195. novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
  196. novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
  197. novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
  198. novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
  199. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
  200. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
  201. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
  202. novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
  203. novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
  204. novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
  205. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
  206. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
  207. novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
  208. novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
  209. novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
  210. novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
  211. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
  212. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
  213. novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
  214. novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
  215. novelwriter/assets/icons/typicons_light/README.md +0 -29
  216. novelwriter/assets/icons/typicons_light/icons.conf +0 -134
  217. novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
  218. novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
  219. novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
  220. novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
  221. novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
  222. novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
  223. novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
  224. novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
  225. novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
  226. novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
  227. novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
  228. novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
  229. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
  230. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
  231. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
  232. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
  233. novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
  234. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
  235. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
  236. novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
  237. novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
  238. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
  239. novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
  240. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
  241. novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
  242. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
  243. novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
  244. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
  245. novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
  246. novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
  247. novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
  248. novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
  249. novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
  250. novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
  251. novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
  252. novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
  253. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
  254. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
  255. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
  256. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
  257. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
  258. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
  259. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
  260. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
  261. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
  262. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
  263. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
  264. novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
  265. novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
  266. novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
  267. novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
  268. novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
  269. novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
  270. novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
  271. novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
  272. novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
  273. novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
  274. novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
  275. novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
  276. novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
  277. novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
  278. novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
  279. novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
  280. novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
  281. novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
  282. novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
  283. novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
  284. novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
  285. novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
  286. novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
  287. novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
  288. novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
  289. novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
  290. novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
  291. novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
  292. novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
  293. novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
  294. novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
  295. novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
  296. novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
  297. novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
  298. novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
  299. novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
  300. novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
  301. novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
  302. novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
  303. novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
  304. novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
  305. novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
  306. novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
  307. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
  308. novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
  309. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
  310. novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
  311. novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
  312. novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
  313. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
  314. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
  315. novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
  316. novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
  317. novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
  318. novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
  319. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
  320. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
  321. novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
  322. novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
  323. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/entry_points.txt +0 -0
  324. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info/licenses}/LICENSE.md +0 -0
  325. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/top_level.txt +0 -0
@@ -34,7 +34,7 @@ from novelwriter.common import (
34
34
  )
35
35
  from novelwriter.core.status import NWStatus
36
36
 
37
- if TYPE_CHECKING: # pragma: no cover
37
+ if TYPE_CHECKING:
38
38
  from novelwriter.core.project import NWProject
39
39
 
40
40
  logger = logging.getLogger(__name__)
@@ -66,13 +66,13 @@ class NWProjectData:
66
66
  self._spellLang = None
67
67
 
68
68
  # Project Dictionaries
69
- self._initCounts = [0, 0]
70
- self._currCounts = [0, 0]
69
+ self._initCounts = [0, 0, 0, 0]
70
+ self._currCounts = [0, 0, 0, 0]
71
71
  self._lastHandle: dict[str, str | None] = {
72
- "editor": None,
73
- "viewer": None,
74
- "novelTree": None,
75
- "outline": None,
72
+ "editor": None,
73
+ "viewer": None,
74
+ "novel": None,
75
+ "outline": None,
76
76
  }
77
77
  self._autoReplace: dict[str, str] = {}
78
78
  self._titleFormat: dict[str, str] = {
@@ -148,18 +148,18 @@ class NWProjectData:
148
148
  return self._spellLang
149
149
 
150
150
  @property
151
- def initCounts(self) -> tuple[int, int]:
152
- """Return the initial count of words for novel and note
153
- documents.
151
+ def initCounts(self) -> tuple[int, int, int, int]:
152
+ """Return the initial count of words and characters for novel
153
+ and note documents.
154
154
  """
155
- return self._initCounts[0], self._initCounts[1]
155
+ return self._initCounts[0], self._initCounts[1], self._initCounts[2], self._initCounts[3]
156
156
 
157
157
  @property
158
- def currCounts(self) -> tuple[int, int]:
159
- """Return the current count of words for novel and note
160
- documents.
158
+ def currCounts(self) -> tuple[int, int, int, int]:
159
+ """Return the current count of words and characters for novel
160
+ and note documents.
161
161
  """
162
- return self._currCounts[0], self._currCounts[1]
162
+ return self._currCounts[0], self._currCounts[1], self._currCounts[2], self._currCounts[3]
163
163
 
164
164
  @property
165
165
  def lastHandle(self) -> dict[str, str | None]:
@@ -301,22 +301,40 @@ class NWProjectData:
301
301
  self._project.setProjectChanged(True)
302
302
  return
303
303
 
304
- def setInitCounts(self, novel: Any = None, notes: Any = None) -> None:
305
- """Set the word count totals for novel and note files."""
306
- if novel is not None:
307
- self._initCounts[0] = checkInt(novel, 0)
308
- self._currCounts[0] = checkInt(novel, 0)
309
- if notes is not None:
310
- self._initCounts[1] = checkInt(notes, 0)
311
- self._currCounts[1] = checkInt(notes, 0)
304
+ def setInitCounts(
305
+ self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
306
+ ) -> None:
307
+ """Set the count totals for novel and note files."""
308
+ if wNovel is not None:
309
+ count = checkInt(wNovel, 0)
310
+ self._initCounts[0] = count
311
+ self._currCounts[0] = count
312
+ if wNotes is not None:
313
+ count = checkInt(wNotes, 0)
314
+ self._initCounts[1] = count
315
+ self._currCounts[1] = count
316
+ if cNovel is not None:
317
+ count = checkInt(cNovel, 0)
318
+ self._initCounts[2] = count
319
+ self._currCounts[2] = count
320
+ if cNotes is not None:
321
+ count = checkInt(cNotes, 0)
322
+ self._initCounts[3] = count
323
+ self._currCounts[3] = count
312
324
  return
313
325
 
314
- def setCurrCounts(self, novel: Any = None, notes: Any = None) -> None:
315
- """Set the word count totals for novel and note files."""
316
- if novel is not None:
317
- self._currCounts[0] = checkInt(novel, 0)
318
- if notes is not None:
319
- self._currCounts[1] = checkInt(notes, 0)
326
+ def setCurrCounts(
327
+ self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
328
+ ) -> None:
329
+ """Set the count totals for novel and note files."""
330
+ if wNovel is not None:
331
+ self._currCounts[0] = checkInt(wNovel, 0)
332
+ if wNotes is not None:
333
+ self._currCounts[1] = checkInt(wNotes, 0)
334
+ if cNovel is not None:
335
+ self._currCounts[2] = checkInt(cNovel, 0)
336
+ if cNotes is not None:
337
+ self._currCounts[3] = checkInt(cNotes, 0)
320
338
  return
321
339
 
322
340
  def setAutoReplace(self, value: dict) -> None:
@@ -39,14 +39,14 @@ from novelwriter.common import (
39
39
  hexToInt, simplified, xmlIndent, yesNo
40
40
  )
41
41
 
42
- if TYPE_CHECKING: # pragma: no cover
42
+ if TYPE_CHECKING:
43
43
  from novelwriter.core.projectdata import NWProjectData
44
44
  from novelwriter.core.status import NWStatus
45
45
 
46
46
  logger = logging.getLogger(__name__)
47
47
 
48
48
  FILE_VERSION = "1.5" # The current project file format version
49
- FILE_REVISION = "4" # The current project file format revision
49
+ FILE_REVISION = "5" # The current project file format revision
50
50
  HEX_VERSION = 0x0105
51
51
 
52
52
  NUM_VERSION = {
@@ -109,6 +109,8 @@ class ProjectXMLReader:
109
109
  Rev 3: Added TEMPLATE class. 2.3.
110
110
  Rev 4: Added shape attribute to status and importance entry
111
111
  nodes. 2.5.
112
+ Rev 5: Added novelChars and notesChars attributes to content
113
+ node. 2.7 RC 1.
112
114
  """
113
115
 
114
116
  def __init__(self, path: str | Path) -> None:
@@ -286,9 +288,9 @@ class ProjectXMLReader:
286
288
  elif xItem.tag == "spellLang": # Changed to spellChecking in 1.5
287
289
  data.setSpellLang(xItem.text)
288
290
  elif xItem.tag == "novelWordCount": # Moved to content attribute in 1.5
289
- data.setInitCounts(novel=xItem.text)
291
+ data.setInitCounts(wNovel=xItem.text)
290
292
  elif xItem.tag == "notesWordCount": # Moved to content attribute in 1.5
291
- data.setInitCounts(notes=xItem.text)
293
+ data.setInitCounts(wNotes=xItem.text)
292
294
 
293
295
  return
294
296
 
@@ -298,8 +300,13 @@ class ProjectXMLReader:
298
300
  """Parse the content section of the XML file."""
299
301
  logger.debug("Parsing <content> section")
300
302
 
301
- data.setInitCounts(novel=xSection.attrib.get("novelWords", None)) # Moved in 1.5
302
- data.setInitCounts(notes=xSection.attrib.get("notesWords", None)) # Moved in 1.5
303
+ # Moved in 1.5
304
+ data.setInitCounts(
305
+ wNovel=xSection.attrib.get("novelWords", None),
306
+ wNotes=xSection.attrib.get("notesWords", None),
307
+ cNovel=xSection.attrib.get("novelChars", None),
308
+ cNotes=xSection.attrib.get("notesChars", None),
309
+ )
303
310
 
304
311
  for xItem in xSection:
305
312
  if xItem.tag != "item":
@@ -527,10 +534,13 @@ class ProjectXMLWriter:
527
534
  self._packSingleValue(xImport, "entry", label, attrib=attrib)
528
535
 
529
536
  # Save Tree Content
537
+ counts = data.currCounts
530
538
  contAttr = {
531
539
  "items": str(len(content)),
532
- "novelWords": str(data.currCounts[0]),
533
- "notesWords": str(data.currCounts[1]),
540
+ "novelWords": str(counts[0]),
541
+ "notesWords": str(counts[1]),
542
+ "novelChars": str(counts[2]),
543
+ "notesChars": str(counts[3]),
534
544
  }
535
545
 
536
546
  xContent = ET.SubElement(xRoot, "content", attrib=contAttr)
@@ -26,7 +26,6 @@ from __future__ import annotations
26
26
  import json
27
27
  import logging
28
28
 
29
- from collections.abc import Iterable
30
29
  from pathlib import Path
31
30
  from time import time
32
31
  from typing import TYPE_CHECKING
@@ -35,7 +34,9 @@ from novelwriter.common import formatTimeStamp
35
34
  from novelwriter.constants import nwFiles
36
35
  from novelwriter.error import logException
37
36
 
38
- if TYPE_CHECKING: # pragma: no cover
37
+ if TYPE_CHECKING:
38
+ from collections.abc import Iterable
39
+
39
40
  from novelwriter.core.project import NWProject
40
41
 
41
42
  logger = logging.getLogger(__name__)
@@ -78,29 +79,36 @@ class NWSessionLog:
78
79
  return False
79
80
 
80
81
  now = time()
81
- iNovel, iNotes = self._project.data.initCounts
82
- cNovel, cNotes = self._project.data.currCounts
83
- iTotal = iNovel + iNotes
84
- wDiff = cNovel + cNotes - iTotal
82
+ iWNovel, iWNotes, iCNovel, iCNotes = self._project.data.initCounts
83
+ cWNovel, cWNotes, cCNovel, cCNotes = self._project.data.currCounts
84
+ iWTotal = iWNovel + iWNotes
85
+ iCTotal = iCNovel + iCNotes
86
+ wDiff = cWNovel + cWNotes - iWTotal
87
+ cDiff = cCNovel + cCNotes - iCTotal
85
88
  sTime = now - self._start
86
89
 
87
- logger.info("The session lasted %d sec and added %d words", int(sTime), wDiff)
88
- if sTime < 300 and wDiff == 0:
90
+ logger.info(
91
+ "The session lasted %d sec and added %d words abd %d characters",
92
+ int(sTime), wDiff, cDiff
93
+ )
94
+ if sTime < 300 and (wDiff == 0 or cDiff == 0):
89
95
  logger.info("Session too short, skipping log entry")
90
96
  return False
91
97
 
92
98
  try:
93
99
  if not sessFile.exists():
94
100
  with open(sessFile, mode="w", encoding="utf-8") as fObj:
95
- fObj.write(self.createInitial(iTotal))
101
+ fObj.write(self.createInitial(iWTotal))
96
102
 
97
103
  with open(sessFile, mode="a+", encoding="utf-8") as fObj:
98
104
  fObj.write(self.createRecord(
99
105
  start=formatTimeStamp(self._start),
100
106
  end=formatTimeStamp(now),
101
- novel=cNovel,
102
- notes=cNotes,
103
- idle=round(idleTime)
107
+ novel=cWNovel,
108
+ notes=cWNotes,
109
+ idle=round(idleTime),
110
+ cnovel=cCNovel,
111
+ cnotes=cCNotes,
104
112
  ))
105
113
 
106
114
  except Exception:
@@ -128,10 +136,19 @@ class NWSessionLog:
128
136
  data = json.dumps({"type": "initial", "offset": total})
129
137
  return f"{data}\n"
130
138
 
131
- def createRecord(self, start: str, end: str, novel: int, notes: int, idle: int) -> str:
139
+ def createRecord(
140
+ self, start: str, end: str, novel: int, notes: int, idle: int,
141
+ cnovel: int = 0, cnotes: int = 0,
142
+ ) -> str:
132
143
  """Low level function to create a log record."""
133
144
  data = json.dumps({
134
- "type": "record", "start": start, "end": end,
135
- "novel": novel, "notes": notes, "idle": idle,
145
+ "type": "record",
146
+ "start": start,
147
+ "end": end,
148
+ "novel": novel,
149
+ "notes": notes,
150
+ "cnovel": cnovel,
151
+ "cnotes": cnotes,
152
+ "idle": idle,
136
153
  })
137
154
  return f"{data}\n"
@@ -27,16 +27,17 @@ from __future__ import annotations
27
27
  import json
28
28
  import logging
29
29
 
30
- from collections.abc import Iterator
31
30
  from pathlib import Path
32
31
  from typing import TYPE_CHECKING
33
32
 
34
- from PyQt5.QtCore import QLocale
33
+ from PyQt6.QtCore import QLocale
35
34
 
36
35
  from novelwriter.constants import nwFiles
37
36
  from novelwriter.error import logException
38
37
 
39
- if TYPE_CHECKING: # pragma: no cover
38
+ if TYPE_CHECKING:
39
+ from collections.abc import Iterator
40
+
40
41
  from novelwriter.core.project import NWProject
41
42
 
42
43
  logger = logging.getLogger(__name__)
@@ -28,19 +28,18 @@ import dataclasses
28
28
  import logging
29
29
  import random
30
30
 
31
- from collections.abc import Iterable
32
- from typing import TYPE_CHECKING, Literal
31
+ from typing import TYPE_CHECKING, Literal, TypeGuard
33
32
 
34
- from PyQt5.QtCore import QPointF, Qt
35
- from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF
33
+ from PyQt6.QtCore import QPointF, Qt
34
+ from PyQt6.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF
36
35
 
37
36
  from novelwriter import SHARED
38
37
  from novelwriter.common import simplified
39
38
  from novelwriter.enum import nwStatusShape
40
39
  from novelwriter.types import QtPaintAntiAlias, QtTransparent
41
40
 
42
- if TYPE_CHECKING: # pragma: no cover
43
- from typing import TypeGuard # Requires Python 3.10
41
+ if TYPE_CHECKING:
42
+ from collections.abc import Iterable
44
43
 
45
44
  logger = logging.getLogger(__name__)
46
45
 
@@ -57,18 +56,16 @@ class StatusEntry:
57
56
  @classmethod
58
57
  def duplicate(cls, source: StatusEntry) -> StatusEntry:
59
58
  """Create a deep copy of the source object."""
60
- cls = dataclasses.replace(source)
61
- cls.color = QColor(source.color)
62
- cls.icon = QIcon(source.icon)
63
- return cls
59
+ status = dataclasses.replace(source)
60
+ status.color = QColor(source.color)
61
+ status.icon = QIcon(source.icon)
62
+ return status
64
63
 
65
64
 
66
65
  NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)
67
66
 
68
- if TYPE_CHECKING: # pragma: no cover
69
- # Requires Python 3.10
70
- T_UpdateEntry = list[tuple[str | None, StatusEntry]]
71
- T_StatusKind = Literal["s", "i"]
67
+ T_UpdateEntry = list[tuple[str | None, StatusEntry]]
68
+ T_StatusKind = Literal["s", "i"]
72
69
 
73
70
 
74
71
  class NWStatus:
@@ -76,7 +73,7 @@ class NWStatus:
76
73
  STATUS = "s"
77
74
  IMPORT = "i"
78
75
 
79
- __slots__ = ("_store", "_default", "_prefix", "_height")
76
+ __slots__ = ("_default", "_height", "_prefix", "_store")
80
77
 
81
78
  def __init__(self, prefix: T_StatusKind) -> None:
82
79
  self._store: dict[str, StatusEntry] = {}
@@ -40,7 +40,7 @@ from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
40
40
  from novelwriter.core.spellcheck import UserDictionary
41
41
  from novelwriter.error import logException
42
42
 
43
- if TYPE_CHECKING: # pragma: no cover
43
+ if TYPE_CHECKING:
44
44
  from novelwriter.core.project import NWProject
45
45
 
46
46
  logger = logging.getLogger(__name__)
novelwriter/core/tree.py CHANGED
@@ -27,20 +27,21 @@ from __future__ import annotations
27
27
  import logging
28
28
  import random
29
29
 
30
- from collections.abc import Iterable, Iterator
31
30
  from pathlib import Path
32
31
  from typing import TYPE_CHECKING, Literal, overload
33
32
 
34
- from PyQt5.QtCore import QModelIndex
33
+ from PyQt6.QtCore import QModelIndex
35
34
 
36
35
  from novelwriter import SHARED
37
- from novelwriter.constants import nwFiles, nwLabels, trConst
36
+ from novelwriter.constants import nwFiles, nwLabels, nwStyles, trConst
38
37
  from novelwriter.core.item import NWItem
39
38
  from novelwriter.core.itemmodel import ProjectModel, ProjectNode
40
39
  from novelwriter.enum import nwChange, nwItemClass, nwItemLayout, nwItemType
41
40
  from novelwriter.error import logException
42
41
 
43
- if TYPE_CHECKING: # pragma: no cover
42
+ if TYPE_CHECKING:
43
+ from collections.abc import Iterable, Iterator
44
+
44
45
  from novelwriter.core.project import NWProject
45
46
 
46
47
  logger = logging.getLogger(__name__)
@@ -60,7 +61,7 @@ class NWTree:
60
61
  also used for file names.
61
62
  """
62
63
 
63
- __slots__ = ("_project", "_model", "_items", "_nodes", "_trash")
64
+ __slots__ = ("_items", "_model", "_nodes", "_project", "_ready", "_trash")
64
65
 
65
66
  def __init__(self, project: NWProject) -> None:
66
67
  self._project = project
@@ -68,6 +69,7 @@ class NWTree:
68
69
  self._items: dict[str, NWItem] = {}
69
70
  self._nodes: dict[str, ProjectNode] = {}
70
71
  self._trash = None
72
+ self._ready = False
71
73
  logger.debug("Ready: NWTree")
72
74
  return
73
75
 
@@ -106,6 +108,11 @@ class NWTree:
106
108
  # Properties
107
109
  ##
108
110
 
111
+ @property
112
+ def project(self) -> NWProject:
113
+ """Return the parent project."""
114
+ return self._project
115
+
109
116
  @property
110
117
  def trash(self) -> ProjectNode | None:
111
118
  """Return trash node, if it exists."""
@@ -249,11 +256,37 @@ class NWTree:
249
256
  logger.error("Not all items could be added to project tree")
250
257
 
251
258
  self._trash = self._getTrashNode()
259
+ self._ready = True
252
260
  self._model.endInsertRows()
253
261
  self._model.layoutChanged.emit()
254
262
 
255
263
  return
256
264
 
265
+ def pickParent(self, sNode: ProjectNode, hLevel: int, isNote: bool) -> tuple[str | None, int]:
266
+ """Pick an appropriate parent handle for adding a new item."""
267
+ if sNode.item.isFolderType() or sNode.item.isRootType():
268
+ # Always add as a direct child of folders
269
+ return sNode.item.itemHandle, sNode.childCount()
270
+
271
+ pNode = sNode.parent()
272
+ pLevel = nwStyles.H_LEVEL.get(pNode.item.mainHeading, 0) if pNode else 0
273
+
274
+ # Notes are treated as H0, and scenes and sections both as H3
275
+ sLevel = min(0 if isNote else nwStyles.H_LEVEL.get(sNode.item.mainHeading, 0), 3)
276
+
277
+ if pNode and pNode.item.isFileType() and pLevel >= hLevel and sLevel > hLevel:
278
+ # If the selected item is a smaller heading and the parent heading
279
+ # is equal or larger, we make it a sibling of the parent (See #2260)
280
+ return pNode.item.itemParent, pNode.row() + 1
281
+
282
+ if sNode.childCount() > 0 and (0 < sLevel < hLevel or isNote):
283
+ # If the selected item already has child nodes and has a larger
284
+ # heading or is a note, we make the new item a child
285
+ return sNode.item.itemHandle, sNode.childCount()
286
+
287
+ # The default behaviour is to make the new item a sibling
288
+ return sNode.item.itemParent, sNode.row() + 1
289
+
257
290
  def refreshItems(self, items: list[str]) -> None:
258
291
  """Refresh these items on the GUI. If they are an ordered range,
259
292
  also set the isRange flag to True.
@@ -278,6 +311,12 @@ class NWTree:
278
311
  self._model.layoutChanged.emit()
279
312
  return
280
313
 
314
+ def novelStructureChanged(self, tHandle: str) -> None:
315
+ """Emit a novel structure change signal."""
316
+ if self._ready:
317
+ SHARED.novelStructureChanged.emit(tHandle)
318
+ return
319
+
281
320
  def checkConsistency(self, prefix: str) -> tuple[int, int]:
282
321
  """Check the project tree consistency. Also check the content
283
322
  folder and add back files that were discovered but were not
@@ -371,16 +410,20 @@ class NWTree:
371
410
 
372
411
  return True
373
412
 
374
- def sumWords(self) -> tuple[int, int]:
375
- """Loop over all entries and add up the word counts."""
376
- noteWords = 0
413
+ def sumCounts(self) -> tuple[int, int, int, int]:
414
+ """Loop over all entries and add up the word and char counts."""
377
415
  novelWords = 0
416
+ notesWords = 0
417
+ novelChars = 0
418
+ notesChars = 0
378
419
  for item in self._items.values():
379
420
  if item.itemLayout == nwItemLayout.NOTE:
380
- noteWords += item.wordCount
421
+ notesWords += item.wordCount
422
+ notesChars += item.charCount
381
423
  elif item.itemLayout == nwItemLayout.DOCUMENT:
382
424
  novelWords += item.wordCount
383
- return novelWords, noteWords
425
+ novelChars += item.charCount
426
+ return novelWords, notesWords, novelChars, notesChars
384
427
 
385
428
  ##
386
429
  # Tree Item Methods
@@ -388,7 +431,7 @@ class NWTree:
388
431
 
389
432
  def checkType(self, tHandle: str, itemType: nwItemType) -> bool:
390
433
  """Check if item exists and is of the specified item type."""
391
- if tItem := self.__getitem__(tHandle):
434
+ if tItem := self[tHandle]:
392
435
  return tItem.itemType == itemType
393
436
  return False
394
437
 
@@ -406,8 +449,7 @@ class NWTree:
406
449
  node = parent
407
450
  else:
408
451
  return path
409
- else:
410
- logger.error("Max project tree depth reached")
452
+ logger.error("Max project tree depth reached")
411
453
  return path
412
454
 
413
455
  def subTree(self, tHandle: str) -> list[str]:
@@ -25,17 +25,21 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from PyQt5.QtGui import QCloseEvent, QColor
29
- from PyQt5.QtWidgets import (
28
+ from typing import TYPE_CHECKING
29
+
30
+ from PyQt6.QtWidgets import (
30
31
  QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget
31
32
  )
32
33
 
33
34
  from novelwriter import CONFIG, SHARED
34
- from novelwriter.common import cssCol, readTextFile
35
- from novelwriter.extensions.configlayout import NColourLabel
35
+ from novelwriter.common import readTextFile
36
+ from novelwriter.extensions.configlayout import NColorLabel
36
37
  from novelwriter.extensions.modified import NDialog
37
38
  from novelwriter.extensions.versioninfo import VersionInfoWidget
38
- from novelwriter.types import QtAlignRightTop, QtDialogClose
39
+ from novelwriter.types import QtAlignRightTop, QtDialogClose, QtHexArgb
40
+
41
+ if TYPE_CHECKING:
42
+ from PyQt6.QtGui import QCloseEvent
39
43
 
40
44
  logger = logging.getLogger(__name__)
41
45
 
@@ -49,19 +53,13 @@ class GuiAbout(NDialog):
49
53
  self.setObjectName("GuiAbout")
50
54
 
51
55
  self.setWindowTitle(self.tr("About novelWriter"))
52
- self.resize(CONFIG.pxInt(700), CONFIG.pxInt(500))
53
-
54
- hA = CONFIG.pxInt(8)
55
- hB = CONFIG.pxInt(16)
56
- nwH = CONFIG.pxInt(36)
57
- nwPx = CONFIG.pxInt(128)
56
+ self.resize(700, 500)
58
57
 
59
58
  # Logo and Banner
60
- self.nwImage = SHARED.theme.loadDecoration("nw-text", h=nwH)
61
- self.bgColor = QColor(255, 255, 255) if SHARED.theme.isLightTheme else QColor(54, 54, 54)
59
+ self.nwImage = SHARED.theme.getDecoration("nw-text", h=36)
62
60
 
63
61
  self.nwLogo = QLabel(self)
64
- self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (nwPx, nwPx)))
62
+ self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (128, 128)))
65
63
 
66
64
  self.nwLabel = QLabel(self)
67
65
  self.nwLabel.setPixmap(self.nwImage)
@@ -74,14 +72,13 @@ class GuiAbout(NDialog):
74
72
  self.nwLicence.setOpenExternalLinks(True)
75
73
 
76
74
  # Credits
77
- self.lblCredits = NColourLabel(
75
+ self.lblCredits = NColorLabel(
78
76
  self.tr("Credits"), self, scale=1.6, bold=True
79
77
  )
80
78
 
81
79
  self.txtCredits = QTextBrowser(self)
82
80
  self.txtCredits.setOpenExternalLinks(True)
83
- self.txtCredits.document().setDocumentMargin(0)
84
- self.txtCredits.setViewportMargins(0, hA, hA, 0)
81
+ self.txtCredits.setViewportMargins(0, 8, 8, 0)
85
82
 
86
83
  # Buttons
87
84
  self.btnBox = QDialogButtonBox(QtDialogClose, self)
@@ -89,15 +86,15 @@ class GuiAbout(NDialog):
89
86
 
90
87
  # Assemble
91
88
  self.innerBox = QVBoxLayout()
92
- self.innerBox.addSpacing(hB)
89
+ self.innerBox.addSpacing(16)
93
90
  self.innerBox.addWidget(self.nwLabel)
94
91
  self.innerBox.addWidget(self.nwInfo)
95
- self.innerBox.addSpacing(hA)
92
+ self.innerBox.addSpacing(8)
96
93
  self.innerBox.addWidget(self.nwLicence)
97
- self.innerBox.addSpacing(hA)
94
+ self.innerBox.addSpacing(8)
98
95
  self.innerBox.addWidget(self.lblCredits)
99
96
  self.innerBox.addWidget(self.txtCredits)
100
- self.innerBox.addSpacing(hB)
97
+ self.innerBox.addSpacing(16)
101
98
  self.innerBox.addWidget(self.btnBox)
102
99
 
103
100
  self.outerBox = QHBoxLayout()
@@ -142,7 +139,7 @@ class GuiAbout(NDialog):
142
139
 
143
140
  def _setStyleSheet(self) -> None:
144
141
  """Set stylesheet text document."""
145
- baseCol = cssCol(self.palette().window().color())
142
+ baseCol = self.palette().window().color().name(QtHexArgb)
146
143
  self.txtCredits.setStyleSheet(
147
144
  f"QTextBrowser {{border: none; background: {baseCol};}} "
148
145
  )