2016-12-04 18:10:04 +01:00
|
|
|
"""Theme support"""
|
|
|
|
|
2016-12-08 09:44:05 +01:00
|
|
|
import os
|
2016-12-08 12:09:21 +01:00
|
|
|
import copy
|
2016-12-08 09:44:05 +01:00
|
|
|
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__))))
|
|
|
|
|
2016-12-04 18:10:04 +01:00
|
|
|
class Theme(object):
|
2016-12-08 08:44:54 +01:00
|
|
|
"""Represents a collection of icons and colors"""
|
2016-12-08 09:44:05 +01:00
|
|
|
def __init__(self, name):
|
2016-12-08 11:52:47 +01:00
|
|
|
self._init(self.load(name))
|
2016-12-08 09:44:05 +01:00
|
|
|
|
2016-12-08 11:52:47 +01:00
|
|
|
def _init(self, data):
|
|
|
|
"""Initialize theme from data structure"""
|
2016-12-08 12:09:21 +01:00
|
|
|
for iconset in data.get("icons", []):
|
|
|
|
self._merge(data, self._load_icons(iconset))
|
|
|
|
self._theme = data
|
2016-12-08 11:52:47 +01:00
|
|
|
self._defaults = data.get("defaults", {})
|
|
|
|
|
|
|
|
def prefix(self, widget):
|
2016-12-08 11:31:20 +01:00
|
|
|
"""Return the theme prefix for a widget's full text"""
|
2016-12-08 11:52:47 +01:00
|
|
|
return self._get(widget, "prefix", None)
|
2016-12-08 11:31:20 +01:00
|
|
|
|
2016-12-08 11:52:47 +01:00
|
|
|
def suffix(self, widget):
|
2016-12-08 11:31:20 +01:00
|
|
|
"""Return the theme suffix for a widget's full text"""
|
2016-12-08 11:52:47 +01:00
|
|
|
return self._get(widget, "suffix", None)
|
|
|
|
|
2016-12-09 08:58:45 +01:00
|
|
|
def fg(self, widget):
|
|
|
|
"""Return the foreground color for this widget"""
|
|
|
|
return self._get(widget, "fg", None)
|
|
|
|
|
|
|
|
def bg(self, widget):
|
|
|
|
"""Return the background color for this widget"""
|
|
|
|
return self._get(widget, "bg", None)
|
|
|
|
|
2016-12-08 11:52:47 +01:00
|
|
|
def loads(self, data):
|
2016-12-09 07:11:23 +01:00
|
|
|
"""Initialize the theme from a JSON string"""
|
2016-12-08 11:52:47 +01:00
|
|
|
theme = json.loads(data)
|
|
|
|
self._init(theme)
|
2016-12-08 11:31:20 +01:00
|
|
|
|
2016-12-08 12:09:21 +01:00
|
|
|
def _load_icons(self, name):
|
2016-12-09 07:11:23 +01:00
|
|
|
"""Load icons for a theme"""
|
2016-12-08 12:09:21 +01:00
|
|
|
path = "{}/icons/".format(theme_path())
|
|
|
|
return self.load(name, path=path)
|
|
|
|
|
|
|
|
def load(self, name, path=theme_path()):
|
2016-12-08 09:44:05 +01:00
|
|
|
"""Load and parse a theme file"""
|
|
|
|
themefile = "{}/{}.json".format(path, name)
|
2016-12-08 12:09:21 +01:00
|
|
|
|
2016-12-08 09:44:05 +01:00
|
|
|
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))
|
2016-12-04 18:10:04 +01:00
|
|
|
|
2016-12-08 12:09:21 +01:00
|
|
|
def _get(self, widget, name, default=None):
|
2016-12-09 07:11:23 +01:00
|
|
|
"""Return the config value 'name' for 'widget'"""
|
2016-12-08 12:09:21 +01:00
|
|
|
module_theme = self._theme.get(widget.module(), {})
|
|
|
|
|
2016-12-08 12:44:52 +01:00
|
|
|
padding = None
|
|
|
|
if name != "padding":
|
|
|
|
padding = self._get(widget, "padding")
|
|
|
|
|
2016-12-08 12:09:21 +01:00
|
|
|
value = self._defaults.get(name, default)
|
|
|
|
value = module_theme.get(name, value)
|
2016-12-08 11:52:47 +01:00
|
|
|
|
2016-12-08 12:44:52 +01:00
|
|
|
if value and padding:
|
|
|
|
value = u"{}{}{}".format(padding, value, padding)
|
|
|
|
|
2016-12-08 11:52:47 +01:00
|
|
|
return value
|
|
|
|
|
2016-12-08 12:09:21 +01:00
|
|
|
# algorithm copied from
|
|
|
|
# http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts
|
|
|
|
# nicely done :)
|
|
|
|
def _merge(self, target, *args):
|
2016-12-09 07:11:23 +01:00
|
|
|
"""Merge two arbitrarily nested data structures"""
|
2016-12-08 12:09:21 +01:00
|
|
|
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
|
|
|
|
|
2016-12-04 18:10:04 +01:00
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|