add render background

This commit is contained in:
Will McGugan
2022-02-23 10:08:47 +00:00
parent d0b1ca5283
commit 9d592e976e
7 changed files with 97 additions and 61 deletions

View File

@@ -33,6 +33,7 @@ from .geometry import Offset, Region, Size
from .layouts.dock import Dock from .layouts.dock import Dock
from .message_pump import MessagePump from .message_pump import MessagePump
from .reactive import Reactive from .reactive import Reactive
from .renderables.gradient import VerticalGradient
from .view import View from .view import View
from .widget import Widget from .widget import Widget
@@ -152,9 +153,6 @@ class App(DOMNode):
def __rich_repr__(self) -> rich.repr.Result: def __rich_repr__(self) -> rich.repr.Result:
yield "title", self.title yield "title", self.title
def __rich__(self) -> RenderableType:
return self.view
@property @property
def animator(self) -> Animator: def animator(self) -> Animator:
return self._animator return self._animator
@@ -287,6 +285,10 @@ class App(DOMNode):
except EmptyQueryError: except EmptyQueryError:
raise KeyError(selector) raise KeyError(selector)
def render_background(self) -> RenderableType:
gradient = VerticalGradient("red", "blue")
return gradient
def update_styles(self) -> None: def update_styles(self) -> None:
"""Request update of styles. """Request update of styles.

View File

