Add opacity, PercentageProperty

This commit is contained in:
Darren Burns
2022-02-11 10:21:44 +00:00
parent d3becefc27
commit e1591f5602
5 changed files with 91 additions and 7 deletions

View File

@@ -34,6 +34,7 @@ Widget:hover {
#header {
text: $text on $primary;
opacity: 0.2;
height: 3;
border-bottom: hkey $secondary;
}

View File

@@ -9,8 +9,7 @@ when setting and getting.
from __future__ import annotations
from typing import Iterable, NamedTuple, TYPE_CHECKING
from typing import Iterable, NamedTuple, TYPE_CHECKING, cast
import rich.repr
from rich.color import Color
@@ -28,7 +27,7 @@ from .scalar import (
ScalarParseError,
)
from .transition import Transition
from ..geometry import Spacing, SpacingDimensions
from ..geometry import Spacing, SpacingDimensions, clamp
if TYPE_CHECKING:
from ..layout import Layout
@@ -756,7 +755,7 @@ class TransitionsProperty:
def __get__(
self, obj: Styles, objtype: type[Styles] | None = None
) -> dict[str, Transition]:
"""Get a mapping of properties to the the transitions applied to them.
"""Get a mapping of properties to the transitions applied to them.
Args:
obj (Styles): The ``Styles`` object.
@@ -774,3 +773,51 @@ class TransitionsProperty:
obj.clear_rule("transitions")
else:
obj.set_rule("transitions", transitions.copy())
class PercentageProperty:
"""Property that can be set either as a float (e.g. 0.1) or a
string percentage (e.g. '10%'). Values will be clamped to the range (0, 1).
"""
def __init__(self, default: float = 1.0):
self.default = default
def __set_name__(self, owner: Styles, name: str) -> None:
self.name = name
def __get__(self, obj: Styles, type: type[Styles]) -> float:
"""Get the property value as a float between 0 and 1
Args:
obj (Styles): The ``Styles`` object.
objtype (type[Styles]): The ``Styles`` class.
Returns:
float: The value of the property (in the range (0, 1))
"""
return cast(float, obj.get_rule(self.name, self.default))
def __set__(self, obj: Styles, value: float | str | None) -> None:
"""Set the property value, clamping it between 0 and 1.
Args:
obj (Styles): The Styles object.
value (float|str|None): The value to set as a float between 0 and 1, or
as a percentage string such as '10%'.
"""
obj.refresh()
name = self.name
if value is None:
obj.clear_rule(name)
return
if isinstance(value, float):
float_value = value
elif isinstance(value, str):
float_value = float(Scalar.parse(value).value) / 100
else:
raise StyleTypeError(
f"{self.name} must be a str (e.g. '10%') or a float (e.g. 0.1)"
)
obj.set_rule(name, clamp(float_value, 0, 1))

View File

@@ -17,8 +17,7 @@ from .transition import Transition
from .types import Edge, Display, Visibility
from .._duration import _duration_as_seconds
from .._easing import EASING
from .._loop import loop_last
from ..geometry import Spacing, SpacingDimensions
from ..geometry import Spacing, SpacingDimensions, clamp
class StylesBuilder:
@@ -124,6 +123,39 @@ class StylesBuilder:
else:
self.error(name, token, f"invalid token {value!r} in this context")
def process_opacity(self, name: str, tokens: list[Token], important: bool) -> None:
if not tokens:
return
token = tokens[0]
if len(tokens) != 1:
self.error(name, token, "expected a single number")
else:
token_name = token.name
value = token.value
if token_name == "scalar" and value.endswith("%"):
percentage = value[:-1]
try:
opacity = clamp(float(percentage) / 100, 0, 1)
self.styles.set_rule(name, opacity)
except ValueError:
self.error(
name, token, f"unable to process value {value!r} as percentage"
)
elif token_name == "number":
try:
opacity = clamp(float(value), 0, 1)
self.styles.set_rule(name, opacity)
except ValueError:
self.error(
name, token, f"unable to process value {value!r} as float"
)
else:
self.error(
name,
token,
f"expected a scalar percentage or float between 0 and 1; found {token.value!r}; example valid values: '0.4', '40%'",
)
def _process_space(self, name: str, tokens: list[Token]) -> None:
space: list[int] = []
append = space.append

View File

@@ -28,6 +28,7 @@ from ._style_properties import (
StyleFlagsProperty,
StyleProperty,
TransitionsProperty,
PercentageProperty,
)
from .constants import VALID_DISPLAY, VALID_VISIBILITY
from .scalar import Scalar, ScalarOffset, Unit
@@ -62,6 +63,8 @@ class RulesMap(TypedDict, total=False):
text_background: Color
text_style: Style
opacity: float
padding: Spacing
margin: Spacing
offset: ScalarOffset
@@ -121,6 +124,8 @@ class StylesBase(ABC):
text_background = ColorProperty()
text_style = StyleFlagsProperty()
opacity = PercentageProperty()
padding = SpacingProperty()
margin = SpacingProperty()
offset = OffsetProperty()

View File

@@ -4,7 +4,6 @@ import re
from typing import NamedTuple
import rich.repr
from rich.cells import cell_len
class EOFError(Exception):