colours.py

changeset 8
303c51137cb2
parent 4
8eb83f200486
child 11
b42788f5d0a9
equal deleted inserted replaced
7:0ab0d61ccee8 8:303c51137cb2
1 #!/usr/bin/env python3
2 class Colour:
3 '''
4 Colour interface. Supports LDConfig colours and direct colours.
5 For LDConfig colours to work, load_colours must be called first.
6 '''
7 def __init__(self, index):
8 if not isinstance(index, int):
9 index = int(index, 0)
10 self.index = index
11 def __str__(self):
12 if self.is_direct_colour:
13 # write direct colours with hex codes
14 return '0x%07X' % self.index
15 else:
16 return str(self.index)
17 def __repr__(self):
18 try:
19 return 'colours.' + colours_inverse_dict[self.index]
20 except KeyError:
21 return str.format('Colour({!r})', self.index)
22 @property
23 def is_direct_colour(self):
24 return self.index >= 0x2000000
25 @property
26 def is_ldconfig_colour(self):
27 return self.index in ldconfig_colour_data
28 @property
29 def name(self):
30 if self.is_ldconfig_colour:
31 return ldconfig_colour_data[self.index]['name']
32 else:
33 return str(self)
34 @property
35 def face_colour(self):
36 if self.is_ldconfig_colour:
37 return ldconfig_colour_data[self.index]['value']
38 elif self.is_direct_colour:
39 return '#%06X' % (self.index & 0xffffff)
40 else:
41 return '#000000'
42 @property
43 def is_valid(self):
44 return self.is_ldconfig_colour or self.is_direct_colour
45 def __eq__(self, other):
46 return self.index == other.index
47 def __lt__(self, other):
48 return self.index < other.index
49 def __le__(self, other):
50 return self.index <= other.index
51 def __gt__(self, other):
52 return self.index > other.index
53 def __ge__(self, other):
54 return self.index >= other.index
55
56 def parse_ldconfig_ldr_line(line):
57 '''
58 Parses a single LDConfig.ldr line.
59
60 Returns:
61 · a dict for a successful parsed colour.
62 · None for empty lines and comments.
63
64 Raises an error for invalid lines.
65 '''
66 line = line.strip()
67 import re
68 def parse_tag(tag):
69 match = re.search(tag + r'\s+([^ ]+)', line)
70 if match:
71 return match.group(1)
72 else:
73 raise KeyError(str.format('Tag {} not found', tag))
74 # parse 0 !COLOUR and get the name
75 match = re.search(r'^0\s+!COLOUR\s([^ ]+)', line)
76 if not match:
77 # failed, check if it's an empty line or comment:
78 if not line or line.startswith('0'):
79 return None
80 else:
81 # failed too, thus the line is bad
82 raise ValueError('Bad LDConfig.ldr line')
83 # replace underscores for readability
84 name = match.group(1).replace('_', ' ')
85 # parse tags
86 code = int(parse_tag('CODE'))
87 value = parse_tag('VALUE')
88 edge = parse_tag('EDGE')
89 return {
90 'name': name,
91 'code': code,
92 'value': value,
93 'edge': edge,
94 }
95
96 def parse_ldconfig_ldr(ldconfig_ldr):
97 '''
98 Parses LDConfig.ldr and returns pairs
99 '''
100 for line in ldconfig_ldr:
101 colour = parse_ldconfig_ldr_line(line)
102 if colour:
103 yield (colour['code'], colour)
104
105 class colours:
106 '''
107 LDConfig colour namespace, exists for interactive mode and for
108 Colour.__repr__ to return something pretty.
109 '''
110 pass
111
112 # LDConfig lookup tables
113 colours_inverse_dict = {}
114 ldconfig_colour_data = {}
115
116 def load_colours(ldconfig_ldr):
117 '''
118 Loads colours. Expects a file pointer to LDConfig.ldr as the parameter.
119 '''
120 global ldconfig_colour_data
121 ldconfig_colour_data = dict(parse_ldconfig_ldr(ldconfig_ldr))
122 for index, colour in ldconfig_colour_data.items():
123 identifier = colour['name'].replace(' ', '_').lower()
124 setattr(colours, identifier, Colour(index))
125 colours_inverse_dict[index] = identifier
126
127 # Interactive mode support (pass LDConfig.ldr path as a command-line argument)
128 if __name__ == '__main__':
129 from sys import argv
130 with open(argv[1]) as ldconfig_ldr:
131 load_colours(ldconfig_ldr)

mercurial