1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# Copyright (C) 2011-2012 Patrick Totzke <patricktotzke@gmail.com>
# This file is released under the GNU GPL, version 3 or a later revision.
# For further details see the COPYING file
import os
from utils import read_config
from checks import align_mode
from checks import attr_triple
from checks import width_tuple
from checks import force_list
from errors import ConfigError
DEFAULTSPATH = os.path.join(os.path.dirname(__file__), '..', 'defaults')
class Theme(object):
"""Colour theme"""
def __init__(self, path):
"""
:param path: path to theme file
:type path: str
:raises: :class:`~alot.settings.errors.ConfigError`
"""
self._spec = os.path.join(DEFAULTSPATH, 'theme.spec')
self._config = read_config(path, self._spec,
checks={'align': align_mode,
'widthtuple': width_tuple,
'force_list': force_list,
'attrtriple': attr_triple})
self._colours = [1, 16, 256]
# make sure every entry in 'order' lists have their own subsections
threadline = self._config['search']['threadline']
for sec in self._config['search']:
if sec.startswith('threadline'):
tline = self._config['search'][sec]
if tline['parts'] is not None:
listed = set(tline['parts'])
here = set(tline.sections)
indefault = set(threadline.sections)
diff = listed.difference(here.union(indefault))
if diff:
msg = 'missing threadline parts: %s' % diff
raise ConfigError(msg)
def get_attribute(self, mode, name, colourmode):
"""
returns requested attribute
:param mode: ui-mode (e.g. `search`,`thread`...)
:type mode: str
:param name: identifier of the atttribute
:type name: str
:param colourmode: colour mode; in [1, 16, 256]
:type colourmode: int
:rtype: urwid.AttrSpec
"""
return self._config[mode][name][self._colours.index(colourmode)]
def get_threadline_theming(self, thread, colourmode):
"""
look up how to display a Threadline wiidget in search mode
for a given thread.
:param thread: Thread to theme Threadline for
:type thread: alot.db.thread.Thread
:param colourmode: colourmode to use, one of 1,16,256.
:type colourmode: int
This will return a dict mapping
:normal: to `urwid.AttrSpec`,
:focus: to `urwid.AttrSpec`,
:parts: to a list of strings indentifying subwidgets
to be displayed in this order.
Moreover, for every part listed this will map 'part' to a dict mapping
:normal: to `urwid.AttrSpec`,
:focus: to `urwid.AttrSpec`,
:width: to a tuple indicating the width of the subpart.
This is either `('fit', min, max)` to force the widget
to be at least `min` and at most `max` characters wide,
or `('weight', n)` which makes it share remaining space
with other 'weight' parts.
:alignment: where to place the content if shorter than the widget.
This is either 'right', 'left' or 'center'.
"""
def pickcolour(triple):
return triple[self._colours.index(colourmode)]
def matches(sec, thread):
if sec.get('tagged_with') is not None:
if not set(sec['tagged_with']).issubset(thread.get_tags()):
return False
if sec.get('query') is not None:
if not thread.matches(sec['query']):
return False
return True
default = self._config['search']['threadline']
match = default
candidates = self._config['search'].sections
for candidatename in candidates:
candidate = self._config['search'][candidatename]
if candidatename.startswith('threadline') and\
(not candidatename == 'threadline') and\
matches(candidate, thread):
match = candidate
break
# fill in values
res = {}
res['normal'] = pickcolour(match.get('normal') or default['normal'])
res['focus'] = pickcolour(match.get('focus') or default['focus'])
res['parts'] = match.get('parts') or default['parts']
for part in res['parts']:
defaultsec = default.get(part)
partsec = match.get(part)
def fill(key, fallback=None):
pvalue = partsec.get(key) or defaultsec.get(key)
return pvalue or fallback
res[part] = {}
res[part]['width'] = fill('width', ('fit', 0, 0))
res[part]['alignment'] = fill('alignment', 'right')
res[part]['normal'] = pickcolour(fill('normal'))
res[part]['focus'] = pickcolour(fill('focus'))
return res
|