A new self-contained widget type showing user-authored rich text -- no
live upstream to poll, like the static image widget, just word-wrapped
styled text instead of an uploaded image.
The dialog's contenteditable HTML is never stored or replayed as HTML:
app/text_content.py parses it server-side (on save) into a plain
paragraphs-of-styled-runs structure -- the actual sanitization
boundary, since raw HTML never round-trips back into any browser DOM
(the dialog rebuilds its editor from that same JSON via
createElement/textContent). app/widgets/text.py renders it with a
custom word-wrap/shrink-to-fit layout, using real vendored font weights
(app/fonts/NotoSans-{Regular,Bold,Italic,BoldItalic}.ttf, OFL-licensed
like the emoji fonts already there) rather than every other widget's
single ImageFont.load_default() -- the one widget type where that
distinction matters.
49 lines
2.1 KiB
Python
49 lines
2.1 KiB
Python
"""Registry mapping a Widget's widget_type to its render/action module --
|
|
the widget-system's analogue of routers/device.py's old RENDERERS/
|
|
ADVANCE_RENDERERS/BACK_RENDERERS dicts, generalized from "one mode owns
|
|
the whole panel" to "each widget renders into its own region and
|
|
optionally responds to named button actions."
|
|
|
|
Each module in this package exposes:
|
|
|
|
render(db, frame, widget, target_w, target_h, is_normal_wake=True) -> Image.Image
|
|
An RGB image exactly target_w x target_h, unquantized -- the
|
|
widget's content composed into its own region. Never returns
|
|
packed panel bytes or raises for a foreseeable failure (a
|
|
widget's own fetch hiccup shows a small placeholder instead) --
|
|
image_pipeline.render_panel composites every widget's own
|
|
render() result onto one shared canvas and quantizes/packs the
|
|
whole thing once (see its own docstring). is_normal_wake
|
|
distinguishes an ordinary /frame/image GET from a button-
|
|
triggered re-render -- only app/widgets/calendar.py's render()
|
|
actually uses it (resetting browse_offset back to "today" on a
|
|
normal wake), but every module accepts it for one uniform call
|
|
signature regardless.
|
|
|
|
ACTIONS: dict[str, Callable[[Session, Frame, Widget], None]]
|
|
Named button actions this widget type supports (e.g. "advance",
|
|
"back", "check_now") -- see models.FrameButtonAction. Each
|
|
function mutates the widget's own state via db.widget_locked
|
|
internally; none return a value or re-render themselves --
|
|
whatever dispatches a button press (routers/device.py, once the
|
|
widget-system cutover lands) re-renders the whole panel once
|
|
after running every assigned action.
|
|
|
|
ACTION_LABELS: dict[str, str]
|
|
Human-readable labels for ACTIONS' keys, for the button-
|
|
assignment UI.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from . import calendar, photos, static_image, tasks, text, whiteboard
|
|
|
|
WIDGET_TYPES = {
|
|
"photos": photos,
|
|
"calendar": calendar,
|
|
"whiteboard": whiteboard,
|
|
"tasks": tasks,
|
|
"static": static_image,
|
|
"text": text,
|
|
}
|