diff options
Diffstat (limited to 'bin/udt-accent')
| -rwxr-xr-x | bin/udt-accent | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/bin/udt-accent b/bin/udt-accent index a47460e..fbd6a65 100755 --- a/bin/udt-accent +++ b/bin/udt-accent @@ -14,6 +14,7 @@ including the terminal's ANSI colors. See the design spec for why that matters. import math import os +import subprocess import sys import tempfile from pathlib import Path @@ -37,6 +38,7 @@ FALLBACK = "mauve" MIN_CHROMA = 10.0 OUTPUT = Path.home() / ".cache" / "wal" / "udt-accent.rasi" +BORDER_OUTPUT = Path.home() / ".cache" / "wal" / "udt-border.lua" def _to_lab(hexval): @@ -121,6 +123,45 @@ def write_accent(name): raise +def hue_neighbours(name): + """The accent either side of `name` on the perceptual hue wheel. + + The animated border rotates a gradient, so it needs more than one colour to + show motion. Using the accent's own neighbours keeps the movement visible + while staying inside one region of the palette. + """ + order = sorted(ACCENTS, key=lambda n: _hue(ACCENTS[n])) + i = order.index(name) + return order[(i - 1) % len(order)], order[(i + 1) % len(order)] + + +def write_border(name): + """Write the Hyprland border gradient, atomically. + + Emitted as Lua rather than a .conf snippet: Hyprland's Lua parser refuses + `hyprctl keyword` ("keyword can't work with non-legacy parsers") and has no + source directive, so the config reads this file with dofile() instead. + """ + before, after = hue_neighbours(name) + stops = ", ".join(f'"rgb({ACCENTS[n].lstrip("#")})"' for n in (before, name, after)) + + content = ( + "-- Generated by udt-accent. Do not edit.\n" + f"return {{ {stops} }}\n" + ) + + BORDER_OUTPUT.parent.mkdir(parents=True, exist_ok=True) + fd, tmp = tempfile.mkstemp(dir=str(BORDER_OUTPUT.parent), suffix=".tmp") + try: + with os.fdopen(fd, "w") as handle: + handle.write(content) + os.replace(tmp, BORDER_OUTPUT) + except BaseException: + if os.path.exists(tmp): + os.unlink(tmp) + raise + + def main(image): try: name = snap(signature_color(image)) @@ -130,7 +171,13 @@ def main(image): name = FALLBACK write_accent(name) - print(f"{name} {ACCENTS[name]}") + write_border(name) + + # Hyprland only rereads its config on request, and may not be running. + subprocess.run(["hyprctl", "reload"], capture_output=True, check=False) + + before, after = hue_neighbours(name) + print(f"{name} {ACCENTS[name]} (border: {before} .. {name} .. {after})") def selftest(): @@ -146,6 +193,13 @@ def selftest(): # A near-grey has an unstable hue angle and must take the fallback. assert snap("#888888") == FALLBACK, snap("#888888") + # Border neighbours must be distinct from the accent and from each other, + # or the gradient has nothing to animate between. + for name in ACCENTS: + before, after = hue_neighbours(name) + assert len({before, name, after}) == 3, (name, before, after) + assert hue_neighbours("peach") == ("red", "yellow"), hue_neighbours("peach") + print("selftest OK") |
