| 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 |