@@ -31,7 +31,7 @@ from ..geometry import Spacing, SpacingDimensions, clamp
if TYPE_CHECKING: if TYPE_CHECKING:
from ..layout import Layout from ..layout import Layout
from .styles import Styles from .styles import Styles, StylesBase
from .styles import DockGroup from .styles import DockGroup
from .._box import BoxType from .._box import BoxType
@@ -55,7 +55,7 @@ class ScalarProperty:
self.name = name self.name = name
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[Styles] | None = None
) -> Scalar | None: ) -> Scalar | None:
"""Get the scalar property """Get the scalar property
@@ -69,7 +69,7 @@ class ScalarProperty:
value = obj.get_rule(self.name) value = obj.get_rule(self.name)
return value return value
def __set__(self, obj: Styles, value: float | Scalar | str | None) -> None: def __set__(self, obj: StylesBase, value: float | Scalar | str | None) -> None:
"""Set the scalar property """Set the scalar property
Args: Args:
@@ -116,14 +116,14 @@ class BoxProperty:
DEFAULT = ("", Color.default()) DEFAULT = ("", Color.default())
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
_type, edge = name.split("_") _type, edge = name.split("_")
self._type = _type self._type = _type
self.edge = edge self.edge = edge
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> tuple[BoxType, Color]: ) -> tuple[BoxType, Color]:
"""Get the box property """Get the box property
@@ -206,7 +206,7 @@ class Edges(NamedTuple):
class BorderProperty: class BorderProperty:
"""Descriptor for getting and setting full borders and outlines.""" """Descriptor for getting and setting full borders and outlines."""
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
self._properties = ( self._properties = (
f"{name}_top", f"{name}_top",
@@ -215,7 +215,9 @@ class BorderProperty:
f"{name}_left", f"{name}_left",
) )
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Edges: def __get__(
self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> Edges:
"""Get the border """Get the border
Args: Args:
@@ -237,7 +239,7 @@ class BorderProperty:
def __set__( def __set__(
self, self,
obj: Styles, obj: StylesBase,
border: BorderDefinition | None, border: BorderDefinition | None,
) -> None: ) -> None:
"""Set the border """Set the border
@@ -298,7 +300,9 @@ class StyleProperty:
DEFAULT_STYLE = Style() DEFAULT_STYLE = Style()
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style: def __get__(
self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> Style:
"""Get the Style """Get the Style
Args: Args:
@@ -319,7 +323,7 @@ class StyleProperty:
return style return style
def __set__(self, obj: Styles, style: Style | str | None): def __set__(self, obj: StylesBase, style: Style | str | None):
"""Set the Style """Set the Style
Args: Args:
@@ -352,10 +356,12 @@ class StyleProperty:
class SpacingProperty: class SpacingProperty:
"""Descriptor for getting and setting spacing properties (e.g. padding and margin).""" """Descriptor for getting and setting spacing properties (e.g. padding and margin)."""
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Spacing: def __get__(
self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> Spacing:
"""Get the Spacing """Get the Spacing
Args: Args:
@@ -367,7 +373,7 @@ class SpacingProperty:
""" """
return obj.get_rule(self.name, NULL_SPACING) return obj.get_rule(self.name, NULL_SPACING)
def __set__(self, obj: Styles, spacing: SpacingDimensions | None): def __set__(self, obj: StylesBase, spacing: SpacingDimensions | None):
"""Set the Spacing """Set the Spacing
Args: Args:
@@ -394,7 +400,7 @@ class DocksProperty:
""" """
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> tuple[DockGroup, ...]: ) -> tuple[DockGroup, ...]:
"""Get the Docks property """Get the Docks property
@@ -407,7 +413,7 @@ class DocksProperty:
""" """
return obj.get_rule("docks", ()) return obj.get_rule("docks", ())
def __set__(self, obj: Styles, docks: Iterable[DockGroup] | None): def __set__(self, obj: StylesBase, docks: Iterable[DockGroup] | None):
"""Set the Docks property """Set the Docks property
Args: Args:
@@ -429,7 +435,7 @@ class DockProperty:
the docks themselves, and where they are located on screen. the docks themselves, and where they are located on screen.
""" """
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str: def __get__(self, obj: StylesBase, objtype: type[StylesBase] | None = None) -> str:
"""Get the Dock property """Get the Dock property
Args: Args:
@@ -455,11 +461,11 @@ class DockProperty:
class LayoutProperty: class LayoutProperty:
"""Descriptor for getting and setting layout.""" """Descriptor for getting and setting layout."""
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> Layout | None: ) -> Layout | None:
""" """
Args: Args:
@@ -470,7 +476,7 @@ class LayoutProperty:
""" """
return obj.get_rule(self.name) return obj.get_rule(self.name)
def __set__(self, obj: Styles, layout: str | Layout | None): def __set__(self, obj: StylesBase, layout: str | Layout | None):
""" """
Args: Args:
obj (Styles): The Styles object. obj (Styles): The Styles object.
@@ -497,10 +503,12 @@ class OffsetProperty:
will be adjusted by before it is rendered. will be adjusted by before it is rendered.
""" """
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> ScalarOffset: def __get__(
self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> ScalarOffset:
"""Get the offset """Get the offset
Args: Args:
@@ -514,7 +522,7 @@ class OffsetProperty:
return obj.get_rule(self.name, ScalarOffset.null()) return obj.get_rule(self.name, ScalarOffset.null())
def __set__( def __set__(
self, obj: Styles, offset: tuple[int | str, int | str] | ScalarOffset | None self, obj: StylesBase, offset: tuple[int | str, int | str] | ScalarOffset | None
): ):
"""Set the offset """Set the offset
@@ -562,10 +570,10 @@ class StringEnumProperty:
self._valid_values = valid_values self._valid_values = valid_values
self._default = default self._default = default
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str: def __get__(self, obj: StylesBase, objtype: type[StylesBase] | None = None) -> str:
"""Get the string property, or the default value if it's not set """Get the string property, or the default value if it's not set
Args: Args:
@@ -577,7 +585,7 @@ class StringEnumProperty:
""" """
return obj.get_rule(self.name, self._default) return obj.get_rule(self.name, self._default)
def __set__(self, obj: Styles, value: str | None = None): def __set__(self, obj: StylesBase, value: str | None = None):
"""Set the string property and ensure it is in the set of allowed values. """Set the string property and ensure it is in the set of allowed values.
Args: Args:
@@ -603,10 +611,10 @@ class StringEnumProperty:
class NameProperty: class NameProperty:
"""Descriptor for getting and setting name properties.""" """Descriptor for getting and setting name properties."""
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None) -> str: def __get__(self, obj: StylesBase, objtype: type[StylesBase] | None) -> str:
"""Get the name property """Get the name property
Args: Args:
@@ -618,7 +626,7 @@ class NameProperty:
""" """
return obj.get_rule(self.name, "") return obj.get_rule(self.name, "")
def __set__(self, obj: Styles, name: str | None): def __set__(self, obj: StylesBase, name: str | None):
"""Set the name property """Set the name property
Args: Args:
@@ -640,16 +648,16 @@ class NameProperty:
class NameListProperty: class NameListProperty:
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> tuple[str, ...]: ) -> tuple[str, ...]:
return obj.get_rule(self.name, ()) return obj.get_rule(self.name, ())
def __set__( def __set__(
self, obj: Styles, names: str | tuple[str] | None = None self, obj: StylesBase, names: str | tuple[str] | None = None
) -> str | tuple[str] | None: ) -> str | tuple[str] | None:
if names is None: if names is None:
@@ -668,10 +676,12 @@ class NameListProperty:
class ColorProperty: class ColorProperty:
"""Descriptor for getting and setting color properties.""" """Descriptor for getting and setting color properties."""
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Color: def __get__(
self, obj: StylesBaseStylesBase, objtype: type[Styles] | None = None
) -> Color:
"""Get the ``Color``, or ``Color.default()`` if no color is set. """Get the ``Color``, or ``Color.default()`` if no color is set.
Args: Args:
@@ -683,7 +693,7 @@ class ColorProperty:
""" """
return obj.get_rule(self.name) or Color.default() return obj.get_rule(self.name) or Color.default()
def __set__(self, obj: Styles, color: Color | str | None): def __set__(self, obj: StylesBase, color: Color | str | None):
"""Set the Color """Set the Color
Args: Args:
@@ -727,7 +737,9 @@ class StyleFlagsProperty:
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: Styles, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style: def __get__(
self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> Style:
"""Get the ``Style`` """Get the ``Style``
Args: Args:
@@ -739,7 +751,7 @@ class StyleFlagsProperty:
""" """
return obj.get_rule(self.name, Style.null()) return obj.get_rule(self.name, Style.null())
def __set__(self, obj: Styles, style_flags: Style | str | None): def __set__(self, obj: StylesBase, style_flags: Style | str | None):
"""Set the style using a style flag string """Set the style using a style flag string
Args: Args:
@@ -774,7 +786,7 @@ class TransitionsProperty:
"""Descriptor for getting transitions properties""" """Descriptor for getting transitions properties"""
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: StylesBase, objtype: type[StylesBase] | None = None
) -> dict[str, Transition]: ) -> dict[str, Transition]:
"""Get a mapping of properties to the transitions applied to them. """Get a mapping of properties to the transitions applied to them.
@@ -804,10 +816,10 @@ class FractionalProperty:
def __init__(self, default: float = 1.0): def __init__(self, default: float = 1.0):
self.default = default self.default = default
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: StylesBase, name: str) -> None:
self.name = name self.name = name
def __get__(self, obj: Styles, type: type[Styles]) -> float: def __get__(self, obj: StylesBase, type: type[StylesBase]) -> float:
"""Get the property value as a float between 0 and 1 """Get the property value as a float between 0 and 1
Args: Args:
@@ -819,7 +831,7 @@ class FractionalProperty:
""" """
return cast(float, obj.get_rule(self.name, self.default)) return cast(float, obj.get_rule(self.name, self.default))
def __set__(self, obj: Styles, value: float | str | None) -> None: def __set__(self, obj: StylesBase, value: float | str | None) -> None:
"""Set the property value, clamping it between 0 and 1. """Set the property value, clamping it between 0 and 1.
Args: Args:

