Files
espresso_frame/server/app/widgets/_shared.py
T
tfaour d34eb1bf45
Build and push server image / test (push) Successful in 38s
Build and push server image / build-and-push (push) Successful in 2m46s
Build and push server image / deploy (push) Successful in 58s
Modernize on-panel widget visuals: real typography, theme colors, gutter
Introduces app/panel_style.py, a shared style module every render
module now draws through instead of independently duplicating margins/
colors/fonts: Inter Bold/Regular (already vendored, previously only
used by widgets/text.py) replace PIL's single-weight bundled default
font everywhere else; a per-widget-kind accent color (calendar=blue,
tasks=green, weather=black header) replaces plain black-on-white chrome
and is centralized in one THEME mapping so a future global theme only
needs to touch panel_style.py; a small per-widget gutter separates
adjacent widgets without touching grid.py's cell math; header bars,
color chips, and the battery icon get rounded corners.

Also drops the MUTED gray text color used throughout calendar_render.py
and weather_render.py -- a non-palette color that has no close match in
the panel's 6-ink palette and dithers into visible speckle once the
composited canvas is quantized. Secondary text now reads through size/
weight alone, always exact black.

widgets/battery.py and manage_overlay.py's previously-duplicated
battery-glyph-drawing code now share one implementation (panel_style.
draw_battery_icon). widgets/_shared.py's placeholder image is fixed to
use exact palette colors and route through image_pipeline.draw_text,
same as everything else -- it was quietly violating both rules already.

image_pipeline.draw_widget_border gains an opt-in radius param (default
0, unused by any call site) for a possible future rounded-border
setting -- doesn't touch the exact-corner-pixel behavior test_widget_
border.py already pins.

Deliberately out of scope: DEFAULT_PALETTE_RGB and the Floyd-Steinberg
quantization pipeline are untouched, per the prior reverted measured-
palette/OKLab attempt (05b417a/dfe9d701).
2026-07-30 03:12:17 +00:00

33 lines
1.1 KiB
Python

"""Tiny widget-region placeholder image, shared by every widget-type
module for the "not configured yet" / "temporarily unavailable" case --
deliberately much simpler than image_pipeline.render_placeholder (no QR
code, no full-panel-scale fonts): a widget's own region can be a small
fraction of the panel, so its placeholder needs to scale down with it.
"""
from __future__ import annotations
from PIL import Image, ImageDraw
from .. import panel_style
from ..image_pipeline import draw_text
_BG = (255, 255, 255)
def placeholder_image(target_w: int, target_h: int, lines: list[str]) -> Image.Image:
img = Image.new("RGB", (target_w, target_h), _BG)
draw = ImageDraw.Draw(img)
font_size = max(10, min(20, target_h // 8))
font = panel_style.font_regular(font_size)
line_h = font_size + 4
total_h = line_h * len(lines)
y = max(4, (target_h - total_h) // 2)
for line in lines:
bbox = draw.textbbox((0, 0), line, font=font)
line_w = bbox[2] - bbox[0]
x = max(4, (target_w - line_w) // 2)
draw_text(img, (x, y), line, font)
y += line_h
return img