@typecad/ui 1.0.0-alpha.11 → 1.0.0-alpha.13
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.
- package/README.md +21 -1
- package/assets/fonts/dejavu/DejaVuSans-Bold.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans-Oblique.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSans.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSansMono-Bold.ttf +0 -0
- package/assets/fonts/dejavu/DejaVuSansMono.ttf +0 -0
- package/assets/fonts/dejavu/LICENSE +187 -0
- package/assets/fonts/dejavu/README.md +49 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +74 -0
- package/dist/engine-index.js +2 -0
- package/dist/preview/build-program.d.ts +7 -1
- package/dist/preview/build-program.js +94 -15
- package/dist/preview/host-gfx.d.ts +3 -0
- package/dist/preview/host-gfx.js +30 -3
- package/dist/preview/host-ui-runtime.d.ts +115 -0
- package/dist/preview/host-ui-runtime.js +928 -46
- package/dist/ui-engine/block-layout.js +25 -11
- package/dist/ui-engine/color.d.ts +6 -0
- package/dist/ui-engine/color.js +80 -2
- package/dist/ui-engine/compat-report.d.ts +8 -0
- package/dist/ui-engine/compat-report.js +124 -0
- package/dist/ui-engine/css-imports.d.ts +4 -0
- package/dist/ui-engine/css-imports.js +70 -0
- package/dist/ui-engine/css-parser.js +58 -14
- package/dist/ui-engine/default-font.d.ts +25 -0
- package/dist/ui-engine/default-font.js +80 -0
- package/dist/ui-engine/font-assets.d.ts +2 -2
- package/dist/ui-engine/font-assets.js +22 -5
- package/dist/ui-engine/html-parser.d.ts +4 -0
- package/dist/ui-engine/html-parser.js +241 -26
- package/dist/ui-engine/image-assets.d.ts +8 -1
- package/dist/ui-engine/image-assets.js +35 -2
- package/dist/ui-engine/image-decode.d.ts +22 -0
- package/dist/ui-engine/image-decode.js +194 -0
- package/dist/ui-engine/inline-parser.js +1 -1
- package/dist/ui-engine/layout-engine.d.ts +19 -0
- package/dist/ui-engine/layout-engine.js +59 -3
- package/dist/ui-engine/model.d.ts +18 -0
- package/dist/ui-engine/model.js +76 -8
- package/dist/ui-engine/runtime-header/blend-bodies.js +29 -9
- package/dist/ui-engine/runtime-header/canvas-helpers.js +5 -2
- package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -111
- package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +21 -0
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -179
- package/dist/ui-engine/runtime-header/forward-decls.js +215 -167
- package/dist/ui-engine/runtime-header/init-press-input.js +138 -135
- package/dist/ui-engine/runtime-header/keyboard.js +682 -380
- package/dist/ui-engine/runtime-header/node-draw-body.js +1656 -1377
- package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -214
- package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -568
- package/dist/ui-engine/runtime-header/scroll-physics.js +25 -1
- package/dist/ui-engine/runtime-header/state-bindings-nav.js +9 -0
- package/dist/ui-engine/runtime-header/structs.js +228 -216
- package/dist/ui-engine/runtime-header/text-rendering.js +888 -770
- package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -116
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +897 -633
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -25
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +79 -23
- package/dist/ui-engine/runtime-header/types-defines.js +110 -93
- package/dist/ui-engine/shadcn-kit.d.ts +1 -0
- package/dist/ui-engine/shadcn-kit.js +502 -0
- package/dist/ui-engine/style-resolver.d.ts +4 -0
- package/dist/ui-engine/style-resolver.js +58 -6
- package/dist/ui-engine/transpile-ui.js +12 -5
- package/dist/ui-engine/ua-stylesheet.d.ts +22 -1
- package/dist/ui-engine/ua-stylesheet.js +119 -32
- package/dist/ui-engine/ui-lowering.js +37 -3
- package/dist/ui-engine/ui-registry.js +32 -4
- package/dist/ui-engine/yoga-layout.js +57 -52
- package/dist/wizard/config-writer.d.ts +49 -0
- package/dist/wizard/config-writer.js +366 -0
- package/dist/wizard/display-catalog.d.ts +75 -0
- package/dist/wizard/display-catalog.js +207 -0
- package/dist/wizard/index.d.ts +7 -0
- package/dist/wizard/index.js +10 -0
- package/dist/wizard/integration-wizard.d.ts +15 -0
- package/dist/wizard/integration-wizard.js +486 -0
- package/dist/wizard/prompts.d.ts +32 -0
- package/dist/wizard/prompts.js +95 -0
- package/dist/wizard/starter-ui.d.ts +1 -0
- package/dist/wizard/starter-ui.js +56 -0
- package/package.json +18 -5
- package/src/cli.ts +87 -0
- package/src/engine-index.ts +53 -51
- package/src/preview/build-program.ts +810 -734
- package/src/preview/host-gfx.ts +30 -3
- package/src/preview/host-ui-runtime.ts +4133 -3289
- package/src/ui-engine/block-layout.ts +24 -11
- package/src/ui-engine/color.ts +77 -2
- package/src/ui-engine/compat-report.ts +139 -0
- package/src/ui-engine/css-imports.ts +69 -0
- package/src/ui-engine/css-parser.ts +64 -15
- package/src/ui-engine/default-font.ts +95 -0
- package/src/ui-engine/font-assets.ts +545 -525
- package/src/ui-engine/html-parser.ts +615 -397
- package/src/ui-engine/image-assets.ts +37 -2
- package/src/ui-engine/image-decode.ts +244 -0
- package/src/ui-engine/inline-parser.ts +1 -1
- package/src/ui-engine/layout-engine.ts +61 -3
- package/src/ui-engine/model.ts +1317 -1230
- package/src/ui-engine/runtime-header/blend-bodies.ts +29 -9
- package/src/ui-engine/runtime-header/canvas-helpers.ts +5 -2
- package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -117
- package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +21 -0
- package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -185
- package/src/ui-engine/runtime-header/forward-decls.ts +227 -179
- package/src/ui-engine/runtime-header/init-press-input.ts +144 -141
- package/src/ui-engine/runtime-header/keyboard.ts +689 -386
- package/src/ui-engine/runtime-header/node-draw-body.ts +1681 -1402
- package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -220
- package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -574
- package/src/ui-engine/runtime-header/scroll-physics.ts +25 -1
- package/src/ui-engine/runtime-header/state-bindings-nav.ts +9 -0
- package/src/ui-engine/runtime-header/structs.ts +234 -222
- package/src/ui-engine/runtime-header/text-rendering.ts +894 -776
- package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -122
- package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -638
- package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -31
- package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +79 -23
- package/src/ui-engine/runtime-header/types-defines.ts +116 -99
- package/src/ui-engine/shadcn-kit.ts +503 -0
- package/src/ui-engine/style-resolver.ts +471 -416
- package/src/ui-engine/transpile-ui.ts +12 -5
- package/src/ui-engine/ua-stylesheet.ts +137 -31
- package/src/ui-engine/ui-lowering.ts +486 -452
- package/src/ui-engine/ui-registry.ts +556 -524
- package/src/ui-engine/yoga-layout.ts +307 -309
- package/src/wizard/config-writer.ts +404 -0
- package/src/wizard/display-catalog.ts +273 -0
- package/src/wizard/index.ts +38 -0
- package/src/wizard/integration-wizard.ts +619 -0
- package/src/wizard/prompts.ts +145 -0
- package/src/wizard/starter-ui.ts +58 -0
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
// Slice of the C++ runtime header (original source lines 5279-5287).
|
|
2
|
-
// scrollbar + buffered scroll canvas push.
|
|
3
|
-
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
-
export function emitTickScrollCanvasPhase(): string {
|
|
5
|
-
return `
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 5279-5287).
|
|
2
|
+
// scrollbar + buffered scroll canvas push.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTickScrollCanvasPhase(): string {
|
|
5
|
+
return `
|
|
6
|
+
// ②b Draw scrollbar + push canvas for the buffered scroll container.
|
|
7
|
+
if (bufferedScrollNode >= 0 && bufferedScrollCanvas) {
|
|
8
|
+
ui_push_buffered_scroll_canvas(bufferedScrollCanvas, bufferedScrollRepaintCanvas,
|
|
9
|
+
bufferedScrollNode, bufferedScrollVX, bufferedScrollVY,
|
|
10
|
+
bufferedScrollRepaintY, bufferedScrollRepaintH, __ui_draw_target);
|
|
11
|
+
} else if (bufferedScrollNode >= 0 && bufferedScrollBands) {
|
|
12
|
+
// Band render fallback: the main loop didn't trigger it at the owner's
|
|
13
|
+
// z-slot (e.g. the owner was filtered out after dispatch). Render now so
|
|
14
|
+
// the subtree is never left unpainted. ui_render_scroll_bands sets
|
|
15
|
+
// lastPaintedScrollY itself on success; only the failure fallback (band
|
|
16
|
+
// canvas wouldn't allocate) needs to record the scrollY here so the next
|
|
17
|
+
// frame's delta is correct.
|
|
18
|
+
if (!ui_render_scroll_bands(static_cast<uint16_t>(bufferedScrollNode))) {
|
|
19
|
+
// No band canvas means there is no coherent frame to submit. Retain the
|
|
20
|
+
// previous viewport rather than drawing the scrollbar/direct subtree to
|
|
21
|
+
// the live SPI target, which would reintroduce tearing.
|
|
22
|
+
if (__ui_scroll_render_locked) __ui_scroll_render_locked[static_cast<uint16_t>(bufferedScrollNode)] = 1;
|
|
23
|
+
__ui_nodes[bufferedScrollNode].dirty = 0;
|
|
24
|
+
}
|
|
25
|
+
} else if (bufferedScrollNode >= 0 && bufferedScrollDirectFull) {
|
|
26
|
+
// The direct-full path is intentionally disabled for tear-sensitive scroll
|
|
27
|
+
// rendering. Keep the retained pixels when no compositor is available.
|
|
28
|
+
if (__ui_scroll_render_locked) __ui_scroll_render_locked[static_cast<uint16_t>(bufferedScrollNode)] = 1;
|
|
29
|
+
__ui_nodes[bufferedScrollNode].dirty = 0;`;
|
|
30
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
4
|
export function emitTouchKeyboardFwd(): string {
|
|
5
5
|
return `
|
|
6
|
+
#include <cstdlib> // abs() for drag-distance thresholds (self-sufficient slice)
|
|
6
7
|
// ── Touch hit-testing + click dispatch ─────────────────────────────────────
|
|
7
8
|
// Radio groups for mutual exclusion
|
|
8
9
|
struct UIRadioGroup {
|
|
@@ -13,11 +14,14 @@ extern UIRadioGroup __ui_radio_groups[];
|
|
|
13
14
|
extern const uint16_t __ui_radio_group_count;
|
|
14
15
|
|
|
15
16
|
// Forward-declare the click handler type + tables (defined by the emit layer).
|
|
16
|
-
|
|
17
|
-
extern void (*
|
|
18
|
-
extern void (*
|
|
17
|
+
// The tables are const (flash rodata) — they are never written at runtime.
|
|
18
|
+
extern void (*const __ui_click_handlers[])();
|
|
19
|
+
extern void (*const __ui_hold_handlers[])();
|
|
20
|
+
extern void (*const __ui_release_handlers[])();
|
|
19
21
|
extern void (*__ui_rangechange_handlers[])();
|
|
20
22
|
extern const uint16_t __ui_click_handler_count;
|
|
23
|
+
extern const uint16_t __ui_hold_handler_count;
|
|
24
|
+
extern const uint16_t __ui_release_handler_count;
|
|
21
25
|
extern const uint16_t __ui_rangechange_handler_count;
|
|
22
26
|
|
|
23
27
|
// Touch state machine: tracks down → hold → up → click lifecycle
|
|
@@ -77,6 +81,10 @@ static inline void ui_kb_handle_touch(int16_t tx, int16_t ty);
|
|
|
77
81
|
static inline void ui_kb_handle_tap(int16_t tx, int16_t ty);
|
|
78
82
|
static inline void ui_kb_key_rect(uint8_t idx, UIRect* out);
|
|
79
83
|
static inline void ui_kb_draw();
|
|
84
|
+
|
|
85
|
+
// Modal <select> + <drawer> declarations live in forward-decls.ts
|
|
86
|
+
// (emit order: ui_navigate/visibility/ui_init reference them before this module).
|
|
87
|
+
|
|
80
88
|
static inline void ui_kb_draw_key(uint8_t i);
|
|
81
89
|
static inline void ui_kb_draw_text_row();
|
|
82
90
|
static inline void ui_kb_compute_box();
|
|
@@ -85,13 +93,22 @@ static inline void ui_kb_compute_box();
|
|
|
85
93
|
#define UI_DRAG_THRESHOLD 10
|
|
86
94
|
|
|
87
95
|
// Hit-test a touch point against all visible nodes (topmost first).
|
|
88
|
-
// Returns the node
|
|
89
|
-
//
|
|
96
|
+
// Returns the node the tap TARGETS, resolved like the DOM: the topmost node
|
|
97
|
+
// whose box contains the point, then bubbling to ANCESTORS only. Returns -1
|
|
98
|
+
// if no ancestor of the target is interactive or handler-bearing.
|
|
90
99
|
static int16_t ui_hit_test(int16_t tx, int16_t ty) {
|
|
91
|
-
|
|
100
|
+
// Phase 1 — the event target: the TOPMOST node containing the tap (last in
|
|
101
|
+
// draw order), regardless of handlers. Filtering for handler-bearing nodes
|
|
102
|
+
// here let a tap fall through SIBLING layers: a modal card (no handler,
|
|
103
|
+
// higher z) over a click-to-close scrim (handler) routed every card tap to
|
|
104
|
+
// the scrim underneath, so any tap dismissed the dialog. In the DOM the
|
|
105
|
+
// click targets the topmost element and never propagates sideways to a
|
|
106
|
+
// covered sibling.
|
|
107
|
+
int16_t target = -1;
|
|
92
108
|
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
93
109
|
if (!ui_is_effectively_visible(i)) continue;
|
|
94
110
|
if (__ui_nodes[i].screenId != __ui_active_screen) continue;
|
|
111
|
+
if (__ui_nodes[i].disabled) continue; // HTML disabled: not a tap target
|
|
95
112
|
int16_t drawX = ui_draw_x_for_node(static_cast<uint16_t>(i));
|
|
96
113
|
int16_t drawY = ui_draw_y_for_node(static_cast<uint16_t>(i));
|
|
97
114
|
if (tx >= drawX && tx < drawX + __ui_nodes[i].box.w &&
|
|
@@ -101,26 +118,29 @@ static int16_t ui_hit_test(int16_t tx, int16_t ty) {
|
|
|
101
118
|
// a tall wrapped paragraph can overflow below the fold yet still have a
|
|
102
119
|
// tappable link segment in its visible portion.
|
|
103
120
|
if (ui_is_point_clipped_by_scroll(static_cast<uint16_t>(i), tx, ty)) continue;
|
|
104
|
-
|
|
105
|
-
// Exceptions: NODE_RANGE (horizontal drag), NODE_INPUT (opens keyboard),
|
|
106
|
-
// NODE_LIST (virtualized item tap), and NODE_BUTTON — the last so a button
|
|
107
|
-
// gets :pressed/transition visual feedback even with no JS onClick wired
|
|
108
|
-
// (a pure-CSS button like a demo "tap to transition" control).
|
|
109
|
-
if (__ui_nodes[i].kind == NODE_RANGE || __ui_nodes[i].kind == NODE_INPUT || __ui_nodes[i].kind == NODE_LIST || __ui_nodes[i].kind == NODE_BUTTON || __ui_nodes[i].kind == NODE_CHECK || __ui_nodes[i].kind == NODE_RADIO) {
|
|
110
|
-
if (best < 0 || ui_node_draws_before(best, i)) best = i;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
if (i < __ui_click_handler_count &&
|
|
114
|
-
(__ui_click_handlers[i] || __ui_hold_handlers[i] || __ui_release_handlers[i])) {
|
|
115
|
-
if (best < 0 || ui_node_draws_before(best, i)) best = i;
|
|
116
|
-
}
|
|
121
|
+
if (target < 0 || ui_node_draws_before(target, i)) target = static_cast<int16_t>(i);
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
|
-
|
|
124
|
+
// Phase 2 — bubbling: walk from the target up through its ancestors.
|
|
125
|
+
// Interactive kinds match even with no JS handler wired — NODE_RANGE
|
|
126
|
+
// (horizontal drag), NODE_INPUT (opens the keyboard), NODE_LIST
|
|
127
|
+
// (virtualized item tap), and NODE_BUTTON/NODE_CHECK/NODE_RADIO so a
|
|
128
|
+
// pure-CSS control still gets :pressed/transition visual feedback.
|
|
129
|
+
int16_t n = target;
|
|
130
|
+
while (n >= 0) {
|
|
131
|
+
uint16_t u = static_cast<uint16_t>(n);
|
|
132
|
+
if (__ui_nodes[u].kind == NODE_RANGE || __ui_nodes[u].kind == NODE_INPUT || __ui_nodes[u].kind == NODE_LIST || __ui_nodes[u].kind == NODE_BUTTON || __ui_nodes[u].kind == NODE_CHECK || __ui_nodes[u].kind == NODE_RADIO) return n;
|
|
133
|
+
if ((u < __ui_click_handler_count && __ui_click_handlers[u]) ||
|
|
134
|
+
(u < __ui_hold_handler_count && __ui_hold_handlers[u]) ||
|
|
135
|
+
(u < __ui_release_handler_count && __ui_release_handlers[u])) return n;
|
|
136
|
+
if (__ui_nodes[u].parent == UI_NO_PARENT || __ui_nodes[u].parent >= __ui_node_count) break;
|
|
137
|
+
n = static_cast<int16_t>(__ui_nodes[u].parent);
|
|
138
|
+
}
|
|
139
|
+
return -1;
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
// Dispatch a handler from the given table if registered for the node.
|
|
123
|
-
static void ui_dispatch(void (
|
|
143
|
+
static void ui_dispatch(void (*const* table)(), uint16_t count, int16_t node) {
|
|
124
144
|
if (node >= 0 && static_cast<uint16_t>(node) < count && table[node]) {
|
|
125
145
|
table[node]();
|
|
126
146
|
}
|
|
@@ -150,6 +170,13 @@ static inline void ui_open_keyboard_for_input(uint16_t nodeIdx) {
|
|
|
150
170
|
|
|
151
171
|
// Touch down: called when screen is first touched.
|
|
152
172
|
static void ui_touch_down(int16_t tx, int16_t ty) {
|
|
173
|
+
// Modal <select> list: record the touch position; tap-up routes to the
|
|
174
|
+
// option rows. No hit-test/press/scroll while the overlay is open.
|
|
175
|
+
if (__ui_select_menu >= 0) {
|
|
176
|
+
__ui_touch_state = 1;
|
|
177
|
+
__ui_touch_down_time = millis();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
153
180
|
int16_t node = ui_hit_test(tx, ty);
|
|
154
181
|
__ui_touch_node = node;
|
|
155
182
|
__ui_touch_state = 1;
|
|
@@ -208,6 +235,35 @@ static void ui_touch_up() {
|
|
|
208
235
|
// Modal keyboard: route tap-up to the keyboard; swallow normal click logic.
|
|
209
236
|
// (Skipped on UI_HIDE_OSK desktop targets — touches pass through to the app,
|
|
210
237
|
// since the editing session is driven by the real keyboard, not the grid.)
|
|
238
|
+
// Open drawers close on outside taps (device parity with the preview).
|
|
239
|
+
{
|
|
240
|
+
int16_t dx0 = __ui_last_touch_x;
|
|
241
|
+
int16_t dy0 = __ui_last_touch_y;
|
|
242
|
+
for (uint8_t s = 0; s < __ui_drawer_slots; s++) {
|
|
243
|
+
if (__ui_drawer_idx[s] < 0 || !__ui_drawer_open[s] || __ui_drawer_progress[s] < 255) continue;
|
|
244
|
+
uint16_t di = static_cast<uint16_t>(__ui_drawer_idx[s]);
|
|
245
|
+
// Hit-test the SUBTREE rect: a <dialog> root with absolutely
|
|
246
|
+
// positioned children lays out at h=0 — the root box made every tap
|
|
247
|
+
// count as "outside" and closed the dialog immediately.
|
|
248
|
+
UIRect panelRect;
|
|
249
|
+
if (!ui_subtree_current_paint_rect(di, &panelRect)) {
|
|
250
|
+
panelRect.x = ui_draw_x_for_node(di);
|
|
251
|
+
panelRect.y = ui_draw_y_for_node(di);
|
|
252
|
+
panelRect.w = __ui_nodes[di].box.w;
|
|
253
|
+
panelRect.h = __ui_nodes[di].box.h;
|
|
254
|
+
}
|
|
255
|
+
if (dx0 < panelRect.x || dx0 >= panelRect.x + panelRect.w ||
|
|
256
|
+
dy0 < panelRect.y || dy0 >= panelRect.y + panelRect.h) {
|
|
257
|
+
__ui_drawer_open[s] = 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (__ui_select_menu >= 0) {
|
|
262
|
+
ui_select_menu_tap(__ui_last_touch_x, __ui_last_touch_y);
|
|
263
|
+
__ui_touch_state = 0;
|
|
264
|
+
__ui_last_touch_time = millis();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
211
267
|
#if !defined(UI_HIDE_OSK)
|
|
212
268
|
if (__ui_kb_visible) {
|
|
213
269
|
ui_kb_handle_tap(__ui_last_touch_x, __ui_last_touch_y);
|
|
@@ -241,7 +297,7 @@ static void ui_touch_up() {
|
|
|
241
297
|
if (target >= 0) ui_navigate(static_cast<uint8_t>(target));
|
|
242
298
|
}
|
|
243
299
|
}
|
|
244
|
-
ui_dispatch(__ui_release_handlers,
|
|
300
|
+
ui_dispatch(__ui_release_handlers, __ui_release_handler_count, __ui_touch_node);
|
|
245
301
|
// Built-in check/radio/select handlers mutate the node value during click
|
|
246
302
|
// dispatch and need one repaint. Buttons are already dirty from releasing
|
|
247
303
|
// :pressed; links, lists, inputs, and ordinary callbacks are either handled
|
|
@@ -389,7 +445,7 @@ static inline void ui_handle_touch(int16_t tx, int16_t ty) {
|
|
|
389
445
|
if (__ui_touch_state == 1 && __ui_touch_node >= 0 && !__ui_is_dragging) {
|
|
390
446
|
if (now - __ui_touch_down_time >= UI_TOUCH_HOLD_MS) {
|
|
391
447
|
__ui_touch_state = 2;
|
|
392
|
-
ui_dispatch(__ui_hold_handlers,
|
|
448
|
+
ui_dispatch(__ui_hold_handlers, __ui_hold_handler_count, __ui_touch_node);
|
|
393
449
|
}
|
|
394
450
|
}
|
|
395
451
|
}
|
|
@@ -1,99 +1,116 @@
|
|
|
1
|
-
// Slice of the C++ runtime header (original source lines 17-89).
|
|
2
|
-
// Guard open, includes, and #define knobs.
|
|
3
|
-
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
-
export function emitTypesDefines(): string {
|
|
5
|
-
return `
|
|
6
|
-
// ── Cuttlefish UI runtime (emit once per TU) ──────────────────────────────
|
|
7
|
-
#ifndef __TC_UI_RUNTIME
|
|
8
|
-
#define __TC_UI_RUNTIME
|
|
9
|
-
#include <stdint.h>
|
|
10
|
-
#include <cstring>
|
|
11
|
-
#include <new>
|
|
12
|
-
#define UI_TEXT_BUF 32 // max stored UI text chars, excluding the trailing NUL
|
|
13
|
-
#define UI_TEXT_LINE_BUF 96
|
|
14
|
-
#define UI_WS_NORMAL 0
|
|
15
|
-
#define UI_WS_NOWRAP 1
|
|
16
|
-
#define UI_WS_PRE 2
|
|
17
|
-
#define UI_WS_PRE_LINE 3
|
|
18
|
-
#ifndef UI_MAX_BUFFERED_PAINT_PIXELS
|
|
19
|
-
#define UI_MAX_BUFFERED_PAINT_PIXELS 20000
|
|
20
|
-
#endif
|
|
21
|
-
// Above this many pixels, prefer the band renderer (small ~10KB SRAM canvas,
|
|
22
|
-
// strip-at-a-time) over the repair canvas even when the repair canvas could
|
|
23
|
-
// allocate (e.g. in PSRAM). A large repair canvas (a full-width button is
|
|
24
|
-
// ~15-30KB) has higher alloc/seed/push latency than banding — the per-band
|
|
25
|
-
// push is smaller and the band canvas lives in fast internal SRAM. Set below
|
|
26
|
-
// UI_MAX_BUFFERED_PAINT_PIXELS so large rects band while small repaints keep
|
|
27
|
-
// the fast single-canvas composite. Tune per target; 0 = always prefer the
|
|
28
|
-
// repair canvas when it allocates (the pre-PSRAM behavior).
|
|
29
|
-
#ifndef UI_BAND_PREFER_PIXELS
|
|
30
|
-
#define UI_BAND_PREFER_PIXELS 8000
|
|
31
|
-
#endif
|
|
32
|
-
#ifndef UI_USE_FULL_FRAMEBUFFER
|
|
33
|
-
#define UI_USE_FULL_FRAMEBUFFER 0
|
|
34
|
-
#endif
|
|
35
|
-
#ifndef UI_TRANSITION_SNAP_MS
|
|
36
|
-
#define UI_TRANSITION_SNAP_MS 100
|
|
37
|
-
#endif
|
|
38
|
-
// Scroll physics + capability defaults. The per-TU #define overrides emitted
|
|
39
|
-
// by the UI emitter (from resolveScrollConfig) hit BEFORE this header, so these
|
|
40
|
-
// #ifndef guards adopt the configured values. Spec: 2026-06-28-scroll-engine-rewrite-design.md
|
|
41
|
-
#ifndef UI_SCROLL_MAX_OVERSCROLL
|
|
42
|
-
#define UI_SCROLL_MAX_OVERSCROLL 40
|
|
43
|
-
#endif
|
|
44
|
-
#ifndef UI_SCROLL_STIFFNESS_X10
|
|
45
|
-
#define UI_SCROLL_STIFFNESS_X10 5
|
|
46
|
-
#endif
|
|
47
|
-
#ifndef UI_SCROLL_EDGE_SNAP_PX
|
|
48
|
-
#define UI_SCROLL_EDGE_SNAP_PX 12
|
|
49
|
-
#endif
|
|
50
|
-
#ifndef UI_SCROLL_DRAG_SCALE_X10
|
|
51
|
-
#define UI_SCROLL_DRAG_SCALE_X10 10
|
|
52
|
-
#endif
|
|
53
|
-
#ifndef UI_SCROLL_SETTLE_MS
|
|
54
|
-
#define UI_SCROLL_SETTLE_MS 180
|
|
55
|
-
#endif
|
|
56
|
-
#ifndef UI_SCROLL_DEADBAND_PX
|
|
57
|
-
#define UI_SCROLL_DEADBAND_PX 2
|
|
58
|
-
#endif
|
|
59
|
-
// Capability tier flags (emitted per-TU before this header; defaults = full).
|
|
60
|
-
#ifndef
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
64
|
-
#define UI_SCROLL_INPUT_TIER_RESISTIVE
|
|
65
|
-
#endif
|
|
66
|
-
#ifndef
|
|
67
|
-
#define
|
|
68
|
-
#endif
|
|
69
|
-
#ifndef
|
|
70
|
-
#define
|
|
71
|
-
#endif
|
|
72
|
-
#ifndef
|
|
73
|
-
#define
|
|
74
|
-
#endif
|
|
75
|
-
#
|
|
76
|
-
#define
|
|
77
|
-
#endif
|
|
78
|
-
#
|
|
79
|
-
#define
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
#define
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 17-89).
|
|
2
|
+
// Guard open, includes, and #define knobs.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTypesDefines(): string {
|
|
5
|
+
return `
|
|
6
|
+
// ── Cuttlefish UI runtime (emit once per TU) ──────────────────────────────
|
|
7
|
+
#ifndef __TC_UI_RUNTIME
|
|
8
|
+
#define __TC_UI_RUNTIME
|
|
9
|
+
#include <stdint.h>
|
|
10
|
+
#include <cstring>
|
|
11
|
+
#include <new>
|
|
12
|
+
#define UI_TEXT_BUF 32 // max stored UI text chars, excluding the trailing NUL
|
|
13
|
+
#define UI_TEXT_LINE_BUF 96
|
|
14
|
+
#define UI_WS_NORMAL 0
|
|
15
|
+
#define UI_WS_NOWRAP 1
|
|
16
|
+
#define UI_WS_PRE 2
|
|
17
|
+
#define UI_WS_PRE_LINE 3
|
|
18
|
+
#ifndef UI_MAX_BUFFERED_PAINT_PIXELS
|
|
19
|
+
#define UI_MAX_BUFFERED_PAINT_PIXELS 20000
|
|
20
|
+
#endif
|
|
21
|
+
// Above this many pixels, prefer the band renderer (small ~10KB SRAM canvas,
|
|
22
|
+
// strip-at-a-time) over the repair canvas even when the repair canvas could
|
|
23
|
+
// allocate (e.g. in PSRAM). A large repair canvas (a full-width button is
|
|
24
|
+
// ~15-30KB) has higher alloc/seed/push latency than banding — the per-band
|
|
25
|
+
// push is smaller and the band canvas lives in fast internal SRAM. Set below
|
|
26
|
+
// UI_MAX_BUFFERED_PAINT_PIXELS so large rects band while small repaints keep
|
|
27
|
+
// the fast single-canvas composite. Tune per target; 0 = always prefer the
|
|
28
|
+
// repair canvas when it allocates (the pre-PSRAM behavior).
|
|
29
|
+
#ifndef UI_BAND_PREFER_PIXELS
|
|
30
|
+
#define UI_BAND_PREFER_PIXELS 8000
|
|
31
|
+
#endif
|
|
32
|
+
#ifndef UI_USE_FULL_FRAMEBUFFER
|
|
33
|
+
#define UI_USE_FULL_FRAMEBUFFER 0
|
|
34
|
+
#endif
|
|
35
|
+
#ifndef UI_TRANSITION_SNAP_MS
|
|
36
|
+
#define UI_TRANSITION_SNAP_MS 100
|
|
37
|
+
#endif
|
|
38
|
+
// Scroll physics + capability defaults. The per-TU #define overrides emitted
|
|
39
|
+
// by the UI emitter (from resolveScrollConfig) hit BEFORE this header, so these
|
|
40
|
+
// #ifndef guards adopt the configured values. Spec: 2026-06-28-scroll-engine-rewrite-design.md
|
|
41
|
+
#ifndef UI_SCROLL_MAX_OVERSCROLL
|
|
42
|
+
#define UI_SCROLL_MAX_OVERSCROLL 40
|
|
43
|
+
#endif
|
|
44
|
+
#ifndef UI_SCROLL_STIFFNESS_X10
|
|
45
|
+
#define UI_SCROLL_STIFFNESS_X10 5
|
|
46
|
+
#endif
|
|
47
|
+
#ifndef UI_SCROLL_EDGE_SNAP_PX
|
|
48
|
+
#define UI_SCROLL_EDGE_SNAP_PX 12
|
|
49
|
+
#endif
|
|
50
|
+
#ifndef UI_SCROLL_DRAG_SCALE_X10
|
|
51
|
+
#define UI_SCROLL_DRAG_SCALE_X10 10
|
|
52
|
+
#endif
|
|
53
|
+
#ifndef UI_SCROLL_SETTLE_MS
|
|
54
|
+
#define UI_SCROLL_SETTLE_MS 180
|
|
55
|
+
#endif
|
|
56
|
+
#ifndef UI_SCROLL_DEADBAND_PX
|
|
57
|
+
#define UI_SCROLL_DEADBAND_PX 2
|
|
58
|
+
#endif
|
|
59
|
+
// Capability tier flags (emitted per-TU before this header; defaults = full).
|
|
60
|
+
// The default-on check must run BEFORE the per-flag #ifndef defaults below —
|
|
61
|
+
// after them, all three flags are defined 0 and the fallback would redefine
|
|
62
|
+
// UI_SCROLL_INPUT_TIER_RESISTIVE with a different value (ill-formed).
|
|
63
|
+
#if !defined(UI_SCROLL_INPUT_TIER_CAPACITIVE) && !defined(UI_SCROLL_INPUT_TIER_RESISTIVE) && !defined(UI_SCROLL_INPUT_TIER_NONE)
|
|
64
|
+
#define UI_SCROLL_INPUT_TIER_RESISTIVE 1
|
|
65
|
+
#endif
|
|
66
|
+
#ifndef UI_SCROLL_INPUT_TIER_CAPACITIVE
|
|
67
|
+
#define UI_SCROLL_INPUT_TIER_CAPACITIVE 0
|
|
68
|
+
#endif
|
|
69
|
+
#ifndef UI_SCROLL_INPUT_TIER_RESISTIVE
|
|
70
|
+
#define UI_SCROLL_INPUT_TIER_RESISTIVE 0
|
|
71
|
+
#endif
|
|
72
|
+
#ifndef UI_SCROLL_INPUT_TIER_NONE
|
|
73
|
+
#define UI_SCROLL_INPUT_TIER_NONE 0
|
|
74
|
+
#endif
|
|
75
|
+
#ifndef UI_SCROLL_RENDER_TIER_FULL
|
|
76
|
+
#define UI_SCROLL_RENDER_TIER_FULL 1
|
|
77
|
+
#endif
|
|
78
|
+
#ifndef UI_SCROLL_RENDER_TIER_CONSTRAINED
|
|
79
|
+
#define UI_SCROLL_RENDER_TIER_CONSTRAINED 0
|
|
80
|
+
#endif
|
|
81
|
+
#define UI_SCROLL_HAS_TOUCH (UI_SCROLL_INPUT_TIER_CAPACITIVE || UI_SCROLL_INPUT_TIER_RESISTIVE)
|
|
82
|
+
#define UI_SCROLL_ELASTIC (UI_SCROLL_RENDER_TIER_FULL)
|
|
83
|
+
// Telemetry: emits per-frame scrollY/overscrollPx/dy over Serial when defined.
|
|
84
|
+
#ifndef UI_SCROLL_DEBUG
|
|
85
|
+
#define UI_SCROLL_DEBUG 0
|
|
86
|
+
#endif
|
|
87
|
+
// Band renderer: height (px) of the horizontal band canvas used to composite
|
|
88
|
+
// scroll subtrees tear-free when no viewport canvas fits (no PSRAM / over
|
|
89
|
+
// budget). Each band is vw × UI_STRIP_BAND_HEIGHT. Must be tall enough that a
|
|
90
|
+
// single line of AA text (glyph height ~lineHeight, typically 16-22px at ts=2)
|
|
91
|
+
// fits within one band — if a glyph straddles a band boundary, its anti-
|
|
92
|
+
// aliased edge pixels blend toward the wrong bg in the adjacent band, visible
|
|
93
|
+
// as a clipped/faded text bottom. 32 ensures most fonts fit; at 480px wide
|
|
94
|
+
// that's ~30KB (fits SRAM on most ESP32 targets).
|
|
95
|
+
// Dirty-rect merging (LVGL refresh-cycle technique): several same-frame
|
|
96
|
+
// dirty nodes whose paint rects are near each other composite as one banded
|
|
97
|
+
// region instead of per-node transactions. Regions cap at the band-
|
|
98
|
+
// compositable pixel budget; singleton rects keep the per-node ladder.
|
|
99
|
+
#ifndef UI_MERGE_INFLATE
|
|
100
|
+
#define UI_MERGE_INFLATE 8
|
|
101
|
+
#endif
|
|
102
|
+
#ifndef UI_MERGE_MAX_REGIONS
|
|
103
|
+
#define UI_MERGE_MAX_REGIONS 6
|
|
104
|
+
#endif
|
|
105
|
+
#ifndef UI_MERGE_MAX_NODES
|
|
106
|
+
#define UI_MERGE_MAX_NODES 12
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
#ifndef UI_STRIP_BAND_HEIGHT
|
|
110
|
+
#define UI_STRIP_BAND_HEIGHT 32
|
|
111
|
+
#endif
|
|
112
|
+
#if defined(ESP32) || defined(ESP8266)
|
|
113
|
+
#include <Esp.h>
|
|
114
|
+
#endif
|
|
115
|
+
`;
|
|
116
|
+
}
|