auto color

This commit is contained in:
Will McGugan
2022-09-12 17:18:28 +01:00
parent 150af18026
commit 86a5f8ab35
8 changed files with 82 additions and 8 deletions

20
sandbox/will/design.css Normal file
View File

@@ -0,0 +1,20 @@
Container {
height: auto;
background: $surface;
margin: 1 2;
}
Panel {
height: auto;
background: $surface;
margin: 1 2;
padding: 1 2;
}
Content {
background: $surface;
padding: 1 2;
margin: 1 2;
color: auto 95%;
}

36
sandbox/will/design.py Normal file
View File

@@ -0,0 +1,36 @@
from textual.app import App
from textual.layout import Container
from textual.widgets import Header, Footer, Static
class Content(Static):
pass
class Panel(Container):
pass
class Panel2(Container):
pass
class DesignApp(App):
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
def compose(self):
yield Header()
yield Footer()
yield Panel(
Content("content"),
Panel(
Content("more content"),
Content("more content"),
),
)
yield Panel(Static("Hello World"))
app = DesignApp(css_path="design.css")
if __name__ == "__main__":
app.run()

View File

@@ -271,9 +271,9 @@ class StylesCache:
pad_bottom and y >= height - gutter.bottom
):
background_style = from_color(bgcolor=background.rich_color)
left_style = from_color(color=border_left_color.rich_color)
left_style = from_color(color=(background + border_left_color).rich_color)
left = get_box(border_left, inner, outer, left_style)[1][0]
right_style = from_color(color=border_right_color.rich_color)
right_style = from_color(color=(background + border_right_color).rich_color)
right = get_box(border_right, inner, outer, right_style)[1][2]
if border_left and border_right:
line = [left, Segment(" " * (width - 2), background_style), right]

View File

@@ -279,7 +279,7 @@ class Color(NamedTuple):
r, g, b, _ = self
return Color(r, g, b, alpha)
def blend(self, destination: Color, factor: float) -> Color:
def blend(self, destination: Color, factor: float, alpha: float = 1) -> Color:
"""Generate a new color between two colors.
Args:
@@ -299,6 +299,7 @@ class Color(NamedTuple):
int(r1 + (r2 - r1) * factor),
int(g1 + (g2 - g1) * factor),
int(b1 + (b2 - b1) * factor),
alpha,
)
def __add__(self, other: object) -> Color:
@@ -407,7 +408,7 @@ class Color(NamedTuple):
"""
l, a, b = rgb_to_lab(self)
l -= amount * 100
return lab_to_rgb(Lab(l, a, b)).clamped
return lab_to_rgb(Lab(l, a, b), self.a).clamped
def lighten(self, amount: float) -> Color:
"""Lighten the color by a given amount.
@@ -508,7 +509,7 @@ def rgb_to_lab(rgb: Color) -> Lab:
return Lab(116 * y - 16, 500 * (x - y), 200 * (y - z))
def lab_to_rgb(lab: Lab) -> Color:
def lab_to_rgb(lab: Lab, alpha: float = 1.0) -> Color:
"""Convert a CIE-L*ab color to RGB.
Uses the standard RGB color space with a D65/2⁰ standard illuminant.
@@ -533,7 +534,7 @@ def lab_to_rgb(lab: Lab) -> Color:
g = 1.055 * pow(g, 1 / 2.4) - 0.055 if g > 0.0031308 else 12.92 * g
b = 1.055 * pow(b, 1 / 2.4) - 0.055 if b > 0.0031308 else 12.92 * b
return Color(int(r * 255), int(g * 255), int(b * 255))
return Color(int(r * 255), int(g * 255), int(b * 255), alpha)
if __name__ == "__main__":

View File

@@ -102,6 +102,11 @@ class IntegerProperty(GenericProperty[int, int]):
raise StyleValueError(f"Expected a number here, got f{value}")
class BooleanProperty(GenericProperty[bool, bool]):
def validate_value(self, value: object) -> bool:
return bool(value)
class ScalarProperty:
"""Descriptor for getting and setting scalar properties. Scalars are numeric values with a unit, e.g. "50vh"."""

View File

@@ -580,7 +580,9 @@ class StylesBuilder:
alpha: float | None = None
for token in tokens:
if token.name == "scalar":
if token.name == "token" and token.value == "auto":
self.styles._rules["auto_color"] = True
elif token.name == "scalar":
alpha_scalar = Scalar.parse(token.value)
if alpha_scalar.unit != Unit.PERCENT:
self.error(name, token, "alpha must be given as a percentage.")

View File

@@ -16,6 +16,7 @@ from ..color import Color
from ..geometry import Offset, Spacing
from ._style_properties import (
AlignProperty,
BooleanProperty,
BorderProperty,
BoxProperty,
ColorProperty,
@@ -83,6 +84,7 @@ class RulesMap(TypedDict, total=False):
visibility: Visibility
layout: "Layout"
auto_color: bool
color: Color
background: Color
text_style: Style
@@ -183,6 +185,7 @@ class StylesBase(ABC):
"min_height",
"max_width",
"max_height",
"auto_color",
"color",
"background",
"opacity",
@@ -202,6 +205,7 @@ class StylesBase(ABC):
visibility = StringEnumProperty(VALID_VISIBILITY, "visible")
layout = LayoutProperty()
auto_color = BooleanProperty(default=False)
color = ColorProperty(Color(255, 255, 255))
background = ColorProperty(Color(0, 0, 0, 0), background=True)
text_style = StyleFlagsProperty()

View File

@@ -497,6 +497,8 @@ class DOMNode(MessagePump):
if styles.has_rule("color"):
color = styles.color
style += styles.text_style
if styles.has_rule("auto_color") and styles.auto_color:
color = background.get_contrast_text(color.a)
style += Style.from_color(
(background + color).rich_color, background.rich_color
)
@@ -534,7 +536,11 @@ class DOMNode(MessagePump):
background += styles.background
if styles.has_rule("color"):
base_color = color
color = styles.color
if styles.auto_color:
color = background.get_contrast_text(color.a)
else:
color = styles.color
return (base_background, base_color, background, color)
@property