diff --git a/src/calibre/gui2/palette.py b/src/calibre/gui2/palette.py index 39fced09a6..8fcc67a241 100644 --- a/src/calibre/gui2/palette.py +++ b/src/calibre/gui2/palette.py @@ -7,7 +7,7 @@ from contextlib import contextmanager from functools import lru_cache from qt.core import ( QAbstractNativeEventFilter, QApplication, QColor, QIcon, QPalette, QSettings, - QStyle, Qt, QTimer, pyqtSlot, QObject + QStyle, Qt, QTimer, pyqtSlot, QObject, QDataStream, QByteArray, QIODeviceBase ) from calibre.constants import DEBUG, dark_link_color, ismacos, iswindows @@ -15,6 +15,9 @@ from calibre.constants import DEBUG, dark_link_color, ismacos, iswindows dark_link_color = QColor(dark_link_color) dark_color = QColor(45,45,45) dark_text_color = QColor('#ddd') +light_color = QColor(0xef, 0xef, 0xef) +light_text_color = QColor(0,0,0) +light_link_color = QColor(0, 0, 255) if iswindows: @@ -61,10 +64,39 @@ def linux_is_system_dark_mode_enabled(): def palette_is_dark(self): - return self.color(QPalette.ColorRole.Window).lightnessF() < self.color(QPalette.ColorRole.WindowText).lightnessF() + col = self.color(QPalette.ColorRole.Window) + return max(col.getRgb()[:3]) < 115 + + +def serialize_palette(self): + ba = QByteArray() + ds = QDataStream(ba, QIODeviceBase.OpenModeFlag.WriteOnly) + ds << self + return bytes(ba) + + +def unserialize_palette(self, data: bytes): + QDataStream(QByteArray(data)) >> self + + +def serialize_palette_as_python(self): + lines = [] + for group in QPalette.ColorGroup: + if group in (QPalette.ColorGroup.All, QPalette.ColorGroup.NColorGroups): + continue + for role in QPalette.ColorRole: + if role == QPalette.ColorRole.NColorRoles: + continue + c = self.color(group, role) + lines.append( + f'self.setColor(QPalette.ColorGroup.{group.name}, QPalette.ColorRole.{role.name}, QColor({c.red()}, {c.green()}, {c.blue()}, {c.alpha()}))') + return '\n'.join(lines) QPalette.is_dark_theme = palette_is_dark +QPalette.serialize_as_bytes = serialize_palette +QPalette.serialize_as_python = serialize_palette_as_python +QPalette.unserialize_from_bytes = unserialize_palette def fix_palette_colors(p): @@ -103,6 +135,96 @@ def dark_palette(): return p +def light_palette(): + # generated by serializing the light palette on my Linux system + self = QPalette() + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.WindowText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Button, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Light, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Midlight, QColor(202, 202, 202, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Dark, QColor(159, 159, 159, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Mid, QColor(184, 184, 184, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Text, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.BrightText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.ButtonText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Base, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Window, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Shadow, QColor(118, 118, 118, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight, QColor(48, 140, 198, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.HighlightedText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Link, QColor(0, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.LinkVisited, QColor(255, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.AlternateBase, QColor(247, 247, 247, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.ToolTipBase, QColor(255, 255, 220, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.ToolTipText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.PlaceholderText, QColor(0, 0, 0, 128)) + self.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.NoRole, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.WindowText, QColor(190, 190, 190, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Button, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Light, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Midlight, QColor(202, 202, 202, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Dark, QColor(190, 190, 190, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Mid, QColor(184, 184, 184, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, QColor(190, 190, 190, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.BrightText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, QColor(190, 190, 190, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Base, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Window, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Shadow, QColor(177, 177, 177, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Highlight, QColor(145, 145, 145, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.HighlightedText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Link, QColor(0, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.LinkVisited, QColor(255, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.AlternateBase, QColor(247, 247, 247, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ToolTipBase, QColor(255, 255, 220, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ToolTipText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.PlaceholderText, QColor(0, 0, 0, 128)) + self.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.NoRole, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.WindowText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Button, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Light, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Midlight, QColor(202, 202, 202, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Dark, QColor(159, 159, 159, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Mid, QColor(184, 184, 184, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Text, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.BrightText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.ButtonText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Base, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Window, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Shadow, QColor(118, 118, 118, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Highlight, QColor(48, 140, 198, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.HighlightedText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Link, QColor(0, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.LinkVisited, QColor(255, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.AlternateBase, QColor(247, 247, 247, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.ToolTipBase, QColor(255, 255, 220, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.ToolTipText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.PlaceholderText, QColor(0, 0, 0, 128)) + self.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.NoRole, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.WindowText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Button, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Light, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Midlight, QColor(202, 202, 202, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Dark, QColor(159, 159, 159, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Mid, QColor(184, 184, 184, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Text, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.BrightText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.ButtonText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Base, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Window, QColor(239, 239, 239, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Shadow, QColor(118, 118, 118, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Highlight, QColor(48, 140, 198, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.HighlightedText, QColor(255, 255, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.Link, QColor(0, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.LinkVisited, QColor(255, 0, 255, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.AlternateBase, QColor(247, 247, 247, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.ToolTipBase, QColor(255, 255, 220, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.ToolTipText, QColor(0, 0, 0, 255)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.PlaceholderText, QColor(0, 0, 0, 128)) + self.setColor(QPalette.ColorGroup.Current, QPalette.ColorRole.NoRole, QColor(0, 0, 0, 255)) + return self + + class PaletteManager(QObject): color_palette: str @@ -167,6 +289,11 @@ class PaletteManager(QObject): self.set_dark_mode_palette() elif self.original_palette_modified: self.set_palette(self.original_palette) + if self.has_fixed_palette and (self.color_palette == 'dark') != QApplication.instance().palette().is_dark_theme(): + if self.color_palette == 'dark': + self.set_dark_mode_palette() + else: + self.set_light_mode_palette() if DEBUG: print('Using calibre Qt style:', self.using_calibre_style, file=sys.stderr) @@ -247,6 +374,9 @@ class PaletteManager(QObject): def set_dark_mode_palette(self): self.set_palette(dark_palette()) + def set_light_mode_palette(self): + self.set_palette(light_palette()) + if not iswindows and not ismacos: @pyqtSlot(str, str, QDBusVariant) def linux_desktop_setting_changed(self, namespace, key, val):