From 855c525670c46a5b0863b5a416a5d8e6a091802a Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 27 Jan 2024 15:22:37 +0100 Subject: [PATCH] Redesign Build Settings tool to match other config dialogs --- novelwriter/extensions/configlayout.py | 13 +- novelwriter/tools/manussettings.py | 120 +++++++++---------- tests/test_tools/test_tools_manuscript.py | 4 +- tests/test_tools/test_tools_manussettings.py | 36 +++--- 4 files changed, 92 insertions(+), 81 deletions(-) diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py index 99d38c03..532db30a 100644 --- a/novelwriter/extensions/configlayout.py +++ b/novelwriter/extensions/configlayout.py @@ -52,7 +52,18 @@ class NFixedPage(QFrame): super().__init__(parent=parent) self.setFrameShadow(QFrame.Shadow.Sunken) self.setFrameShape(QFrame.Shape.StyledPanel) - self.setCentralLayout = self.setLayout + return + + def setCentralLayout(self, layout: QLayout) -> None: + """Set a layout as the central object.""" + self.setLayout(layout) + return + + def setCentralWidget(self, widget: QWidget) -> None: + """Set a layout as the central object.""" + layout = QHBoxLayout() + layout.addWidget(widget) + self.setLayout(layout) return # END Class NFixedPage diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index e0c034af..044b6376 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -42,7 +42,9 @@ from novelwriter.constants import nwHeadFmt, nwLabels, trConst from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switchbox import NSwitchBox -from novelwriter.extensions.configlayout import NConfigLayout, NSimpleLayout +from novelwriter.extensions.configlayout import ( + NColourLabel, NConfigLayout, NFixedPage, NScrollablePage, NSimpleLayout +) from novelwriter.extensions.pagedsidebar import NPagedSideBar if TYPE_CHECKING: # pragma: no cover @@ -90,34 +92,37 @@ class GuiBuildSettings(QDialog): CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winHeight", hWin)) ) - # Options SideBar - # =============== + # Title + self.titleLabel = NColourLabel( + self.tr("Manuscript Build Settings"), SHARED.theme.helpText, + parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4) + ) - self.optSideBar = NPagedSideBar(self) - self.optSideBar.setMinimumWidth(mPx) - self.optSideBar.setMaximumWidth(mPx) - self.optSideBar.setLabelColor(SHARED.theme.helpText) + # Settings Name + self.lblBuildName = QLabel(self.tr("Name")) + self.editBuildName = QLineEdit(self) - self.optSideBar.addLabel(self.tr("Options")) - self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS) - self.optSideBar.addButton(self.tr("Headings"), self.OPT_HEADINGS) - self.optSideBar.addButton(self.tr("Content"), self.OPT_CONTENT) - self.optSideBar.addButton(self.tr("Format"), self.OPT_FORMAT) - self.optSideBar.addButton(self.tr("Output"), self.OPT_OUTPUT) + # SideBar + self.sidebar = NPagedSideBar(self) + self.sidebar.setMinimumWidth(mPx) + self.sidebar.setMaximumWidth(mPx) + self.sidebar.setLabelColor(SHARED.theme.helpText) - self.optSideBar.buttonClicked.connect(self._stackPageSelected) + self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS) + self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS) + self.sidebar.addButton(self.tr("Content"), self.OPT_CONTENT) + self.sidebar.addButton(self.tr("Format"), self.OPT_FORMAT) + self.sidebar.addButton(self.tr("Output"), self.OPT_OUTPUT) - # Options Area - # ============ + self.sidebar.buttonClicked.connect(self._stackPageSelected) - # Create Tabs + # Content self.optTabSelect = _FilterTab(self, self._build) self.optTabHeadings = _HeadingsTab(self, self._build) self.optTabContent = _ContentTab(self, self._build) self.optTabFormat = _FormatTab(self, self._build) self.optTabOutput = _OutputTab(self, self._build) - # Add Tabs self.toolStack = QStackedWidget(self) self.toolStack.addWidget(self.optTabSelect) self.toolStack.addWidget(self.optTabHeadings) @@ -125,38 +130,36 @@ class GuiBuildSettings(QDialog): self.toolStack.addWidget(self.optTabContent) self.toolStack.addWidget(self.optTabOutput) - # Main Settings + Buttons - # ======================= - - self.lblBuildName = QLabel(self.tr("Name")) - self.editBuildName = QLineEdit() - self.dlgButtons = QDialogButtonBox( - QDialogButtonBox.Apply | QDialogButtonBox.Save | QDialogButtonBox.Close + # Buttons + self.buttonBox = QDialogButtonBox( + QDialogButtonBox.StandardButton.Apply + | QDialogButtonBox.StandardButton.Save + | QDialogButtonBox.StandardButton.Close ) - self.dlgButtons.clicked.connect(self._dialogButtonClicked) + self.buttonBox.clicked.connect(self._dialogButtonClicked) - self.buttonBox = QHBoxLayout() - self.buttonBox.addWidget(self.lblBuildName) - self.buttonBox.addWidget(self.editBuildName) - self.buttonBox.addWidget(self.dlgButtons) - - # Assemble GUI - # ============ + # Assemble + self.topBox = QHBoxLayout() + self.topBox.addWidget(self.titleLabel) + self.topBox.addStretch(1) + self.topBox.addWidget(self.lblBuildName) + self.topBox.addWidget(self.editBuildName, 1) self.mainBox = QHBoxLayout() - self.mainBox.addWidget(self.optSideBar) + self.mainBox.addWidget(self.sidebar) self.mainBox.addWidget(self.toolStack) self.mainBox.setContentsMargins(0, 0, 0, 0) self.outerBox = QVBoxLayout() + self.outerBox.addLayout(self.topBox) self.outerBox.addLayout(self.mainBox) - self.outerBox.addLayout(self.buttonBox) + self.outerBox.addWidget(self.buttonBox) self.outerBox.setSpacing(CONFIG.pxInt(12)) self.setLayout(self.outerBox) # Set Default Tab - self.optSideBar.setSelected(self.OPT_FILTERS) + self.sidebar.setSelected(self.OPT_FILTERS) logger.debug("Ready: GuiBuildSettings") @@ -185,6 +188,21 @@ class GuiBuildSettings(QDialog): """The build ID of the build of the dialog.""" return self._build.buildID + ## + # Events + ## + + def closeEvent(self, event: QEvent) -> None: + """Capture the user closing the window so we can save + settings. + """ + logger.debug("Closing: GuiBuildSettings") + self._askToSaveBuild() + self._saveSettings() + event.accept() + self.deleteLater() + return + ## # Private Slots ## @@ -207,7 +225,7 @@ class GuiBuildSettings(QDialog): @pyqtSlot("QAbstractButton*") def _dialogButtonClicked(self, button: QAbstractButton) -> None: """Handle button clicks from the dialog button box.""" - role = self.dlgButtons.buttonRole(button) + role = self.buttonBox.buttonRole(button) if role == QDialogButtonBox.ApplyRole: self._emitBuildData() elif role == QDialogButtonBox.AcceptRole: @@ -217,21 +235,6 @@ class GuiBuildSettings(QDialog): self.close() return - ## - # Events - ## - - def closeEvent(self, event: QEvent) -> None: - """Capture the user closing the window so we can save - settings. - """ - logger.debug("Closing: GuiBuildSettings") - self._askToSaveBuild() - self._saveSettings() - event.accept() - self.deleteLater() - return - ## # Internal Functions ## @@ -279,7 +282,7 @@ class GuiBuildSettings(QDialog): # END Class GuiBuildSettings -class _FilterTab(QWidget): +class _FilterTab(NFixedPage): C_DATA = 0 C_NAME = 0 @@ -395,11 +398,7 @@ class _FilterTab(QWidget): CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "filterWidth", 300)) ]) - self.outerBox = QHBoxLayout() - self.outerBox.addWidget(self.mainSplit) - self.outerBox.setContentsMargins(0, 0, 0, 0) - - self.setLayout(self.outerBox) + self.setCentralWidget(self.mainSplit) return @@ -580,7 +579,7 @@ class _FilterTab(QWidget): # END Class _FilterTab -class _HeadingsTab(QWidget): +class _HeadingsTab(NScrollablePage): EDIT_TITLE = 1 EDIT_CHAPTER = 2 @@ -758,7 +757,7 @@ class _HeadingsTab(QWidget): self.outerBox.addLayout(self.editFormBox) self.outerBox.addStretch(1) - self.setLayout(self.outerBox) + self.setCentralLayout(self.outerBox) return @@ -825,6 +824,7 @@ class _HeadingsTab(QWidget): # Private Slots ## + @pyqtSlot() def _saveFormat(self) -> None: """Save the format from the edit text box.""" heading = self._editing diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index ed9eb756..0978ee05 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -116,7 +116,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings.dlgButtons.button(QDialogButtonBox.Save).click() + bSettings.buttonBox.button(QDialogButtonBox.Save).click() assert isinstance(build, BuildSettings) assert build.name == "Test Build" @@ -133,7 +133,7 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings.dlgButtons.button(QDialogButtonBox.Apply).click() # Should leave the dialog open + bSettings.buttonBox.button(QDialogButtonBox.Apply).click() # Should leave the dialog open assert isinstance(build, BuildSettings) assert build.name == "Test Build" diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py index de3a68a0..d347d817 100644 --- a/tests/test_tools/test_tools_manussettings.py +++ b/tests/test_tools/test_tools_manussettings.py @@ -53,19 +53,19 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd bSettings.loadContent() # Flip through pages - bSettings.optSideBar._group.button(bSettings.OPT_OUTPUT).click() + bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() assert isinstance(bSettings.toolStack.currentWidget(), _OutputTab) - bSettings.optSideBar._group.button(bSettings.OPT_FORMAT).click() + bSettings.sidebar._group.button(bSettings.OPT_FORMAT).click() assert isinstance(bSettings.toolStack.currentWidget(), _FormatTab) - bSettings.optSideBar._group.button(bSettings.OPT_CONTENT).click() + bSettings.sidebar._group.button(bSettings.OPT_CONTENT).click() assert isinstance(bSettings.toolStack.currentWidget(), _ContentTab) - bSettings.optSideBar._group.button(bSettings.OPT_HEADINGS).click() + bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click() assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab) - bSettings.optSideBar._group.button(bSettings.OPT_FILTERS).click() + bSettings.sidebar._group.button(bSettings.OPT_FILTERS).click() assert isinstance(bSettings.toolStack.currentWidget(), _FilterTab) # Check dialog buttons @@ -80,7 +80,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd # Capture Apply button with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Apply)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Apply)) assert triggered @@ -89,7 +89,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000): bSettings.newSettingsReady.connect(_testNewSettingsReady) - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Save)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Save)) assert triggered @@ -106,7 +106,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd assert triggered # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Init @@ -141,7 +141,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR bSettings.loadContent() filterTab = bSettings.optTabSelect - bSettings.optSideBar._group.button(bSettings.OPT_FILTERS).click() + bSettings.sidebar._group.button(bSettings.OPT_FILTERS).click() assert bSettings.toolStack.currentWidget() is filterTab # Check content @@ -312,7 +312,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR ] # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Filter @@ -343,7 +343,7 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain): bSettings.loadContent() headTab = bSettings.optTabHeadings - bSettings.optSideBar._group.button(bSettings.OPT_HEADINGS).click() + bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click() assert bSettings.toolStack.currentWidget() is headTab # Check initial values @@ -468,7 +468,7 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain): assert build.getBool("headings.hideSection") is True # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Headings @@ -492,7 +492,7 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain): bSettings.loadContent() contTab = bSettings.optTabContent - bSettings.optSideBar._group.button(bSettings.OPT_CONTENT).click() + bSettings.sidebar._group.button(bSettings.OPT_CONTENT).click() assert bSettings.toolStack.currentWidget() is contTab # Check initial values @@ -522,7 +522,7 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain): assert build.getBool("text.addNoteHeadings") is True # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Content @@ -559,7 +559,7 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain): bSettings.loadContent() fmtTab = bSettings.optTabFormat - bSettings.optSideBar._group.button(bSettings.OPT_FORMAT).click() + bSettings.sidebar._group.button(bSettings.OPT_FORMAT).click() assert bSettings.toolStack.currentWidget() is fmtTab # Check initial values @@ -624,7 +624,7 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain): assert fmtTab.textSize.value() == 10 # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Format @@ -644,7 +644,7 @@ def testBuildSettings_Output(qtbot: QtBot, nwGUI: GuiMain): bSettings.loadContent() outTab = bSettings.optTabOutput - bSettings.optSideBar._group.button(bSettings.OPT_OUTPUT).click() + bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() assert bSettings.toolStack.currentWidget() is outTab # Check initial values @@ -662,7 +662,7 @@ def testBuildSettings_Output(qtbot: QtBot, nwGUI: GuiMain): assert build.getBool("html.addStyles") is True # Finish - bSettings._dialogButtonClicked(bSettings.dlgButtons.button(QDialogButtonBox.Close)) + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QDialogButtonBox.Close)) # qtbot.stop() # END Test testBuildSettings_Output