bumblebee-status/bumblebee/theme.py
Tobi-wan Kenobi 2fa8d7b778 [core/themes] Add module-specific themes
Allow module-specific theme information to overload "default"
configuration. I.e. it is now possible to have specific prefix or
postfix configurations for different modules. The module name is derived
for each widget from the module (__module__) from which it was
instantiated.

see #23
2016-12-08 12:44:52 +01:00

89 lines
2.7 KiB
Python

"""Theme support"""
import os
import copy
import json
import bumblebee.error
def theme_path():
"""Return the path of the theme directory"""
return os.path.dirname("{}/../themes/".format(os.path.dirname(os.path.realpath(__file__))))
class Theme(object):
"""Represents a collection of icons and colors"""
def __init__(self, name):
self._init(self.load(name))
def _init(self, data):
"""Initialize theme from data structure"""
for iconset in data.get("icons", []):
self._merge(data, self._load_icons(iconset))
self._theme = data
self._defaults = data.get("defaults", {})
def prefix(self, widget):
"""Return the theme prefix for a widget's full text"""
return self._get(widget, "prefix", None)
def suffix(self, widget):
"""Return the theme suffix for a widget's full text"""
return self._get(widget, "suffix", None)
def loads(self, data):
theme = json.loads(data)
self._init(theme)
def _load_icons(self, name):
path = "{}/icons/".format(theme_path())
return self.load(name, path=path)
def load(self, name, path=theme_path()):
"""Load and parse a theme file"""
themefile = "{}/{}.json".format(path, name)
if os.path.isfile(themefile):
try:
with open(themefile) as data:
return json.load(data)
except ValueError as exception:
raise bumblebee.error.ThemeLoadError("JSON error: {}".format(exception))
else:
raise bumblebee.error.ThemeLoadError("no such theme: {}".format(name))
def _get(self, widget, name, default=None):
module_theme = self._theme.get(widget.module(), {})
padding = None
if name != "padding":
padding = self._get(widget, "padding")
value = self._defaults.get(name, default)
value = module_theme.get(name, value)
if value and padding:
value = u"{}{}{}".format(padding, value, padding)
return value
# algorithm copied from
# http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts
# nicely done :)
def _merge(self, target, *args):
if len(args) > 1:
for item in args:
self._merge(item)
return target
item = args[0]
if not isinstance(item, dict):
return item
for key, value in item.items():
if key in target and isinstance(target[key], dict):
self._merge(target[key], value)
else:
target[key] = copy.deepcopy(value)
return target
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4