diff --git a/novelwriter/assets/i18n/project_en_GB.json b/novelwriter/assets/i18n/project_en_GB.json index 39d52e6e..19cdda1e 100644 --- a/novelwriter/assets/i18n/project_en_GB.json +++ b/novelwriter/assets/i18n/project_en_GB.json @@ -14,6 +14,7 @@ "Objects": "Objects", "Entities": "Entities", "Custom": "Custom", + "New Page": "New Page", "0": "Zero", "1": "One", "2": "Two", diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py index 7161a794..96d88145 100644 --- a/novelwriter/core/docbuild.py +++ b/novelwriter/core/docbuild.py @@ -87,15 +87,6 @@ class NWBuildDocument: """ return self._cache - ## - # Setters - ## - - def setBuildOutline(self, state: bool) -> None: - """Turn on/off outline for builds.""" - self._outline = state - return - ## # Special Methods ## @@ -122,11 +113,12 @@ class NWBuildDocument: self._queue.append(item.itemHandle) return - def iterBuildPreview(self) -> Iterable[tuple[int, bool]]: + def iterBuildPreview(self, newPage: bool) -> Iterable[tuple[int, bool]]: """Build a preview QTextDocument.""" makeObj = ToQTextDocument(self._project) filtered = self._setupBuild(makeObj) makeObj.initDocument() + makeObj.setShowNewPage(newPage) self._outline = True yield from self._iterBuild(makeObj, filtered) makeObj.closeDocument() @@ -352,14 +344,17 @@ class NWBuildDocument: tItem = self._project.tree[tHandle] if isinstance(tItem, NWItem): try: - if tItem.isRootType() and not tItem.isNovelLike(): - bldObj.addRootHeading(tHandle) - if convert: - bldObj.doConvert() - if self._count: - bldObj.countStats() - if self._outline: - bldObj.buildOutline() + if tItem.isRootType(): + if tItem.isNovelLike(): + bldObj.setBreakNext() + else: + bldObj.addRootHeading(tHandle) + if convert: + bldObj.doConvert() + if self._count: + bldObj.countStats() + if self._outline: + bldObj.buildOutline() elif tItem.isFileType(): bldObj.setText(tHandle) bldObj.doPreProcessing() @@ -370,8 +365,6 @@ class NWBuildDocument: bldObj.buildOutline() if convert: bldObj.doConvert() - else: - logger.info(f"Build: Skipping '{tHandle}'") except Exception: self._error = f"Build: Failed to build '{tHandle}'" diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py index 419e4ec2..35bd72d4 100644 --- a/novelwriter/core/options.py +++ b/novelwriter/core/options.py @@ -60,7 +60,7 @@ VALID_MAP: dict[str, set[str]] = { }, "GuiManuscript": { "winWidth", "winHeight", "optsWidth", "viewWidth", "listHeight", - "detailsHeight", "detailsWidth", "detailsExpanded", + "detailsHeight", "detailsWidth", "detailsExpanded", "showNewPage", }, "GuiManuscriptBuild": { "winWidth", "winHeight", "fmtWidth", "sumWidth", diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index cad13292..25399053 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -48,6 +48,7 @@ from novelwriter.core.buildsettings import BuildCollection, BuildSettings from novelwriter.core.docbuild import NWBuildDocument from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog from novelwriter.extensions.progressbars import NProgressCircle +from novelwriter.extensions.switch import NSwitch from novelwriter.formats.tokenizer import HeadingFormatter from novelwriter.formats.toqdoc import ToQTextDocument from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON @@ -87,6 +88,7 @@ class GuiManuscript(NToolDialog): self.setMinimumWidth(CONFIG.pxInt(600)) self.setMinimumHeight(CONFIG.pxInt(500)) + iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize wWin = CONFIG.pxInt(900) hWin = CONFIG.pxInt(600) @@ -191,15 +193,31 @@ class GuiManuscript(NToolDialog): self.processBox.addWidget(self.btnBuild, 1, 0) self.processBox.addWidget(self.btnClose, 1, 1) + # Preview Options + # =============== + + self.swtNewPage = NSwitch(self, height=iPx) + self.swtNewPage.setChecked(pOptions.getBool("GuiManuscript", "showNewPage", True)) + self.swtNewPage.clicked.connect(self._generatePreview) + + self.lblNewPage = QLabel(self.tr("Show Page Breaks"), self) + self.lblNewPage.setBuddy(self.swtNewPage) + # Assemble GUI # ============ self.docPreview = _PreviewWidget(self) self.docStats = _StatsWidget(self) + self.docBar = QHBoxLayout() + self.docBar.addWidget(self.docStats, 1, QtAlignTop) + self.docBar.addWidget(self.lblNewPage, 0, QtAlignTop) + self.docBar.addWidget(self.swtNewPage, 0, QtAlignTop) + self.docBar.setContentsMargins(0, 0, 0, 0) + self.docBox = QVBoxLayout() self.docBox.addWidget(self.docPreview, 1) - self.docBox.addWidget(self.docStats, 0) + self.docBox.addLayout(self.docBar, 0) self.docBox.setContentsMargins(0, 0, 0, 0) self.docWdiget = QWidget(self) @@ -344,6 +362,7 @@ class GuiManuscript(NToolDialog): return start = time() + showNewPage = self.swtNewPage.isChecked() # Make sure editor content is saved before we start SHARED.saveEditor() @@ -352,7 +371,7 @@ class GuiManuscript(NToolDialog): docBuild.queueAll() self.docPreview.beginNewBuild(len(docBuild)) - for step, _ in docBuild.iterBuildPreview(): + for step, _ in docBuild.iterBuildPreview(showNewPage): self.docPreview.buildStep(step + 1) QApplication.processEvents() @@ -434,6 +453,7 @@ class GuiManuscript(NToolDialog): detailsHeight = CONFIG.rpxInt(buildSplit[1]) detailsWidth = CONFIG.rpxInt(self.buildDetails.getColumnWidth()) detailsExpanded = self.buildDetails.getExpandedState() + showNewPage = self.swtNewPage.isChecked() logger.debug("Saving State: GuiManuscript") pOptions = SHARED.project.options @@ -445,6 +465,7 @@ class GuiManuscript(NToolDialog): pOptions.setValue("GuiManuscript", "detailsHeight", detailsHeight) pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth) pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded) + pOptions.setValue("GuiManuscript", "showNewPage", showNewPage) pOptions.saveSettings() return @@ -945,7 +966,7 @@ class _StatsWidget(QWidget): self.toggleButton = NIconToggleButton(self, SHARED.theme.baseIconSize, "unfold") self.toggleButton.toggled.connect(self._toggleView) - self._buildStatsPanel() + self._buildBottomPanel() self.mainStack = QStackedWidget(self) self.mainStack.addWidget(self.minWidget) @@ -1010,8 +1031,8 @@ class _StatsWidget(QWidget): # Internal Functions ## - def _buildStatsPanel(self) -> None: - """Build the minimal stats page.""" + def _buildBottomPanel(self) -> None: + """Build the bottom page.""" mPx = CONFIG.pxInt(8) hPx = CONFIG.pxInt(12) vPx = CONFIG.pxInt(4) diff --git a/tests/test_core/test_core_docbuild.py b/tests/test_core/test_core_docbuild.py index 04ec4e75..cbb6c52f 100644 --- a/tests/test_core/test_core_docbuild.py +++ b/tests/test_core/test_core_docbuild.py @@ -88,7 +88,7 @@ def testCoreDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstP build.unpack(BUILD_CONF) docBuild = NWBuildDocument(project, build) - docBuild.setBuildOutline(True) + docBuild._outline = True docBuild.queueAll() assert docBuild._outline is True diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index df528751..6d94477a 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -48,7 +48,7 @@ def testToolManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd): buildTestProject(nwGUI, projPath) nwGUI.openProject(projPath) SHARED.project.storage.getDocument(C.hChapterDoc).writeDocument("## A Chapter\n\n\t\tHi") - allText = "New Novel\nBy Jane Doe\nA Chapter\n\t\tHi" + allText = "New Novel\nBy Jane Doe\n\nNew Page\nA Chapter\n\t\tHi" nwGUI.mainMenu.aBuildManuscript.activate(QAction.ActionEvent.Trigger) qtbot.waitUntil(lambda: SHARED.findTopLevelWidget(GuiManuscript) is not None, timeout=1000)