Merge branch 'main' into material_icons

This commit is contained in:
Veronica Berglyd Olsen
2025-01-10 01:59:49 +01:00
24 changed files with 16597 additions and 15576 deletions
+40
View File
@@ -1,5 +1,45 @@
# novelWriter Changelog
## Version 2.6 RC 1 [2025-01-09]
### Release Notes
This is a release candidate of the next release version, and is intended for testing purposes.
Please be careful when using this version on live writing projects, and make sure you take frequent
backups.
### Detailed Changelog
**New Features**
* The session timer in the status bar can now be hidden by clicking on it. Issue #1029. PR #2149.
* Status and importance labels can now be exported and imported. Issue #1847. PRs #2152 and #2153.
**Bugfixes**
* Fix a beta release bug where it was not possible to change the status or importance flag on
folders in the project tree. Issue #2145. PR #2147.
* Fix an issue where the word counter would override the selection counter in the editor. This was
caused by the selection counter being on a much shorter timer than the word counter, so in some
cases the latter result came in after the former even if the user actions where the other way
around. The selection counter now takes precedence, always. Issue #2155. PRs #2156 and #2157.
* Fix a minor issue where the search panel header background would not update colour when the theme
was changed. Issue #2162. PR #2167.
**Improvements**
* It is no longer necessary to click the "Apply" button when making changes to status and
importance labels, or auto-replace settings, in Project Settings. The changes are applied
directly to the listed items. They are not applied to the project until the Project Settings are
accepted. This is a more intuitive approach. Issue #2150. PR #2151.
**Packaging and Installation**
* MacOS packages are now built on the latest MacOS image available on GitHub. The x86_64 build was
previously locked to MacOS 12, which is no loner available. PR #2141.
----
## Version 2.6 Beta 2 [2024-12-23]
### Release Notes
+1328 -1252
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+1264 -1188
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -47,9 +47,9 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net"
__version__ = "2.6b2"
__hexversion__ = "0x020600b2"
__date__ = "2024-12-23"
__version__ = "2.7a0"
__hexversion__ = "0x020700a0"
__date__ = "2025-01-10"
__status__ = "Stable"
__domain__ = "novelwriter.io"
+35 -35
View File
@@ -207,7 +207,7 @@ class nwLists:
class nwStats:
CHARS_ALL = "allChars"
CHARS = "allChars"
CHARS_TEXT = "textChars"
CHARS_TITLE = "titleChars"
PARAGRAPHS = "paragraphCount"
@@ -215,14 +215,14 @@ class nwStats:
WCHARS_ALL = "allWordChars"
WCHARS_TEXT = "textWordChars"
WCHARS_TITLE = "titleWordChars"
WORDS_ALL = "allWords"
WORDS = "allWords"
WORDS_TEXT = "textWords"
WORDS_TITLE = "titleWords"
# Note: The order here affects the order of menu entries
ALL_FIELDS = [
WORDS_ALL, WORDS_TEXT, WORDS_TITLE,
CHARS_ALL, CHARS_TEXT, CHARS_TITLE,
WORDS, WORDS_TEXT, WORDS_TITLE,
CHARS, CHARS_TEXT, CHARS_TITLE,
WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
PARAGRAPHS, TITLES,
]
@@ -329,17 +329,17 @@ class nwLabels:
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
}
STATS_NAME = {
nwStats.CHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text"),
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings"),
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Constant", "Paragraphs"),
nwStats.TITLES: QT_TRANSLATE_NOOP("Constant", "Headings"),
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters, No Spaces"),
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text, No Spaces"),
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings, No Spaces"),
nwStats.WORDS_ALL: QT_TRANSLATE_NOOP("Constant", "Words"),
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Constant", "Words in Text"),
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Constant", "Words in Headings"),
nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text"),
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings"),
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Stats", "Paragraphs"),
nwStats.TITLES: QT_TRANSLATE_NOOP("Stats", "Headings"),
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Stats", "Characters, No Spaces"),
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text, No Spaces"),
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings, No Spaces"),
nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words"),
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in Text"),
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in Headings"),
}
BUILD_FMT = {
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
@@ -366,32 +366,32 @@ class nwLabels:
nwBuildFmt.J_NWD: ".json",
}
SHAPES_PLAIN = {
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Shape", "Square"),
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Shape", "Triangle"),
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Shape", "Nabla"),
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Shape", "Diamond"),
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Shape", "Pentagon"),
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Shape", "Hexagon"),
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Shape", "Star"),
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Shape", "Pacman"),
}
SHAPES_CIRCLE = {
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Shape", "1/4 Circle"),
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Shape", "Half Circle"),
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Shape", "3/4 Circle"),
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Shape", "Full Circle"),
}
SHAPES_BARS = {
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Shape", "1 Bar"),
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Shape", "2 Bars"),
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Shape", "3 Bars"),
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Shape", "4 Bars"),
}
SHAPES_BLOCKS = {
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Shape", "1 Block"),
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Shape", "2 Blocks"),
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Shape", "3 Blocks"),
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Shape", "4 Blocks"),
}
FILE_FILTERS = {
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
+1 -1
View File
@@ -608,7 +608,7 @@ class GuiPreferences(NDialog):
self.narratorBreak.setText(CONFIG.narratorBreak)
self.mainForm.addRow(
self.tr("Narrator break symbol"), self.narratorBreak,
self.tr("Symbol to indicate a narrator break in dialogue")
self.tr("Symbol to indicate a narrator break in dialogue.")
)
self.narratorDialog = QLineEdit(self)
+1 -1
View File
@@ -76,7 +76,7 @@ class NWErrorMessage(QDialog):
font = QFont()
font.setPointSize(round(0.9*self.font().pointSize()))
font.setFamily(QFontDatabase.systemFont(QFontDatabase.FixedFont).family())
font.setFamily(QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont).family())
self.msgBody = QPlainTextEdit()
self.msgBody.setFont(font)
+4 -4
View File
@@ -946,11 +946,11 @@ class Tokenizer(ABC):
titleCount = self._counts.get(nwStats.TITLES, 0)
paragraphCount = self._counts.get(nwStats.PARAGRAPHS, 0)
allWords = self._counts.get(nwStats.WORDS_ALL, 0)
allWords = self._counts.get(nwStats.WORDS, 0)
textWords = self._counts.get(nwStats.WORDS_TEXT, 0)
titleWords = self._counts.get(nwStats.WORDS_TITLE, 0)
allChars = self._counts.get(nwStats.CHARS_ALL, 0)
allChars = self._counts.get(nwStats.CHARS, 0)
textChars = self._counts.get(nwStats.CHARS_TEXT, 0)
titleChars = self._counts.get(nwStats.CHARS_TITLE, 0)
@@ -1004,11 +1004,11 @@ class Tokenizer(ABC):
self._counts[nwStats.TITLES] = titleCount
self._counts[nwStats.PARAGRAPHS] = paragraphCount
self._counts[nwStats.WORDS_ALL] = allWords
self._counts[nwStats.WORDS] = allWords
self._counts[nwStats.WORDS_TEXT] = textWords
self._counts[nwStats.WORDS_TITLE] = titleWords
self._counts[nwStats.CHARS_ALL] = allChars
self._counts[nwStats.CHARS] = allChars
self._counts[nwStats.CHARS_TEXT] = textChars
self._counts[nwStats.CHARS_TITLE] = titleChars
+2 -2
View File
@@ -65,8 +65,8 @@ class GuiItemDetails(QWidget):
fntValue = self.font()
fntValue.setPointSizeF(0.9*fPt)
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
# Label
+2 -2
View File
@@ -815,8 +815,8 @@ class GuiOutlineDetails(QScrollArea):
bFont = SHARED.theme.guiFontB
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
# Details Area
+1 -8
View File
@@ -133,12 +133,8 @@ class GuiProjectSearch(QWidget):
self.headerBox.setContentsMargins(0, 0, 0, 0)
self.headerBox.setSpacing(0)
self.headerWidget = QWidget(self)
self.headerWidget.setLayout(self.headerBox)
self.headerWidget.setContentsMargins(0, 0, 0, 0)
self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.headerWidget, 0)
self.outerBox.addLayout(self.headerBox, 0)
self.outerBox.addWidget(self.searchText, 0)
self.outerBox.addWidget(self.searchResult, 1)
self.outerBox.setContentsMargins(0, 0, 0, 0)
@@ -164,9 +160,6 @@ class GuiProjectSearch(QWidget):
colBase = cssCol(qPalette.base().color())
colFocus = cssCol(qPalette.highlight().color())
self.headerWidget.setStyleSheet(f"QWidget {{background: {colBase};}}")
self.headerWidget.setAutoFillBackground(True)
self.setStyleSheet(
"QToolBar {padding: 0; background: none;} "
f"QLineEdit {{border: {bPx}px solid {colBase}; padding: {mPx}px;}} "
+6 -6
View File
@@ -986,17 +986,17 @@ class _StatsWidget(QWidget):
def updateStats(self, data: dict[str, int]) -> None:
"""Update the stats values from a Tokenizer stats dict."""
# Minimal
self.minWordCount.setText("{0:n}".format(data.get(nwStats.WORDS_ALL, 0)))
self.minCharCount.setText("{0:n}".format(data.get(nwStats.CHARS_ALL, 0)))
self.minWordCount.setText("{0:n}".format(data.get(nwStats.WORDS, 0)))
self.minCharCount.setText("{0:n}".format(data.get(nwStats.CHARS, 0)))
# Maximal
self.maxTotalWords.setText("{0:n}".format(data.get(nwStats.WORDS_ALL, 0)))
self.maxTotalWords.setText("{0:n}".format(data.get(nwStats.WORDS, 0)))
self.maxHeadWords.setText("{0:n}".format(data.get(nwStats.WORDS_TITLE, 0)))
self.maxTextWords.setText("{0:n}".format(data.get(nwStats.WORDS_TEXT, 0)))
self.maxTitleCount.setText("{0:n}".format(data.get(nwStats.TITLES, 0)))
self.maxParCount.setText("{0:n}".format(data.get(nwStats.PARAGRAPHS, 0)))
self.maxTotalChars.setText("{0:n}".format(data.get(nwStats.CHARS_ALL, 0)))
self.maxTotalChars.setText("{0:n}".format(data.get(nwStats.CHARS, 0)))
self.maxHeaderChars.setText("{0:n}".format(data.get(nwStats.CHARS_TITLE, 0)))
self.maxTextChars.setText("{0:n}".format(data.get(nwStats.CHARS_TEXT, 0)))
@@ -1037,7 +1037,7 @@ class _StatsWidget(QWidget):
hPx = CONFIG.pxInt(12)
vPx = CONFIG.pxInt(4)
trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
trTextChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TEXT])
trTitleChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TITLE])
trParagraphCount = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
@@ -1045,7 +1045,7 @@ class _StatsWidget(QWidget):
trAllWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_ALL])
trTextWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_TEXT])
trTitleWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_TITLE])
trAllWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
trAllWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
trTextWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_TEXT])
trTitleWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_TITLE])
+6 -6
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.6b2" hexVersion="0x020600b2" fileVersion="1.5" fileRevision="4" timeStamp="2025-01-08 01:15:46">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2297" autoCount="287" editTime="98390">
<novelWriterXML appVersion="2.7a0" hexVersion="0x020700a0" fileVersion="1.5" fileRevision="4" timeStamp="2025-01-10 01:59:38">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2149" autoCount="281" editTime="95624">
<name>Sample Project</name>
<author>Jane Smith</author>
</project>
@@ -42,11 +42,11 @@
<name status="sc24b8f" import="ia857f0">Novel</name>
</item>
<item handle="53b69b83cdafc" parent="7031beac91f75" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H1" charCount="148" wordCount="29" paraCount="4" cursorPos="227" />
<meta expanded="no" heading="H1" charCount="148" wordCount="29" paraCount="4" cursorPos="178" />
<name status="sc24b8f" import="ia857f0" active="yes">Title Page</name>
</item>
<item handle="974e400180a99" parent="7031beac91f75" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H0" charCount="233" wordCount="47" paraCount="2" cursorPos="30" />
<meta expanded="no" heading="H0" charCount="233" wordCount="47" paraCount="2" cursorPos="194" />
<name status="sf12341" import="ia857f0" active="yes">Page</name>
</item>
<item handle="edca4be2fcaf8" parent="7031beac91f75" root="7031beac91f75" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -58,7 +58,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="65" />
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="1035" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -66,7 +66,7 @@
<name status="s90e6c9" import="ia857f0" active="yes">Another Scene</name>
</item>
<item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H2" charCount="617" wordCount="101" paraCount="3" cursorPos="1182" />
<meta expanded="no" heading="H2" charCount="649" wordCount="101" paraCount="3" cursorPos="1182" />
<name status="s78ea90" import="ia857f0" active="yes">Interlude</name>
</item>
<item handle="96b68994dfa3d" parent="7031beac91f75" root="7031beac91f75" order="5" type="FILE" class="NOVEL" layout="NOTE">