Skip to content

Commit 3de7196

Browse files
authored
Merge branch 'main' into fix-get-event-loop-call
2 parents a5ce9bb + 0f24783 commit 3de7196

File tree

7 files changed

+58
-6
lines changed

7 files changed

+58
-6
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1616
- Fixed triggering a deprecation warning in py >= 3.10 https://github.com/Textualize/textual/pull/5799
1717
- Fixed `Input` invalid cursor position after updating the value https://github.com/Textualize/textual/issues/5811
1818

19+
### Added
20+
21+
- Exposed `CollapsibleTitle` https://github.com/Textualize/textual/pull/5810
22+
23+
### Added
24+
25+
- Added `Color.hsv` property and `Color.from_hsv` class method https://github.com/Textualize/textual/pull/5803
26+
1927
## [3.2.0] - 2025-05-02
2028

2129
### Fixed

questions/why-no-ansi-themes.question.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ alt_titles:
77

88
Textual will not generate escape sequences for the 16 themeable *ANSI* colors.
99

10-
This is an intentional design decision we took for for the following reasons:
10+
This is an intentional design decision we took for the following reasons:
1111

1212
- Not everyone has a carefully chosen ANSI color theme. Color combinations which may look fine on your system, may be unreadable on another machine. There is very little an app author or Textual can do to resolve this. Asking users to simply pick a better theme is not a good solution, since not all users will know how.
1313
- ANSI colors can't be manipulated in the way Textual can do with other colors. Textual can blend colors and produce light and dark shades from an original color, which is used to create more readable text and user interfaces. Color blending will also be used to power future accessibility features.

src/textual/color.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from __future__ import annotations
3232

3333
import re
34-
from colorsys import hls_to_rgb, rgb_to_hls
34+
from colorsys import hls_to_rgb, hsv_to_rgb, rgb_to_hls, rgb_to_hsv
3535
from functools import lru_cache
3636
from operator import itemgetter
3737
from typing import Callable, NamedTuple
@@ -82,7 +82,7 @@ class HSV(NamedTuple):
8282
s: float
8383
"""Saturation in range 0 to 1."""
8484
v: float
85-
"""Value un range 0 to 1."""
85+
"""Value in range 0 to 1."""
8686

8787

8888
class Lab(NamedTuple):
@@ -212,6 +212,21 @@ def from_hsl(cls, h: float, s: float, l: float) -> Color:
212212
r, g, b = hls_to_rgb(h, l, s)
213213
return cls(int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
214214

215+
@classmethod
216+
def from_hsv(cls, h: float, s: float, v: float) -> Color:
217+
"""Create a color from HSV components.
218+
219+
Args:
220+
h: Hue.
221+
s: Saturation.
222+
v: Value.
223+
224+
Returns:
225+
A new color.
226+
"""
227+
r, g, b = hsv_to_rgb(h, s, v)
228+
return cls(int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
229+
215230
@property
216231
def inverse(self) -> Color:
217232
"""The inverse of this color.
@@ -286,6 +301,19 @@ def hsl(self) -> HSL:
286301
h, l, s = rgb_to_hls(r, g, b)
287302
return HSL(h, s, l)
288303

304+
@property
305+
def hsv(self) -> HSV:
306+
"""This color in HSV format.
307+
308+
HSV color is an alternative way of representing a color, which can be used in certain color calculations.
309+
310+
Returns:
311+
Color encoded in HSV format.
312+
"""
313+
r, g, b = self.normalized
314+
h, s, v = rgb_to_hsv(r, g, b)
315+
return HSV(h, s, v)
316+
289317
@property
290318
def brightness(self) -> float:
291319
"""The human perceptual brightness.
@@ -301,7 +329,7 @@ def brightness(self) -> float:
301329
def hex(self) -> str:
302330
"""The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA.
303331
304-
For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha.
332+
For example, `"#46B3DE"` for an RGB color, or `"#3342457F"` for a color with alpha.
305333
"""
306334
r, g, b, a, ansi, _ = self.clamped
307335
if ansi is not None:
@@ -316,7 +344,7 @@ def hex(self) -> str:
316344
def hex6(self) -> str:
317345
"""The color in CSS hex form, with 6 digits for RGB. Alpha is ignored.
318346
319-
For example, `"#46b3de"`.
347+
For example, `"#46B3DE"`.
320348
"""
321349
r, g, b, _a, _, _ = self.clamped
322350
return f"#{r:02X}{g:02X}{b:02X}"

src/textual/widgets/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from textual.widget import Widget
1313
from textual.widgets._button import Button
1414
from textual.widgets._checkbox import Checkbox
15-
from textual.widgets._collapsible import Collapsible
15+
from textual.widgets._collapsible import Collapsible, CollapsibleTitle
1616
from textual.widgets._content_switcher import ContentSwitcher
1717
from textual.widgets._data_table import DataTable
1818
from textual.widgets._digits import Digits
@@ -54,6 +54,7 @@
5454
"Button",
5555
"Checkbox",
5656
"Collapsible",
57+
"CollapsibleTitle",
5758
"ContentSwitcher",
5859
"DataTable",
5960
"Digits",

src/textual/widgets/__init__.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from ._button import Button as Button
33
from ._checkbox import Checkbox as Checkbox
44
from ._collapsible import Collapsible as Collapsible
5+
from ._collapsible import CollapsibleTitle as CollapsibleTitle
56
from ._content_switcher import ContentSwitcher as ContentSwitcher
67
from ._data_table import DataTable as DataTable
78
from ._digits import Digits as Digits

src/textual/widgets/collapsible.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from textual.widgets._collapsible import CollapsibleTitle
2+
3+
__all__ = ["CollapsibleTitle"]

tests/test_color.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ def test_hsl():
5252
assert red.hsl.css == "hsl(356,81.8%,43.1%)"
5353

5454

55+
def test_hsv():
56+
red = Color(200, 20, 32)
57+
print(red.hsv)
58+
assert red.hsv == pytest.approx(
59+
(0.9888888888888889, 0.8999999999999999, 0.7843137254901961)
60+
)
61+
assert Color.from_hsv(
62+
0.9888888888888889, 0.8999999999999999, 0.7843137254901961
63+
).normalized == pytest.approx(red.normalized, rel=1e-5)
64+
65+
5566
def test_color_brightness():
5667
assert Color(255, 255, 255).brightness == 1
5768
assert Color(0, 0, 0).brightness == 0

0 commit comments

Comments
 (0)