From 78958ed5cfcfc1951699f4ed22ae7ed4d43399b9 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 11 Mar 2024 23:26:16 +0100 Subject: [PATCH] Add hard scene break formatting --- novelwriter/core/buildsettings.py | 4 +++ novelwriter/core/docbuild.py | 4 +++ novelwriter/core/tokenizer.py | 17 +++++++++-- novelwriter/tools/manussettings.py | 45 +++++++++++++++++++++++++++--- sample/content/bc0cbd2a407f3.nwd | 6 ++-- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 8557a523..d033c83f 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -56,8 +56,10 @@ SETTINGS_TEMPLATE = { "headings.fmtChapter": (str, nwHeadFmt.TITLE), "headings.fmtUnnumbered": (str, nwHeadFmt.TITLE), "headings.fmtScene": (str, "* * *"), + "headings.fmtHardScene": (str, ""), "headings.fmtSection": (str, ""), "headings.hideScene": (bool, False), + "headings.hideHardScene": (bool, False), "headings.hideSection": (bool, True), "headings.centerTitle": (bool, True), "headings.centerChapter": (bool, False), @@ -104,8 +106,10 @@ SETTINGS_LABELS = { "headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Headings"), "headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Headings"), "headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Headings"), + "headings.fmtHardScene": QT_TRANSLATE_NOOP("Builds", "Hard Scene Headings"), "headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Headings"), "headings.hideScene": QT_TRANSLATE_NOOP("Builds", "Hide Scene Headings"), + "headings.hideHardScene": QT_TRANSLATE_NOOP("Builds", "Hide Hard Scene Headings"), "headings.hideSection": QT_TRANSLATE_NOOP("Builds", "Hide Section Headings"), "text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"), diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py index f36d7345..23b10791 100644 --- a/novelwriter/core/docbuild.py +++ b/novelwriter/core/docbuild.py @@ -282,6 +282,10 @@ class NWBuildDocument: self._build.getStr("headings.fmtScene"), self._build.getBool("headings.hideScene") ) + bldObj.setHardSceneFormat( + self._build.getStr("headings.fmtHardScene"), + self._build.getBool("headings.hideHardScene") + ) bldObj.setSectionFormat( self._build.getStr("headings.fmtSection"), self._build.getBool("headings.hideSection") diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py index 55d89637..e1ee5550 100644 --- a/novelwriter/core/tokenizer.py +++ b/novelwriter/core/tokenizer.py @@ -156,9 +156,11 @@ class Tokenizer(ABC): self._fmtChapter = nwHeadFmt.TITLE # Formatting for numbered chapters self._fmtUnNum = nwHeadFmt.TITLE # Formatting for unnumbered chapters self._fmtScene = nwHeadFmt.TITLE # Formatting for scenes + self._fmtHScene = nwHeadFmt.TITLE # Formatting for hard scenes self._fmtSection = nwHeadFmt.TITLE # Formatting for sections self._hideScene = False # Do not include scene headings + self._hideHScene = False # Do not include hard scene headings self._hideSection = False # Do not include section headings self._linkHeaders = False # Add an anchor before headings @@ -254,6 +256,12 @@ class Tokenizer(ABC): self._hideScene = hide return + def setHardSceneFormat(self, hFormat: str, hide: bool) -> None: + """Set the hard scene format pattern and hidden status.""" + self._fmtHScene = hFormat.strip() + self._hideHScene = hide + return + def setSectionFormat(self, hFormat: str, hide: bool) -> None: """Set the section format pattern and hidden status.""" self._fmtSection = hFormat.strip() @@ -603,7 +611,7 @@ class Tokenizer(ABC): if self._keepMarkdown: tmpMarkdown.append(f"{aLine}\n") - elif aLine[:4] == "### ": + elif aLine[:4] == "### " or aLine[:5] == "###! ": # Scene Headings # ============== # Scene headings in novel documents are treated as centred @@ -619,12 +627,15 @@ class Tokenizer(ABC): tText = aLine[4:].strip() tType = self.T_HEAD3 tStyle = self.A_NONE + isHard = aLine[:5] == "###! " + sHide = self._hideHScene if isHard else self._hideScene + fScene = self._fmtHScene if isHard else self._fmtScene if self._isNovel: self._hFormatter.incScene() - tText = self._hFormatter.apply(self._fmtScene, tText, nHead) + tText = self._hFormatter.apply(fScene, tText, nHead) tStyle = self._sceneStyle if tText == "": - tType = self.T_EMPTY if self._noSep or self._hideScene else self.T_SKIP + tType = self.T_EMPTY if self._noSep or sHide else self.T_SKIP tStyle = self.A_NONE elif tText == self._fmtScene: tText = "" if self._noSep else tText diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index 14a3d529..a0f9c75d 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -584,7 +584,8 @@ class _HeadingsTab(NScrollablePage): EDIT_CHAPTER = 2 EDIT_UNNUM = 3 EDIT_SCENE = 4 - EDIT_SECTION = 5 + EDIT_HSCENE = 5 + EDIT_SECTION = 6 def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) @@ -677,6 +678,33 @@ class _HeadingsTab(NScrollablePage): self.formatBox.addLayout(wrapScene, 3, 1) self.formatBox.addLayout(wrapSceneHide, 3, 2) + # Alt Scene Heading + hardSceneHideTip = self._build.getLabel("headings.hideHardScene") + self.lblHScene = QLabel(self._build.getLabel("headings.fmtHardScene")) + self.fmtHScene = QLineEdit("", self) + self.fmtHScene.setReadOnly(True) + self.btnHScene = QToolButton(self) + self.btnHScene.setIcon(SHARED.theme.getIcon("edit")) + self.btnHScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE)) + self.hdeHScene = QLabel(self.tr("Hide")) + self.hdeHScene.setToolTip(hardSceneHideTip) + self.swtHScene = NSwitch(self, height=iPx) + self.swtHScene.setToolTip(hardSceneHideTip) + + wrapHScene = QHBoxLayout() + wrapHScene.addWidget(self.fmtHScene) + wrapHScene.addWidget(self.btnHScene) + wrapHScene.setSpacing(bSp) + + wrapHSceneHide = QHBoxLayout() + wrapHSceneHide.addWidget(self.hdeHScene) + wrapHSceneHide.addWidget(self.swtHScene) + wrapHSceneHide.setSpacing(bSp) + + self.formatBox.addWidget(self.lblHScene, 4, 0) + self.formatBox.addLayout(wrapHScene, 4, 1) + self.formatBox.addLayout(wrapHSceneHide, 4, 2) + # Section Heading sectionHideTip = self._build.getLabel("headings.hideSection") self.lblSection = QLabel(self._build.getLabel("headings.fmtSection")) @@ -700,9 +728,9 @@ class _HeadingsTab(NScrollablePage): wrapSectionHide.addWidget(self.swtSection) wrapSectionHide.setSpacing(bSp) - self.formatBox.addWidget(self.lblSection, 4, 0) - self.formatBox.addLayout(wrapSection, 4, 1) - self.formatBox.addLayout(wrapSectionHide, 4, 2) + self.formatBox.addWidget(self.lblSection, 5, 0) + self.formatBox.addLayout(wrapSection, 5, 1) + self.formatBox.addLayout(wrapSectionHide, 5, 2) # Edit Form # ========= @@ -830,8 +858,10 @@ class _HeadingsTab(NScrollablePage): self.fmtChapter.setText(self._build.getStr("headings.fmtChapter")) self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered")) self.fmtScene.setText(self._build.getStr("headings.fmtScene")) + self.fmtHScene.setText(self._build.getStr("headings.fmtHardScene")) self.fmtSection.setText(self._build.getStr("headings.fmtSection")) self.swtScene.setChecked(self._build.getBool("headings.hideScene")) + self.swtHScene.setChecked(self._build.getBool("headings.hideHardScene")) self.swtSection.setChecked(self._build.getBool("headings.hideSection")) self.centerTitle.setChecked(self._build.getBool("headings.centerTitle")) self.centerChapter.setChecked(self._build.getBool("headings.centerChapter")) @@ -844,6 +874,7 @@ class _HeadingsTab(NScrollablePage): def saveContent(self) -> None: """Save choices back into build object.""" self._build.setValue("headings.hideScene", self.swtScene.isChecked()) + self._build.setValue("headings.hideHardScene", self.swtHScene.isChecked()) self._build.setValue("headings.hideSection", self.swtSection.isChecked()) self._build.setValue("headings.centerTitle", self.centerTitle.isChecked()) self._build.setValue("headings.centerChapter", self.centerChapter.isChecked()) @@ -881,6 +912,9 @@ class _HeadingsTab(NScrollablePage): elif heading == self.EDIT_SCENE: text = self.fmtScene.text() label = self._build.getLabel("headings.fmtScene") + elif heading == self.EDIT_HSCENE: + text = self.fmtHScene.text() + label = self._build.getLabel("headings.fmtHardScene") elif heading == self.EDIT_SECTION: text = self.fmtSection.text() label = self._build.getLabel("headings.fmtSection") @@ -916,6 +950,9 @@ class _HeadingsTab(NScrollablePage): elif heading == self.EDIT_SCENE: self.fmtScene.setText(text) self._build.setValue("headings.fmtScene", text) + elif heading == self.EDIT_HSCENE: + self.fmtHScene.setText(text) + self._build.setValue("headings.fmtHardScene", text) elif heading == self.EDIT_SECTION: self.fmtSection.setText(text) self._build.setValue("headings.fmtSection", text) diff --git a/sample/content/bc0cbd2a407f3.nwd b/sample/content/bc0cbd2a407f3.nwd index 00642bba..2b51fe91 100644 --- a/sample/content/bc0cbd2a407f3.nwd +++ b/sample/content/bc0cbd2a407f3.nwd @@ -1,8 +1,8 @@ %%~name: Another Scene %%~path: 6a2d6d5f4f401/bc0cbd2a407f3 %%~kind: NOVEL/DOCUMENT -%%~hash: b3f9e4b097f7041c77489876577014c435a8be0c -%%~date: Unknown/2023-08-25 16:51:57 +%%~hash: d35e2629876e627b1a2418affa40d477022984f8 +%%~date: Unknown/2024-03-11 22:56:28 ### Another Scene @pov: John @@ -13,7 +13,7 @@ Adding more scenes to a chapter is as easy as adding more scene files with a lev In fact, if you wish, you can add all the scenes in the chapter file too. All novelWriter cares about is the level of the headings and the order in which they appear. -### More Scenes +###! More Scenes @pov: Jane @focus: John