View File

@@ -162,6 +162,16 @@ class StylesBase(ABC):
return NotImplemented return NotImplemented
return self.get_rules() == styles.get_rules() return self.get_rules() == styles.get_rules()
@property
def gutter(self) -> Spacing:
"""Get space around widget.
Returns:
Spacing: Space around widget.
"""
return self.margin
@abstractmethod @abstractmethod
def has_rule(self, rule: str) -> bool: def has_rule(self, rule: str) -> bool:
"""Check if a rule is set on this Styles object. """Check if a rule is set on this Styles object.

View File

@@ -75,18 +75,19 @@ class DockLayout(Layout):
def make_dock_options(widget, edge: Edge) -> DockOptions: def make_dock_options(widget, edge: Edge) -> DockOptions:
styles = widget.styles styles = widget.styles
has_rule = styles.has_rule
return ( return (
DockOptions( DockOptions(
styles.width.cells if styles.has_rule("width") else None, styles.width.cells if has_rule("width") else None,
styles.width.fraction if styles.has_rule("width") else 1, styles.width.fraction if has_rule("width") else 1,
styles.min_width.cells if styles.has_rule("min_width") else 1, styles.min_width.cells if has_rule("min_width") else 1,
) )
if edge in ("left", "right") if edge in ("left", "right")
else DockOptions( else DockOptions(
styles.height.cells if styles.has_rule("height") else None, styles.height.cells if has_rule("height") else None,
styles.height.fraction if styles.has_rule("height") else 1, styles.height.fraction if has_rule("height") else 1,
styles.min_height.cells if styles.has_rule("min_height") else 1, styles.min_height.cells if has_rule("min_height") else 1,
) )
) )

View File

@@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
from asyncio import Event
from time import monotonic from time import monotonic
from typing import ClassVar from typing import ClassVar

View File

@@ -21,3 +21,26 @@ def blend_colors(color1: Color, color2: Color, ratio: float) -> Color:
return Color.from_rgb( return Color.from_rgb(
red=r1 + dr * ratio, green=g1 + dg * ratio, blue=b1 + db * ratio red=r1 + dr * ratio, green=g1 + dg * ratio, blue=b1 + db * ratio
) )
def blend_colors_rgb(
color1: tuple[int, int, int], color2: tuple[int, int, int], ratio: float
) -> Color:
"""Blend two colors given as a tuple of 3 values for red, green, and blue.
Args:
color1 (tuple[int, int, int]): The first color.
color2 (tuple[int, int, int]): The second color.
ratio (float): The ratio of color1 to color2.
Returns:
Color: A Color representing the blending of the two supplied colors.
"""
r1, g1, b1 = color1
r2, g2, b2 = color2
dr = r2 - r1
dg = g2 - g1
db = b2 - b1
return Color.from_rgb(
red=r1 + dr * ratio, green=g1 + dg * ratio, blue=b1 + db * ratio
)

View File

@@ -204,17 +204,6 @@ class Widget(DOMNode):
assert self._animate is not None assert self._animate is not None
return self._animate return self._animate
@property
def gutter(self) -> Spacing:
"""Get additional space reserved by margin / padding / border.
Returns:
Spacing: [description]
"""
styles = self.styles
gutter = styles.margin + styles.padding + styles.border.spacing
return gutter
def on_style_change(self) -> None: def on_style_change(self) -> None:
self.clear_render_cache() self.clear_render_cache()