bumblebee-status/bumblebee/theme.py
Tobi-wan Kenobi 209fa83324 [themes] Make it possible to merge themes to get "icon themes"
Add code that allows themes to be merged (i.e. if certain elements are
not present in a theme, another theme can be "overlaid" to add missing
elements).

Effectively, this is used to create the logical concept of an "icon
theme", which is loaded after the main theme. So, the main theme can
define colors, and the icon theme fills in any missing elements
(practically, all the icons in the form of prefixes and suffixes).

Icon sets are defined in a theme using the "icons" directive, which
should be an array.

see #17
2016-11-25 21:06:24 +01:00

130 lines
4.2 KiB
Python

import os
import copy
import json
import yaml
import glob
def getpath():
return os.path.dirname("{}/../themes/".format(os.path.dirname(os.path.realpath(__file__))))
def themes():
d = getpath()
return [ os.path.basename(f).replace(".json", "") for f in glob.iglob("{}/*.json".format(d)) ]
class Theme:
def __init__(self, config):
self._config = config
self._data = self.get_theme(config.theme())
for iconset in self._data.get("icons", []):
self.merge(self._data, self.get_theme(iconset))
self._defaults = self._data.get("defaults", {})
self._cycles = self._defaults.get("cycle", [])
self.begin()
def get_theme(self, name):
for path in [ getpath(), "{}/icons/".format(getpath()) ]:
if os.path.isfile("{}/{}.yaml".format(path, name)):
with open("{}/{}.yaml".format(path, name)) as f:
return yaml.load(f)
if os.path.isfile("{}/{}.json".format(path, name)):
with open("{}/{}.json".format(path, name)) as f:
return json.load(f)
return None
# 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.iteritems():
if key in target and isinstance(target[key], dict):
self.merge(target[key], value)
else:
target[key] = copy.deepcopy(value)
return target
def begin(self):
self._config.set("theme.cycleidx", 0)
self._cycle = self._cycles[0] if len(self._cycles) > 0 else {}
self._background = [ None, None ]
def next_widget(self):
self._background[1] = self._background[0]
idx = self._config.increase("theme.cycleidx", len(self._cycles), 0)
self._cycle = self._cycles[idx] if len(self._cycles) > idx else {}
def prefix(self, widget):
return self._get(widget, "prefix")
def suffix(self, widget):
return self._get(widget, "suffix")
def color(self, widget):
result = self._get(widget, "fg")
if widget.warning():
result = self._get(widget, "fg-warning")
if widget.critical():
result = self._get(widget, "fg-critical")
return result
def background(self, widget):
result = self._get(widget, "bg")
if widget.warning():
result = self._get(widget, "bg-warning")
if widget.critical():
result = self._get(widget, "bg-critical")
self._background[0] = result
return result
def separator(self, widget):
return self._get(widget, "separator")
def default_separators(self, widget):
return self._get(widget, "default-separators")
def separator_color(self, widget):
return self.background(widget)
def separator_background(self, widget):
return self._background[1]
def separator_block_width(self, widget):
return self._get(widget, "separator-block-width")
def _get(self, widget, name):
module = widget.module()
state = widget.state()
inst = widget.instance()
inst = inst.replace("{}.".format(module), "")
module_theme = self._data.get(module, {})
state_theme = module_theme.get("states", {}).get(state, {})
instance_theme = module_theme.get(inst, {})
instance_state_theme = instance_theme.get("states", {}).get(state, {})
value = None
value = self._defaults.get(name, value)
value = self._cycle.get(name, value)
value = module_theme.get(name, value)
value = state_theme.get(name, value)
value = instance_theme.get(name, value)
value = instance_state_theme.get(name, value)
if type(value) is list:
key = "{}{}".format(repr(widget), value)
idx = self._config.parameter(key, 0)
self._config.increase(key, len(value), 0)
value = value[idx]
return value
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4