CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
CanvasView.h
Go to the documentation of this file.
1#pragma once
2
3#include "cdc_ui/IView.h"
4#include "cdc_core/Raii.h"
6#include "freertos/FreeRTOS.h"
7#include "freertos/semphr.h"
8#include <cstddef>
9#include <cstdint>
10
11class Gdey029T94;
12
13namespace cdc::ui {
14
26class CanvasView : public ViewBase, private anim::AnimTarget {
27public:
28 enum class WidgetType : uint8_t {
29 None = 0,
30 Slider = 1,
31 Text = 2,
32 Button = 3,
33 };
34
35 enum class WidgetEvent : uint8_t {
39 };
40
41 static constexpr uint8_t MAX_WIDGETS = 8;
42 static constexpr uint8_t MAX_ELEMS = 16;
43 static constexpr uint16_t MAX_TEXT_LEN = 256;
44 static constexpr uint16_t T9_SETTLE_MS = 800;
45
48 static constexpr uint16_t MAX_CMDS = 128;
49 static constexpr uint16_t TEXT_ARENA = 2048;
51 static constexpr uint16_t BLOB_ARENA = 8192;
53 static constexpr uint32_t SPRITE_ARENA = 65536;
54
56 enum : uint8_t {
59 };
62 static constexpr uint8_t ANIM_FPS_DEFAULT = 4;
63 static constexpr uint8_t ANIM_FPS_MAX = 5;
65 static constexpr uint16_t ANIM_CLEANUP_IDLE_MS = 1000;
67 static constexpr uint8_t ANIM_HYGIENE_COMMITS = 128;
68
69 using KeyCallback = void(*)(char key, uint32_t focused_widget);
70 using WidgetCallback = void(*)(uint32_t widget_id, WidgetEvent event);
71 using LongPressCallback = void(*)(char key);
74 using AnimCallback = void(*)(uint32_t done_action_id, uint32_t handle,
75 uint32_t ref_id);
76
77 void init(const char* title);
78
88 void setEditMutex(SemaphoreHandle_t mutex) { editMutex_ = mutex; }
89
90 void setKeyCallback(KeyCallback cb) { keyCb_ = cb; }
91 void setWidgetCallback(WidgetCallback cb) { widgetCb_ = cb; }
95 void setFooter(const char* hint);
96 void setKeyRepeat(uint16_t initial_ms, uint16_t repeat_ms);
97 void getBodySize(uint16_t* w, uint16_t* h) const;
98
102 void clearBody(bool keep_sprites = false);
103 void setTextSize(uint8_t size) { textSize_ = size > 0 ? size : 1; }
104 void setTextInverted(bool inverted) { textInverted_ = inverted; }
106 void setFontId(uint8_t font_id) { fontId_ = font_id; }
108 void setShade(uint8_t shade) { shade_ = shade; }
110 void setInkWhite(bool white) { inkWhite_ = white; }
111 void drawText(int16_t x, int16_t y, const char* text);
112 void drawTextAligned(int16_t x, int16_t y, int16_t w, const char* text, uint8_t align);
113 void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, bool filled);
114 void drawPixel(int16_t x, int16_t y);
115 void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);
116 void drawCircle(int16_t x, int16_t y, int16_t r, bool filled);
117 void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
118 int16_t x2, int16_t y2, bool filled);
119 void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, bool filled);
122 void drawBitmap(int16_t x, int16_t y, int16_t w, int16_t h,
123 const uint8_t* data, uint32_t len);
124 void drawHLine(int16_t x, int16_t y, int16_t w);
125 void drawVLine(int16_t x, int16_t y, int16_t h);
126 void commit(bool full_refresh);
127
132 bool beginElem(uint32_t id);
134 void endElem();
136 bool elemSetOffset(uint32_t id, int16_t ox, int16_t oy);
138 bool elemMove(uint32_t id, int16_t dx, int16_t dy);
140 bool elemShow(uint32_t id, bool visible);
143 bool elemRemove(uint32_t id);
146 bool elemClear(uint32_t id);
150 bool elemSetZ(uint32_t id, int8_t z);
152 bool elemGetOffset(uint32_t id, int16_t* ox, int16_t* oy) const;
155 bool elemGetBounds(uint32_t id, int16_t* x, int16_t* y,
156 uint16_t* w, uint16_t* h);
157
158 // --- Sprites (multi-frame 1-bpp resources, drawn by reference) ---------
159
162 int32_t spriteCreate(uint16_t w, uint16_t h, uint16_t frame_count,
163 const uint8_t* data, uint32_t len);
164 bool spriteSetMask(uint32_t handle, const uint8_t* mask, uint32_t len);
165 bool spriteSetFlags(uint32_t handle, uint8_t flags);
167 bool spriteSetScale(uint32_t handle, uint8_t scale);
168 bool spriteSetFrame(uint32_t handle, uint16_t frame);
169 int32_t spriteGetFrame(uint32_t handle) const;
170 bool spriteSetFrameDurations(uint32_t handle, const uint16_t* ms,
171 uint16_t count);
172 bool spritePlay(uint32_t handle, uint8_t mode, uint16_t frame_ms,
173 uint16_t repeat, uint32_t done_action_id);
174 bool spriteStop(uint32_t handle);
177 bool spriteDestroy(uint32_t handle);
179 void drawSprite(int16_t x, int16_t y, uint32_t handle);
182 bool spriteFrameView(uint32_t handle, anim::SpriteStore::FrameView* out) const;
183
191 int32_t marquee(int16_t x, int16_t y, int16_t window_w, const char* text,
192 uint16_t step_px, uint16_t frame_ms);
193
194 // --- Tweens (host-driven element-offset animation) ---------------------
195
198 uint32_t animStart(const anim::TweenConfig& cfg);
201 uint32_t animBlink(uint32_t elem_id, uint16_t period_ms, uint16_t count,
202 uint32_t done_action_id);
203 bool animCancel(uint32_t handle);
204 bool animPause(uint32_t handle, bool paused);
205 int8_t animState(uint32_t handle) const;
207 uint8_t animActiveCount() const;
208 void setAnimCallback(AnimCallback cb) { animCb_ = cb; }
210 bool setAnimPolicy(uint8_t policy, uint8_t max_fps);
211
212 bool addSlider(uint32_t id, int32_t min, int32_t max, int32_t initial, int32_t step);
213 bool addText(uint32_t id, uint16_t max_len, const char* initial);
214 bool addButton(uint32_t id);
215 bool removeWidget(uint32_t id);
216
217 bool setValue(uint32_t id, int32_t value);
218 bool getValue(uint32_t id, int32_t* out) const;
219 bool setText(uint32_t id, const char* text);
220 int getText(uint32_t id, char* out, size_t cap) const;
221
222 bool setFocus(uint32_t id);
223 uint32_t getFocus() const { return focused_; }
224
225 void render(bool partial) override;
226 InputResult onKey(char key) override;
227 InputResult onLongPress(char key) override;
228 void onEnter(void* context) override;
229 void onResume() override;
230 void onPause() override;
231 void onExit() override;
232 void onTick(uint32_t nowMs) override;
233 const char* getName() const override { return "CanvasView"; }
234
238
241 bool prefersLightRefresh() const override { return animActive_; }
242
243private:
244 enum class CmdType : uint8_t {
245 Text, TextAligned, Rect, HLine, VLine,
246 Pixel, Line, Circle, Triangle, RoundRect, Bitmap, Sprite
247 };
248
249 struct DrawCmd {
250 CmdType type = CmdType::Text;
251 int16_t x = 0;
252 int16_t y = 0;
253 int16_t w = 0; // width, or 2nd point x (Line/Triangle), or radius (Circle)
254 int16_t h = 0; // height, or 2nd point y (Line/Triangle)
255 int16_t x2 = 0; // 3rd point x (Triangle), or corner radius (RoundRect)
256 int16_t y2 = 0; // 3rd point y (Triangle)
257 uint16_t strOff = 0; // byte offset into textArena_ (or blobArena_ for
258 // Bitmap), or the sprite handle (Sprite)
259 uint16_t strLen = 0; // string/blob length (text excludes NUL)
260 uint32_t elemId = 0; // owning element (0 = untagged)
261 uint8_t align = 0;
262 uint8_t fontId = 0;
263 uint8_t textSize = 1;
264 uint8_t shade = 255; // fill ink: 0=none, 255=solid; between = dither
265 bool filled = false;
266 bool inverted = false;
267 };
268
269 struct Widget {
270 uint32_t id = 0;
272 int32_t value = 0;
273 int32_t min = 0;
274 int32_t max = 0;
275 int32_t step = 1;
276 uint16_t max_len = 0;
277 uint16_t text_len = 0;
278 char text[MAX_TEXT_LEN] = {0};
279 char t9_last_key = 0;
280 uint8_t t9_press_count = 0;
281 uint32_t t9_last_time = 0;
282 };
283
286 struct Elem {
287 uint32_t id = 0;
288 int16_t ox = 0;
289 int16_t oy = 0;
290 int8_t z = 0;
291 bool hidden = false;
292 };
293
294 Widget* findWidget(uint32_t id);
295 const Widget* findWidget(uint32_t id) const;
296 Elem* findElem(uint32_t id);
297 const Elem* findElem(uint32_t id) const;
298 void applyElemOffset(DrawCmd& c, int16_t ox, int16_t oy) const;
299 void compactArenas();
300 void pushCmd(DrawCmd& c);
301 bool dropElemCmds(uint32_t id);
302 void replayCmd(const DrawCmd& cmd);
303 bool cmdBounds(const DrawCmd& c, int16_t* x, int16_t* y,
304 uint16_t* w, uint16_t* h);
305 bool ensureSpriteArena();
306
307 // anim::AnimTarget (called under editMutex_ from onTick/animStart paths).
308 bool getElemOffset(uint32_t elemId, int16_t* ox, int16_t* oy) override;
309 bool setElemOffset(uint32_t elemId, int16_t ox, int16_t oy) override;
310 bool setElemVisible(uint32_t elemId, bool visible) override;
311 Widget* focusedWidget();
312 InputResult dispatchKeyToWidget(Widget& w, char key);
313 void t9_commit_pending(Widget& w);
314 void t9_apply_key(Widget& w, char key, uint32_t now);
315
316 Gdey029T94* gfx() const;
317 void applyKeypadConfig();
318 uint16_t internText(const char* text, uint16_t* outLen);
319 uint16_t internBlob(const uint8_t* data, uint16_t len);
320 void allocArenas();
321 void replayDisplayList();
322 void paintText(int16_t x, int16_t y, int16_t w, const char* text,
323 uint8_t align, uint8_t fontId, uint8_t textSize,
324 bool inverted);
325 int bodyTop() const { return headerHeight_; }
326 int bodyBottom() const;
327
329 uint8_t widgetCount_ = 0;
330 uint32_t focused_ = 0;
331
332 Elem elems_[MAX_ELEMS] = {};
333 uint8_t elemCount_ = 0;
334 uint32_t curElem_ = 0;
335
336 const char* footer_ = nullptr;
337 KeyCallback keyCb_ = nullptr;
338 WidgetCallback widgetCb_ = nullptr;
339 LongPressCallback longPressCb_ = nullptr;
340
342 uint16_t cmdCount_ = 0;
344 uint16_t textArenaUsed_ = 0;
346 uint16_t blobUsed_ = 0;
347 bool overflowLogged_ = false;
348
349 uint8_t textSize_ = 1;
350 uint8_t fontId_ = 0;
351 uint8_t shade_ = 255;
352 bool inkWhite_ = false;
353 bool textInverted_ = false;
354 int headerHeight_ = 18;
355 bool needsFullRefresh_ = true;
356
357 uint16_t keyRepeatInitialMs_ = 0;
358 uint16_t keyRepeatPeriodMs_ = 0;
359 bool headerDrawnOnce_ = false;
360
361 // Optional, borrowed (not owned): serialises display-list access with a
362 // cross-task writer. Null disables locking. See setEditMutex().
363 SemaphoreHandle_t editMutex_ = nullptr;
364
365 // --- Animation state ----------------------------------------------------
366 anim::CanvasAnimator animator_;
367 anim::SpriteStore sprites_;
369 AnimCallback animCb_ = nullptr;
370 uint8_t animPolicy_ = ANIM_REFRESH_AUTO;
371 uint16_t animFrameIntervalMs_ = 1000 / ANIM_FPS_DEFAULT;
372 uint32_t lastAnimStepMs_ = 0;
373 uint32_t idleCleanupAtMs_ = 0; // 0 = no cleanup pending
374 uint32_t pausedAtMs_ = 0;
375 uint8_t animCommitCount_ = 0; // hygiene-FAST counter
376 // Written under editMutex_ in onTick, read lock-free by the render task's
377 // prefersLightRefresh(); a stale read only delays escalation by one frame.
378 volatile bool animActive_ = false;
379};
380
381} // namespace cdc::ui
Host-side animation engine for the plugin canvas: fixed-point easing, element-offset tweens and multi...
uint8_t flags
Shared RAII wrappers for firmware resources.
Generic canvas view exposed to WASM plugins for custom UIs.
Definition CanvasView.h:26
bool elemShow(uint32_t id, bool visible)
Show or hide the element (hidden elements are skipped on replay).
void setAnimCallback(AnimCallback cb)
Definition CanvasView.h:208
uint32_t animStart(const anim::TweenConfig &cfg)
void getBodySize(uint16_t *w, uint16_t *h) const
bool removeWidget(uint32_t id)
void endElem()
Stop tagging draw calls with an element id.
bool spriteSetScale(uint32_t handle, uint8_t scale)
Integer upscale 1..4 applied whenever the sprite is drawn.
static constexpr uint8_t ANIM_FPS_DEFAULT
Definition CanvasView.h:62
bool elemGetBounds(uint32_t id, int16_t *x, int16_t *y, uint16_t *w, uint16_t *h)
InputResult onLongPress(char key) override
int getText(uint32_t id, char *out, size_t cap) const
uint32_t animBlink(uint32_t elem_id, uint16_t period_ms, uint16_t count, uint32_t done_action_id)
void(*)(uint32_t widget_id, WidgetEvent event) WidgetCallback
Definition CanvasView.h:70
@ ANIM_REFRESH_LIGHT
PARTIAL_LIGHT always, no automatic cleanup.
Definition CanvasView.h:58
@ ANIM_REFRESH_AUTO
PARTIAL_LIGHT while running + FAST cleanup.
Definition CanvasView.h:57
void drawText(int16_t x, int16_t y, const char *text)
void(*)(char key) LongPressCallback
Definition CanvasView.h:71
void drawHLine(int16_t x, int16_t y, int16_t w)
uint32_t getFocus() const
Definition CanvasView.h:223
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
static constexpr uint8_t ANIM_FPS_MAX
Definition CanvasView.h:63
void clearBody(bool keep_sprites=false)
bool beginElem(uint32_t id)
void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, bool filled)
void init(const char *title)
InputResult onKey(char key) override
void(*)(uint32_t done_action_id, uint32_t handle, uint32_t ref_id) AnimCallback
Definition CanvasView.h:74
bool elemClear(uint32_t id)
void commit(bool full_refresh)
bool spriteFrameView(uint32_t handle, anim::SpriteStore::FrameView *out) const
bool spriteDestroy(uint32_t handle)
void onResume() override
static constexpr uint16_t MAX_CMDS
Definition CanvasView.h:48
static constexpr uint8_t ANIM_HYGIENE_COMMITS
Endless animations get one hygiene FAST every this many anim commits.
Definition CanvasView.h:67
void onExit() override
bool spriteSetFlags(uint32_t handle, uint8_t flags)
void setLongPressCallback(LongPressCallback cb)
void onEnter(void *context) override
bool animPause(uint32_t handle, bool paused)
bool spriteStop(uint32_t handle)
static constexpr uint16_t ANIM_CLEANUP_IDLE_MS
Idle time after the last animation before the AUTO ghost-cleanup FAST.
Definition CanvasView.h:65
uint8_t animActiveCount() const
Live tweens plus playing sprites.
void setWidgetCallback(WidgetCallback cb)
Definition CanvasView.h:91
static constexpr uint16_t BLOB_ARENA
Pixel-data arena for recorded bitmaps. 8 KB holds one full-body mono bitmap.
Definition CanvasView.h:51
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool filled)
bool spriteSetMask(uint32_t handle, const uint8_t *mask, uint32_t len)
static constexpr uint8_t MAX_WIDGETS
Definition CanvasView.h:41
bool setFocus(uint32_t id)
bool spritePlay(uint32_t handle, uint8_t mode, uint16_t frame_ms, uint16_t repeat, uint32_t done_action_id)
void setFontId(uint8_t font_id)
Select one of the canonical font ids (see cdc_views/Fonts.h).
Definition CanvasView.h:106
bool spriteSetFrameDurations(uint32_t handle, const uint16_t *ms, uint16_t count)
int8_t animState(uint32_t handle) const
void drawBitmap(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *data, uint32_t len)
bool animCancel(uint32_t handle)
Handle 0 cancels all (no events).
bool setValue(uint32_t id, int32_t value)
bool addText(uint32_t id, uint16_t max_len, const char *initial)
bool elemSetZ(uint32_t id, int8_t z)
static constexpr uint32_t SPRITE_ARENA
Pixel arena for sprite frame sheets (lazy PSRAM allocation).
Definition CanvasView.h:53
bool getValue(uint32_t id, int32_t *out) const
bool addButton(uint32_t id)
void setEditMutex(SemaphoreHandle_t mutex)
Definition CanvasView.h:88
bool setText(uint32_t id, const char *text)
static constexpr uint16_t T9_SETTLE_MS
Definition CanvasView.h:44
bool elemRemove(uint32_t id)
hal::RefreshMode preferredEnterRefresh() const override
Definition CanvasView.h:237
bool elemMove(uint32_t id, int16_t dx, int16_t dy)
Shift the element's replay offset by a delta.
int32_t spriteGetFrame(uint32_t handle) const
static constexpr uint16_t MAX_TEXT_LEN
Definition CanvasView.h:43
void setKeyRepeat(uint16_t initial_ms, uint16_t repeat_ms)
int32_t marquee(int16_t x, int16_t y, int16_t window_w, const char *text, uint16_t step_px, uint16_t frame_ms)
void setShade(uint8_t shade)
Fill ink for subsequent filled shapes: 0=none, 255=solid, between=dither.
Definition CanvasView.h:108
bool spriteSetFrame(uint32_t handle, uint16_t frame)
void drawCircle(int16_t x, int16_t y, int16_t r, bool filled)
bool elemSetOffset(uint32_t id, int16_t ox, int16_t oy)
Set the element's replay offset relative to its recorded coordinates.
bool addSlider(uint32_t id, int32_t min, int32_t max, int32_t initial, int32_t step)
bool setAnimPolicy(uint8_t policy, uint8_t max_fps)
Configure refresh policy and step-rate cap (0 = default 4 fps).
void drawPixel(int16_t x, int16_t y)
void setFooter(const char *hint)
static constexpr uint16_t TEXT_ARENA
Definition CanvasView.h:49
void drawTextAligned(int16_t x, int16_t y, int16_t w, const char *text, uint8_t align)
void onPause() override
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, bool filled)
void(*)(char key, uint32_t focused_widget) KeyCallback
Definition CanvasView.h:69
void setTextInverted(bool inverted)
Definition CanvasView.h:104
bool elemGetOffset(uint32_t id, int16_t *ox, int16_t *oy) const
Read the element's current replay offset.
void drawSprite(int16_t x, int16_t y, uint32_t handle)
Record a draw-by-reference of the sprite's current frame at (x, y).
bool prefersLightRefresh() const override
Definition CanvasView.h:241
int32_t spriteCreate(uint16_t w, uint16_t h, uint16_t frame_count, const uint8_t *data, uint32_t len)
void onTick(uint32_t nowMs) override
const char * getName() const override
Definition CanvasView.h:233
void setTextSize(uint8_t size)
Definition CanvasView.h:103
static constexpr uint8_t MAX_ELEMS
Definition CanvasView.h:42
void setKeyCallback(KeyCallback cb)
Definition CanvasView.h:90
void drawVLine(int16_t x, int16_t y, int16_t h)
void setInkWhite(bool white)
Draw subsequent shapes in white instead of black (eraser/wipes).
Definition CanvasView.h:110
Interface the animator drives; implemented by CanvasView on its elements.
Definition CanvasAnim.h:77
SemaphoreHandle_t mutex
Definition ctaphid.cpp:51
std::unique_ptr< T[], CapsFreeDeleter > PsramUniquePtr
Definition Raii.h:44
Centralized key-code constants for cdc_views.
Definition IModule.h:8
InputResult
Definition IView.h:11
Replay accessors: geometry, flags and pixel pointers of a sprite.
Definition CanvasAnim.h:267
Tween start configuration (mirrors host_anim_t plus the blink shorthand).
Definition CanvasAnim.h:94