From 309065bcbf7852facef9c0a82981e680b1d20aab Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 May 2024 09:14:34 +0200 Subject: [PATCH 01/11] Add general keep line breaks setting to build --- novelwriter/core/buildsettings.py | 2 ++ novelwriter/tools/manussettings.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index f7392e26..5449db6b 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -82,6 +82,7 @@ SETTINGS_TEMPLATE = { "format.justifyText": (bool, False), "format.stripUnicode": (bool, False), "format.replaceTabs": (bool, False), + "format.keepBreaks": (bool, True), "format.firstLineIndent": (bool, False), "format.firstIndentWidth": (float, 1.4), "format.indentFirstPar": (bool, False), @@ -132,6 +133,7 @@ SETTINGS_LABELS = { "format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"), "format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"), "format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"), + "format.keepBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"), "format.grpParIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"), "format.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "Enable Indent"), diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index dca739f9..b575a9ae 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -1098,10 +1098,12 @@ class _FormatTab(NScrollableForm): self.justifyText = NSwitch(self, height=iPx) self.stripUnicode = NSwitch(self, height=iPx) self.replaceTabs = NSwitch(self, height=iPx) + self.keepBreaks = NSwitch(self, height=iPx) self.addRow(self._build.getLabel("format.justifyText"), self.justifyText) self.addRow(self._build.getLabel("format.stripUnicode"), self.stripUnicode) self.addRow(self._build.getLabel("format.replaceTabs"), self.replaceTabs) + self.addRow(self._build.getLabel("format.keepBreaks"), self.keepBreaks) # First Line Indent # ================= @@ -1184,6 +1186,7 @@ class _FormatTab(NScrollableForm): self.justifyText.setChecked(self._build.getBool("format.justifyText")) self.stripUnicode.setChecked(self._build.getBool("format.stripUnicode")) self.replaceTabs.setChecked(self._build.getBool("format.replaceTabs")) + self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks")) self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent")) self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth")) @@ -1223,6 +1226,7 @@ class _FormatTab(NScrollableForm): self._build.setValue("format.justifyText", self.justifyText.isChecked()) self._build.setValue("format.stripUnicode", self.stripUnicode.isChecked()) self._build.setValue("format.replaceTabs", self.replaceTabs.isChecked()) + self._build.setValue("format.keepBreaks", self.keepBreaks.isChecked()) self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked()) self._build.setValue("format.firstIndentWidth", self.indentWidth.value()) From 04a7e092a93e8046e7aa49dc95e58bc423f792c3 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 May 2024 16:55:05 +0200 Subject: [PATCH 02/11] Clean up Markdown build code --- novelwriter/core/buildsettings.py | 4 --- novelwriter/core/docbuild.py | 9 ++---- novelwriter/core/tomarkdown.py | 30 ++++++-------------- novelwriter/tools/manussettings.py | 8 ------ tests/test_core/test_core_tohtml.py | 10 ++----- tests/test_core/test_core_tokenizer.py | 2 +- tests/test_core/test_core_tomarkdown.py | 12 ++++---- tests/test_core/test_core_toodt.py | 2 -- tests/test_tools/test_tools_manussettings.py | 3 -- 9 files changed, 18 insertions(+), 62 deletions(-) diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 5449db6b..932dc0f7 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -97,7 +97,6 @@ SETTINGS_TEMPLATE = { "odt.addColours": (bool, True), "odt.pageHeader": (str, nwHeadFmt.ODT_AUTO), "odt.pageCountOffset": (int, 0), - "md.preserveBreaks": (bool, True), "html.addStyles": (bool, True), "html.preserveTabs": (bool, False), } @@ -155,9 +154,6 @@ SETTINGS_LABELS = { "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"), "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"), - "md": QT_TRANSLATE_NOOP("Builds", "Markdown (.md)"), - "md.preserveBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"), - "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"), "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"), "html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"), diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py index c65ac0be..a2a2ba87 100644 --- a/novelwriter/core/docbuild.py +++ b/novelwriter/core/docbuild.py @@ -216,16 +216,10 @@ class NWBuildDocument: makeObj = ToMarkdown(self._project) filtered = self._setupBuild(makeObj) - if extendedMd: - makeObj.setExtendedMarkdown() - else: - makeObj.setStandardMarkdown() - + makeObj.setExtendedMarkdown(extendedMd) if self._build.getBool("format.replaceTabs"): makeObj.replaceTabs(nSpaces=4, spaceChar=" ") - makeObj.setPreserveBreaks(self._build.getBool("md.preserveBreaks")) - for i, tHandle in enumerate(self._queue): self._error = None if filtered.get(tHandle, (False, 0))[0]: @@ -333,6 +327,7 @@ class NWBuildDocument: bldObj.setFont(fontFamily, textSize, textFixed) bldObj.setJustify(self._build.getBool("format.justifyText")) bldObj.setLineHeight(self._build.getFloat("format.lineHeight")) + bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks")) bldObj.setFirstLineIndent( self._build.getBool("format.firstLineIndent"), self._build.getFloat("format.firstIndentWidth"), diff --git a/novelwriter/core/tomarkdown.py b/novelwriter/core/tomarkdown.py index 440da0e0..eccf2300 100644 --- a/novelwriter/core/tomarkdown.py +++ b/novelwriter/core/tomarkdown.py @@ -81,15 +81,11 @@ class ToMarkdown(Tokenizer): supports concatenating novelWriter markup files. """ - M_STD = 0 # Standard Markdown - M_EXT = 1 # Extended Markdown - def __init__(self, project: NWProject) -> None: super().__init__(project) - self._genMode = self.M_STD self._fullMD: list[str] = [] - self._preserveBreaks = True self._usedNotes: dict[str, int] = {} + self._extended = True return ## @@ -105,19 +101,9 @@ class ToMarkdown(Tokenizer): # Setters ## - def setStandardMarkdown(self) -> None: - """Set the converter to use standard Markdown formatting.""" - self._genMode = self.M_STD - return - - def setExtendedMarkdown(self) -> None: + def setExtendedMarkdown(self, state: bool) -> None: """Set the converter to use Extended Markdown formatting.""" - self._genMode = self.M_EXT - return - - def setPreserveBreaks(self, state: bool) -> None: - """Preserve line breaks in paragraphs.""" - self._preserveBreaks = state + self._extended = state return ## @@ -132,12 +118,12 @@ class ToMarkdown(Tokenizer): """Convert the list of text tokens into a Markdown document.""" self._result = "" - if self._genMode == self.M_STD: - mTags = STD_MD - cSkip = "" - else: + if self._extended: mTags = EXT_MD cSkip = nwUnicode.U_MMSP + else: + mTags = STD_MD + cSkip = "" lines = [] for tType, _, tText, tFormat, tStyle in self._tokens: @@ -195,7 +181,7 @@ class ToMarkdown(Tokenizer): def appendFootnotes(self) -> None: """Append the footnotes in the buffer.""" if self._usedNotes: - tags = STD_MD if self._genMode == self.M_STD else EXT_MD + tags = EXT_MD if self._extended else STD_MD footnotes = self._localLookup("Footnotes") lines = [] diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index b575a9ae..e49bb546 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -1383,12 +1383,6 @@ class _OutputTab(NScrollableForm): self.htmlPreserveTabs = NSwitch(self, height=iPx) self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs) - # Markdown Document - self.addGroupLabel(self._build.getLabel("md")) - - self.mdPreserveBreaks = NSwitch(self, height=iPx) - self.addRow(self._build.getLabel("md.preserveBreaks"), self.mdPreserveBreaks) - # Finalise self.finalise() @@ -1401,7 +1395,6 @@ class _OutputTab(NScrollableForm): self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset")) self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles")) self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs")) - self.mdPreserveBreaks.setChecked(self._build.getBool("md.preserveBreaks")) self.odtPageHeader.setCursorPosition(0) return @@ -1412,7 +1405,6 @@ class _OutputTab(NScrollableForm): self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value()) self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked()) self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked()) - self._build.setValue("md.preserveBreaks", self.mdPreserveBreaks.isChecked()) return ## diff --git a/tests/test_core/test_core_tohtml.py b/tests/test_core/test_core_tohtml.py index 2cea3328..c02e833c 100644 --- a/tests/test_core/test_core_tohtml.py +++ b/tests/test_core/test_core_tohtml.py @@ -316,7 +316,6 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Title html._tokens = [ (html.T_TITLE, 1, "A Title", [], html.A_PBB | html.A_CENTRE), - (html.T_EMPTY, 1, "", [], html.A_NONE), ] html.doConvert() assert html.result == ( @@ -327,7 +326,6 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Unnumbered html._tokens = [ (html.T_HEAD2, 1, "Prologue", [], html.A_PBB), - (html.T_EMPTY, 1, "", [], html.A_NONE), ] html.doConvert() assert html.result == ( @@ -341,7 +339,6 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Separator html._tokens = [ (html.T_SEP, 1, "* * *", [], html.A_CENTRE), - (html.T_EMPTY, 1, "", [], html.A_NONE), ] html.doConvert() assert html.result == "
* * *
\n" @@ -349,7 +346,6 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Skip html._tokens = [ (html.T_SKIP, 1, "", [], html.A_NONE), - (html.T_EMPTY, 1, "", [], html.A_NONE), ] html.doConvert() assert html.result == "\n" @@ -425,8 +421,7 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Indent Left html._tokens = [ - (html.T_TEXT, 1, "Some text ...", [], html.A_IND_L), - (html.T_EMPTY, 2, "", [], html.A_NONE), + (html.T_TEXT, 1, "Some text ...", [], html.A_IND_L), ] html.doConvert() assert html.result == ( @@ -435,8 +430,7 @@ def testCoreToHtml_ConvertDirect(mockGUI): # Indent Right html._tokens = [ - (html.T_TEXT, 1, "Some text ...", [], html.A_IND_R), - (html.T_EMPTY, 2, "", [], html.A_NONE), + (html.T_TEXT, 1, "Some text ...", [], html.A_IND_R), ] html.doConvert() assert html.result == ( diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index 388b8843..5e45916e 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -1835,7 +1835,7 @@ def testCoreToken_SceneSeparators(mockGUI): # =========================== # Requires a fresh builder class md = ToMarkdown(project) - md.setExtendedMarkdown() + md.setExtendedMarkdown(True) md._isNovel = True md._text = ( diff --git a/tests/test_core/test_core_tomarkdown.py b/tests/test_core/test_core_tomarkdown.py index 8547f778..8ef04caf 100644 --- a/tests/test_core/test_core_tomarkdown.py +++ b/tests/test_core/test_core_tomarkdown.py @@ -82,7 +82,7 @@ def testCoreToMarkdown_ConvertParagraphs(mockGUI): toMD._isFirst = True # Text for Extended Markdown - toMD.setExtendedMarkdown() + toMD.setExtendedMarkdown(True) toMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n" toMD.tokenizeText() toMD.doConvert() @@ -91,7 +91,7 @@ def testCoreToMarkdown_ConvertParagraphs(mockGUI): ) # Text for Standard Markdown - toMD.setStandardMarkdown() + toMD.setExtendedMarkdown(False) toMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n" toMD.tokenizeText() toMD.doConvert() @@ -100,7 +100,7 @@ def testCoreToMarkdown_ConvertParagraphs(mockGUI): ) # Shortcodes for Extended Markdown - toMD.setExtendedMarkdown() + toMD.setExtendedMarkdown(True) toMD._text = ( "Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], " "super[sup]script[/sup], sub[sub]script[/sub] here\n" @@ -113,7 +113,7 @@ def testCoreToMarkdown_ConvertParagraphs(mockGUI): ) # Shortcodes for Standard Markdown - toMD.setStandardMarkdown() + toMD.setExtendedMarkdown(False) toMD._text = ( "Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], " "super[sup]script[/sup], sub[sub]script[/sub] here\n" @@ -215,6 +215,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI): toMD = ToMarkdown(project) toMD._isNovel = True + toMD.setExtendedMarkdown(False) # Special Titles # ============== @@ -222,7 +223,6 @@ def testCoreToMarkdown_ConvertDirect(mockGUI): # Title toMD._tokens = [ (toMD.T_TITLE, 1, "A Title", [], toMD.A_PBB | toMD.A_CENTRE), - (toMD.T_EMPTY, 1, "", [], toMD.A_NONE), ] toMD.doConvert() assert toMD.result == "# A Title\n\n" @@ -233,7 +233,6 @@ def testCoreToMarkdown_ConvertDirect(mockGUI): # Separator toMD._tokens = [ (toMD.T_SEP, 1, "* * *", [], toMD.A_CENTRE), - (toMD.T_EMPTY, 1, "", [], toMD.A_NONE), ] toMD.doConvert() assert toMD.result == "* * *\n\n" @@ -241,7 +240,6 @@ def testCoreToMarkdown_ConvertDirect(mockGUI): # Skip toMD._tokens = [ (toMD.T_SKIP, 1, "", [], toMD.A_NONE), - (toMD.T_EMPTY, 1, "", [], toMD.A_NONE), ] toMD.doConvert() assert toMD.result == "\n\n" diff --git a/tests/test_core/test_core_toodt.py b/tests/test_core/test_core_toodt.py index 19f2fd20..59977577 100644 --- a/tests/test_core/test_core_toodt.py +++ b/tests/test_core/test_core_toodt.py @@ -683,7 +683,6 @@ def testCoreToOdt_ConvertDirect(mockGUI): doc = ToOdt(project, isFlat=True) doc._tokens = [ (doc.T_TEXT, 1, "This is a paragraph", [], doc.A_JUSTIFY), - (doc.T_EMPTY, 1, "", [], doc.A_NONE), ] doc.initDocument() doc.doConvert() @@ -704,7 +703,6 @@ def testCoreToOdt_ConvertDirect(mockGUI): doc = ToOdt(project, isFlat=True) doc._tokens = [ (doc.T_TEXT, 1, "This is a paragraph", [], doc.A_PBA), - (doc.T_EMPTY, 1, "", [], doc.A_NONE), ] doc.initDocument() doc.doConvert() diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py index 1d1ef591..e1b12202 100644 --- a/tests/test_tools/test_tools_manussettings.py +++ b/tests/test_tools/test_tools_manussettings.py @@ -677,13 +677,11 @@ def testBuildSettings_Output(qtbot, nwGUI): assert outTab.odtPageCountOffset.value() == 0 assert outTab.htmlAddStyles.isChecked() is False assert outTab.htmlPreserveTabs.isChecked() is False - assert outTab.mdPreserveBreaks.isChecked() is True # Toggle all outTab.odtAddColours.setChecked(True) outTab.htmlAddStyles.setChecked(True) outTab.htmlPreserveTabs.setChecked(True) - outTab.mdPreserveBreaks.setChecked(False) # Change Values outTab.odtPageCountOffset.setValue(1) @@ -697,7 +695,6 @@ def testBuildSettings_Output(qtbot, nwGUI): assert build.getInt("odt.pageCountOffset") == 1 assert build.getBool("html.addStyles") is True assert build.getBool("html.preserveTabs") is True - assert build.getBool("md.preserveBreaks") is False # Reset header format outTab.btnPageHeader.click() From c63a0c2f5863f16afbb34b55d01ec11074b67651 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 May 2024 16:55:36 +0200 Subject: [PATCH 03/11] Add new font and quote button icons --- novelwriter/assets/icons/typicons_dark/icons.conf | 2 ++ novelwriter/assets/icons/typicons_dark/nw_font.svg | 4 ++++ novelwriter/assets/icons/typicons_dark/nw_quote.svg | 4 ++++ novelwriter/assets/icons/typicons_light/icons.conf | 2 ++ novelwriter/assets/icons/typicons_light/nw_font.svg | 4 ++++ novelwriter/assets/icons/typicons_light/nw_quote.svg | 4 ++++ novelwriter/gui/theme.py | 6 +++--- 7 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 novelwriter/assets/icons/typicons_dark/nw_font.svg create mode 100644 novelwriter/assets/icons/typicons_dark/nw_quote.svg create mode 100644 novelwriter/assets/icons/typicons_light/nw_font.svg create mode 100644 novelwriter/assets/icons/typicons_light/nw_quote.svg diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf index 28d72c83..a4f8cf16 100644 --- a/novelwriter/assets/icons/typicons_dark/icons.conf +++ b/novelwriter/assets/icons/typicons_dark/icons.conf @@ -59,6 +59,7 @@ fmt_strike-md = nw_tb-strike-md.svg fmt_subscript = nw_tb-subscript.svg fmt_superscript = nw_tb-superscript.svg fmt_underline = nw_tb-underline.svg +font = nw_font.svg forward = typ_chevron-right.svg import = mixed_import.svg list = typ_th-list.svg @@ -78,6 +79,7 @@ proj_scene = mixed_document-scene.svg proj_section = mixed_document-section.svg proj_stats = typ_chart-bar-grey.svg proj_title = mixed_document-title.svg +quote = nw_quote.svg refresh = typ_refresh.svg remove = typ_minus.svg revert = typ_refresh-flipped.svg diff --git a/novelwriter/assets/icons/typicons_dark/nw_font.svg b/novelwriter/assets/icons/typicons_dark/nw_font.svg new file mode 100644 index 00000000..588dd615 --- /dev/null +++ b/novelwriter/assets/icons/typicons_dark/nw_font.svg @@ -0,0 +1,4 @@ + + diff --git a/novelwriter/assets/icons/typicons_dark/nw_quote.svg b/novelwriter/assets/icons/typicons_dark/nw_quote.svg new file mode 100644 index 00000000..db50fcb4 --- /dev/null +++ b/novelwriter/assets/icons/typicons_dark/nw_quote.svg @@ -0,0 +1,4 @@ + + diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf index 1af2ee60..022f417e 100644 --- a/novelwriter/assets/icons/typicons_light/icons.conf +++ b/novelwriter/assets/icons/typicons_light/icons.conf @@ -59,6 +59,7 @@ fmt_strike-md = nw_tb-strike-md.svg fmt_subscript = nw_tb-subscript.svg fmt_superscript = nw_tb-superscript.svg fmt_underline = nw_tb-underline.svg +font = nw_font.svg forward = typ_chevron-right.svg import = mixed_import.svg list = typ_th-list.svg @@ -78,6 +79,7 @@ proj_scene = mixed_document-scene.svg proj_section = mixed_document-section.svg proj_stats = typ_chart-bar-grey.svg proj_title = mixed_document-title.svg +quote = nw_quote.svg refresh = typ_refresh.svg remove = typ_minus.svg revert = typ_refresh-flipped.svg diff --git a/novelwriter/assets/icons/typicons_light/nw_font.svg b/novelwriter/assets/icons/typicons_light/nw_font.svg new file mode 100644 index 00000000..987f2fc6 --- /dev/null +++ b/novelwriter/assets/icons/typicons_light/nw_font.svg @@ -0,0 +1,4 @@ + + diff --git a/novelwriter/assets/icons/typicons_light/nw_quote.svg b/novelwriter/assets/icons/typicons_light/nw_quote.svg new file mode 100644 index 00000000..bdf76e81 --- /dev/null +++ b/novelwriter/assets/icons/typicons_light/nw_quote.svg @@ -0,0 +1,4 @@ + + diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index a986f86a..72a95178 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -501,9 +501,9 @@ class GuiIcons: # General Button Icons "add", "add_document", "backward", "bookmark", "browse", "checked", "close", "cross", - "document", "down", "edit", "export", "forward", "import", "list", "maximise", "menu", - "minimise", "more", "noncheckable", "open", "panel", "refresh", "remove", "revert", - "search_replace", "search", "settings", "star", "unchecked", "up", "view", + "document", "down", "edit", "export", "font", "forward", "import", "list", "maximise", + "menu", "minimise", "more", "noncheckable", "open", "panel", "quote", "refresh", "remove", + "revert", "search_replace", "search", "settings", "star", "unchecked", "up", "view", # Switches "sticky-on", "sticky-off", From 7e1f1a725cb5786c19caf5bbbd2ff62b65e5303e Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 May 2024 16:57:50 +0200 Subject: [PATCH 04/11] Switch Tokenizer to use QFont instead of font family and size --- novelwriter/core/buildsettings.py | 6 ++-- novelwriter/core/docbuild.py | 13 +++------ novelwriter/core/tokenizer.py | 12 ++++---- novelwriter/dialogs/preferences.py | 12 ++++---- novelwriter/tools/manuscript.py | 24 +++++++--------- novelwriter/tools/manussettings.py | 40 ++++++++++---------------- novelwriter/types.py | 35 +++++++++++++++++++++- tests/test_core/test_core_tokenizer.py | 12 ++++---- 8 files changed, 81 insertions(+), 73 deletions(-) diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 932dc0f7..aa295b6b 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -76,8 +76,7 @@ SETTINGS_TEMPLATE = { "text.includeBodyText": (bool, True), "text.ignoredKeywords": (str, ""), "text.addNoteHeadings": (bool, True), - "format.textFont": (str, CONFIG.textFont.family()), - "format.textSize": (int, 12), + "format.textFont": (str, CONFIG.textFont.toString()), "format.lineHeight": (float, 1.15, 0.75, 3.0), "format.justifyText": (bool, False), "format.stripUnicode": (bool, False), @@ -125,8 +124,7 @@ SETTINGS_LABELS = { "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"), "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"), - "format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"), - "format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"), + "format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"), "format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"), "format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"), "format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"), diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py index a2a2ba87..1b5350a8 100644 --- a/novelwriter/core/docbuild.py +++ b/novelwriter/core/docbuild.py @@ -28,7 +28,7 @@ import logging from collections.abc import Iterable from pathlib import Path -from PyQt5.QtGui import QFont, QFontInfo +from PyQt5.QtGui import QFont from novelwriter import CONFIG from novelwriter.constants import nwLabels @@ -279,13 +279,9 @@ class NWBuildDocument: def _setupBuild(self, bldObj: Tokenizer) -> dict: """Configure the build object.""" # Get Settings - textFont = self._build.getStr("format.textFont") - textSize = self._build.getInt("format.textSize") - - fontFamily = textFont or CONFIG.textFont.family() - bldFont = QFont(fontFamily, textSize) - fontInfo = QFontInfo(bldFont) - textFixed = fontInfo.fixedPitch() + textFont = QFont(CONFIG.textFont) + textFont.fromString(self._build.getStr("format.textFont")) + bldObj.setFont(textFont) bldObj.setTitleFormat( self._build.getStr("headings.fmtTitle"), @@ -324,7 +320,6 @@ class NWBuildDocument: self._build.getBool("headings.breakScene") ) - bldObj.setFont(fontFamily, textSize, textFixed) bldObj.setJustify(self._build.getBool("format.justifyText")) bldObj.setLineHeight(self._build.getFloat("format.lineHeight")) bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks")) diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py index 448cb2ed..5eefc616 100644 --- a/novelwriter/core/tokenizer.py +++ b/novelwriter/core/tokenizer.py @@ -34,7 +34,9 @@ from pathlib import Path from time import time from PyQt5.QtCore import QCoreApplication, QRegularExpression +from PyQt5.QtGui import QFont +from novelwriter import CONFIG from novelwriter.common import checkInt, formatTimeStamp, numberToRoman from novelwriter.constants import ( nwHeadFmt, nwKeyWords, nwLabels, nwRegEx, nwShortcode, nwUnicode, trConst @@ -139,9 +141,7 @@ class Tokenizer(ABC): self._markdown: list[str] = [] # User Settings - self._textFont = "Serif" # Output text font - self._textSize = 11 # Output text size - self._textFixed = False # Fixed width text + self._textFont = CONFIG.textFont # Output text font self._lineHeight = 1.15 # Line height in units of em self._blockIndent = 4.00 # Block indent in units of em self._firstIndent = False # Enable first line indent @@ -315,11 +315,9 @@ class Tokenizer(ABC): ) return - def setFont(self, family: str, size: int, isFixed: bool = False) -> None: + def setFont(self, font: QFont) -> None: """Set the build font.""" - self._textFont = family - self._textSize = round(int(size)) - self._textFixed = isFixed + self._textFont = font return def setLineHeight(self, height: float) -> None: diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 3158fa24..affe3117 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -183,7 +183,7 @@ class GuiPreferences(QDialog): self.guiFont.setMinimumWidth(fontWidth) self.guiFont.setText(describeFont(self._guiFont)) self.guiFont.setCursorPosition(0) - self.guiFontButton = NIconToolButton(self, iSz, "more") + self.guiFontButton = NIconToolButton(self, iSz, "font") self.guiFontButton.clicked.connect(self._selectGuiFont) self.mainForm.addRow( self.tr("Application font"), self.guiFont, @@ -233,7 +233,7 @@ class GuiPreferences(QDialog): self.textFont.setMinimumWidth(fontWidth) self.textFont.setText(describeFont(CONFIG.textFont)) self.textFont.setCursorPosition(0) - self.textFontButton = NIconToolButton(self, iSz, "more") + self.textFontButton = NIconToolButton(self, iSz, "font") self.textFontButton.clicked.connect(self._selectTextFont) self.mainForm.addRow( self.tr("Document font"), self.textFont, @@ -695,7 +695,7 @@ class GuiPreferences(QDialog): self.quoteSym["SO"].setFixedWidth(boxFixed) self.quoteSym["SO"].setAlignment(QtAlignCenter) self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen) - self.btnSingleStyleO = NIconToolButton(self, iSz, "more") + self.btnSingleStyleO = NIconToolButton(self, iSz, "quote") self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO")) self.mainForm.addRow( self.tr("Single quote open style"), self.quoteSym["SO"], @@ -709,7 +709,7 @@ class GuiPreferences(QDialog): self.quoteSym["SC"].setFixedWidth(boxFixed) self.quoteSym["SC"].setAlignment(QtAlignCenter) self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose) - self.btnSingleStyleC = NIconToolButton(self, iSz, "more") + self.btnSingleStyleC = NIconToolButton(self, iSz, "quote") self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC")) self.mainForm.addRow( self.tr("Single quote close style"), self.quoteSym["SC"], @@ -724,7 +724,7 @@ class GuiPreferences(QDialog): self.quoteSym["DO"].setFixedWidth(boxFixed) self.quoteSym["DO"].setAlignment(QtAlignCenter) self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen) - self.btnDoubleStyleO = NIconToolButton(self, iSz, "more") + self.btnDoubleStyleO = NIconToolButton(self, iSz, "quote") self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO")) self.mainForm.addRow( self.tr("Double quote open style"), self.quoteSym["DO"], @@ -738,7 +738,7 @@ class GuiPreferences(QDialog): self.quoteSym["DC"].setFixedWidth(boxFixed) self.quoteSym["DC"].setAlignment(QtAlignCenter) self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose) - self.btnDoubleStyleC = NIconToolButton(self, iSz, "more") + self.btnDoubleStyleC = NIconToolButton(self, iSz, "quote") self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC")) self.mainForm.addRow( self.tr("Double quote close style"), self.quoteSym["DC"], diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index ca19e6d0..d70442f0 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -31,7 +31,7 @@ from time import time from typing import TYPE_CHECKING from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot -from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QPalette, QResizeEvent +from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog from PyQt5.QtWidgets import ( QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout, @@ -404,10 +404,10 @@ class GuiManuscript(NToolDialog): """Update the preview widget and set relevant values.""" self.docPreview.setContent(data) self.docPreview.setBuildName(build.name) - self.docPreview.setTextFont( - build.getStr("format.textFont"), - build.getInt("format.textSize") - ) + + textFont = QFont() + textFont.fromString(build.getStr("format.textFont")) + self.docPreview.setTextFont(textFont) self.docPreview.setJustify( build.getBool("format.justifyText") ) @@ -787,7 +787,7 @@ class _PreviewWidget(QTextBrowser): self._updateDocMargins() self._updateBuildAge() - self.setTextFont(CONFIG.textFont.family(), CONFIG.textFont.pointSize()) + self.setTextFont(CONFIG.textFont) # Age Timer self.ageTimer = QTimer(self) @@ -817,18 +817,14 @@ class _PreviewWidget(QTextBrowser): self.document().setDefaultTextOption(pOptions) return - def setTextFont(self, family: str, size: int) -> None: + def setTextFont(self, font: QFont) -> None: """Set the text font properties and then reset for sub-widgets. This needs special attention since there appears to be a bug in Qt 5.15.3. See issues #1862 and #1875. """ - if family and size > 4: - font = self.font() - font.setFamily(family) - font.setPointSize(size) - self.setFont(font) - self.buildProgress.setFont(SHARED.theme.guiFont) - self.ageLabel.setFont(SHARED.theme.guiFontSmall) + self.setFont(font) + self.buildProgress.setFont(SHARED.theme.guiFont) + self.ageLabel.setFont(SHARED.theme.guiFontSmall) return ## diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index e49bb546..53a84be6 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -37,6 +37,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG, SHARED +from novelwriter.common import describeFont from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.extensions.configlayout import ( @@ -1052,6 +1053,7 @@ class _FormatTab(NScrollableForm): self._build = build self._unitScale = 1.0 + self._textFont = QFont(CONFIG.textFont) iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize @@ -1063,24 +1065,16 @@ class _FormatTab(NScrollableForm): self.addGroupLabel(self._build.getLabel("format.grpFormat")) - # Font Family + # Text Font self.textFont = QLineEdit(self) self.textFont.setReadOnly(True) - self.btnTextFont = NIconToolButton(self, iSz, "more") + self.btnTextFont = NIconToolButton(self, iSz, "font") self.btnTextFont.clicked.connect(self._selectFont) self.addRow( self._build.getLabel("format.textFont"), self.textFont, - button=self.btnTextFont, stretch=(3, 2) + button=self.btnTextFont, stretch=(1, 1) ) - # Font Size - self.textSize = NSpinBox(self) - self.textSize.setMinimum(8) - self.textSize.setMaximum(60) - self.textSize.setSingleStep(1) - self.textSize.setMinimumWidth(spW) - self.addRow(self._build.getLabel("format.textSize"), self.textSize, unit="pt") - # Line Height self.lineHeight = NDoubleSpinBox(self) self.lineHeight.setFixedWidth(spW) @@ -1175,14 +1169,13 @@ class _FormatTab(NScrollableForm): def loadContent(self) -> None: """Populate the widgets.""" - textFont = self._build.getStr("format.textFont") - if not textFont: - textFont = str(CONFIG.textFont.family()) + self._textFont = QFont() + self._textFont.fromString(self._build.getStr("format.textFont")) + + self.textFont.setText(describeFont(self._textFont)) + self.textFont.setCursorPosition(0) - self.textFont.setText(textFont) - self.textSize.setValue(self._build.getInt("format.textSize")) self.lineHeight.setValue(self._build.getFloat("format.lineHeight")) - self.justifyText.setChecked(self._build.getBool("format.justifyText")) self.stripUnicode.setChecked(self._build.getBool("format.stripUnicode")) self.replaceTabs.setChecked(self._build.getBool("format.replaceTabs")) @@ -1219,8 +1212,7 @@ class _FormatTab(NScrollableForm): def saveContent(self) -> None: """Save choices back into build object.""" - self._build.setValue("format.textFont", self.textFont.text()) - self._build.setValue("format.textSize", self.textSize.value()) + self._build.setValue("format.textFont", self._textFont.toString()) self._build.setValue("format.lineHeight", self.lineHeight.value()) self._build.setValue("format.justifyText", self.justifyText.isChecked()) @@ -1249,13 +1241,11 @@ class _FormatTab(NScrollableForm): @pyqtSlot() def _selectFont(self) -> None: """Open the QFontDialog and set a font for the font style.""" - currFont = QFont() - currFont.setFamily(self.textFont.text()) - currFont.setPointSize(self.textSize.value()) - newFont, status = QFontDialog.getFont(currFont, self) + font, status = QFontDialog.getFont(self._textFont, self) if status: - self.textFont.setText(newFont.family()) - self.textSize.setValue(newFont.pointSize()) + self.textFont.setText(describeFont(font)) + self.textFont.setCursorPosition(0) + self._textFont = font return @pyqtSlot(int) diff --git a/novelwriter/types.py b/novelwriter/types.py index e4051f8e..d0e8eff9 100644 --- a/novelwriter/types.py +++ b/novelwriter/types.py @@ -24,7 +24,7 @@ along with this program. If not, see