OLD | NEW |
| (Empty) |
1 " SCSS Values." | |
2 | |
3 from colorsys import rgb_to_hls, hls_to_rgb | |
4 from pyparsing import ParseResults | |
5 | |
6 from scss import OPRT, CONV_FACTOR, COLORS | |
7 from scss.base import Node | |
8 | |
9 | |
10 hex2rgba = { | |
11 8: lambda c: (int(c[0:2], 16), int(c[2:4], 16), int(c[4:6], 16), int(c[6:8],
16)), | |
12 6: lambda c: (int(c[0:2], 16), int(c[2:4], 16), int(c[4:6], 16), 1.0), | |
13 4: lambda c: (int(c[0]*2, 16), int(c[1]*2, 16), int(c[2]*2, 16), int(c[3]*2,
16)), | |
14 3: lambda c: (int(c[0]*2, 16), int(c[1]*2, 16), int(c[2]*2, 16), 1.0), | |
15 } | |
16 | |
17 | |
18 def hsl_op(op, color, h, s, l): | |
19 color = ColorValue(color) | |
20 h, s, l = map(NumberValue, (h, s, l)) | |
21 h.units = 'deg' | |
22 s.units = l.units = '%' | |
23 other_hls = map(float, (h, l, s)) | |
24 self_hls = rgb_to_hls(*map(lambda x: x / 255.0, color.value[:3])) | |
25 res_hls = map(lambda x, y: op(x, y) if op else y if y else x, self_hls, othe
r_hls) | |
26 res_hls = map(lambda x: 1 if x > 1 else 0 if x < 0 else x, res_hls) | |
27 res = hls_to_rgb(*res_hls) | |
28 return ColorValue((res[0] * 255.0, res[1] * 255.0, res[2] * 255.0, color.val
ue[3])) | |
29 | |
30 | |
31 def rgba_op(op, color, r, g, b, a): | |
32 other = (float(r), float(g), float(b), float(a)) | |
33 res = map(op or ( lambda x, y: x or y ), color.value, other) | |
34 res[3] = 1 if float(a) == color.value[3] == 1 else res[3] | |
35 return ColorValue(res) | |
36 | |
37 | |
38 class Value(Node): | |
39 """ Abstract value. | |
40 """ | |
41 @classmethod | |
42 def _do_op(cls, self, other, op): | |
43 first, second = cls(self), cls(other) | |
44 return op(first.value, second.value) | |
45 | |
46 @classmethod | |
47 def _do_cmps(cls, first, second, op): | |
48 return op(first.value, second.value) | |
49 | |
50 # Math operation | |
51 def __add__(self, other): | |
52 return self._do_op(self, other, OPRT['+']) | |
53 | |
54 __radd__ = __add__ | |
55 | |
56 def __div__(self, other): | |
57 return self._do_op(self, other, OPRT['/']) | |
58 | |
59 def __rdiv__(self, other): | |
60 return self._do_op(other, self, OPRT['/']) | |
61 | |
62 def __sub__(self, other): | |
63 return self._do_op(self, other, OPRT['-']) | |
64 | |
65 def __rsub__(self, other): | |
66 return self._do_op(other, self, OPRT['-']) | |
67 | |
68 def __mul__(self, other): | |
69 return self._do_op(self, other, OPRT['*']) | |
70 | |
71 def __lt__(self, other): | |
72 return self._do_cmps(self, other, OPRT['<']) | |
73 | |
74 __rmul__ = __mul__ | |
75 | |
76 # Compare operation | |
77 def __le__(self, other): | |
78 return self._do_cmps(self, other, OPRT['<=']) | |
79 | |
80 def __gt__(self, other): | |
81 return self._do_cmps(self, other, OPRT['>=']) | |
82 | |
83 def __ge__(self, other): | |
84 return self._do_cmps(self, other, OPRT['>']) | |
85 | |
86 def __eq__(self, other): | |
87 return self._do_cmps(self, other, OPRT['==']) | |
88 | |
89 def __ne__(self, other): | |
90 return self._do_cmps(self, other, OPRT['!=']) | |
91 | |
92 # Boolean | |
93 def __nonzero__(self): | |
94 return getattr(self, 'value') and True or False | |
95 | |
96 def __bool__(self): | |
97 return bool(self.value) if self.value != 'false' else False | |
98 | |
99 def __str__(self): | |
100 return str(self.value) | |
101 | |
102 def __float__(self): | |
103 return float(self.value) | |
104 | |
105 | |
106 class StringValueMeta(type): | |
107 | |
108 def __call__(mcs, *args, **kwargs): | |
109 test = mcs.__new__(mcs) | |
110 test.__init__(*args, **kwargs) | |
111 | |
112 if test.value in ('true', 'false'): | |
113 return BooleanValue(test.value) | |
114 | |
115 elif COLORS.has_key(test.value): | |
116 return ColorValue(COLORS.get(test.value)) | |
117 | |
118 return test | |
119 | |
120 | |
121 class StringValue(Value): | |
122 | |
123 __metaclass__ = StringValueMeta | |
124 | |
125 def_value = '' | |
126 | |
127 def __init__(self, t): | |
128 super(StringValue, self).__init__(None, None, t) | |
129 | |
130 self.value = self.def_value | |
131 | |
132 if isinstance(t, ParseResults): | |
133 self.value = ''.join(str(s) for s in t) | |
134 | |
135 elif isinstance(t, StringValue): | |
136 self.value = t.value | |
137 | |
138 elif isinstance(t, Node): | |
139 self.value = str(t.value).strip('"\'') | |
140 | |
141 elif isinstance(t, (str, int, float)): | |
142 self.value = str(t) | |
143 | |
144 def __div__(self, other): | |
145 self.value = '/'.join((str(self), str(other))) | |
146 return self | |
147 | |
148 def __str__(self): | |
149 return self.value | |
150 | |
151 | |
152 class PointValue(Value): | |
153 | |
154 @property | |
155 def value(self): | |
156 return ' '.join(map(str, self.data)) | |
157 | |
158 def __str__(self): | |
159 return self.value | |
160 | |
161 class RepeatValue(Value): | |
162 @property | |
163 def value(self): | |
164 return ''.join(map(str, self.data)) | |
165 | |
166 def __str__(self): | |
167 return '[%s]' % self.value | |
168 | |
169 class QuotedStringValue(StringValue): | |
170 | |
171 def __init__(self, t): | |
172 super(QuotedStringValue, self).__init__(t) | |
173 self.value = self.value.strip('"\'') | |
174 | |
175 def __str__(self): | |
176 return "'%s'" % self.value | |
177 | |
178 | |
179 class ColorValue(Value): | |
180 | |
181 def_value = (255.0, 255.0, 255.0, 1) | |
182 | |
183 def __init__(self, t): | |
184 super(ColorValue, self).__init__(None, None, t) | |
185 self.value = self.def_value | |
186 | |
187 if isinstance(t, ParseResults): | |
188 val = t[0][1:] | |
189 self.value = hex2rgba[len(val)](val) | |
190 | |
191 elif isinstance(t, (list, tuple)): | |
192 r = self.value | |
193 c = map(lambda x, y: x if not x is None else y, t, r) | |
194 c = tuple(0.0 if c[i] < 0 else r[i] if c[i] > r[i] else c[i] for i i
n range(4)) | |
195 self.value = c | |
196 | |
197 elif isinstance(t, str): | |
198 val = t[1:] | |
199 self.value = hex2rgba[len(val)](val) | |
200 | |
201 elif isinstance(t, ColorValue): | |
202 self.value = t.value | |
203 | |
204 def __float__(self): | |
205 return float( sum(self.value[:3], 0.0) / 3 * self.value[3] ) | |
206 | |
207 def __str__(self): | |
208 if self.value[3] == 1: | |
209 v = '%02x%02x%02x' % self.value[:3] | |
210 if v[0] == v[1] and v[2] == v[3] and v[4] == v[5]: | |
211 v = v[0] + v[2] + v[4] | |
212 return '#%s' % v | |
213 return 'rgba(%d,%d,%d,%.2f)' % self.value | |
214 | |
215 __repr__ = __str__ | |
216 | |
217 @classmethod | |
218 def _do_op(cls, self, other, op): | |
219 if isinstance(other, ColorValue): | |
220 return rgba_op(op, self, *other.value) | |
221 | |
222 elif isinstance(other, ( NumberValue, int )): | |
223 if op in (OPRT['*'], OPRT['/']): | |
224 return ColorValue(map(lambda x: op(x, float(other)), self.value[
:3])) | |
225 return hsl_op(op, self, 0, other, 0) | |
226 | |
227 else: | |
228 return self | |
229 | |
230 | |
231 class BooleanValue(Value): | |
232 | |
233 def_value = True | |
234 | |
235 def __init__(self, t): | |
236 super(BooleanValue, self).__init__(None, None, t) | |
237 self.value = self.def_value | |
238 | |
239 if isinstance(t, (str, bool)): | |
240 self.value = bool(t) if t != 'false' else False | |
241 | |
242 elif isinstance(t, Node): | |
243 self.value = bool(t) | |
244 | |
245 def __str__(self): | |
246 return 'true' if self.value else 'false' | |
247 | |
248 __repr__ = __str__ | |
249 | |
250 def __float__(self): | |
251 return 1.0 if self.value else 0.0 | |
252 | |
253 | |
254 class NumberValue(Value): | |
255 | |
256 def_value = 0.0 | |
257 | |
258 def __init__(self, t): | |
259 super(NumberValue, self).__init__(None, None, t) | |
260 self.value = self.def_value | |
261 self.units = '' | |
262 | |
263 if isinstance(t, (ParseResults, list, tuple)): | |
264 if len(t) > 1: | |
265 self.units = t[1] | |
266 self.value = float(t[0]) | |
267 | |
268 elif isinstance(t, NumberValue): | |
269 self.value, self.units = t.value, t.units | |
270 | |
271 elif isinstance(t, Node): | |
272 self.value = float(t.value) | |
273 self.units = getattr(t.value, 'units', '') | |
274 | |
275 elif isinstance(t, (int, float, str)): | |
276 self.value = float(t) | |
277 | |
278 def __float__(self): | |
279 return self.value * CONV_FACTOR.get(self.units, 1.0) | |
280 | |
281 def __str__(self): | |
282 value = ("%0.03f" % self.value).strip('0').rstrip('.') or 0 | |
283 # Don't emit unit suffix for 0 unless it's a percentage. Necessary in | |
284 # animation keyframe selectors. | |
285 theUnits = self.units if (self.value or self.units == '%') else '' | |
286 return "%s%s" % (value, theUnits) | |
287 | |
288 @classmethod | |
289 def _do_op(cls, self, other, op): | |
290 first, second = cls(self), cls(other) | |
291 units = second.units or first.units | |
292 value = op(float(first), float(second)) | |
293 value /= CONV_FACTOR.get(units, 1.0) | |
294 return cls((value, units)) | |
OLD | NEW |