From d83c0090b12536ee6076c4239bf28f9ce7f2134e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 23 Feb 2022 11:34:25 +0000 Subject: [PATCH] Renderables --- sandbox/uber.css | 4 +++ sandbox/uber.py | 18 +++++++++++++ src/textual/geometry.py | 9 +++++++ src/textual/renderables/blank.py | 28 +++++++++++++++++++++ src/textual/renderables/gradient.py | 39 +++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 sandbox/uber.css create mode 100644 sandbox/uber.py create mode 100644 src/textual/renderables/blank.py create mode 100644 src/textual/renderables/gradient.py diff --git a/sandbox/uber.css b/sandbox/uber.css new file mode 100644 index 000000000..960f4b47b --- /dev/null +++ b/sandbox/uber.css @@ -0,0 +1,4 @@ +#uber { + border: heavy green; + margin: 5; +} diff --git a/sandbox/uber.py b/sandbox/uber.py new file mode 100644 index 000000000..472f4c20e --- /dev/null +++ b/sandbox/uber.py @@ -0,0 +1,18 @@ +from textual.app import App +from textual import events +from textual.widgets import Placeholder +from textual.widget import Widget + + +class BasicApp(App): + """Sandbox application used for testing/development by Textual developers""" + + def on_mount(self): + """Build layout here.""" + self.mount(uber=Widget()) + + async def on_key(self, event: events.Key) -> None: + await self.dispatch_key(event) + + +BasicApp.run(css_file="uber.css", log="textual.log") diff --git a/src/textual/geometry.py b/src/textual/geometry.py index cf07808f4..922084c44 100644 --- a/src/textual/geometry.py +++ b/src/textual/geometry.py @@ -1,3 +1,10 @@ +""" + +Functions and classes to manage terminal geometry (anything involving coordinates or dimensions). + +""" + + from __future__ import annotations from math import sqrt @@ -209,6 +216,7 @@ class Region(NamedTuple): return cls(x, y, width, height) def __bool__(self) -> bool: + """A Region is considered False when it has no area.""" return bool(self.width and self.height) @property @@ -509,6 +517,7 @@ class Spacing(NamedTuple): @property def css(self) -> str: + """Gets a string containing the spacing in CSS format.""" top, right, bottom, left = self if top == right == bottom == left: return f"{top}" diff --git a/src/textual/renderables/blank.py b/src/textual/renderables/blank.py new file mode 100644 index 000000000..50c949283 --- /dev/null +++ b/src/textual/renderables/blank.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from rich.console import ConsoleOptions, Console, RenderResult +from rich.color import Color +from rich.segment import Segment +from rich.style import Style + + +class Blank: + """Draw solid background color.""" + + def __init__(self, color: str) -> None: + self._style = Style.from_color(None, Color.parse(color)) + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = options.max_width + height = options.height or options.max_height + + segment = Segment(f"{' ' * width}\n", self._style) + yield from [segment] * height + + +if __name__ == "__main__": + from rich import print + + print(Blank("red")) diff --git a/src/textual/renderables/gradient.py b/src/textual/renderables/gradient.py new file mode 100644 index 000000000..c7eb1a53f --- /dev/null +++ b/src/textual/renderables/gradient.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from rich.console import ConsoleOptions, Console, RenderResult +from rich.color import Color +from rich.segment import Segment +from rich.style import Style + +from ._blend_colors import blend_colors_rgb + + +class VerticalGradient: + """Draw a vertical gradient.""" + + def __init__(self, color1: str, color2: str) -> None: + self._color1 = Color.parse(color1).get_truecolor() + self._color2 = Color.parse(color2).get_truecolor() + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = options.max_width + height = options.height or options.max_height + color1 = self._color1 + color2 = self._color2 + default_color = Color.default() + from_color = Style.from_color + for y in range(height): + yield Segment( + f"{width * ' '}\n", + from_color( + default_color, blend_colors_rgb(color1, color2, y / (height - 1)) + ), + ) + + +if __name__ == "__main__": + from rich import print + + print(VerticalGradient("red", "blue"))