Anki/qt/aqt/theme.py
Damien Elmes 7dcbc7efec basic night mode support
Forces the Fusion theme when running night mode, so we don't need
to work around platform themes that don't respond to the defined
palette.

Feedback/suggestions on the chosen colours welcome - _vars.scss is the
file to change if you want to experiment with adjustments.
2020-01-23 17:27:07 +10:00

126 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import platform
from typing import Dict
from aqt import QApplication, gui_hooks, isWin
from aqt.colors import colors
from aqt.qt import QColor, QIcon, QPalette, QPixmap, QStyleFactory, Qt
class ThemeManager:
night_mode = True
_icon_cache: Dict[str, QIcon] = {}
_icon_size = 128
def icon_from_resources(self, path: str) -> QIcon:
"Fetch icon from Qt resources, and invert if in night mode."
icon = self._icon_cache.get(path)
if icon:
return icon
icon = QIcon(path)
if self.night_mode:
img = icon.pixmap(self._icon_size, self._icon_size).toImage()
img.invertPixels()
icon = QIcon(QPixmap(img))
return self._icon_cache.setdefault(path, icon)
def body_class(self) -> str:
"Returns '' in normal mode, 'nightMode' in night mode."
return self.night_mode and "nightMode" or ""
def body_classes_for_card_ord(self, card_ord: int) -> str:
"Returns body classes used when showing a card."
return f"card card{card_ord+1} {self.body_class()}"
def str_color(self, key: str) -> str:
"""Get a color defined in _vars.scss
If the colour is called '$day-frame-bg', key should be
'frame-bg'.
Returns the color as a string hex code or color name."""
prefix = self.night_mode and "night-" or "day-"
c = colors.get(prefix + key)
if c is None:
raise Exception("no such color:", key)
return c
def qcolor(self, key: str) -> QColor:
"""Get a color defined in _vars.scss as a QColor."""
return QColor(self.str_color(key))
def apply_style(self, app: QApplication) -> None:
self._apply_palette(app)
self._apply_style(app)
def _apply_style(self, app: QApplication) -> None:
buf = ""
if isWin and platform.release() == "10" and not self.night_mode:
# add missing bottom border to menubar
buf += """
QMenuBar {
border-bottom: 1px solid #aaa;
background: white;
}
"""
# qt bug? setting the above changes the browser sidebar
# to white as well, so set it back
buf += """
QTreeWidget {
background: #eee;
}
"""
# allow addons to modify the styling
buf = gui_hooks.style_did_init(buf)
app.setStyleSheet(buf)
def _apply_palette(self, app: QApplication) -> None:
if not self.night_mode:
return
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
palette = QPalette()
text_fg = self.qcolor("text-fg")
palette.setColor(QPalette.WindowText, text_fg)
palette.setColor(QPalette.ToolTipBase, text_fg)
palette.setColor(QPalette.ToolTipText, text_fg)
palette.setColor(QPalette.Text, text_fg)
palette.setColor(QPalette.ButtonText, text_fg)
hlbg = self.qcolor("highlight-bg")
hlbg.setAlpha(64)
palette.setColor(QPalette.HighlightedText, self.qcolor("highlight-fg"))
palette.setColor(QPalette.Highlight, hlbg)
window_bg = self.qcolor("window-bg")
palette.setColor(QPalette.Window, window_bg)
palette.setColor(QPalette.AlternateBase, window_bg)
palette.setColor(QPalette.Button, window_bg)
palette.setColor(QPalette.Base, self.qcolor("frame-bg"))
disabled_color = self.qcolor("disabled")
palette.setColor(QPalette.Disabled, QPalette.Text, disabled_color)
palette.setColor(QPalette.Disabled, QPalette.ButtonText, disabled_color)
palette.setColor(QPalette.Disabled, QPalette.HighlightedText, disabled_color)
palette.setColor(QPalette.Link, self.qcolor("link"))
palette.setColor(QPalette.BrightText, Qt.red)
app.setPalette(palette)
theme_manager = ThemeManager()