From 32079fc8f7f05d957cc2c9110eace0abde76bc08 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 11 Sep 2022 10:25:51 +0100 Subject: [PATCH] color docs --- docs/guide/styles.md | 32 +++++++++++++++++++++++++++----- docs/reference/screen.md | 1 + src/textual/color.py | 27 ++++++++++++++++++++------- 3 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 docs/reference/screen.md diff --git a/docs/guide/styles.md b/docs/guide/styles.md index 2c24eb9b0..b34faeb1b 100644 --- a/docs/guide/styles.md +++ b/docs/guide/styles.md @@ -1,30 +1,52 @@ # Styles -Textual provides a large number of *styles* you can use to customize how your app looks and feels. In this chapter will will look at how you can edit styles in your applications. +In this chapter will explore how you can apply styles to your application to create beautiful user interfaces. ## Styles object -Every widget class in Textual provides a `styles` object which contains a number of writable attributes. You can write to any of these attributes and Textual will update the screen accordingly. +Every Textual widget class provides a `styles` object which contains a number of attributes. These attributes tell Textual how the widget should be displayed, and how it should be positioned on the screen relative to other widgets. -Let's look at a simple example which sets the styles on the `screen` (a special widget that represents the screen). +!!! note + + These docs use the term *screen* to describe the contents of the terminal, which will typically be a window on your desktop. + +If you write to any styles attribute the screen will update accordingly. + +Let's look at a simple example which sets the styles on `screen` (a special widget that represents the screen). ```python title="screen.py" hl_lines="6-7" --8<-- "docs/examples/guide/styles/screen.py" ``` -The first line sets [background](../styles/background.md) to `"darkblue"` which will change the background color to dark blue. There are a few other ways of setting color which we will explore later. +The first line sets the [background](../styles/background.md) style to `"darkblue"` which will change the background color to dark blue. There are a few other ways of setting color which we will explore later. The second line sets [border](../styles/border.md) to a tuple of `("heavy", "white")` which tells Textual to draw a white border with a style of `"heavy"`. Running this code will show the following: ```{.textual path="docs/examples/guide/styles/screen.py"} ``` +## Styling widgets + ## Colors -The [color](../styles/color.md) property set the color of text on a widget. The [background](..styles/background/md) property sets the color of the background (under the text). +There are a number of style attribute which accept colors. The most commonly used arel be [color](../styles/color.md) which sets the default color of text on a widget, and [background](..styles/background/md) which sets the background color (under the text). + +You can set a color value to one of a number of pre-defined color constants, such as "crimson", "lime", and "palegreen". You can find a full list in the [Color reference](../reference/color.md#textual.color--named-colors). + +Here's how you would set the screen background to lime: + +```python +self.screen.background = "lime" +``` + +In addition to color names, there are other ways you can specify a color in Textual (which give you access to all 16.7 million colors a typical monitor can display). + +- RGB hex colors starts with a `#` followed by three pairs of one or two hex digits; one for the red, green, and blue color components. For example, `#f00` is an intense red color, and `#9932CC` is *dark orchid*. +- RGB decimal color start with `rgb` followed by a tuple of three numbers in the range 0 to 255. For example `rgb(255,0,0)` is intense red, and `rgb(153,50,204)` is *dark orchid*. +- HSL colors start with `hsl` followed by a tuple of three colors in the range 0 to 255, representing the Hue Saturation and Lightness. For example `hsl(0,100%,50%)` is intense red and `hsl(280,60%,49%)` is *dark orchid* diff --git a/docs/reference/screen.md b/docs/reference/screen.md new file mode 100644 index 000000000..c7054aef5 --- /dev/null +++ b/docs/reference/screen.md @@ -0,0 +1 @@ +::: textual.screen diff --git a/src/textual/color.py b/src/textual/color.py index edb3c076b..9146e33cd 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -10,16 +10,19 @@ The following named colors are used by the [parse][textual.color.Color.parse] me ```{.rich title="colors"} from textual._color_constants import COLOR_NAME_TO_RGB +from textual.color import Color from rich.table import Table from rich.text import Text -table = Table("Name", "RGB", "Color", expand=True, highlight=True) +table = Table("Name", "hex", "RGB", "Color", expand=True, highlight=True) for name, triplet in sorted(COLOR_NAME_TO_RGB.items()): if len(triplet) != 3: continue + color = Color(*triplet) r, g, b = triplet table.add_row( f'"{name}"', + f"{color.hex}", f"rgb({r}, {g}, {b})", Text(" ", style=f"on rgb({r},{g},{b})") ) @@ -64,6 +67,16 @@ class HLS(NamedTuple): s: float """Saturation""" + @property + def css(self) -> str: + """HLS in css format.""" + h, l, s = self + + def as_str(number: float) -> str: + return f"{number:.1f}".rstrip("0").rstrip(".") + + return f"hsl({as_str(h*360)},{as_str(s*100)}%,{as_str(l*100)}%)" + class HSV(NamedTuple): """A color in HSV format.""" @@ -99,11 +112,11 @@ hsla{OPEN_BRACE}({DECIMAL}{COMMA}{PERCENT}{COMMA}{PERCENT}{COMMA}{DECIMAL}){CLOS ) # Fast way to split a string of 6 characters in to 3 pairs of 2 characters -split_pairs3: Callable[[str], tuple[str, str, str]] = itemgetter( +_split_pairs3: Callable[[str], tuple[str, str, str]] = itemgetter( slice(0, 2), slice(2, 4), slice(4, 6) ) # Fast way to split a string of 8 characters in to 4 pairs of 2 characters -split_pairs4: Callable[[str], tuple[str, str, str, str]] = itemgetter( +_split_pairs4: Callable[[str], tuple[str, str, str, str]] = itemgetter( slice(0, 2), slice(2, 4), slice(4, 6), slice(6, 8) ) @@ -237,7 +250,7 @@ class Color(NamedTuple): """Get the color as HLS. Returns: - HLS: + HLS: Color in HLS format. """ r, g, b = self.normalized return HLS(*rgb_to_hls(r, g, b)) @@ -350,7 +363,7 @@ class Color(NamedTuple): - `rgb(RED,GREEN,BLUE)` - `rgba(RED,GREEN,BLUE,ALPHA)` - `hsl(RED,GREEN,BLUE)` - - `hsl(RED,GREEN,BLUE,ALPHA)` + - `hsla(RED,GREEN,BLUE,ALPHA)` All other text will raise a `ColorParseError`. @@ -402,10 +415,10 @@ class Color(NamedTuple): int(f"{a}{a}", 16) / 255.0, ) elif rgb_hex is not None: - r, g, b = [int(pair, 16) for pair in split_pairs3(rgb_hex)] + r, g, b = [int(pair, 16) for pair in _split_pairs3(rgb_hex)] color = cls(r, g, b, 1.0) elif rgba_hex is not None: - r, g, b, a = [int(pair, 16) for pair in split_pairs4(rgba_hex)] + r, g, b, a = [int(pair, 16) for pair in _split_pairs4(rgba_hex)] color = cls(r, g, b, a / 255.0) elif rgb is not None: r, g, b = [clamp(int(float(value)), 0, 255) for value in rgb.split(",")]