- Add Theme class and THEME_REGISTRY to engine/themes.py - Add set_active_theme() function to config.py - Add msg_gradient() function to use theme-based message gradients - Support --theme CLI flag to select theme (green, orange, purple) - Initialize theme on module load with fallback to default
137 lines
4.1 KiB
Python
137 lines
4.1 KiB
Python
"""Gradient coloring for rendered block characters.
|
|
|
|
Provides left-to-right and complementary gradient effects for terminal display.
|
|
"""
|
|
|
|
from engine.terminal import RST
|
|
|
|
# Left → right: white-hot leading edge fades to near-black
|
|
GRAD_COLS = [
|
|
"\033[1;38;5;231m", # white
|
|
"\033[1;38;5;195m", # pale cyan-white
|
|
"\033[38;5;123m", # bright cyan
|
|
"\033[38;5;118m", # bright lime
|
|
"\033[38;5;82m", # lime
|
|
"\033[38;5;46m", # bright green
|
|
"\033[38;5;40m", # green
|
|
"\033[38;5;34m", # medium green
|
|
"\033[38;5;28m", # dark green
|
|
"\033[38;5;22m", # deep green
|
|
"\033[2;38;5;22m", # dim deep green
|
|
"\033[2;38;5;235m", # near black
|
|
]
|
|
|
|
# Complementary sweep for queue messages (opposite hue family from ticker greens)
|
|
MSG_GRAD_COLS = [
|
|
"\033[1;38;5;231m", # white
|
|
"\033[1;38;5;225m", # pale pink-white
|
|
"\033[38;5;219m", # bright pink
|
|
"\033[38;5;213m", # hot pink
|
|
"\033[38;5;207m", # magenta
|
|
"\033[38;5;201m", # bright magenta
|
|
"\033[38;5;165m", # orchid-red
|
|
"\033[38;5;161m", # ruby-magenta
|
|
"\033[38;5;125m", # dark magenta
|
|
"\033[38;5;89m", # deep maroon-magenta
|
|
"\033[2;38;5;89m", # dim deep maroon-magenta
|
|
"\033[2;38;5;235m", # near black
|
|
]
|
|
|
|
|
|
def lr_gradient(rows, offset=0.0, grad_cols=None):
|
|
"""Color each non-space block character with a shifting left-to-right gradient.
|
|
|
|
Args:
|
|
rows: List of text lines with block characters
|
|
offset: Gradient offset (0.0-1.0) for animation
|
|
grad_cols: List of ANSI color codes (default: GRAD_COLS)
|
|
|
|
Returns:
|
|
List of lines with gradient coloring applied
|
|
"""
|
|
cols = grad_cols or GRAD_COLS
|
|
n = len(cols)
|
|
max_x = max((len(r.rstrip()) for r in rows if r.strip()), default=1)
|
|
out = []
|
|
for row in rows:
|
|
if not row.strip():
|
|
out.append(row)
|
|
continue
|
|
buf = []
|
|
for x, ch in enumerate(row):
|
|
if ch == " ":
|
|
buf.append(" ")
|
|
else:
|
|
shifted = (x / max(max_x - 1, 1) + offset) % 1.0
|
|
idx = min(round(shifted * (n - 1)), n - 1)
|
|
buf.append(f"{cols[idx]}{ch}{RST}")
|
|
out.append("".join(buf))
|
|
return out
|
|
|
|
|
|
def lr_gradient_opposite(rows, offset=0.0):
|
|
"""Complementary (opposite wheel) gradient used for queue message panels.
|
|
|
|
Args:
|
|
rows: List of text lines with block characters
|
|
offset: Gradient offset (0.0-1.0) for animation
|
|
|
|
Returns:
|
|
List of lines with complementary gradient coloring applied
|
|
"""
|
|
return lr_gradient(rows, offset, MSG_GRAD_COLS)
|
|
|
|
|
|
def msg_gradient(rows, offset):
|
|
"""Apply message (ntfy) gradient using theme complementary colors.
|
|
|
|
Returns colored rows using ACTIVE_THEME.message_gradient if available,
|
|
falling back to default magenta if no theme is set.
|
|
|
|
Args:
|
|
rows: List of text strings to colorize
|
|
offset: Gradient offset (0.0-1.0) for animation
|
|
|
|
Returns:
|
|
List of rows with ANSI color codes applied
|
|
"""
|
|
from engine import config
|
|
|
|
# Check if theme is set and use it
|
|
if config.ACTIVE_THEME:
|
|
cols = _color_codes_to_ansi(config.ACTIVE_THEME.message_gradient)
|
|
else:
|
|
# Fallback to default magenta gradient
|
|
cols = MSG_GRAD_COLS
|
|
|
|
return lr_gradient(rows, offset, cols)
|
|
|
|
|
|
def _color_codes_to_ansi(color_codes):
|
|
"""Convert a list of 256-color codes to ANSI escape code strings.
|
|
|
|
Pattern: first 2 are bold, middle 8 are normal, last 2 are dim.
|
|
|
|
Args:
|
|
color_codes: List of 12 integers (256-color palette codes)
|
|
|
|
Returns:
|
|
List of ANSI escape code strings
|
|
"""
|
|
if not color_codes or len(color_codes) != 12:
|
|
# Fallback to default green if invalid
|
|
return GRAD_COLS
|
|
|
|
result = []
|
|
for i, code in enumerate(color_codes):
|
|
if i < 2:
|
|
# Bold for first 2 (bright leading edge)
|
|
result.append(f"\033[1;38;5;{code}m")
|
|
elif i < 10:
|
|
# Normal for middle 8
|
|
result.append(f"\033[38;5;{code}m")
|
|
else:
|
|
# Dim for last 2 (dark trailing edge)
|
|
result.append(f"\033[2;38;5;{code}m")
|
|
return result
|