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.
- novelwriter/__init__.py +98 -75
- novelwriter/assets/i18n/project_en_GB.json +2 -0
- novelwriter/assets/icons/font_awesome.icons +109 -0
- novelwriter/assets/icons/material_filled_bold.icons +109 -0
- novelwriter/assets/icons/material_filled_normal.icons +109 -0
- novelwriter/assets/icons/material_filled_thin.icons +109 -0
- novelwriter/assets/icons/material_rounded_bold.icons +109 -0
- novelwriter/assets/icons/material_rounded_normal.icons +109 -0
- novelwriter/assets/icons/material_rounded_thin.icons +109 -0
- novelwriter/assets/icons/remix_filled.icons +109 -0
- novelwriter/assets/icons/remix_outline.icons +109 -0
- novelwriter/assets/images/splash.png +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
- novelwriter/assets/syntax/snazzy.conf +3 -3
- novelwriter/assets/text/credits_en.htm +6 -6
- novelwriter/assets/themes/cyberpunk_night.conf +23 -7
- novelwriter/assets/themes/default_dark.conf +20 -4
- novelwriter/assets/themes/default_light.conf +21 -5
- novelwriter/assets/themes/dracula.conf +20 -4
- novelwriter/assets/themes/snazzy.conf +48 -0
- novelwriter/assets/themes/solarized_dark.conf +24 -8
- novelwriter/assets/themes/solarized_light.conf +22 -6
- novelwriter/common.py +43 -27
- novelwriter/config.py +201 -139
- novelwriter/constants.py +67 -36
- novelwriter/core/buildsettings.py +25 -16
- novelwriter/core/coretools.py +52 -41
- novelwriter/core/docbuild.py +20 -13
- novelwriter/core/document.py +2 -2
- novelwriter/core/index.py +166 -432
- novelwriter/core/indexdata.py +406 -0
- novelwriter/core/item.py +50 -32
- novelwriter/core/itemmodel.py +43 -38
- novelwriter/core/novelmodel.py +225 -0
- novelwriter/core/options.py +1 -1
- novelwriter/core/project.py +24 -25
- novelwriter/core/projectdata.py +47 -29
- novelwriter/core/projectxml.py +18 -8
- novelwriter/core/sessions.py +32 -15
- novelwriter/core/spellcheck.py +4 -3
- novelwriter/core/status.py +12 -15
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +55 -13
- novelwriter/dialogs/about.py +19 -22
- novelwriter/dialogs/docmerge.py +23 -24
- novelwriter/dialogs/docsplit.py +26 -26
- novelwriter/dialogs/editlabel.py +19 -20
- novelwriter/dialogs/preferences.py +143 -69
- novelwriter/dialogs/projectsettings.py +51 -54
- novelwriter/dialogs/quotes.py +14 -19
- novelwriter/dialogs/wordlist.py +25 -30
- novelwriter/enum.py +8 -0
- novelwriter/error.py +16 -16
- novelwriter/extensions/configlayout.py +24 -20
- novelwriter/extensions/eventfilters.py +9 -5
- novelwriter/extensions/modified.py +34 -15
- novelwriter/extensions/novelselector.py +18 -5
- novelwriter/extensions/pagedsidebar.py +39 -49
- novelwriter/extensions/progressbars.py +10 -8
- novelwriter/extensions/statusled.py +6 -13
- novelwriter/extensions/switch.py +31 -41
- novelwriter/extensions/switchbox.py +8 -3
- novelwriter/extensions/versioninfo.py +4 -4
- novelwriter/formats/shared.py +1 -1
- novelwriter/formats/todocx.py +14 -10
- novelwriter/formats/tohtml.py +7 -5
- novelwriter/formats/tokenizer.py +37 -33
- novelwriter/formats/tomarkdown.py +6 -2
- novelwriter/formats/toodt.py +27 -22
- novelwriter/formats/toqdoc.py +19 -14
- novelwriter/formats/toraw.py +6 -2
- novelwriter/gui/doceditor.py +314 -305
- novelwriter/gui/dochighlight.py +46 -45
- novelwriter/gui/docviewer.py +102 -104
- novelwriter/gui/docviewerpanel.py +47 -51
- novelwriter/gui/editordocument.py +8 -5
- novelwriter/gui/itemdetails.py +11 -14
- novelwriter/gui/mainmenu.py +146 -145
- novelwriter/gui/noveltree.py +246 -406
- novelwriter/gui/outline.py +141 -72
- novelwriter/gui/projtree.py +139 -132
- novelwriter/gui/search.py +34 -31
- novelwriter/gui/sidebar.py +13 -18
- novelwriter/gui/statusbar.py +27 -21
- novelwriter/gui/theme.py +554 -436
- novelwriter/guimain.py +56 -38
- novelwriter/shared.py +32 -23
- novelwriter/splash.py +74 -0
- novelwriter/text/comments.py +70 -0
- novelwriter/text/patterns.py +4 -4
- novelwriter/tools/dictionaries.py +20 -29
- novelwriter/tools/lipsum.py +18 -18
- novelwriter/tools/manusbuild.py +39 -42
- novelwriter/tools/manuscript.py +102 -115
- novelwriter/tools/manussettings.py +116 -96
- novelwriter/tools/noveldetails.py +60 -72
- novelwriter/tools/welcome.py +57 -75
- novelwriter/tools/writingstats.py +112 -102
- novelwriter/types.py +5 -7
- {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/METADATA +6 -6
- novelwriter-2.7rc1.dist-info/RECORD +162 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/WHEEL +1 -1
- novelWriter-2.6.3.dist-info/RECORD +0 -363
- novelwriter/assets/icons/typicons_dark/README.md +0 -29
- novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
- novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
- novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
- novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
- novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
- novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
- novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
- novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
- novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
- novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
- novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/README.md +0 -29
- novelwriter/assets/icons/typicons_light/icons.conf +0 -134
- novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
- novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
- novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
- novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
- novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
- novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
- novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
- novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
- novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
- novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
- {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info/licenses}/LICENSE.md +0 -0
- {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/top_level.txt +0 -0
novelwriter/guimain.py
CHANGED
@@ -30,11 +30,11 @@ from datetime import datetime
|
|
30
30
|
from pathlib import Path
|
31
31
|
from time import time
|
32
32
|
|
33
|
-
from
|
34
|
-
from
|
35
|
-
from
|
33
|
+
from PyQt6.QtCore import Qt, QTimer, pyqtSlot
|
34
|
+
from PyQt6.QtGui import QCloseEvent, QCursor, QIcon, QShortcut
|
35
|
+
from PyQt6.QtWidgets import (
|
36
36
|
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
37
|
-
|
37
|
+
QSplitter, QStackedWidget, QVBoxLayout, QWidget
|
38
38
|
)
|
39
39
|
|
40
40
|
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
@@ -56,7 +56,6 @@ from novelwriter.gui.projtree import GuiProjectView
|
|
56
56
|
from novelwriter.gui.search import GuiProjectSearch
|
57
57
|
from novelwriter.gui.sidebar import GuiSideBar
|
58
58
|
from novelwriter.gui.statusbar import GuiMainStatus
|
59
|
-
from novelwriter.gui.theme import GuiTheme
|
60
59
|
from novelwriter.tools.dictionaries import GuiDictionaries
|
61
60
|
from novelwriter.tools.manuscript import GuiManuscript
|
62
61
|
from novelwriter.tools.noveldetails import GuiNovelDetails
|
@@ -92,8 +91,8 @@ class GuiMain(QMainWindow):
|
|
92
91
|
logger.info("OS: %s", CONFIG.osType)
|
93
92
|
logger.info("Kernel: %s", CONFIG.kernelVer)
|
94
93
|
logger.info("Host: %s", CONFIG.hostName)
|
95
|
-
logger.info("
|
96
|
-
logger.info("
|
94
|
+
logger.info("Qt: %s (0x%06x)", CONFIG.verQtString, CONFIG.verQtValue)
|
95
|
+
logger.info("PyQt: %s (0x%06x)", CONFIG.verPyQtString, CONFIG.verPyQtValue)
|
97
96
|
logger.info("Python: %s (0x%08x)", CONFIG.verPyString, sys.hexversion)
|
98
97
|
logger.info("GUI Language: %s", CONFIG.guiLocale)
|
99
98
|
|
@@ -101,7 +100,7 @@ class GuiMain(QMainWindow):
|
|
101
100
|
# ============
|
102
101
|
|
103
102
|
# Initialise UserData Instance
|
104
|
-
SHARED.initSharedData(self
|
103
|
+
SHARED.initSharedData(self)
|
105
104
|
|
106
105
|
# Prepare Main Window
|
107
106
|
self.resize(*CONFIG.mainWinSize)
|
@@ -115,10 +114,6 @@ class GuiMain(QMainWindow):
|
|
115
114
|
# Build the GUI
|
116
115
|
# =============
|
117
116
|
|
118
|
-
# Sizes
|
119
|
-
mPx = CONFIG.pxInt(4)
|
120
|
-
hWd = CONFIG.pxInt(4)
|
121
|
-
|
122
117
|
# Main GUI Elements
|
123
118
|
self.mainStatus = GuiMainStatus(self)
|
124
119
|
self.projView = GuiProjectView(self)
|
@@ -143,7 +138,7 @@ class GuiMain(QMainWindow):
|
|
143
138
|
self.treePane = QWidget(self)
|
144
139
|
self.treeBox = QVBoxLayout()
|
145
140
|
self.treeBox.setContentsMargins(0, 0, 0, 0)
|
146
|
-
self.treeBox.setSpacing(
|
141
|
+
self.treeBox.setSpacing(4)
|
147
142
|
self.treeBox.addWidget(self.projStack)
|
148
143
|
self.treeBox.addWidget(self.itemDetails)
|
149
144
|
self.treePane.setLayout(self.treeBox)
|
@@ -152,7 +147,7 @@ class GuiMain(QMainWindow):
|
|
152
147
|
self.splitView = QSplitter(Qt.Orientation.Vertical, self)
|
153
148
|
self.splitView.addWidget(self.docViewer)
|
154
149
|
self.splitView.addWidget(self.docViewerPanel)
|
155
|
-
self.splitView.setHandleWidth(
|
150
|
+
self.splitView.setHandleWidth(4)
|
156
151
|
self.splitView.setOpaqueResize(False)
|
157
152
|
self.splitView.setSizes(CONFIG.viewPanePos)
|
158
153
|
self.splitView.setCollapsible(0, False)
|
@@ -163,7 +158,7 @@ class GuiMain(QMainWindow):
|
|
163
158
|
self.splitDocs.addWidget(self.docEditor)
|
164
159
|
self.splitDocs.addWidget(self.splitView)
|
165
160
|
self.splitDocs.setOpaqueResize(False)
|
166
|
-
self.splitDocs.setHandleWidth(
|
161
|
+
self.splitDocs.setHandleWidth(4)
|
167
162
|
self.splitDocs.setCollapsible(0, False)
|
168
163
|
self.splitDocs.setCollapsible(1, False)
|
169
164
|
|
@@ -173,7 +168,7 @@ class GuiMain(QMainWindow):
|
|
173
168
|
self.splitMain.addWidget(self.treePane)
|
174
169
|
self.splitMain.addWidget(self.splitDocs)
|
175
170
|
self.splitMain.setOpaqueResize(False)
|
176
|
-
self.splitMain.setHandleWidth(
|
171
|
+
self.splitMain.setHandleWidth(4)
|
177
172
|
self.splitMain.setSizes(CONFIG.mainPanePos)
|
178
173
|
self.splitMain.setCollapsible(0, False)
|
179
174
|
self.splitMain.setCollapsible(0, False)
|
@@ -252,8 +247,6 @@ class GuiMain(QMainWindow):
|
|
252
247
|
self.docEditor.itemHandleChanged.connect(self.novelView.setActiveHandle)
|
253
248
|
self.docEditor.itemHandleChanged.connect(self.projView.setActiveHandle)
|
254
249
|
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
|
255
|
-
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
256
|
-
self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree)
|
257
250
|
self.docEditor.openDocumentRequest.connect(self._openDocument)
|
258
251
|
self.docEditor.requestNewNoteCreation.connect(SHARED.createNewNote)
|
259
252
|
self.docEditor.requestNextDocument.connect(self.openNextDocument)
|
@@ -317,11 +310,11 @@ class GuiMain(QMainWindow):
|
|
317
310
|
self.asProjTimer.start()
|
318
311
|
self.asDocTimer.start()
|
319
312
|
self.mainStatus.clearStatus()
|
320
|
-
self.showNormal()
|
321
313
|
|
322
314
|
logger.debug("Ready: GUI")
|
323
315
|
logger.info("novelWriter is ready ...")
|
324
316
|
self.mainStatus.setStatusMessage(self.tr("novelWriter is ready ..."))
|
317
|
+
CONFIG.splashMessage("novelWriter is ready ...")
|
325
318
|
|
326
319
|
return
|
327
320
|
|
@@ -347,6 +340,15 @@ class GuiMain(QMainWindow):
|
|
347
340
|
logger.info("Command line path: %s", cmdOpen)
|
348
341
|
self.openProject(cmdOpen)
|
349
342
|
|
343
|
+
# Add a small delay for the window coordinates to be ready
|
344
|
+
# before showing any dialogs
|
345
|
+
QTimer.singleShot(50, self.showPostLaunchDialogs)
|
346
|
+
|
347
|
+
return
|
348
|
+
|
349
|
+
@pyqtSlot()
|
350
|
+
def showPostLaunchDialogs(self) -> None:
|
351
|
+
"""Show post launch dialogs."""
|
350
352
|
if not SHARED.hasProject:
|
351
353
|
self.showWelcomeDialog()
|
352
354
|
|
@@ -377,7 +379,7 @@ class GuiMain(QMainWindow):
|
|
377
379
|
return True
|
378
380
|
|
379
381
|
if not isYes:
|
380
|
-
msgYes = SHARED.question("
|
382
|
+
msgYes = SHARED.question("{0}<br>{1}".format(
|
381
383
|
self.tr("Close the current project?"),
|
382
384
|
self.tr("Changes are saved automatically.")
|
383
385
|
))
|
@@ -537,7 +539,7 @@ class GuiMain(QMainWindow):
|
|
537
539
|
) -> bool:
|
538
540
|
"""Open a specific document, optionally at a given line."""
|
539
541
|
if not (SHARED.hasProject and tHandle):
|
540
|
-
logger.error("Nothing to open
|
542
|
+
logger.error("Nothing to open")
|
541
543
|
return False
|
542
544
|
|
543
545
|
if sTitle and tLine is None:
|
@@ -740,7 +742,6 @@ class GuiMain(QMainWindow):
|
|
740
742
|
|
741
743
|
SHARED.project.index.rebuild()
|
742
744
|
SHARED.project.tree.refreshAllItems()
|
743
|
-
self.novelView.refreshTree()
|
744
745
|
|
745
746
|
tEnd = time()
|
746
747
|
self.mainStatus.setStatusMessage(
|
@@ -852,7 +853,7 @@ class GuiMain(QMainWindow):
|
|
852
853
|
|
853
854
|
def closeMain(self) -> bool:
|
854
855
|
"""Save everything, and close novelWriter."""
|
855
|
-
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("
|
856
|
+
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("{0}<br>{1}".format(
|
856
857
|
self.tr("Do you want to exit novelWriter?"),
|
857
858
|
self.tr("Changes are saved automatically.")
|
858
859
|
)):
|
@@ -861,10 +862,10 @@ class GuiMain(QMainWindow):
|
|
861
862
|
logger.info("Exiting novelWriter")
|
862
863
|
|
863
864
|
if not SHARED.focusMode:
|
864
|
-
CONFIG.
|
865
|
-
CONFIG.
|
865
|
+
CONFIG.mainPanePos = self.splitMain.sizes()
|
866
|
+
CONFIG.outlinePanePos = self.outlineView.splitSizes()
|
866
867
|
if self.docViewerPanel.isVisible():
|
867
|
-
CONFIG.
|
868
|
+
CONFIG.viewPanePos = self.splitView.sizes()
|
868
869
|
|
869
870
|
CONFIG.showViewerPanel = self.docViewerPanel.isVisible()
|
870
871
|
wFull = Qt.WindowState.WindowFullScreen
|
@@ -1017,7 +1018,7 @@ class GuiMain(QMainWindow):
|
|
1017
1018
|
fN = self.novelView.treeHasFocus()
|
1018
1019
|
|
1019
1020
|
self._changeView(nwView.EDITOR)
|
1020
|
-
if (vM and (vP and fP or vN and not fN)) or (not vM and vN):
|
1021
|
+
if (vM and ((vP and fP) or (vN and not fN))) or (not vM and vN):
|
1021
1022
|
self._changeView(nwView.NOVEL)
|
1022
1023
|
self.novelView.setTreeFocus()
|
1023
1024
|
else:
|
@@ -1047,13 +1048,14 @@ class GuiMain(QMainWindow):
|
|
1047
1048
|
self.initMain()
|
1048
1049
|
self.saveDocument()
|
1049
1050
|
|
1050
|
-
if tree:
|
1051
|
+
if tree and not theme:
|
1052
|
+
# These are also updated by a theme refresh
|
1051
1053
|
SHARED.project.tree.refreshAllItems()
|
1054
|
+
self.novelView.refreshCurrentTree()
|
1052
1055
|
|
1053
1056
|
if theme:
|
1054
|
-
# We are doing this manually instead of connecting to
|
1055
|
-
# paletteChanged since the processing order matters
|
1056
1057
|
SHARED.theme.loadTheme()
|
1058
|
+
self.setPalette(QApplication.palette())
|
1057
1059
|
self.docEditor.updateTheme()
|
1058
1060
|
self.docViewer.updateTheme()
|
1059
1061
|
self.docViewerPanel.updateTheme()
|
@@ -1064,16 +1066,18 @@ class GuiMain(QMainWindow):
|
|
1064
1066
|
self.outlineView.updateTheme()
|
1065
1067
|
self.itemDetails.updateTheme()
|
1066
1068
|
self.mainStatus.updateTheme()
|
1069
|
+
SHARED.project.tree.refreshAllItems()
|
1067
1070
|
|
1068
1071
|
if syntax:
|
1069
1072
|
SHARED.theme.loadSyntax()
|
1070
|
-
self.docEditor.
|
1073
|
+
self.docEditor.updateSyntaxColors()
|
1071
1074
|
|
1072
1075
|
self.docEditor.initEditor()
|
1073
1076
|
self.docViewer.initViewer()
|
1074
1077
|
self.projView.initSettings()
|
1075
1078
|
self.novelView.initSettings()
|
1076
1079
|
self.outlineView.initSettings()
|
1080
|
+
self.mainStatus.initSettings()
|
1077
1081
|
|
1078
1082
|
# Force update of word count
|
1079
1083
|
self._lastTotalCount = 0
|
@@ -1179,6 +1183,12 @@ class GuiMain(QMainWindow):
|
|
1179
1183
|
)
|
1180
1184
|
elif view == nwView.OUTLINE:
|
1181
1185
|
self.mainStack.setCurrentWidget(self.outlineView)
|
1186
|
+
|
1187
|
+
# Set active status
|
1188
|
+
isMain = self.mainStack.currentWidget() == self.splitMain
|
1189
|
+
isNovel = self.projStack.currentWidget() == self.novelView
|
1190
|
+
self.novelView.setActive(isMain and isNovel)
|
1191
|
+
|
1182
1192
|
return
|
1183
1193
|
|
1184
1194
|
@pyqtSlot(nwDocAction)
|
@@ -1254,15 +1264,23 @@ class GuiMain(QMainWindow):
|
|
1254
1264
|
if self._lastTotalCount != currentTotalCount:
|
1255
1265
|
self._lastTotalCount = currentTotalCount
|
1256
1266
|
|
1257
|
-
SHARED.project.
|
1267
|
+
SHARED.project.updateCounts()
|
1258
1268
|
if CONFIG.incNotesWCount:
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1269
|
+
if CONFIG.useCharCount:
|
1270
|
+
iTotal = sum(SHARED.project.data.initCounts[2:])
|
1271
|
+
cTotal = sum(SHARED.project.data.currCounts[2:])
|
1272
|
+
else:
|
1273
|
+
iTotal = sum(SHARED.project.data.initCounts[:2])
|
1274
|
+
cTotal = sum(SHARED.project.data.currCounts[:2])
|
1262
1275
|
else:
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1276
|
+
if CONFIG.useCharCount:
|
1277
|
+
iTotal = SHARED.project.data.initCounts[2]
|
1278
|
+
cTotal = SHARED.project.data.currCounts[2]
|
1279
|
+
else:
|
1280
|
+
iTotal = SHARED.project.data.initCounts[0]
|
1281
|
+
cTotal = SHARED.project.data.currCounts[0]
|
1282
|
+
|
1283
|
+
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
1266
1284
|
|
1267
1285
|
return
|
1268
1286
|
|
novelwriter/shared.py
CHANGED
@@ -31,16 +31,16 @@ from pathlib import Path
|
|
31
31
|
from time import time
|
32
32
|
from typing import TYPE_CHECKING, TypeVar
|
33
33
|
|
34
|
-
from
|
35
|
-
from
|
36
|
-
from
|
34
|
+
from PyQt6.QtCore import QObject, QRunnable, QThreadPool, QTimer, QUrl, pyqtSignal, pyqtSlot
|
35
|
+
from PyQt6.QtGui import QDesktopServices, QFont
|
36
|
+
from PyQt6.QtWidgets import QFileDialog, QFontDialog, QMessageBox, QWidget
|
37
37
|
|
38
38
|
from novelwriter.common import formatFileFilter
|
39
39
|
from novelwriter.constants import nwFiles
|
40
40
|
from novelwriter.core.spellcheck import NWSpellEnchant
|
41
41
|
from novelwriter.enum import nwChange, nwItemClass
|
42
42
|
|
43
|
-
if TYPE_CHECKING:
|
43
|
+
if TYPE_CHECKING:
|
44
44
|
from novelwriter.core.project import NWProject
|
45
45
|
from novelwriter.core.status import T_StatusKind
|
46
46
|
from novelwriter.gui.theme import GuiTheme
|
@@ -54,8 +54,8 @@ NWWidget = TypeVar("NWWidget", bound=QWidget)
|
|
54
54
|
class SharedData(QObject):
|
55
55
|
|
56
56
|
__slots__ = (
|
57
|
-
"_gui", "
|
58
|
-
"
|
57
|
+
"_gui", "_idleRefTime", "_idleTime", "_lastAlert", "_lockedBy",
|
58
|
+
"_project", "_spelling", "_theme",
|
59
59
|
)
|
60
60
|
|
61
61
|
focusModeChanged = pyqtSignal(bool)
|
@@ -63,10 +63,11 @@ class SharedData(QObject):
|
|
63
63
|
indexChangedTags = pyqtSignal(list, list)
|
64
64
|
indexCleared = pyqtSignal()
|
65
65
|
mainClockTick = pyqtSignal()
|
66
|
+
novelStructureChanged = pyqtSignal(str)
|
66
67
|
projectItemChanged = pyqtSignal(str, Enum)
|
67
|
-
rootFolderChanged = pyqtSignal(str, Enum)
|
68
68
|
projectStatusChanged = pyqtSignal(bool)
|
69
69
|
projectStatusMessage = pyqtSignal(str)
|
70
|
+
rootFolderChanged = pyqtSignal(str, Enum)
|
70
71
|
spellLanguageChanged = pyqtSignal(str, str)
|
71
72
|
statusLabelsChanged = pyqtSignal(str)
|
72
73
|
|
@@ -100,28 +101,28 @@ class SharedData(QObject):
|
|
100
101
|
def mainGui(self) -> GuiMain:
|
101
102
|
"""Return the Main GUI instance."""
|
102
103
|
if self._gui is None:
|
103
|
-
raise
|
104
|
+
raise RuntimeError("SharedData class not fully initialised")
|
104
105
|
return self._gui
|
105
106
|
|
106
107
|
@property
|
107
108
|
def theme(self) -> GuiTheme:
|
108
109
|
"""Return the GUI Theme instance."""
|
109
110
|
if self._theme is None:
|
110
|
-
raise
|
111
|
+
raise RuntimeError("SharedData class not fully initialised")
|
111
112
|
return self._theme
|
112
113
|
|
113
114
|
@property
|
114
115
|
def project(self) -> NWProject:
|
115
116
|
"""Return the active NWProject instance."""
|
116
117
|
if self._project is None:
|
117
|
-
raise
|
118
|
+
raise RuntimeError("SharedData class not fully initialised")
|
118
119
|
return self._project
|
119
120
|
|
120
121
|
@property
|
121
122
|
def spelling(self) -> NWSpellEnchant:
|
122
123
|
"""Return the active NWProject instance."""
|
123
124
|
if self._spelling is None:
|
124
|
-
raise
|
125
|
+
raise RuntimeError("SharedData class not fully initialised")
|
125
126
|
return self._spelling
|
126
127
|
|
127
128
|
@property
|
@@ -164,17 +165,24 @@ class SharedData(QObject):
|
|
164
165
|
# Methods
|
165
166
|
##
|
166
167
|
|
167
|
-
def
|
168
|
+
def initTheme(self, theme: GuiTheme) -> None:
|
169
|
+
"""Initialise the GUI theme. This must be called before the GUI
|
170
|
+
is created.
|
171
|
+
"""
|
172
|
+
self._theme = theme
|
173
|
+
return
|
174
|
+
|
175
|
+
def initSharedData(self, gui: GuiMain) -> None:
|
168
176
|
"""Initialise the SharedData instance. This must be called as
|
169
177
|
soon as the Main GUI is created to ensure the SHARED singleton
|
170
178
|
has the properties needed for operation.
|
171
179
|
"""
|
172
180
|
self._clock.start()
|
173
181
|
self._gui = gui
|
174
|
-
self._theme = theme
|
175
182
|
self._resetProject()
|
176
183
|
logger.debug("Ready: SharedData")
|
177
|
-
|
184
|
+
if pool := QThreadPool.globalInstance():
|
185
|
+
logger.debug("Thread Pool Max Count: %d", pool.maxThreadCount())
|
178
186
|
return
|
179
187
|
|
180
188
|
def closeDocument(self, tHandle: str | None = None) -> None:
|
@@ -266,7 +274,8 @@ class SharedData(QObject):
|
|
266
274
|
|
267
275
|
def runInThreadPool(self, runnable: QRunnable, priority: int = 0) -> None:
|
268
276
|
"""Queue a runnable in the application thread pool."""
|
269
|
-
QThreadPool.globalInstance()
|
277
|
+
if pool := QThreadPool.globalInstance():
|
278
|
+
pool.start(runnable, priority=priority)
|
270
279
|
return
|
271
280
|
|
272
281
|
def getProjectPath(
|
@@ -278,13 +287,13 @@ class SharedData(QObject):
|
|
278
287
|
label = (self.tr("novelWriter Project File or Zip File")
|
279
288
|
if allowZip else self.tr("novelWriter Project File"))
|
280
289
|
ext = f"{nwFiles.PROJ_FILE} *.zip" if allowZip else nwFiles.PROJ_FILE
|
281
|
-
|
290
|
+
fFilter = formatFileFilter([(label, ext), "*"])
|
282
291
|
selected, _ = QFileDialog.getOpenFileName(
|
283
|
-
parent, self.tr("Open Project"), str(path or ""), filter=
|
292
|
+
parent, self.tr("Open Project"), str(path or ""), filter=fFilter
|
284
293
|
)
|
285
294
|
return Path(selected) if selected else None
|
286
295
|
|
287
|
-
def getFont(self, current: QFont, native: bool) -> tuple[QFont, bool]:
|
296
|
+
def getFont(self, current: QFont, native: bool) -> tuple[QFont, bool | None]:
|
288
297
|
"""Open the font dialog and select a font."""
|
289
298
|
kwargs = {}
|
290
299
|
if not native:
|
@@ -471,7 +480,7 @@ class _GuiAlert(QMessageBox):
|
|
471
480
|
def setException(self, exception: Exception) -> None:
|
472
481
|
"""Add exception details."""
|
473
482
|
info = self.informativeText()
|
474
|
-
text = f"<b>{type(exception).__name__}</b>: {
|
483
|
+
text = f"<b>{type(exception).__name__}</b>: {exception!s}"
|
475
484
|
self.setInformativeText(f"{info}<br>{text}" if info else text)
|
476
485
|
return
|
477
486
|
|
@@ -485,15 +494,15 @@ class _GuiAlert(QMessageBox):
|
|
485
494
|
self.setStandardButtons(QMessageBox.StandardButton.Ok)
|
486
495
|
pSz = 2*self._theme.baseIconHeight
|
487
496
|
if level == self.INFO:
|
488
|
-
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz)))
|
497
|
+
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz), "blue"))
|
489
498
|
self.setWindowTitle(self.tr("Information"))
|
490
499
|
elif level == self.WARN:
|
491
|
-
self.setIconPixmap(self._theme.getPixmap("alert_warn", (pSz, pSz)))
|
500
|
+
self.setIconPixmap(self._theme.getPixmap("alert_warn", (pSz, pSz), "orange"))
|
492
501
|
self.setWindowTitle(self.tr("Warning"))
|
493
502
|
elif level == self.ERROR:
|
494
|
-
self.setIconPixmap(self._theme.getPixmap("alert_error", (pSz, pSz)))
|
503
|
+
self.setIconPixmap(self._theme.getPixmap("alert_error", (pSz, pSz), "red"))
|
495
504
|
self.setWindowTitle(self.tr("Error"))
|
496
505
|
elif level == self.ASK:
|
497
|
-
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz)))
|
506
|
+
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz), "blue"))
|
498
507
|
self.setWindowTitle(self.tr("Question"))
|
499
508
|
return
|
novelwriter/splash.py
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Splash Screen
|
3
|
+
===========================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2015-04-25 [2.7rc1]
|
7
|
+
|
8
|
+
This file is a part of novelWriter
|
9
|
+
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
10
|
+
|
11
|
+
This program is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
This program is distributed in the hope that it will be useful, but
|
17
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
+
General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU General Public License
|
22
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
+
"""
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
import logging
|
27
|
+
|
28
|
+
from pathlib import Path
|
29
|
+
from time import sleep
|
30
|
+
|
31
|
+
from PyQt6.QtCore import QRect, Qt
|
32
|
+
from PyQt6.QtGui import QColor, QPainter, QPixmap
|
33
|
+
from PyQt6.QtWidgets import QSplashScreen
|
34
|
+
|
35
|
+
logger = logging.getLogger(__name__)
|
36
|
+
|
37
|
+
SPLASH_IMG = Path(__file__).parent / "assets" / "images" / "splash.png"
|
38
|
+
|
39
|
+
|
40
|
+
class NSplashScreen(QSplashScreen):
|
41
|
+
|
42
|
+
__slots__ = ("_color", "_rect", "_text")
|
43
|
+
|
44
|
+
def __init__(self) -> None:
|
45
|
+
super().__init__(pixmap=QPixmap(str(SPLASH_IMG)), flags=Qt.WindowType.WindowStaysOnTopHint)
|
46
|
+
|
47
|
+
logger.debug("Create: NSplashScreen")
|
48
|
+
|
49
|
+
font = self.font()
|
50
|
+
font.setPointSizeF(12.0)
|
51
|
+
self.setFont(font)
|
52
|
+
self._color = QColor(26, 52, 78)
|
53
|
+
self._rect = QRect(144, 110, 440, 30)
|
54
|
+
self._text = ""
|
55
|
+
return
|
56
|
+
|
57
|
+
def __del__(self) -> None: # pragma: no cover
|
58
|
+
logger.debug("Delete: NSplashScreen")
|
59
|
+
return
|
60
|
+
|
61
|
+
def drawContents(self, painter: QPainter) -> None:
|
62
|
+
"""Draw the text message."""
|
63
|
+
painter.setPen(self._color)
|
64
|
+
painter.drawText(self._rect, Qt.AlignmentFlag.AlignLeft, self._text)
|
65
|
+
return
|
66
|
+
|
67
|
+
def showStatus(self, message: str) -> None:
|
68
|
+
"""Update the status message."""
|
69
|
+
self._text = message
|
70
|
+
self.showMessage(message)
|
71
|
+
if message:
|
72
|
+
logger.info("[Splash] %s", message)
|
73
|
+
sleep(0.025)
|
74
|
+
return
|
@@ -0,0 +1,70 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Text Comments
|
3
|
+
===========================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2023-11-23 [2.2b1]
|
7
|
+
Moved: 2025-02-09 [2.7b1]
|
8
|
+
|
9
|
+
This file is a part of novelWriter
|
10
|
+
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
11
|
+
|
12
|
+
This program is free software: you can redistribute it and/or modify
|
13
|
+
it under the terms of the GNU General Public License as published by
|
14
|
+
the Free Software Foundation, either version 3 of the License, or
|
15
|
+
(at your option) any later version.
|
16
|
+
|
17
|
+
This program is distributed in the hope that it will be useful, but
|
18
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
20
|
+
General Public License for more details.
|
21
|
+
|
22
|
+
You should have received a copy of the GNU General Public License
|
23
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
24
|
+
"""
|
25
|
+
from __future__ import annotations
|
26
|
+
|
27
|
+
from novelwriter.enum import nwComment
|
28
|
+
|
29
|
+
MODIFIERS = {
|
30
|
+
"synopsis": nwComment.SYNOPSIS,
|
31
|
+
"short": nwComment.SHORT,
|
32
|
+
"note": nwComment.NOTE,
|
33
|
+
"footnote": nwComment.FOOTNOTE,
|
34
|
+
"story": nwComment.STORY,
|
35
|
+
}
|
36
|
+
KEY_REQ = {
|
37
|
+
"synopsis": 0, # Key not allowed
|
38
|
+
"short": 0, # Key not allowed
|
39
|
+
"note": 1, # Key optional
|
40
|
+
"footnote": 2, # Key required
|
41
|
+
"story": 2, # Key required
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
def _checkModKey(modifier: str, key: str) -> bool:
|
46
|
+
"""Check if a modifier and key set are ok."""
|
47
|
+
if modifier in MODIFIERS:
|
48
|
+
if key == "":
|
49
|
+
return KEY_REQ[modifier] < 2
|
50
|
+
elif key.replace("_", "").isalnum():
|
51
|
+
return KEY_REQ[modifier] > 0
|
52
|
+
return False
|
53
|
+
|
54
|
+
|
55
|
+
def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
|
56
|
+
"""Extract comment style, key and text. Should only be called on
|
57
|
+
text starting with a %.
|
58
|
+
"""
|
59
|
+
if text[:2] == "%~":
|
60
|
+
return nwComment.IGNORE, "", text[2:].lstrip(), 0, 0
|
61
|
+
|
62
|
+
check = text[1:].strip()
|
63
|
+
start, _, content = check.partition(":")
|
64
|
+
modifier, _, key = start.rstrip().partition(".")
|
65
|
+
if content and (clean := modifier.lower()) and _checkModKey(clean, key):
|
66
|
+
col = text.find(":") + 1
|
67
|
+
dot = text.find(".", 0, col) + 1
|
68
|
+
return MODIFIERS[clean], key, content.lstrip(), dot, col
|
69
|
+
|
70
|
+
return nwComment.PLAIN, "", check, 0, 0
|
novelwriter/text/patterns.py
CHANGED
@@ -93,7 +93,7 @@ class RegExPatterns:
|
|
93
93
|
if CONFIG.dialogStyle in (1, 3):
|
94
94
|
qO = CONFIG.fmtSQuoteOpen.strip()[:1]
|
95
95
|
qC = CONFIG.fmtSQuoteClose.strip()[:1]
|
96
|
-
if qO == qC:
|
96
|
+
if qO == qC or qC in self.AMBIGUOUS:
|
97
97
|
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
98
98
|
else:
|
99
99
|
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
@@ -102,7 +102,7 @@ class RegExPatterns:
|
|
102
102
|
if CONFIG.dialogStyle in (2, 3):
|
103
103
|
qO = CONFIG.fmtDQuoteOpen.strip()[:1]
|
104
104
|
qC = CONFIG.fmtDQuoteClose.strip()[:1]
|
105
|
-
if qO == qC:
|
105
|
+
if qO == qC or qC in self.AMBIGUOUS:
|
106
106
|
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
107
107
|
else:
|
108
108
|
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
@@ -128,8 +128,8 @@ REGEX_PATTERNS = RegExPatterns()
|
|
128
128
|
class DialogParser:
|
129
129
|
|
130
130
|
__slots__ = (
|
131
|
-
"
|
132
|
-
"_narrator", "
|
131
|
+
"_alternate", "_breakD", "_breakQ", "_dialog", "_enabled", "_mode",
|
132
|
+
"_narrator", "_quotes",
|
133
133
|
)
|
134
134
|
|
135
135
|
def __init__(self) -> None:
|