-
Notifications
You must be signed in to change notification settings - Fork 766
/
_color.py
77 lines (64 loc) · 2.78 KB
/
_color.py
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
"""
Helper functions to work with Textual Colors.
"""
from __future__ import annotations
from textual.color import Color
from textual.css._help_text import color_property_help_text
from textual.css.errors import DeclarationError, StyleValueError
from textual.css.scalar import Scalar, Unit
from textual.css.tokenizer import Token
def parse_color_tokens(property_name: str, tokens: list[Token]) -> tuple[Color, bool]:
"""
Parses the tokens of a color expression, such as "red", "#FFCC00", "rgb(1,255,50)", "lime 50%", "95% auto"...
Args:
property_name (str): The name of the CSS property. Only used to raise DeclarationErrors that include this name.
tokens (list[Token]): CSS tokens describing a color - i.e. an expression supported by ``Color.parse``,
optionally prefixed or suffixed with a percentage value token.
Returns:
tuple[Color, bool]: a Color instance, as well as a boolean telling us if it's a pseudo-color "auto" one.
Raises:
DeclarationError: if we come across an unexpected value
"""
property_name = property_name.replace("-", "_")
alpha = 1.0
color = None
is_auto = False
for token in tokens:
if token.name == "token" and token.value == "auto":
is_auto = True
elif token.name == "scalar":
alpha_scalar = Scalar.parse(token.value)
if alpha_scalar.unit != Unit.PERCENT:
raise DeclarationError(
property_name, token, "alpha must be given as a percentage."
)
alpha = alpha_scalar.value / 100.0
elif token.name in ("color", "token"):
try:
color = Color.parse(token.value)
except Exception as error:
raise DeclarationError(
property_name,
token,
color_property_help_text(property_name, context="css", error=error),
)
elif token.name == "whitespace":
continue
else:
raise DeclarationError(
property_name,
token,
color_property_help_text(property_name, context="css"),
)
if is_auto:
# For "auto" colors we're still using a Color object, but only to store their alpha.
# We could use anything for the RGB values since we won't use them, but using (1,2,3) is handy to
# be able to spot such "I'm just an alpha bearer" Color instances when we debug:
return Color(1, 2, 3, alpha), True
if color is None:
raise StyleValueError(
f"no Color could be extracted from the given expression for property '{property_name}'."
)
if alpha is not None and alpha < 1:
color = color.with_alpha(alpha)
return color, False