Update buttons and manuscript build (#2553)

This commit is contained in:
Veronica Berglyd Olsen
2025-10-27 21:12:59 +01:00
committed by GitHub
8 changed files with 80 additions and 40 deletions
+1 -1
View File
@@ -56,7 +56,7 @@ VALID_MAP: dict[str, set[str]] = {
"GuiWordList": {"winWidth", "winHeight"},
"GuiNovelView": {"lastCol", "lastColSize"},
"GuiBuildSettings": {
"winWidth", "winHeight", "treeWidth", "filterWidth",
"winWidth", "winHeight", "treeWidth", "filterWidth", "autoPreview",
},
"GuiManuscript": {
"winWidth", "winHeight", "optsWidth", "viewWidth", "listHeight",
+5 -5
View File
@@ -158,7 +158,7 @@ class GuiPreferences(NDialog):
self.mainForm.addGroupLabel(title, section)
# Display Language
self.guiLocale = NComboBox(self, scrollable=True)
self.guiLocale = NComboBox(self)
self.guiLocale.setMinimumWidth(200)
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
self.guiLocale.addItem(name, lang)
@@ -170,9 +170,9 @@ class GuiPreferences(NDialog):
)
# Colour Theme
self.lightTheme = NComboBox(self, scrollable=True)
self.lightTheme = NComboBox(self)
self.lightTheme.setMinimumWidth(200)
self.darkTheme = NComboBox(self, scrollable=True)
self.darkTheme = NComboBox(self)
self.darkTheme.setMinimumWidth(200)
for key, theme in SHARED.theme.colourThemes.items():
if theme.dark:
@@ -193,7 +193,7 @@ class GuiPreferences(NDialog):
)
# Icon Theme
self.iconTheme = NComboBox(self, scrollable=True)
self.iconTheme = NComboBox(self)
self.iconTheme.setMinimumWidth(200)
for key, theme in SHARED.theme.iconCache.iconThemes.items():
self.iconTheme.addItem(theme.name, key)
@@ -513,7 +513,7 @@ class GuiPreferences(NDialog):
self.mainForm.addGroupLabel(title, section)
# Spell Checking
self.spellLanguage = NComboBox(self, scrollable=True)
self.spellLanguage = NComboBox(self)
self.spellLanguage.setMinimumWidth(200)
if CONFIG.hasEnchant:
+2 -2
View File
@@ -257,7 +257,7 @@ class _SettingsPage(NScrollableForm):
# Project Language
projLang = data.language or CONFIG.guiLocale
self.projLang = NComboBox(self, scrollable=True)
self.projLang = NComboBox(self)
self.projLang.setMinimumWidth(200)
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
self.projLang.addItem(language, tag)
@@ -269,7 +269,7 @@ class _SettingsPage(NScrollableForm):
)
# Spell Check Language
self.spellLang = NComboBox(self, scrollable=True)
self.spellLang = NComboBox(self)
self.spellLang.setMinimumWidth(200)
self.spellLang.addItem(self.tr("Default"), "None")
if CONFIG.hasEnchant:
+8 -7
View File
@@ -125,16 +125,11 @@ class NComboBox(QComboBox):
window of many widgets.
"""
def __init__(
self, parent: QWidget | None = None, maxItems: int = 15, scrollable: bool = False
) -> None:
def __init__(self, parent: QWidget | None = None, maxItems: int = 15) -> None:
super().__init__(parent=parent)
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
self.setMaxVisibleItems(maxItems)
if scrollable:
# The style sheet disables Fusion style pop-up mode on some
# platforms and allows for scrolling of long lists of items
self.setStyleSheet("QComboBox {combobox-popup: 0;}")
self.updateStyle()
def wheelEvent(self, event: QWheelEvent) -> None:
"""Only capture the mouse wheel if the widget has focus."""
@@ -148,6 +143,12 @@ class NComboBox(QComboBox):
idx = self.findData(data)
self.setCurrentIndex(self.findData(default) if idx < 0 else idx)
def updateStyle(self) -> None:
"""Update the style sheet."""
# The style sheet disables Fusion style pop-up mode on some
# platforms and allows for scrolling of long lists of items
self.setStyleSheet("QComboBox {combobox-popup: 0;}")
class NSpinBox(QSpinBox):
"""Custom: Modified QSpinBox.
+17 -14
View File
@@ -92,10 +92,10 @@ class GuiManuscript(NToolDialog):
iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize
pOptions = SHARED.project.options
options = SHARED.project.options
self.resize(
pOptions.getInt("GuiManuscript", "winWidth", 900),
pOptions.getInt("GuiManuscript", "winHeight", 600),
options.getInt("GuiManuscript", "winWidth", 900),
options.getInt("GuiManuscript", "winHeight", 600),
)
# Build Controls
@@ -142,7 +142,7 @@ class GuiManuscript(NToolDialog):
# ============
self.buildDetails = _DetailsWidget(self)
self.buildDetails.setColumnWidth(pOptions.getInt("GuiManuscript", "detailsWidth", 100))
self.buildDetails.setColumnWidth(options.getInt("GuiManuscript", "detailsWidth", 100))
self.buildOutline = _OutlineWidget(self)
@@ -154,8 +154,8 @@ class GuiManuscript(NToolDialog):
self.buildSplit.addWidget(self.buildList)
self.buildSplit.addWidget(self.detailsTabs)
self.buildSplit.setSizes([
pOptions.getInt("GuiManuscript", "listHeight", 50),
pOptions.getInt("GuiManuscript", "detailsHeight", 50),
options.getInt("GuiManuscript", "listHeight", 50),
options.getInt("GuiManuscript", "detailsHeight", 50),
])
# Process Controls
@@ -183,7 +183,7 @@ class GuiManuscript(NToolDialog):
# ===============
self.swtNewPage = NSwitch(self, height=iPx)
self.swtNewPage.setChecked(pOptions.getBool("GuiManuscript", "showNewPage", True))
self.swtNewPage.setChecked(options.getBool("GuiManuscript", "showNewPage", True))
self.swtNewPage.clicked.connect(self._generatePreview)
self.lblNewPage = QLabel(self.tr("Show Page Breaks"), self)
@@ -226,8 +226,8 @@ class GuiManuscript(NToolDialog):
self.mainSplit.setStretchFactor(0, 0)
self.mainSplit.setStretchFactor(1, 1)
self.mainSplit.setSizes([
pOptions.getInt("GuiManuscript", "optsWidth", 225),
pOptions.getInt("GuiManuscript", "viewWidth", 675),
options.getInt("GuiManuscript", "optsWidth", 225),
options.getInt("GuiManuscript", "viewWidth", 675),
])
self.outerBox = QVBoxLayout()
@@ -273,7 +273,7 @@ class GuiManuscript(NToolDialog):
self.tbAdd.setThemeIcon("add", "add")
self.tbDel.setThemeIcon("remove", "remove")
self.tbCopy.setThemeIcon("copy", "accept")
self.tbCopy.setThemeIcon("copy", "action")
self.tbEdit.setThemeIcon("edit", "change")
buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
@@ -352,13 +352,16 @@ class GuiManuscript(NToolDialog):
self._builds.removeBuild(build.buildID)
self._updateBuildsList()
@pyqtSlot(BuildSettings)
def _processNewSettings(self, build: BuildSettings) -> None:
@pyqtSlot(BuildSettings, bool)
def _processNewSettings(self, build: BuildSettings, refreshPreview: bool) -> None:
"""Process new build settings from the settings dialog."""
self._builds.setBuild(build)
self._updateBuildItem(build)
if (current := self.buildList.currentItem()) and current.data(self.D_KEY) == build.buildID:
self._updateBuildDetails(current, current)
if refreshPreview:
self.buildList.setCurrentItem(self._buildMap[build.buildID])
self._generatePreview()
elif (item := self.buildList.currentItem()) and item.data(self.D_KEY) == build.buildID:
self._updateBuildDetails(item, item)
@pyqtSlot()
def _generatePreview(self) -> None:
+28 -9
View File
@@ -72,7 +72,7 @@ class GuiBuildSettings(NToolDialog):
OPT_HEADINGS = 2
OPT_FORMATTING = 10
newSettingsReady = pyqtSignal(BuildSettings)
newSettingsReady = pyqtSignal(BuildSettings, bool)
def __init__(self, parent: GuiMain, build: BuildSettings) -> None:
super().__init__(parent=parent)
@@ -86,6 +86,7 @@ class GuiBuildSettings(NToolDialog):
self.setWindowTitle(self.tr("Manuscript Build Settings"))
self.setMinimumSize(700, 400)
iPx = SHARED.theme.baseIconHeight
options = SHARED.project.options
self.resize(
options.getInt("GuiBuildSettings", "winWidth", 750),
@@ -124,6 +125,13 @@ class GuiBuildSettings(NToolDialog):
self.toolStack.addWidget(self.optTabHeadings)
self.toolStack.addWidget(self.optTabFormatting)
# Preview
self.swtAutoPreview = NSwitch(self, height=iPx)
self.swtAutoPreview.setChecked(options.getBool("GuiBuildSettings", "autoPreview", True))
self.lblAutoPreview = QLabel(self.tr("Auro-Update Preview"), self)
self.lblAutoPreview.setBuddy(self.swtAutoPreview)
# Buttons
self.btnApply = SHARED.theme.getStandardButton(nwStandardButton.APPLY, self)
self.btnSave = SHARED.theme.getStandardButton(nwStandardButton.SAVE, self)
@@ -147,10 +155,17 @@ class GuiBuildSettings(NToolDialog):
self.mainBox.addWidget(self.toolStack)
self.mainBox.setContentsMargins(0, 0, 0, 0)
self.bottomBox = QHBoxLayout()
self.bottomBox.addWidget(self.lblAutoPreview, 0)
self.bottomBox.addWidget(self.swtAutoPreview, 0)
self.bottomBox.addSpacing(8)
self.bottomBox.addWidget(self.btnBox, 1)
self.bottomBox.setContentsMargins(0, 0, 0, 0)
self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.topBox)
self.outerBox.addLayout(self.mainBox)
self.outerBox.addWidget(self.btnBox)
self.outerBox.addLayout(self.bottomBox)
self.outerBox.setSpacing(12)
self.setLayout(self.outerBox)
@@ -259,12 +274,13 @@ class GuiBuildSettings(NToolDialog):
"""Save the various user settings."""
treeWidth, filterWidth = self.optTabSelect.mainSplitSizes()
logger.debug("Saving State: GuiBuildSettings")
pOptions = SHARED.project.options
pOptions.setValue("GuiBuildSettings", "winWidth", self.width())
pOptions.setValue("GuiBuildSettings", "winHeight", self.height())
pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth)
pOptions.setValue("GuiBuildSettings", "filterWidth", filterWidth)
pOptions.saveSettings()
options = SHARED.project.options
options.setValue("GuiBuildSettings", "winWidth", self.width())
options.setValue("GuiBuildSettings", "winHeight", self.height())
options.setValue("GuiBuildSettings", "treeWidth", treeWidth)
options.setValue("GuiBuildSettings", "filterWidth", filterWidth)
options.setValue("GuiBuildSettings", "autoPreview", self.swtAutoPreview.isChecked())
options.saveSettings()
def _applyChanges(self) -> None:
"""Apply all settings changes to the build object."""
@@ -274,7 +290,7 @@ class GuiBuildSettings(NToolDialog):
def _emitBuildData(self) -> None:
"""Assemble the build data and emit the signal."""
self.newSettingsReady.emit(self._build)
self.newSettingsReady.emit(self._build, self.swtAutoPreview.isChecked())
self._build.resetChangedState()
@@ -1329,6 +1345,9 @@ class _FormattingTab(NScrollableForm):
self.pixH.setPixmap(SHARED.theme.getPixmap("fit_height", (iPx, iPx)))
self.pixW.setPixmap(SHARED.theme.getPixmap("fit_width", (iPx, iPx)))
self.pageSize.updateStyle()
self.pageUnit.updateStyle()
def loadContent(self) -> None:
"""Populate the widgets."""
# Text Content
+18 -1
View File
@@ -108,10 +108,11 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
bSettings = SHARED.findTopLevelWidget(GuiBuildSettings)
assert isinstance(bSettings, GuiBuildSettings)
bSettings.editBuildName.setText("Test Build")
bSettings.swtAutoPreview.setChecked(False)
build = None
@pyqtSlot(BuildSettings)
def _testNewSettingsReady(new: BuildSettings):
def _testNewSettingsReady(new: BuildSettings, refresh: bool):
nonlocal build
build = new
@@ -151,6 +152,22 @@ def testToolManuscript_Builds(qtbot, nwGUI, projPath):
assert new is not None
assert new.name == "Test Build 2"
# Processing first build with refresh should change selection
manus.docPreview._docTime = 0
manus._processNewSettings(build, True)
assert manus.docPreview._docTime > 0 # Refreshed
current = manus._getSelectedBuild()
assert current is not None
assert current.name == "Test Build"
# Processing new build without refresh should keep selection
manus.docPreview._docTime = 0
manus._processNewSettings(new, False)
assert manus.docPreview._docTime == 0 # No refresh
current = manus._getSelectedBuild()
assert current is not None
assert current.name == "Test Build"
# Trigger a theme update, which should propagate to settings
nwGUI.refreshThemeColors()
+1 -1
View File
@@ -69,7 +69,7 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
triggered = False
@pyqtSlot(BuildSettings)
def _testNewSettingsReady(new: BuildSettings):
def _testNewSettingsReady(new: BuildSettings, refresh: bool):
nonlocal triggered
assert new.buildID == build.buildID
triggered = True