mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
auto color
This commit is contained in:
20
sandbox/will/design.css
Normal file
20
sandbox/will/design.css
Normal 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
36
sandbox/will/design.py
Normal 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()
|
||||
@@ -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]
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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"."""
|
||||
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user