From f6edda3f97b1449e5974e8a2125c6c689b9a6954 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:16:46 +0100 Subject: [PATCH 1/7] Fix theme update for search widget --- novelwriter/gui/search.py | 17 ++++++++--------- novelwriter/types.py | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index fdf5dbe7..644cdd72 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -35,12 +35,12 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import checkInt, cssCol, qtAddAction +from novelwriter.common import checkInt, qtAddAction from novelwriter.core.coretools import DocSearch from novelwriter.core.item import NWItem from novelwriter.types import ( QtAlignMiddle, QtAlignRight, QtHeaderStretch, QtHeaderToContents, - QtUserRole + QtHexArgb, QtUserRole ) logger = logging.getLogger(__name__) @@ -71,6 +71,9 @@ class GuiProjectSearch(QWidget): self._blocked = False self._map: dict[str, tuple[int, float]] = {} + self.setBackgroundRole(QPalette.ColorRole.Base) + self.setAutoFillBackground(True) + # Header self.viewLabel = QLabel(self.tr("Project Search"), self) self.viewLabel.setFont(SHARED.theme.guiFontB) @@ -138,7 +141,6 @@ class GuiProjectSearch(QWidget): self.outerBox.setContentsMargins(0, 0, 0, 0) self.outerBox.setSpacing(2) - self.setAutoFillBackground(True) self.setLayout(self.outerBox) self.updateTheme() @@ -152,12 +154,9 @@ class GuiProjectSearch(QWidget): def updateTheme(self) -> None: """Update theme elements.""" - - qPalette = self.palette() - colBase = cssCol(qPalette.base().color()) - colFocus = cssCol(qPalette.highlight().color()) - qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) - self.setPalette(qPalette) + palette = QApplication.palette() + colBase = palette.base().color().name(QtHexArgb) + colFocus = palette.highlight().color().name(QtHexArgb) self.setStyleSheet( "QToolBar {padding: 0; background: none;} " diff --git a/novelwriter/types.py b/novelwriter/types.py index e1b05ead..057de3c6 100644 --- a/novelwriter/types.py +++ b/novelwriter/types.py @@ -70,6 +70,7 @@ QtSelected = QStyle.StateFlag.State_Selected # Qt Colour Types QtHexRgb = QColor.NameFormat.HexRgb +QtHexArgb = QColor.NameFormat.HexArgb # Qt Tree and Table Types From 5dee5ecefe2aa5e7b120540f795fcbce7cdf3112 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:27:09 +0100 Subject: [PATCH 2/7] Make trees/search consistent again using background role setter --- novelwriter/gui/noveltree.py | 5 +---- novelwriter/gui/projtree.py | 5 +---- novelwriter/gui/search.py | 1 + 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index 8ce78da3..1679a44f 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -201,6 +201,7 @@ class GuiNovelToolBar(QWidget): iSz = SHARED.theme.baseIconSize self.setContentsMargins(0, 0, 0, 0) + self.setBackgroundRole(QPalette.ColorRole.Base) self.setAutoFillBackground(True) # Novel Selector @@ -270,10 +271,6 @@ class GuiNovelToolBar(QWidget): self.tbRefresh.setThemeIcon("refresh", "green") self.tbMore.setThemeIcon("more_vertical") - qPalette = self.palette() - qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) - self.setPalette(qPalette) - # StyleSheets buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) self.tbNovel.setStyleSheet(buttonStyle) diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 0be15929..5e959342 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -245,6 +245,7 @@ class GuiProjectToolBar(QWidget): iSz = SHARED.theme.baseIconSize self.setContentsMargins(0, 0, 0, 0) + self.setBackgroundRole(QPalette.ColorRole.Base) self.setAutoFillBackground(True) # Widget Label @@ -351,10 +352,6 @@ class GuiProjectToolBar(QWidget): def updateTheme(self) -> None: """Update theme elements.""" - qPalette = self.palette() - qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) - self.setPalette(qPalette) - buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) self.tbQuick.setStyleSheet(buttonStyle) self.tbMoveU.setStyleSheet(buttonStyle) diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index 644cdd72..bf403012 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -71,6 +71,7 @@ class GuiProjectSearch(QWidget): self._blocked = False self._map: dict[str, tuple[int, float]] = {} + self.setContentsMargins(0, 0, 0, 0) self.setBackgroundRole(QPalette.ColorRole.Base) self.setAutoFillBackground(True) From eb34a327601e7e976a03b6b93c008a163c5c3809 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:52:26 +0100 Subject: [PATCH 3/7] Clean up background colours in editor and sidebar --- novelwriter/gui/doceditor.py | 31 ++++++++++--------------------- novelwriter/gui/sidebar.py | 5 ----- novelwriter/guimain.py | 2 -- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 753168c1..d4b923ad 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -42,9 +42,9 @@ from PyQt6.QtCore import ( pyqtSlot ) from PyQt6.QtGui import ( - QAction, QColor, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, - QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent, - QShortcut, QTextBlock, QTextCursor, QTextDocument, QTextOption + QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, QKeyEvent, + QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent, QShortcut, + QTextBlock, QTextCursor, QTextDocument, QTextOption ) from PyQt6.QtWidgets import ( QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, @@ -2662,10 +2662,11 @@ class GuiDocEditSearch(QFrame): def updateTheme(self) -> None: """Update theme elements.""" - qPalette = QApplication.palette() - self.setPalette(qPalette) - self.searchBox.setPalette(qPalette) - self.replaceBox.setPalette(qPalette) + palette = QApplication.palette() + + self.setPalette(palette) + self.searchBox.setPalette(palette) + self.replaceBox.setPalette(palette) # Set icons self.toggleCase.setIcon(SHARED.theme.getIcon("search_case")) @@ -2683,21 +2684,9 @@ class GuiDocEditSearch(QFrame): self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}") # Construct Box Colours - qPalette = self.searchBox.palette() - baseCol = qPalette.base().color() - rCol = baseCol.redF() + 0.1 - gCol = baseCol.greenF() - 0.1 - bCol = baseCol.blueF() - 0.1 - - mCol = max(rCol, gCol, bCol, 1.0) - errCol = QColor() - errCol.setRedF(rCol/mCol) - errCol.setGreenF(gCol/mCol) - errCol.setBlueF(bCol/mCol) - self.rxCol = { - True: baseCol, - False: errCol + True: palette.base().color(), + False: SHARED.theme.errorText.darker(200), } return diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index be08f86a..8e6d16f6 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -28,7 +28,6 @@ import logging from typing import TYPE_CHECKING from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal -from PyQt6.QtGui import QPalette from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget from novelwriter import SHARED @@ -125,10 +124,6 @@ class GuiSideBar(QWidget): def updateTheme(self) -> None: """Initialise GUI elements that depend on specific settings.""" - qPalette = self.palette() - qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base()) - self.setPalette(qPalette) - buttonStyle = SHARED.theme.getStyleSheet(STYLES_BIG_TOOLBUTTON) self.tbProject.setStyleSheet(buttonStyle) diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 4dfcbf07..7d15c722 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -1046,8 +1046,6 @@ class GuiMain(QMainWindow): SHARED.project.tree.refreshAllItems() if theme: - # We are doing this manually instead of connecting to - # paletteChanged since the processing order matters SHARED.theme.loadTheme() self.setPalette(QApplication.palette()) self.docEditor.updateTheme() From 34645be975bc72d428b4a799af0c8e069e9d443a Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:52:50 +0100 Subject: [PATCH 4/7] Remove redundant cssCol helper --- novelwriter/common.py | 7 +------ novelwriter/dialogs/about.py | 6 +++--- novelwriter/gui/theme.py | 16 ++++++++------- novelwriter/tools/dictionaries.py | 30 ++++++++++++----------------- novelwriter/tools/welcome.py | 12 ++++++++---- tests/test_base/test_base_common.py | 24 ++++++++--------------- 6 files changed, 41 insertions(+), 54 deletions(-) diff --git a/novelwriter/common.py b/novelwriter/common.py index 50ae5dfd..771b6232 100644 --- a/novelwriter/common.py +++ b/novelwriter/common.py @@ -38,7 +38,7 @@ from urllib.parse import urljoin from urllib.request import pathname2url from PyQt6.QtCore import QCoreApplication, QMimeData, QUrl -from PyQt6.QtGui import QAction, QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo +from PyQt6.QtGui import QAction, QDesktopServices, QFont, QFontDatabase, QFontInfo from PyQt6.QtWidgets import QMenu, QMenuBar, QWidget from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst @@ -417,11 +417,6 @@ def numberToRoman(value: int, toLower: bool = False) -> str: # Qt Helpers ## -def cssCol(col: QColor, alpha: int | None = None) -> str: - """Convert a QColor object to an rgba entry to use in CSS.""" - return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})" - - def describeFont(font: QFont) -> str: """Describe a font in a way that can be displayed on the GUI.""" if isinstance(font, QFont): diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py index 6cc7b8e1..e122fd19 100644 --- a/novelwriter/dialogs/about.py +++ b/novelwriter/dialogs/about.py @@ -31,11 +31,11 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import cssCol, readTextFile +from novelwriter.common import readTextFile from novelwriter.extensions.configlayout import NColorLabel from novelwriter.extensions.modified import NDialog from novelwriter.extensions.versioninfo import VersionInfoWidget -from novelwriter.types import QtAlignRightTop, QtDialogClose +from novelwriter.types import QtAlignRightTop, QtDialogClose, QtHexArgb logger = logging.getLogger(__name__) @@ -135,7 +135,7 @@ class GuiAbout(NDialog): def _setStyleSheet(self) -> None: """Set stylesheet text document.""" - baseCol = cssCol(self.palette().window().color()) + baseCol = self.palette().window().color().name(QtHexArgb) self.txtCredits.setStyleSheet( f"QTextBrowser {{border: none; background: {baseCol};}} " ) diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 2aaacda3..d7578389 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -37,12 +37,12 @@ from PyQt6.QtGui import ( from PyQt6.QtWidgets import QApplication from novelwriter import CONFIG -from novelwriter.common import NWConfigParser, cssCol, minmax +from novelwriter.common import NWConfigParser, minmax from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX from novelwriter.constants import nwLabels from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType from novelwriter.error import logException -from novelwriter.types import QtBlack, QtPaintAntiAlias, QtTransparent +from novelwriter.types import QtBlack, QtHexArgb, QtPaintAntiAlias, QtTransparent logger = logging.getLogger(__name__) @@ -528,27 +528,29 @@ class GuiTheme: """Build default style sheets.""" self._styleSheets = {} - tCol = palette.text().color() - hCol = palette.highlight().color() + text = palette.text().color() + text.setAlpha(48) + tCol = text.name(QtHexArgb) + hCol = palette.highlight().color().name(QtHexArgb) # Flat Tab Widget and Tab Bar: self._styleSheets[STYLES_FLAT_TABS] = ( "QTabWidget::pane {border: 0;} " "QTabWidget QTabBar::tab {border: 0; padding: 4px 8px;} " - f"QTabWidget QTabBar::tab:selected {{color: {cssCol(hCol)};}} " + f"QTabWidget QTabBar::tab:selected {{color: {hCol};}} " ) # Minimal Tool Button self._styleSheets[STYLES_MIN_TOOLBUTTON] = ( "QToolButton {padding: 2px; margin: 0; border: none; background: transparent;} " - f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} " + f"QToolButton:hover {{border: none; background: {tCol};}} " "QToolButton::menu-indicator {image: none;} " ) # Big Tool Button self._styleSheets[STYLES_BIG_TOOLBUTTON] = ( "QToolButton {padding: 6px; margin: 0; border: none; background: transparent;} " - f"QToolButton:hover {{border: none; background: {cssCol(tCol, 48)};}} " + f"QToolButton:hover {{border: none; background: {tCol};}} " "QToolButton::menu-indicator {image: none;} " ) diff --git a/novelwriter/tools/dictionaries.py b/novelwriter/tools/dictionaries.py index e7d1da1b..90f618bc 100644 --- a/novelwriter/tools/dictionaries.py +++ b/novelwriter/tools/dictionaries.py @@ -36,10 +36,10 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import cssCol, formatFileFilter, formatInt, getFileSize, openExternalPath +from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath from novelwriter.error import formatException from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog -from novelwriter.types import QtDialogClose +from novelwriter.types import QtDialogClose, QtHexArgb logger = logging.getLogger(__name__) @@ -101,7 +101,6 @@ class GuiDictionaries(NNonBlockingDialog): # Info Box self.infoBox = QPlainTextEdit(self) self.infoBox.setReadOnly(True) - self.infoBox.setFixedHeight(4*SHARED.theme.fontPixelSize) self.infoBox.setFrameStyle(QFrame.Shape.NoFrame) # Buttons @@ -109,21 +108,16 @@ class GuiDictionaries(NNonBlockingDialog): self.buttonBox.rejected.connect(self.reject) # Assemble - self.innerBox = QVBoxLayout() - self.innerBox.addWidget(self.huInfo) - self.innerBox.addLayout(self.huPathBox) - self.innerBox.addLayout(self.huAddBox) - self.innerBox.addSpacing(8) - self.innerBox.addWidget(self.inInfo) - self.innerBox.addLayout(self.inBox) - self.innerBox.addWidget(self.infoBox) - self.innerBox.setSpacing(4) - self.outerBox = QVBoxLayout() - self.outerBox.addLayout(self.innerBox, 0) - self.outerBox.addStretch(1) + self.outerBox.addWidget(self.huInfo, 0) + self.outerBox.addLayout(self.huPathBox, 0) + self.outerBox.addLayout(self.huAddBox, 0) + self.outerBox.addSpacing(8) + self.outerBox.addWidget(self.inInfo, 0) + self.outerBox.addLayout(self.inBox, 0) + self.outerBox.addWidget(self.infoBox, 1) + self.outerBox.addSpacing(8) self.outerBox.addWidget(self.buttonBox, 0) - self.outerBox.setSpacing(16) self.setLayout(self.outerBox) @@ -248,8 +242,8 @@ class GuiDictionaries(NNonBlockingDialog): cursor.movePosition(QTextCursor.MoveOperation.End) if cursor.position() > 0: cursor.insertText("\n") - textCol = cssCol(SHARED.theme.errorText if err else self.palette().text().color()) - cursor.insertHtml(f"{text}") + textCol = SHARED.theme.errorText if err else self.palette().text().color() + cursor.insertHtml(f"{text}") cursor.movePosition(QTextCursor.MoveOperation.End) cursor.deleteChar() self.infoBox.setTextCursor(cursor) diff --git a/novelwriter/tools/welcome.py b/novelwriter/tools/welcome.py index 287fd416..4d2a0679 100644 --- a/novelwriter/tools/welcome.py +++ b/novelwriter/tools/welcome.py @@ -40,7 +40,7 @@ from PyQt6.QtWidgets import ( ) from novelwriter import CONFIG, SHARED -from novelwriter.common import cssCol, formatInt, makeFileNameSafe, qtAddAction, qtLambda +from novelwriter.common import formatInt, makeFileNameSafe, qtAddAction, qtLambda from novelwriter.constants import nwFiles from novelwriter.core.coretools import ProjectBuilder from novelwriter.enum import nwItemClass @@ -48,7 +48,7 @@ from novelwriter.extensions.configlayout import NWrappedWidgetBox from novelwriter.extensions.modified import NDialog, NIconToolButton, NSpinBox from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.versioninfo import VersionInfoWidget -from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtScrollAsNeeded, QtSelected +from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtHexArgb, QtScrollAsNeeded, QtSelected logger = logging.getLogger(__name__) @@ -301,7 +301,9 @@ class _OpenProjectPage(QWidget): self._selectFirstItem() - baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA) + base = self.palette().base().color() + base.setAlpha(PANEL_ALPHA) + baseCol = base.name(QtHexArgb) self.setStyleSheet( f"QListView {{border: none; background: {baseCol};}} " f"QLineEdit {{border: none; background: {baseCol}; padding: 4px;}} " @@ -507,7 +509,9 @@ class _NewProjectPage(QWidget): # Styles # ====== - baseCol = cssCol(self.palette().base().color(), PANEL_ALPHA) + base = self.palette().base().color() + base.setAlpha(PANEL_ALPHA) + baseCol = base.name(QtHexArgb) self.setStyleSheet( f"QScrollArea {{border: none; background: {baseCol};}} " f"_NewProjectForm {{border: none; background: {baseCol};}} " diff --git a/tests/test_base/test_base_common.py b/tests/test_base/test_base_common.py index 5bfe2723..7e03b895 100644 --- a/tests/test_base/test_base_common.py +++ b/tests/test_base/test_base_common.py @@ -28,18 +28,17 @@ from xml.etree import ElementTree as ET import pytest from PyQt6.QtCore import QMimeData, QUrl -from PyQt6.QtGui import QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo +from PyQt6.QtGui import QDesktopServices, QFont, QFontDatabase, QFontInfo from novelwriter.common import ( NWConfigParser, checkBool, checkFloat, checkInt, checkIntTuple, checkPath, - checkString, checkStringNone, checkUuid, compact, cssCol, - decodeMimeHandles, describeFont, elide, encodeMimeHandles, firstFloat, - fontMatcher, formatFileFilter, formatInt, formatTime, formatTimeStamp, - formatVersion, fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, - isItemLayout, isItemType, isListInstance, isTitleTag, jsonEncode, - makeFileNameSafe, minmax, numberToRoman, openExternalPath, readTextFile, - simplified, transferCase, uniqueCompact, xmlElement, xmlIndent, xmlSubElem, - yesNo + checkString, checkStringNone, checkUuid, compact, decodeMimeHandles, + describeFont, elide, encodeMimeHandles, firstFloat, fontMatcher, + formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion, + fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout, + isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe, + minmax, numberToRoman, openExternalPath, readTextFile, simplified, + transferCase, uniqueCompact, xmlElement, xmlIndent, xmlSubElem, yesNo ) from tests.mocked import causeOSError @@ -512,13 +511,6 @@ def testBaseCommon_numberToRoman(): assert numberToRoman(999, True) == "cmxcix" -@pytest.mark.base -def testBaseCommon_cssCol(): - """Test the cssCol function.""" - assert cssCol(QColor(0, 0, 0, 0)) == "rgba(0, 0, 0, 0)" - assert cssCol(QColor(10, 20, 30, 40)) == "rgba(10, 20, 30, 40)" - - @pytest.mark.base def testBaseCommon_describeFont(): """Test the describeFont function.""" From a8116a0fd999bc8b4be445585ab11962d00cd1fd Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:20:46 +0100 Subject: [PATCH 5/7] Fix focus after search goes to next document --- novelwriter/gui/doceditor.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index d4b923ad..4a18d7c3 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -100,6 +100,7 @@ class GuiDocEditor(QPlainTextEdit): Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_PageUp, Qt.Key.Key_PageDown ) + ENTER_KEYS = (Qt.Key.Key_Return, Qt.Key.Key_Enter) # Custom Signals closeEditorRequest = pyqtSignal() @@ -927,7 +928,7 @@ class GuiDocEditor(QPlainTextEdit): * We also handle automatic scrolling here. """ self._lastActive = time() - if self.docSearch.anyFocus() and event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter): + if self.docSearch.anyFocus() and event.key() in self.ENTER_KEYS: return elif event == QKeySequence.StandardKey.Redo: self.docAction(nwDocAction.REDO) @@ -1325,6 +1326,7 @@ class GuiDocEditor(QPlainTextEdit): self.beginSearch() return + rFocus = self.docSearch.searchBox if self.docSearch.anyFocus() else self resS, resE = self.findAllOccurences() if len(resS) == 0 and self._docHandle: self.docSearch.setResultCount(0, 0) @@ -1333,7 +1335,7 @@ class GuiDocEditor(QPlainTextEdit): self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) QApplication.processEvents() self.beginSearch() - self.setFocus() + rFocus.setFocus() return cursor = self.textCursor() @@ -1353,7 +1355,7 @@ class GuiDocEditor(QPlainTextEdit): self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) QApplication.processEvents() self.beginSearch() - self.setFocus() + rFocus.setFocus() return else: resIdx = 0 if doLoop else maxIdx @@ -2705,7 +2707,7 @@ class GuiDocEditSearch(QFrame): def anyFocus(self) -> bool: """Return True if any of the input boxes have focus.""" - return self.searchBox.hasFocus() or self.replaceBox.hasFocus() + return self.hasFocus() or self.isAncestorOf(QApplication.focusWidget()) ## # Public Slots From 7c3eb168004e9cb1271f7e16a2bb68db82611135 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:30:02 +0100 Subject: [PATCH 6/7] Be even more specific on what widget to return focus to after searching next document --- novelwriter/gui/doceditor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 4a18d7c3..050487da 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -1326,7 +1326,7 @@ class GuiDocEditor(QPlainTextEdit): self.beginSearch() return - rFocus = self.docSearch.searchBox if self.docSearch.anyFocus() else self + prevFocus = QApplication.focusWidget() or self resS, resE = self.findAllOccurences() if len(resS) == 0 and self._docHandle: self.docSearch.setResultCount(0, 0) @@ -1335,7 +1335,7 @@ class GuiDocEditor(QPlainTextEdit): self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) QApplication.processEvents() self.beginSearch() - rFocus.setFocus() + prevFocus.setFocus() return cursor = self.textCursor() @@ -1355,7 +1355,7 @@ class GuiDocEditor(QPlainTextEdit): self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) QApplication.processEvents() self.beginSearch() - rFocus.setFocus() + prevFocus.setFocus() return else: resIdx = 0 if doLoop else maxIdx From 47ffc83c7381c4fa9d616decbc7bb00dac9ca590 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:43:38 +0100 Subject: [PATCH 7/7] Use error text colour instead for editor search box --- novelwriter/gui/doceditor.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 050487da..6b087da2 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -2685,12 +2685,6 @@ class GuiDocEditSearch(QFrame): self.searchOpt.setStyleSheet("QToolBar {padding: 0;}") self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}") - # Construct Box Colours - self.rxCol = { - True: palette.base().color(), - False: SHARED.theme.errorText.darker(200), - } - return def cycleFocus(self) -> bool: @@ -2791,9 +2785,12 @@ class GuiDocEditSearch(QFrame): """Highlight the search box to indicate the search string is or isn't valid. Take the colour from the replace box. """ - qPalette = self.replaceBox.palette() - qPalette.setColor(QPalette.ColorRole.Base, self.rxCol[isValid]) - self.searchBox.setPalette(qPalette) + palette = self.replaceBox.palette() + palette.setColor( + QPalette.ColorRole.Text, + palette.text().color() if isValid else SHARED.theme.errorText + ) + self.searchBox.setPalette(palette) return