From 550cba2f43b3471d4f4cc6d6827ed07892054d01 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Thu, 5 Jun 2025 18:15:31 +0200 Subject: [PATCH] Add theme settings for active icons, a base colour, and accent palette colour (#2382) --- novelwriter/constants.py | 1 + novelwriter/core/item.py | 8 ++-- novelwriter/extensions/switch.py | 7 +++- novelwriter/gui/itemdetails.py | 10 +---- novelwriter/gui/theme.py | 65 +++++++++++++++++++------------- tests/test_gui/test_gui_theme.py | 7 ++-- 6 files changed, 54 insertions(+), 44 deletions(-) diff --git a/novelwriter/constants.py b/novelwriter/constants.py index 5b7b260d..8c9da88e 100644 --- a/novelwriter/constants.py +++ b/novelwriter/constants.py @@ -445,6 +445,7 @@ class nwLabels: THEME_COLORS: Final[dict[str, str]] = { "theme": QT_TRANSLATE_NOOP("Constant", "Theme Colours"), "default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"), + "base": QT_TRANSLATE_NOOP("Constant", "Background Colour"), "faded": QT_TRANSLATE_NOOP("Constant", "Faded Colour"), "red": QT_TRANSLATE_NOOP("Constant", "Red"), "orange": QT_TRANSLATE_NOOP("Constant", "Orange"), diff --git a/novelwriter/core/item.py b/novelwriter/core/item.py index a8f2fbbd..367fa446 100644 --- a/novelwriter/core/item.py +++ b/novelwriter/core/item.py @@ -363,13 +363,13 @@ class NWItem: """ if self.isFileType(): key = "checked" if self._active else "unchecked" - color = "green" if self._active else "red" + color = "active" if self._active else "inactive" text = trConst(nwLabels.ACTIVE_NAME[key]) - icon = SHARED.theme.getIcon(key, color) else: + key = "noncheckable" + color = "disabled" text = "" - icon = SHARED.theme.getIcon("noncheckable", "faded") - return text, icon + return text, SHARED.theme.getIcon(key, color) ## # Checker Methods diff --git a/novelwriter/extensions/switch.py b/novelwriter/extensions/switch.py index 4699d50a..0a11f52f 100644 --- a/novelwriter/extensions/switch.py +++ b/novelwriter/extensions/switch.py @@ -33,7 +33,7 @@ from novelwriter.types import QtNoPen, QtPaintAntiAlias, QtSizeFixed class NSwitch(QAbstractButton): - __slots__ = ("_offset", "_rH", "_rR", "_xH", "_xR", "_xW") + __slots__ = ("_cOff", "_cOn", "_offset", "_rH", "_rR", "_xH", "_xR", "_xW") def __init__(self, parent: QWidget, height: int = 0) -> None: super().__init__(parent=parent) @@ -44,6 +44,9 @@ class NSwitch(QAbstractButton): self._rH = self._xH - 4 self._rR = self._xR - 2 + self._cOn = SHARED.theme.accentCol + self._cOff = self.palette().alternateBase() + self.setCheckable(True) self.setSizePolicy(QtSizeFixed, QtSizeFixed) self.setFixedWidth(self._xW) @@ -97,7 +100,7 @@ class NSwitch(QAbstractButton): painter.setOpacity(1.0 if self.isEnabled() else 0.5) painter.setPen(palette.highlight().color() if self.hasFocus() else palette.mid().color()) - painter.setBrush(palette.highlight() if self.isChecked() else palette.alternateBase()) + painter.setBrush(self._cOn if self.isChecked() else self._cOff) painter.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR) painter.setPen(QtNoPen) diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py index 9bece183..7bffb923 100644 --- a/novelwriter/gui/itemdetails.py +++ b/novelwriter/gui/itemdetails.py @@ -233,14 +233,8 @@ class GuiItemDetails(QWidget): # Label # ===== - if nwItem.isFileType(): - if nwItem.isActive: - self.labelIcon.setPixmap(SHARED.theme.getPixmap("checked", (iPx, iPx), "green")) - else: - self.labelIcon.setPixmap(SHARED.theme.getPixmap("unchecked", (iPx, iPx), "red")) - else: - self.labelIcon.setPixmap(SHARED.theme.getPixmap("noncheckable", (iPx, iPx), "faded")) - + _, icon = nwItem.getActiveStatus() + self.labelIcon.setPixmap(icon.pixmap(iPx, iPx)) self.labelData.setText(elide(nwItem.itemName, 100)) # Status diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index 89d3fecd..154802d5 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -108,7 +108,7 @@ class GuiTheme: __slots__ = ( "_allThemes", "_currentTheme", "_darkThemes", "_guiPalette", "_lightThemes", "_meta", - "_qColors", "_styleSheets", "_svgColors", "_syntaxList", "baseButtonHeight", + "_qColors", "_styleSheets", "_svgColors", "_syntaxList", "accentCol", "baseButtonHeight", "baseIconHeight", "baseIconSize", "buttonIconSize", "errorText", "fadedText", "fontPixelSize", "fontPointSize", "getDecoration", "getHeaderDecoration", "getHeaderDecorationNarrow", "getIcon", "getItemIcon", "getPixmap", "getToggleIcon", @@ -123,10 +123,11 @@ class GuiTheme: self.syntaxTheme = SyntaxColors() self.isDarkTheme = False - # Special Text Colours + # Special Colours self.helpText = QColor(0, 0, 0) self.fadedText = QColor(0, 0, 0) self.errorText = QColor(255, 0, 0) + self.accentCol = QColor(255, 0, 255) # Needed until we move to Qt 6.6 # Theme Data self._meta = ThemeMeta() @@ -306,6 +307,7 @@ class GuiTheme: # Base sec = "Base" if parser.has_section(sec): + self._setBaseColor("base", self._readColor(parser, sec, "base")) self._setBaseColor("default", self._readColor(parser, sec, "default")) self._setBaseColor("faded", self._readColor(parser, sec, "faded")) self._setBaseColor("red", self._readColor(parser, sec, "red")) @@ -319,13 +321,16 @@ class GuiTheme: # Project sec = "Project" if parser.has_section(sec): - self._setBaseColor("root", self._readColor(parser, sec, "root")) - self._setBaseColor("folder", self._readColor(parser, sec, "folder")) - self._setBaseColor("file", self._readColor(parser, sec, "file")) - self._setBaseColor("title", self._readColor(parser, sec, "title")) - self._setBaseColor("chapter", self._readColor(parser, sec, "chapter")) - self._setBaseColor("scene", self._readColor(parser, sec, "scene")) - self._setBaseColor("note", self._readColor(parser, sec, "note")) + self._setBaseColor("root", self._readColor(parser, sec, "root")) + self._setBaseColor("folder", self._readColor(parser, sec, "folder")) + self._setBaseColor("file", self._readColor(parser, sec, "file")) + self._setBaseColor("title", self._readColor(parser, sec, "title")) + self._setBaseColor("chapter", self._readColor(parser, sec, "chapter")) + self._setBaseColor("scene", self._readColor(parser, sec, "scene")) + self._setBaseColor("note", self._readColor(parser, sec, "note")) + self._setBaseColor("active", self._readColor(parser, sec, "active")) + self._setBaseColor("inactive", self._readColor(parser, sec, "inactive")) + self._setBaseColor("disabled", self._readColor(parser, sec, "disabled")) # Palette sec = "Palette" @@ -344,6 +349,7 @@ class GuiTheme: self._setPalette(parser, sec, "highlightedtext", QPalette.ColorRole.HighlightedText) self._setPalette(parser, sec, "link", QPalette.ColorRole.Link) self._setPalette(parser, sec, "linkvisited", QPalette.ColorRole.LinkVisited) + self.accentCol = self._readColor(parser, sec, "accent") # Special handling 'til Qt 6.6 # GUI sec = "GUI" @@ -427,8 +433,8 @@ class GuiTheme: self._guiPalette.setBrush(QtColDisabled, QPalette.ColorRole.Highlight, grey) if CONFIG.verQtValue >= 0x060600: - self._guiPalette.setBrush(QtColActive, QPalette.ColorRole.Accent, highlight) - self._guiPalette.setBrush(QtColInactive, QPalette.ColorRole.Accent, highlight) + self._guiPalette.setBrush(QtColActive, QPalette.ColorRole.Accent, self.accentCol) + self._guiPalette.setBrush(QtColInactive, QPalette.ColorRole.Accent, self.accentCol) self._guiPalette.setBrush(QtColDisabled, QPalette.ColorRole.Accent, grey) # Set project override colours @@ -506,6 +512,7 @@ class GuiTheme: isDark = self.isDesktopDarkMode() # Reset GUI Palette + base = palette.color(QPalette.ColorRole.Base) default = palette.color(QPalette.ColorRole.Text) faded = QColor(128, 128, 128) dimmed = QColor(130, 130, 130) if isDark else QColor(190, 190, 190) @@ -528,22 +535,26 @@ class GuiTheme: self.iconCache.clear() self._svgColors = {} self._qColors = {} - self._setBaseColor("default", default) - self._setBaseColor("faded", faded) - self._setBaseColor("red", red) - self._setBaseColor("orange", orange) - self._setBaseColor("yellow", yellow) - self._setBaseColor("green", green) - self._setBaseColor("cyan", cyan) - self._setBaseColor("blue", blue) - self._setBaseColor("purple", purple) - self._setBaseColor("root", blue) - self._setBaseColor("folder", yellow) - self._setBaseColor("file", default) - self._setBaseColor("title", green) - self._setBaseColor("chapter", red) - self._setBaseColor("scene", blue) - self._setBaseColor("note", yellow) + self._setBaseColor("base", base) + self._setBaseColor("default", default) + self._setBaseColor("faded", faded) + self._setBaseColor("red", red) + self._setBaseColor("orange", orange) + self._setBaseColor("yellow", yellow) + self._setBaseColor("green", green) + self._setBaseColor("cyan", cyan) + self._setBaseColor("blue", blue) + self._setBaseColor("purple", purple) + self._setBaseColor("root", blue) + self._setBaseColor("folder", yellow) + self._setBaseColor("file", default) + self._setBaseColor("title", green) + self._setBaseColor("chapter", red) + self._setBaseColor("scene", blue) + self._setBaseColor("note", yellow) + self._setBaseColor("active", green) + self._setBaseColor("inactive", red) + self._setBaseColor("disabled", faded) return diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py index 4c834d38..27e5915d 100644 --- a/tests/test_gui/test_gui_theme.py +++ b/tests/test_gui/test_gui_theme.py @@ -616,16 +616,17 @@ def testGuiTheme_CheckTheme(theme): "name", "mode", # The rest are not required ], "Base": [ - "default", "faded", "red", "orange", "yellow", "green", "cyan", - "blue", "purple", + "base", "default", "faded", "red", "orange", "yellow", "green", + "cyan", "blue", "purple", ], "Project": [ "root", "folder", "file", "title", "chapter", "scene", "note", + "active", "inactive", "disabled", ], "Palette": [ "window", "windowtext", "base", "alternatebase", "text", "tooltipbase", "tooltiptext", "button", "buttontext", "brighttext", - "highlight", "highlightedtext", "link", "linkvisited", + "highlight", "highlightedtext", "link", "linkvisited", "accent", ], "GUI": [ "helptext", "fadedtext", "errortext",