Add search bar to preferences
This commit is contained in:
@@ -26,12 +26,12 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtGui import QCloseEvent, QFont
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QFont, QKeyEvent, QKeySequence, QPalette
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractButton, QDialog, QHBoxLayout, QVBoxLayout, QWidget, QComboBox,
|
||||
QSpinBox, QPushButton, QDialogButtonBox, QLineEdit, QFileDialog,
|
||||
QFontDialog, QDoubleSpinBox, qApp
|
||||
QAbstractButton, QComboBox, QCompleter, QDialog, QDialogButtonBox,
|
||||
QDoubleSpinBox, QFileDialog, QFontDialog, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QSpinBox, QVBoxLayout, QWidget, qApp
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
@@ -58,37 +58,80 @@ class GuiPreferences(QDialog):
|
||||
self.setMinimumSize(CONFIG.pxInt(600), CONFIG.pxInt(500))
|
||||
self.resize(*CONFIG.preferencesWinSize)
|
||||
|
||||
# Title
|
||||
font = self.font()
|
||||
font.setPointSizeF(1.5*SHARED.theme.fontPointSize)
|
||||
|
||||
palette = self.palette()
|
||||
palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.helpText))
|
||||
|
||||
self.titleLabel = QLabel(self.tr("Preferences"), self)
|
||||
self.titleLabel.setFont(font)
|
||||
self.titleLabel.setPalette(palette)
|
||||
self.titleLabel.setIndent(CONFIG.pxInt(4))
|
||||
|
||||
# SideBar
|
||||
self.sidebar = NPagedSideBar(self)
|
||||
self.sidebar.setLabelColor(SHARED.theme.helpText)
|
||||
self.sidebar.addLabel(self.tr("Preferences"))
|
||||
self.sidebar.buttonClicked.connect(self._sidebarClicked)
|
||||
|
||||
# Search Box
|
||||
self.searchText = QLineEdit(self)
|
||||
self.searchText.setPlaceholderText(self.tr("Search"))
|
||||
self.searchText.setMinimumWidth(CONFIG.pxInt(200))
|
||||
self.searchAction = self.searchText.addAction(
|
||||
SHARED.theme.getIcon("search"), QLineEdit.ActionPosition.TrailingPosition
|
||||
)
|
||||
self.searchAction.triggered.connect(self._gotoSearch)
|
||||
|
||||
self.searchBox = QHBoxLayout()
|
||||
self.searchBox.addWidget(self.titleLabel)
|
||||
self.searchBox.addStretch(1)
|
||||
self.searchBox.addWidget(self.searchText, 1)
|
||||
|
||||
# Form
|
||||
self.mainForm = NScrollableForm(self)
|
||||
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
||||
|
||||
# Buttons
|
||||
self.buttonBox = QDialogButtonBox(
|
||||
QDialogButtonBox.Apply | QDialogButtonBox.Save | QDialogButtonBox.Close
|
||||
QDialogButtonBox.StandardButton.Apply
|
||||
| QDialogButtonBox.StandardButton.Save
|
||||
| QDialogButtonBox.StandardButton.Close
|
||||
)
|
||||
self.buttonBox.clicked.connect(self._dialogButtonClicked)
|
||||
|
||||
# Assemble
|
||||
self.mainSearch = QVBoxLayout()
|
||||
self.mainSearch.addItem(self.searchBox)
|
||||
self.mainSearch.addWidget(self.mainForm)
|
||||
|
||||
self.mainBox = QHBoxLayout()
|
||||
self.mainBox.addWidget(self.sidebar)
|
||||
# self.mainBox.addLayout(self.mainSearch)
|
||||
self.mainBox.addWidget(self.mainForm)
|
||||
self.mainBox.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addLayout(self.searchBox)
|
||||
self.outerBox.addLayout(self.mainBox)
|
||||
self.outerBox.addWidget(self.buttonBox)
|
||||
self.outerBox.setSpacing(CONFIG.pxInt(8))
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
self.setSizeGripEnabled(True)
|
||||
|
||||
# Build Form
|
||||
self.buildForm()
|
||||
|
||||
# Populate Search
|
||||
self.searchCompleter = QCompleter(self.mainForm.labels, self)
|
||||
self.searchCompleter.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
|
||||
self.searchCompleter.setFilterMode(Qt.MatchFlag.MatchContains)
|
||||
self.searchCompleter.activated.connect(self._gotoSearch)
|
||||
|
||||
self.searchText.setCompleter(self.searchCompleter)
|
||||
|
||||
logger.debug("Ready: GuiPreferences")
|
||||
|
||||
return
|
||||
@@ -768,9 +811,17 @@ class GuiPreferences(QDialog):
|
||||
logger.debug("Close: GuiPreferences")
|
||||
self._saveWindowSize()
|
||||
event.accept()
|
||||
qApp.processEvents()
|
||||
self.deleteLater()
|
||||
return
|
||||
|
||||
def keyPressEvent(self, event: QKeyEvent) -> None:
|
||||
"""Overload keyPressEvent to block enter key to save."""
|
||||
if event.matches(QKeySequence.Cancel):
|
||||
self.reject()
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
@@ -794,6 +845,12 @@ class GuiPreferences(QDialog):
|
||||
self.mainForm.scrollToSection(section)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _gotoSearch(self) -> None:
|
||||
"""Go to the setting indicated by the search text."""
|
||||
self.mainForm.scrollToLabel(self.searchText.text().strip())
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectGuiFont(self) -> None:
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
@@ -972,7 +1029,6 @@ class GuiPreferences(QDialog):
|
||||
# Finalise
|
||||
CONFIG.saveConfig()
|
||||
self.newPreferencesReady.emit(needsRestart, refreshTree, updateTheme, updateSyntax)
|
||||
qApp.processEvents()
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ novelWriter – Custom Widget: Config Layout
|
||||
==========================================
|
||||
|
||||
File History:
|
||||
Created: 2020-05-03 [0.4.5]
|
||||
Created: 2020-05-03 [0.4.5] NConfigLayout, NHelpLabel
|
||||
Created: 2023-05-23 [2.1b1] NSimpleLayout
|
||||
Created: 2024-01-08 [2.3b1] NScrollableForm
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
@@ -45,6 +47,7 @@ class NScrollableForm(QScrollArea):
|
||||
self._fontScale = FONT_SCALE
|
||||
self._sections: dict[int, QLabel] = {}
|
||||
self._editable: dict[str, NHelpLabel] = {}
|
||||
self._index: dict[str, QWidget] = {}
|
||||
|
||||
self._layout = QVBoxLayout()
|
||||
self._layout.setSpacing(CONFIG.pxInt(12))
|
||||
@@ -59,6 +62,18 @@ class NScrollableForm(QScrollArea):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def labels(self) -> list[str]:
|
||||
return list(self._index.keys())
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setHelpTextStyle(self, color: QColor | list | tuple, scale: float = FONT_SCALE) -> None:
|
||||
"""Set the text color for the help text."""
|
||||
self._helpCol = color if isinstance(color, QColor) else QColor(*color)
|
||||
@@ -71,18 +86,24 @@ class NScrollableForm(QScrollArea):
|
||||
qHelp.setText(text)
|
||||
return
|
||||
|
||||
def finalise(self) -> None:
|
||||
"""Finalise the layout when the form is built."""
|
||||
self._layout.addStretch(1)
|
||||
return
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def scrollToSection(self, identifier: int, offset: int = 50) -> None:
|
||||
def scrollToSection(self, identifier: int) -> None:
|
||||
"""Scroll to the requested section identifier."""
|
||||
if identifier in self._sections:
|
||||
yPos = self._sections[identifier].pos().y() - CONFIG.pxInt(8)
|
||||
self.verticalScrollBar().setValue(yPos)
|
||||
return
|
||||
|
||||
def scrollToLabel(self, label: str) -> None:
|
||||
"""Scroll to the requested label."""
|
||||
if label in self._index:
|
||||
yPos = self._index[label].pos().y() - CONFIG.pxInt(8)
|
||||
self.verticalScrollBar().setValue(yPos)
|
||||
return
|
||||
|
||||
def addGroupLabel(self, label: str, identifier: int) -> None:
|
||||
"""Add a text label to separate groups of settings."""
|
||||
hM = CONFIG.pxInt(4)
|
||||
@@ -124,9 +145,15 @@ class NScrollableForm(QScrollArea):
|
||||
row.addWidget(button)
|
||||
|
||||
self._layout.addLayout(row)
|
||||
self._index[label.strip()] = widget
|
||||
|
||||
return
|
||||
|
||||
def finalise(self) -> None:
|
||||
"""Finalise the layout when the form is built."""
|
||||
self._layout.addStretch(1)
|
||||
return
|
||||
|
||||
# END Class NScrollableForm
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user