@typecad/ui 1.0.0-alpha.6 → 1.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/engine-index.js +2 -0
  2. package/dist/ui-engine/runtime-header/canvas-helpers.js +12 -6
  3. package/dist/ui-engine/runtime-header/cuttlefish-gfx.d.ts +1 -0
  4. package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +533 -0
  5. package/dist/ui-engine/runtime-header/forward-decls.js +5 -5
  6. package/dist/ui-engine/runtime-header/keyboard.js +45 -4
  7. package/dist/ui-engine/runtime-header/node-decoration.js +0 -1
  8. package/dist/ui-engine/runtime-header/scroll-physics.js +0 -4
  9. package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +42 -7
  10. package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +4 -1
  11. package/dist/ui-engine/runtime-header.d.ts +10 -1
  12. package/dist/ui-engine/runtime-header.js +5 -1
  13. package/dist/ui-engine/ui-lowering.js +14 -1
  14. package/dist/ui-engine/ui-registry.js +2 -1
  15. package/package.json +2 -2
  16. package/src/engine-index.ts +2 -0
  17. package/src/ui-engine/runtime-header/canvas-helpers.ts +12 -6
  18. package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +536 -0
  19. package/src/ui-engine/runtime-header/forward-decls.ts +5 -5
  20. package/src/ui-engine/runtime-header/keyboard.ts +45 -4
  21. package/src/ui-engine/runtime-header/node-decoration.ts +0 -1
  22. package/src/ui-engine/runtime-header/scroll-physics.ts +0 -4
  23. package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +42 -7
  24. package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +4 -1
  25. package/src/ui-engine/runtime-header.ts +15 -1
  26. package/src/ui-engine/ui-lowering.ts +16 -1
  27. package/src/ui-engine/ui-registry.ts +2 -1
