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