bumblebee-status/core/theme.py
tobi-wan-kenobi 4cd6444bbf [core/theme] Improve items that are lists
Until now, using a list as prefix/suffix didn't work as expected,
because the corresponding method for retrieving the value was called
multiple times, and each time, the next icon would be retrieved.

Changed the logic inside the theme to only update the indices every time
that an actual update was happening.
2020-04-12 14:01:51 +02:00

133 lines
4.4 KiB
Python

import os
import io
import json
import logging
import copy
import core.event
import util.algorithm
log = logging.getLogger(__name__)
THEME_BASE_DIR=os.path.dirname(os.path.realpath(__file__))
PATHS=[
'.',
os.path.join(THEME_BASE_DIR, '../themes'),
os.path.expanduser('~/.config/bumblebee-status/themes'),
]
def merge_replace(value, new_value, key):
if not isinstance(value, dict):
return new_value
if isinstance(new_value, dict):
util.algorithm.merge(value, new_value)
return value
# right now, merging needs explicit pango support :(
if 'pango' in value:
value['pango']['full_text'] = new_value
return value
class Theme(object):
def __init__(self, name='default', iconset='auto', raw_data=None):
self.name = name
self.__widget_count = 0
self.__previous = {}
self.__current = {}
self.__keywords = {}
self.__value_idx = {}
self.__data = raw_data if raw_data else self.load(name)
for icons in self.__data.get('icons', []):
util.algorithm.merge(self.__data, self.load(icons, 'icons'))
if iconset != 'auto':
util.algorithm.merge(self.__data, self.load(iconset, 'icons'))
for colors in self.__data.get('colors', []):
util.algorithm.merge(self.__keywords, self.load_keywords(colors))
core.event.register('update', self.__start)
core.event.register('next-widget', self.__next_widget)
def keywords(self):
return self.__keywords
def load(self, name, subdir=''):
if isinstance(name, dict): return name # support plain data
for path in PATHS:
theme_file = os.path.join(path, subdir, '{}.json'.format(name))
result = self.__load_json(theme_file)
if result != {}: return result
raise RuntimeError('unable to find theme {}'.format(name))
def __load_json(self, filename):
filename = os.path.expanduser(filename)
if not os.path.isfile(filename): return {}
with io.open(filename) as data:
return json.load(data)
def load_keywords(self, name):
try:
if isinstance(name, dict):
return name
if name.lower() == 'wal':
wal = self.__load_json('~/.cache/wal/colors.json')
result = {}
for field in ['special', 'colors']:
for key in wal.get(field, {}):
result[key] = wal[field][key]
return result
except Exception as e:
log.error('failed to load colors: {}', e)
def __start(self):
self.__widget_count = 0
self.__current.clear()
self.__previous.clear()
for key, value in self.__value_idx.items():
self.__value_idx[key] = value + 1
def __next_widget(self):
self.__widget_count = self.__widget_count + 1
self.__previous = dict(self.__current)
self.__current.clear()
def get(self, key, widget=None, default=None):
if not widget:
widget = core.widget.Widget('')
# special handling
if widget == 'previous':
return self.__previous.get(key, None)
value = default
for option in ['defaults', 'cycle']:
if option in self.__data:
tmp = self.__data[option]
if isinstance(tmp, list):
tmp = tmp[self.__widget_count % len(tmp)]
value = merge_replace(value, tmp.get(key, value), key)
if isinstance(value, dict):
value = copy.deepcopy(value)
value = merge_replace(value, self.__data.get(key, value), key)
if widget.module():
value = merge_replace(value, self.get(widget.module().name(), None, {}).get(key, value), key)
if not key in widget.state():
for state in widget.state():
theme = self.get(state, widget, {})
value = merge_replace(value, theme.get(key, value), key)
if not type(value) in (list, dict):
value = self.__keywords.get(value, value)
if isinstance(value, list):
idx = self.__value_idx.get('{}::{}'.format(widget.id, key), 0) % len(value)
self.__value_idx['{}::{}'.format(widget.id, key)] = idx
widget.set(key, idx)
value = value[idx]
self.__current[key] = value
return value
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4