@@ -27,9 +27,48 @@ export function emitTickDirtyDrawPhase(): string {
27
27
  if (__ui_kb_dirty == 1) {
28
28
  ui_kb_draw();
29
29
  } else if (__ui_kb_dirty == 2) {
30
- ui_kb_draw_text_row();
31
- if (__ui_kb_repaint_key >= 0 && __ui_kb_keys[__ui_kb_repaint_key].special != 255) {
32
- ui_kb_draw_key((uint8_t)__ui_kb_repaint_key);
30
+ // Buffer the targeted update through the keyboard canvas too — drawing
31
+ // the text row directly to the display (fill_rect clear + text redraw)
32
+ // flashes on SPI TFTs because the clear is visible for one frame.
33
+ // Re-render into the canvas and push in one transaction. The canvas
34
+ // already holds the last full-keyboard frame, so we only need to redraw
35
+ // the text row + the single changed key on top of it.
36
+ // (__ui_kb_canvas is declared static in the keyboard slice, earlier in
37
+ // this same translation unit — no extern needed.)
38
+ if (__ui_kb_canvas && display_canvasBuffer(__ui_kb_canvas)) {
39
+ int16_t kw = __ui_kb_box.w;
40
+ int16_t saveBoxX = __ui_kb_box.x;
41
+ int16_t saveBoxY = __ui_kb_box.y;
42
+ CuttlefishDisplayTarget* __kb_prev = ui_display_get_target();
43
+ ui_display_set_target(__ui_kb_canvas);
44
+ __ui_kb_box.x = 0;
45
+ __ui_kb_box.y = 0;
46
+ ui_kb_draw_text_row();
47
+ uint8_t has_key_repaint = (__ui_kb_repaint_key >= 0 && __ui_kb_keys[__ui_kb_repaint_key].special != 255) ? 1 : 0;
48
+ if (has_key_repaint) {
49
+ ui_kb_draw_key((uint8_t)__ui_kb_repaint_key);
50
+ }
51
+ __ui_kb_box.x = saveBoxX;
52
+ __ui_kb_box.y = saveBoxY;
53
+ ui_display_set_target(__kb_prev);
54
+ // Push only the changed region: text row alone (UI_KB_TEXT_H) when no
55
+ // key highlight changed, or the full canvas when a key was repainted
56
+ // (the key could be anywhere in the keyboard grid).
57
+ display_startWrite();
58
+ if (has_key_repaint) {
59
+ display_setAddrWindow(saveBoxX, saveBoxY, kw, __ui_kb_box.h);
60
+ display_writePixels(display_canvasBuffer(__ui_kb_canvas), (uint32_t)kw * __ui_kb_box.h);
61
+ } else {
62
+ display_setAddrWindow(saveBoxX, saveBoxY, kw, UI_KB_TEXT_H);
63
+ display_writePixels(display_canvasBuffer(__ui_kb_canvas), (uint32_t)kw * UI_KB_TEXT_H);
64
+ }
65
+ display_endWrite();
66
+ } else {
67
+ // No canvas — fall back to direct draw (slow but correct).
68
+ ui_kb_draw_text_row();
69
+ if (__ui_kb_repaint_key >= 0 && __ui_kb_keys[__ui_kb_repaint_key].special != 255) {
70
+ ui_kb_draw_key((uint8_t)__ui_kb_repaint_key);
71
+ }
33
72
  }
34
73
  }
35
74
  __ui_kb_dirty = 0;
@@ -272,10 +311,6 @@ export function emitTickDirtyDrawPhase(): string {
272
311
 
273
312
  UIRect paintRect;
274
313
  ui_node_paint_rect(i, baseDrawX, baseDrawY, drawX, drawY, paintTextW, paintTextH, &paintRect);
275
- int16_t cullX = paintRect.x;
276
- int16_t cullY = paintRect.y;
277
- int16_t cullW = paintRect.w;
278
- int16_t cullH = paintRect.h;
279
314
  if (drawingBufferedScroll) {
280
315
  // Canvas-local clip: skip nodes fully outside the viewport (0..vw, 0..vh).
281
316
  // Use the node's face rect (box.w/h), NOT the paint rect — the paint rect
@@ -51,6 +51,7 @@ static UIKeyStyle __ui_kb_styles[UI_KB_MAX];
51
51
  static UI_COLOR_T __ui_kb_bg = 0x0000; // keyboard background (resolved from CSS)
52
52
  static uint8_t __ui_kb_bs_held = 0;
53
53
  static uint8_t __ui_kb_dirty = 0; // 0=clean, 1=full redraw, 2=text row + single key
54
+ // (__ui_kb_canvas is declared in forward-decls.ts alongside the other persistent canvases.)
54
55
  // Forward-declared here (defined in the keyboard subsystem block below) so the
55
56
  // UI_HIDE_OSK caret/blink paths in ui_tick and the input draw can reference it.
56
57
  static int16_t __ui_kb_target;
@@ -268,7 +269,9 @@ static void ui_touch_up() {
268
269
  // including holds (released above) and taps on empty space (__ui_touch_node
269
270
  // == -1), which is what makes "wake on any touch" work for display-sleep.
270
271
  // Placed AFTER the click/release dispatch so onClick always fires first.
271
- __ui_tap_seq++;
272
+ // Note: explicit '+ 1' instead of '++' — GCC 13+ (IDF v6) deprecates '++'
273
+ // on volatile-qualified types under -Werror=volatile.
274
+ __ui_tap_seq = __ui_tap_seq + 1;
272
275
  __ui_tap_node = __ui_touch_node;
273
276
  // Virtualized list item tap: if the touch was inside a list, compute the item
274
277
  // index from the touch Y. Use total movement (not drag flag) to distinguish
@@ -42,7 +42,21 @@ import { emitAntialiasing } from "./runtime-header/antialiasing.js";
42
42
  import { emitKeyboard } from "./runtime-header/keyboard.js";
43
43
  import { emitGuardClose } from "./runtime-header/guard-close.js";
44
44
 
45
- export function emitRuntimeHeader(): string {
45
+ export interface EmitRuntimeHeaderOptions {
46
+ /**
47
+ * True when a native display adapter (AVR, ESP32) is in use. Kept for
48
+ * backwards compatibility — the CuttlefishGFX slice is now emitted
49
+ * separately via emitCuttlefishGfx() so it can land BEFORE display adapter
50
+ * declarations that instantiate CuttlefishGFX by value.
51
+ */
52
+ nativeDisplayActive?: boolean;
53
+ }
54
+
55
+ export function emitRuntimeHeader(opts?: EmitRuntimeHeaderOptions): string {
56
+ // Note: the CuttlefishGFX slice (emitCuttlefishGfx) is emitted separately
57
+ // by ui-emitter.ts BEFORE the display adapter declaration. It is NOT
58
+ // emitted here — passing nativeDisplayActive has no effect.
59
+ void opts;
46
60
  return [
47
61
  emitTypesDefines(),
48
62
  emitStructs(),
@@ -199,7 +199,22 @@ function emitKeyboardLoader(name: string, kb: KeyboardTemplate, rules: CSSRule[]
199
199
 
200
200
  /** Emit one key's keys[] + styles[] lines, resolving CSS classes to colors. */
201
201
  function emitKeyLine(key: UIKeyTemplate, kbClasses: string[] | undefined, rules: CSSRule[], colorFormat: ColorFormat): string {
202
- const chEsc = key.ch === "\\" ? "\\\\" : key.ch === "'" ? "\\'" : key.ch;
202
+ // The C++ UIKey.ch field is a single `char`. Special keys (shift=1, bs=2,
203
+ // ok=3, page=4) use the `special` field for their behavior and label — the
204
+ // `ch` value is never read. Their label strings ("OK", "123", "⇧", "⌫") are
205
+ // multi-char or multi-byte and would overflow `char` if emitted as literals.
206
+ // Emit a space placeholder for any key whose ch isn't a single ASCII byte.
207
+ const isSingleAscii = key.special === 0 && key.ch.length === 1 && key.ch.charCodeAt(0) < 128;
208
+ if (key.special === 0 && !isSingleAscii) {
209
+ console.warn(
210
+ `[cuttlefish] keyboard key ch="${key.ch}" is non-ASCII and will be emitted as ` +
211
+ `a space placeholder. The native C++ UIKey.ch field is a single char and ` +
212
+ `cannot hold multi-byte codepoints. Use a custom keyboard layout or the ` +
213
+ `Adafruit path for full Unicode key labels.`,
214
+ );
215
+ }
216
+ const chRaw = isSingleAscii ? key.ch : ' ';
217
+ const chEsc = chRaw === "\\" ? "\\\\" : chRaw === "'" ? "\\'" : chRaw;
203
218
  const style = resolveKeyStyle(key.classes, kbClasses, rules);
204
219
  const bg = style.background ? resolveColor(style.background, colorFormat) : DEFAULT_KEY_BG;
205
220
  const fg = style.color ? resolveColor(style.color, colorFormat) : DEFAULT_KEY_FG;
@@ -220,7 +220,8 @@ export function lowerOnMount(htmlPath: string, opts: LowerOptions): LoweredUI {
220
220
 
221
221
  const imageAssets = loadImageAssets(allStyled.length > 0 ? allStyled : [mod.styled], path.dirname(abs));
222
222
 
223
- const scrollBudget = resolveScrollConfig(getDisplayProfile(), { buildTarget: getDisplayProfile()._buildTarget }).scrollCanvasBudgetBytes;
223
+ const _p = getDisplayProfile() as any;
224
+ const scrollBudget = resolveScrollConfig(_p, { buildTarget: _p._buildTarget, psram: _p._psram } as any).scrollCanvasBudgetBytes;
224
225
  const result = lowerUIToCpp(mod.styled, allBoxes, opts.colorFormat, opts.storage, mod.keyboards, mod.rules, getDisplayProfile(), mod.fontAssets, allStyled, imageAssets.nodeIdToAssetIndex, keyframeSets, scrollBudget);
225
226
 
226
227
  for (const d of result.scrollMemoryDiagnostics) {