mirror of
https://github.com/UN-GCPDS/qt-material.git
synced 2025-01-27 17:02:57 +08:00
206 lines
6.1 KiB
Python
206 lines
6.1 KiB
Python
import os
|
|
import sys
|
|
import logging
|
|
from xml.etree import ElementTree
|
|
|
|
|
|
if 'PySide2' in sys.modules:
|
|
from PySide2.QtGui import QFontDatabase
|
|
from PySide2.QtWidgets import QAction
|
|
elif 'PyQt5' in sys.modules:
|
|
from PyQt5.QtGui import QFontDatabase
|
|
from PyQt5.QtWidgets import QAction
|
|
|
|
|
|
import jinja2
|
|
|
|
template = 'material.css.template'
|
|
_resource = os.path.join('resources', 'resource_rc.py')
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def build_stylesheet(theme='', light_secondary=False, resources=[], extra={}):
|
|
""""""
|
|
theme = get_theme(theme, light_secondary)
|
|
if theme is None:
|
|
return None
|
|
|
|
set_icons_theme(theme)
|
|
|
|
loader = jinja2.FileSystemLoader(os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__))))
|
|
env = jinja2.Environment(autoescape=True, loader=loader)
|
|
|
|
theme['icon'] = None
|
|
|
|
env.filters['opacity'] = opacity
|
|
# env.filters['load'] = load
|
|
|
|
stylesheet = env.get_template(template)
|
|
|
|
theme.update(extra)
|
|
|
|
return stylesheet.render(**theme)
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def get_theme(theme_name, light_secondary=False):
|
|
if theme_name in ['default.xml', 'default_dark.xml', 'default', 'default_dark']:
|
|
theme = os.path.join(os.path.dirname(
|
|
os.path.abspath(__file__)), 'themes', 'dark_teal.xml')
|
|
elif theme_name in ['default_light.xml', 'default_light']:
|
|
light_secondary = True
|
|
theme = os.path.join(os.path.dirname(
|
|
os.path.abspath(__file__)), 'themes', 'light_blue.xml')
|
|
else:
|
|
theme = os.path.join(os.path.dirname(
|
|
os.path.abspath(__file__)), 'themes', theme_name)
|
|
|
|
if not os.path.exists(theme):
|
|
logging.warning(f"{theme} not exist!")
|
|
return None
|
|
|
|
tree = ElementTree.parse(theme)
|
|
theme = {child.attrib['name']: child.text for child in tree.getroot()}
|
|
|
|
for k in theme:
|
|
os.environ[str(k)] = theme[k]
|
|
|
|
if light_secondary:
|
|
theme['secondaryColor'], theme['secondaryLightColor'], theme['secondaryDarkColor'] = theme[
|
|
'secondaryColor'], theme['secondaryDarkColor'], theme['secondaryLightColor']
|
|
theme['primaryTextColor'] = theme['secondaryTextColor']
|
|
|
|
for color in ['primaryColor',
|
|
'primaryLightColor',
|
|
'primaryDarkColor',
|
|
'secondaryColor',
|
|
'secondaryLightColor',
|
|
'secondaryDarkColor',
|
|
'primaryTextColor',
|
|
'secondaryTextColor']:
|
|
os.environ[f'PYSIDEMATERIAL_{color.upper()}'] = theme[color]
|
|
os.environ['PYSIDEMATERIAL_THEME'] = theme_name
|
|
|
|
return theme
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def add_fonts():
|
|
""""""
|
|
fonts_path = os.path.join(os.path.dirname(__file__), 'fonts')
|
|
for font in os.listdir(fonts_path):
|
|
QFontDatabase.addApplicationFont(os.path.join(fonts_path, font))
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def apply_stylesheet(app, theme='', style='Fusion', save_as=None, light_secondary=False, resources=[], extra={}):
|
|
""""""
|
|
add_fonts()
|
|
|
|
if style:
|
|
try:
|
|
app.setStyle(style)
|
|
except:
|
|
pass
|
|
stylesheet = build_stylesheet(theme, light_secondary, resources, extra)
|
|
if stylesheet is None:
|
|
return
|
|
|
|
if save_as:
|
|
with open(save_as, 'w') as file:
|
|
file.writelines(stylesheet)
|
|
|
|
return app.setStyleSheet(stylesheet)
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def opacity(theme, value=0.5):
|
|
""""""
|
|
r, g, b = theme[1:][0:2], theme[1:][2:4], theme[1:][4:]
|
|
r, g, b = int(r, 16), int(g, 16), int(b, 16)
|
|
|
|
return f'rgba({r}, {g}, {b}, {value})'
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def set_icons_theme(theme, resource=None, output=None):
|
|
""""""
|
|
try:
|
|
theme = get_theme(theme)
|
|
except:
|
|
pass
|
|
|
|
if resource is None:
|
|
resource = os.path.join(os.path.dirname(
|
|
os.path.abspath(__file__)), _resource)
|
|
|
|
with open(resource, 'r') as file:
|
|
content = file.read()
|
|
|
|
replaces = (
|
|
|
|
["#0000ff", 'primaryColor'],
|
|
["#ff0000", 'secondaryLightColor'],
|
|
|
|
)
|
|
|
|
for color, replace in replaces:
|
|
colors = [
|
|
color] + [''.join(list(color)[:i] + ['\\\n'] + list(color)[i:]) for i in range(1, 7)]
|
|
for c in colors:
|
|
content = content.replace(c, theme[replace])
|
|
|
|
if output:
|
|
with open(output, 'w') as file:
|
|
file.write(content)
|
|
return
|
|
|
|
try:
|
|
qCleanupResources() # this method is created after the first call to resource_rc
|
|
except:
|
|
pass
|
|
|
|
# This is like import resource_rc, load new resources with icons
|
|
exec(content, globals())
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
def list_themes():
|
|
""""""
|
|
themes = os.listdir(os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)), 'themes'))
|
|
themes = filter(lambda a: a.endswith('xml'), themes)
|
|
return sorted(list(themes))
|
|
|
|
|
|
########################################################################
|
|
class QtStyleSwitcher:
|
|
""""""
|
|
# ----------------------------------------------------------------------
|
|
|
|
def set_style_switcher(self, parent, menu, extra={}):
|
|
""""""
|
|
for theme in ['default'] + list_themes():
|
|
action = QAction(parent)
|
|
action.setText(theme)
|
|
action.triggered.connect(self._wrapper(parent, theme, extra))
|
|
menu.addAction(action)
|
|
|
|
# ----------------------------------------------------------------------
|
|
def _wrapper(self, parent, theme, extra):
|
|
""""""
|
|
def iner():
|
|
self._apply_theme(parent, theme, extra)
|
|
return iner
|
|
|
|
# ----------------------------------------------------------------------
|
|
def _apply_theme(self, parent, theme, extra):
|
|
""""""
|
|
if theme == 'default':
|
|
parent.setStyleSheet('')
|
|
return
|
|
|
|
apply_stylesheet(parent, theme=theme, light_secondary=theme.startswith(
|
|
'light'), extra=extra)
|