fix(frame): start the corner fade at the brightest palette stop
A ladder is a hue walk, not a brightness walk, so painting the hot end backwards put the dim colour at the corner. Sort the ramp by stock brightness and follow the pane height for the bottom-left glow.
This commit is contained in:
1 parent
81116282cb
commit
ec2ca72efb
4 files changed
+117
-39
No files matched your search
+38
-20
@@ -1,15 +1,17 @@
|
||||
"""The BBS frames: grey edges, corners fading white → grey → cyan."""
|
||||
"""The BBS frames: grey edges, and a short palette glow in two corners."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from rich.text import Text
|
||||
|
||||
from beefy_player.palettes import PALETTES
|
||||
from beefy_player.palettes import PALETTES, brightness
|
||||
from beefy_player.widgets import frame
|
||||
|
||||
#: The original ladder, used as a fixed reference in these tests.
|
||||
STOPS = PALETTES["spectrum"]
|
||||
HOT = STOPS[-1] # the corner colour
|
||||
#: Its glow: the brightest cell first, dimmer cells towards the edge.
|
||||
RAMP = frame.fade_ramp(STOPS)
|
||||
HOT = RAMP[0] # the corner colour
|
||||
|
||||
|
||||
def styles_of(line: Text) -> list[tuple[str, str]]:
|
||||
@@ -18,26 +20,29 @@ def styles_of(line: Text) -> list[tuple[str, str]]:
|
||||
]
|
||||
|
||||
|
||||
def test_the_corner_gets_the_brightest_colour_of_the_fade() -> None:
|
||||
ranks = [brightness(colour) for colour in RAMP]
|
||||
assert ranks == sorted(ranks, reverse=True)
|
||||
# spectrum's hot end is red, which is dimmer than the yellow before it:
|
||||
# the corner must still be the bright one, not the ladder's last stop
|
||||
assert STOPS[-1] != HOT
|
||||
assert brightness(HOT) > brightness(STOPS[-1])
|
||||
assert set(RAMP) <= set(STOPS)
|
||||
assert frame.corner_fade(len(RAMP), STOPS) == frame.EDGE
|
||||
|
||||
|
||||
def test_only_the_top_right_corner_fades_on_the_top_edge() -> None:
|
||||
spans = styles_of(frame.top(30, stops=STOPS))
|
||||
assert spans[0] == ("╭", frame.EDGE) # plain grey corner
|
||||
# the fade runs into the top-right corner, hot end last
|
||||
assert [style for _text, style in spans[-4:-1]] == [
|
||||
STOPS[-4],
|
||||
STOPS[-3],
|
||||
STOPS[-2],
|
||||
]
|
||||
# the fade runs into the top-right corner, brightest cell last
|
||||
assert [style for _text, style in spans[-4:-1]] == [RAMP[3], RAMP[2], RAMP[1]]
|
||||
assert spans[-1] == ("╮", f"bold {HOT}")
|
||||
|
||||
|
||||
def test_only_the_bottom_left_corner_fades_on_the_bottom_edge() -> None:
|
||||
spans = styles_of(frame.bottom(30, STOPS))
|
||||
assert spans[0] == ("╰", f"bold {HOT}")
|
||||
assert [style for _text, style in spans[1:4]] == [
|
||||
STOPS[-2],
|
||||
STOPS[-3],
|
||||
STOPS[-4],
|
||||
]
|
||||
assert [style for _text, style in spans[1:4]] == [RAMP[1], RAMP[2], RAMP[3]]
|
||||
assert spans[-1] == ("╯", frame.EDGE) # plain grey corner
|
||||
|
||||
|
||||
@@ -51,15 +56,15 @@ def test_the_sides_glow_towards_their_own_corner_only() -> None:
|
||||
frame.EDGE,
|
||||
frame.EDGE,
|
||||
frame.EDGE,
|
||||
STOPS[-4],
|
||||
STOPS[-3],
|
||||
STOPS[-2],
|
||||
RAMP[3],
|
||||
RAMP[2],
|
||||
RAMP[1],
|
||||
]
|
||||
# right column fades down from the top-right corner
|
||||
assert [frame.side_style(row, 10, "right", STOPS) for row in range(10)] == [
|
||||
STOPS[-2],
|
||||
STOPS[-3],
|
||||
STOPS[-4],
|
||||
RAMP[1],
|
||||
RAMP[2],
|
||||
RAMP[3],
|
||||
frame.EDGE,
|
||||
frame.EDGE,
|
||||
frame.EDGE,
|
||||
@@ -98,3 +103,16 @@ def test_content_wider_than_the_pane_is_trimmed_not_spilled() -> None:
|
||||
assert lines[1].endswith("│")
|
||||
# the original renderable is left untouched
|
||||
assert long_line.plain == "x" * 40
|
||||
|
||||
|
||||
def test_a_short_pane_still_glows_in_its_bottom_left_corner() -> None:
|
||||
"""The fade follows the pane's height, not the number of content rows."""
|
||||
group = frame.wrap([Text("one line")], 20, 6, stops=STOPS)
|
||||
lines = list(group.renderables)
|
||||
# rows 1-4 are the content box; the fade climbs its last three rows
|
||||
assert str(lines[1].spans[0].style) == frame.EDGE
|
||||
assert [str(line.spans[0].style) for line in lines[2:5]] == [
|
||||
RAMP[3],
|
||||
RAMP[2],
|
||||
RAMP[1],
|
||||
]
|
||||
+21
-6
@@ -13,6 +13,7 @@ from beefy_player.palettes import (
|
||||
DEFAULT_PALETTE,
|
||||
PALETTE_ORDER,
|
||||
PALETTES,
|
||||
brightness,
|
||||
palette_stops,
|
||||
)
|
||||
from beefy_player.widgets import frame
|
||||
@@ -133,13 +134,27 @@ async def test_the_spectrum_rows_use_the_active_palette() -> None:
|
||||
assert colours(spectrum._row_palette(12, 0, False)) <= set(PALETTES["neon"])
|
||||
|
||||
|
||||
def test_the_corner_fade_walks_back_down_the_ladder() -> None:
|
||||
def test_the_corner_fade_starts_at_the_brightest_stop() -> None:
|
||||
stops = PALETTES["spectrum"]
|
||||
assert frame.corner_fade(0, stops) == stops[-1]
|
||||
assert frame.corner_fade(1, stops) == stops[-2]
|
||||
assert frame.corner_fade(3, stops) == stops[-4]
|
||||
# the fade is short: past four cells it is just the border grey
|
||||
assert frame.corner_fade(4, stops) == frame.EDGE
|
||||
ramp = frame.fade_ramp(stops)
|
||||
assert frame.corner_fade(0, stops) == ramp[0]
|
||||
assert frame.corner_fade(1, stops) == ramp[1]
|
||||
# the fade is short: past the ramp it is just the border grey
|
||||
assert frame.corner_fade(len(ramp), stops) == frame.EDGE
|
||||
# spectrum's hot end is red, which is dimmer than the yellow before it;
|
||||
# the corner still gets the bright colour
|
||||
assert ramp[0] != stops[-1]
|
||||
assert ramp[-1] == stops[-1]
|
||||
|
||||
|
||||
def test_every_palette_fades_from_bright_to_dim() -> None:
|
||||
"""No palette may put a brighter cell further from the corner."""
|
||||
for name, stops in PALETTES.items():
|
||||
ramp = frame.fade_ramp(stops)
|
||||
assert ramp, name
|
||||
ranks = [brightness(colour) for colour in ramp]
|
||||
assert ranks == sorted(ranks, reverse=True), (name, ramp)
|
||||
assert set(ramp) <= set(stops), name
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in new issue
Block a user