Skip to content

Commit 4a822bc

Browse files
authored
background tint style (#5117)
* background tint style * changelog * hlines * doc fix * added tint * missing snapshots
1 parent 4182ad4 commit 4a822bc

12 files changed

+470
-5
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- Fixed `RadioSet` not being scrollable https://github.com/Textualize/textual/issues/5100
1313

14+
### Added
15+
16+
- Added `background-tint` CSS rule https://github.com/Textualize/textual/pull/5117
17+
1418
## [0.83.0] - 2024-10-10
1519

1620
### Added
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from textual.app import App, ComposeResult
2+
from textual.containers import Vertical
3+
from textual.widgets import Label
4+
5+
6+
class BackgroundTintApp(App):
7+
CSS_PATH = "background_tint.tcss"
8+
9+
def compose(self) -> ComposeResult:
10+
with Vertical(id="tint1"):
11+
yield Label("0%")
12+
with Vertical(id="tint2"):
13+
yield Label("25%")
14+
with Vertical(id="tint3"):
15+
yield Label("50%")
16+
with Vertical(id="tint4"):
17+
yield Label("75%")
18+
with Vertical(id="tint5"):
19+
yield Label("100%")
20+
21+
22+
if __name__ == "__main__":
23+
app = BackgroundTintApp()
24+
app.run()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Vertical {
2+
background: $panel;
3+
color: auto 90%;
4+
}
5+
#tint1 { background-tint: $foreground 0%; }
6+
#tint2 { background-tint: $foreground 25%; }
7+
#tint3 { background-tint: $foreground 50%; }
8+
#tint4 { background-tint: $foreground 75% }
9+
#tint5 { background-tint: $foreground 100% }

docs/styles/background.md

+1
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,5 @@ widget.styles.background = Color(120, 60, 100)
9090

9191
## See also
9292

93+
- [`background-tint`](./background_tint.md) to blend a color with the background.
9394
- [`color`](./color.md) to set the color of text in a widget.

docs/styles/background_tint.md

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Background-tint
2+
3+
The `background-tint` style modifies the background color by tinting (blending) it with a new color.
4+
5+
This style is typically used to subtly change the background of a widget for emphasis.
6+
For instance the following would make a focused widget have a slightly lighter background.
7+
8+
```css
9+
MyWidget:focus {
10+
background-tint: white 10%
11+
}
12+
```
13+
14+
The background tint color should typically have less than 100% alpha, in order to modify the background color.
15+
If the alpha component is 100% then the tint color will replace the background color entirely.
16+
17+
## Syntax
18+
19+
--8<-- "docs/snippets/syntax_block_start.md"
20+
background-tint: <a href="../../css_types/color">&lt;color&gt;</a> [<a href="../../css_types/percentage">&lt;percentage&gt;</a>];
21+
--8<-- "docs/snippets/syntax_block_end.md"
22+
23+
The `background-tint` style requires a [`<color>`](../css_types/color.md) optionally followed by [`<percentage>`](../css_types/percentage.md) to specify the color's opacity (clamped between `0%` and `100%`).
24+
25+
## Examples
26+
27+
### Basic usage
28+
29+
This example shows background tint applied with alpha from 0 to 100%.
30+
31+
=== "Output"
32+
33+
```{.textual path="docs/examples/styles/background_tint.py"}
34+
```
35+
36+
=== "background_tint.py"
37+
38+
```python
39+
--8<-- "docs/examples/styles/background_tint.py"
40+
```
41+
42+
=== "background.tcss"
43+
44+
```css hl_lines="5-9"
45+
--8<-- "docs/examples/styles/background_tint.tcss"
46+
```
47+
48+
49+
## CSS
50+
51+
```css
52+
/* 10% backgrouhnd tint */
53+
background-tint: blue 10%;
54+
55+
56+
/* 20% RGB color */
57+
background-tint: rgb(100, 120, 200, 0.2);
58+
59+
```
60+
61+
## Python
62+
63+
You can use the same syntax as CSS, or explicitly set a `Color` object for finer-grained control.
64+
65+
```python
66+
# Set 20% blue background tint
67+
widget.styles.background_tint = "blue 20%"
68+
69+
from textual.color import Color
70+
# Set with a color object
71+
widget.styles.background_tint = Color(120, 60, 100, 0.5)
72+
```
73+
74+
## See also
75+
76+
- [`background`](./background.md) to set the background color of a widget.
77+
- [`color`](./color.md) to set the color of text in a widget.

mkdocs-nav.yml

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ nav:
7575
- "styles/index.md"
7676
- "styles/align.md"
7777
- "styles/background.md"
78+
- "styles/background_tint.md"
7879
- "styles/border.md"
7980
- "styles/border_subtitle_align.md"
8081
- "styles/border_subtitle_background.md"

src/textual/css/_styles_builder.py

+1
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ def process_color(self, name: str, tokens: list[Token]) -> None:
670670

671671
process_tint = process_color
672672
process_background = process_color
673+
process_background_tint = process_color
673674
process_scrollbar_color = process_color
674675
process_scrollbar_color_hover = process_color
675676
process_scrollbar_color_active = process_color

src/textual/css/styles.py

+10
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class RulesMap(TypedDict, total=False):
9191
background: Color
9292
text_style: Style
9393

94+
background_tint: Color
95+
9496
opacity: float
9597
text_opacity: float
9698

@@ -215,6 +217,7 @@ class StylesBase:
215217
"auto_color",
216218
"color",
217219
"background",
220+
"background_tint",
218221
"opacity",
219222
"text_opacity",
220223
"tint",
@@ -285,6 +288,11 @@ class StylesBase:
285288
Supports `Color` objects but also strings e.g. "red" or "#ff0000"
286289
You can also specify an opacity after a color e.g. "blue 10%"
287290
"""
291+
background_tint = ColorProperty(Color(0, 0, 0, 0))
292+
"""Set a color to tint (blend) with the background.
293+
Supports `Color` objects but also strings e.g. "red" or "#ff0000"
294+
You can also specify an opacity after a color e.g. "blue 10%"
295+
"""
288296
text_style = StyleFlagsProperty()
289297
"""Set the text style of the widget using Rich StyleFlags.
290298
e.g. `"bold underline"` or `"b u strikethrough"`.
@@ -1011,6 +1019,8 @@ def append_declaration(name: str, value: str) -> None:
10111019
append_declaration("color", self.color.hex)
10121020
if "background" in rules:
10131021
append_declaration("background", self.background.hex)
1022+
if "background_tint" in rules:
1023+
append_declaration("background-tint", self.background_tint.hex)
10141024
if "text_style" in rules:
10151025
append_declaration("text-style", str(get_rule("text_style")))
10161026
if "tint" in rules:

src/textual/dom.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1026,8 +1026,12 @@ def rich_style(self) -> Style:
10261026
has_rule = styles.has_rule
10271027
opacity *= styles.opacity
10281028
if has_rule("background"):
1029-
text_background = background + styles.background
1030-
background += styles.background.multiply_alpha(opacity)
1029+
text_background = (
1030+
background + styles.background + styles.background_tint
1031+
)
1032+
background += (
1033+
styles.background + styles.background_tint
1034+
).multiply_alpha(opacity)
10311035
else:
10321036
text_background = background
10331037
if has_rule("color"):
@@ -1115,7 +1119,7 @@ def background_colors(self) -> tuple[Color, Color]:
11151119
for node in reversed(self.ancestors_with_self):
11161120
styles = node.styles
11171121
base_background = background
1118-
background += styles.background
1122+
background += styles.background + styles.background_tint
11191123
return (base_background, background)
11201124

11211125
@property
@@ -1131,7 +1135,9 @@ def _opacity_background_colors(self) -> tuple[Color, Color]:
11311135
styles = node.styles
11321136
base_background = background
11331137
opacity *= styles.opacity
1134-
background += styles.background.multiply_alpha(opacity)
1138+
background += (styles.background + styles.background_tint).multiply_alpha(
1139+
opacity
1140+
)
11351141
return (base_background, background)
11361142

11371143
@property
@@ -1146,7 +1152,7 @@ def colors(self) -> tuple[Color, Color, Color, Color]:
11461152
for node in reversed(self.ancestors_with_self):
11471153
styles = node.styles
11481154
base_background = background
1149-
background += styles.background
1155+
background += styles.background + styles.background_tint
11501156
if styles.has_rule("color"):
11511157
base_color = color
11521158
if styles.auto_color:

0 commit comments

Comments
 (0)