@typecad/ui 0.1.0-alpha.2 → 1.0.0-alpha.10
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 +7 -1
- package/dist/engine-index.js +2 -2
- package/dist/preview/host-ui-runtime.d.ts +1 -0
- package/dist/preview/host-ui-runtime.js +56 -11
- package/dist/ui-engine/font-assets.d.ts +8 -0
- package/dist/ui-engine/font-assets.js +13 -0
- package/dist/ui-engine/layout-engine.js +19 -6
- package/dist/ui-engine/model.d.ts +1 -1
- package/dist/ui-engine/model.js +10 -4
- package/dist/ui-engine/runtime-header/antialiasing.js +52 -32
- package/dist/ui-engine/runtime-header/blend-bodies.js +4 -4
- package/dist/ui-engine/runtime-header/canvas-helpers.js +42 -69
- package/dist/ui-engine/runtime-header/canvas-scrollbar.js +22 -10
- package/dist/ui-engine/runtime-header/color-mono-refresh.js +10 -10
- package/dist/ui-engine/runtime-header/cuttlefish-gfx.d.ts +1 -0
- package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +563 -0
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +26 -10
- package/dist/ui-engine/runtime-header/display-shim.js +8 -8
- package/dist/ui-engine/runtime-header/forward-decls.js +52 -10
- package/dist/ui-engine/runtime-header/image-drawing.js +154 -84
- package/dist/ui-engine/runtime-header/init-press-input.js +20 -5
- package/dist/ui-engine/runtime-header/keyboard.js +62 -18
- package/dist/ui-engine/runtime-header/node-decoration.js +8 -9
- package/dist/ui-engine/runtime-header/node-draw-body.d.ts +1 -0
- package/dist/ui-engine/runtime-header/node-draw-body.js +1402 -0
- package/dist/ui-engine/runtime-header/paint-order-coords.js +48 -18
- package/dist/ui-engine/runtime-header/paint-rects-repair.js +38 -17
- package/dist/ui-engine/runtime-header/scroll-physics.js +15 -18
- package/dist/ui-engine/runtime-header/state-bindings-nav.js +23 -13
- package/dist/ui-engine/runtime-header/structs.js +12 -10
- package/dist/ui-engine/runtime-header/text-rendering.js +132 -71
- package/dist/ui-engine/runtime-header/tick/bindings-phase.js +29 -10
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +336 -749
- package/dist/ui-engine/runtime-header/tick/flush-phase.js +7 -3
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +19 -3
- package/dist/ui-engine/runtime-header/tick/transitions-phase.js +31 -24
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +46 -41
- package/dist/ui-engine/runtime-header/types-defines.js +23 -3
- package/dist/ui-engine/runtime-header.d.ts +10 -1
- package/dist/ui-engine/runtime-header.js +7 -1
- package/dist/ui-engine/transpile-ui.js +2 -2
- package/dist/ui-engine/ua-stylesheet.js +46 -3
- package/dist/ui-engine/ui-lowering.d.ts +1 -3
- package/dist/ui-engine/ui-lowering.js +18 -24
- package/dist/ui-engine/ui-registry.js +1 -6
- package/package.json +2 -2
- package/src/engine-index.ts +2 -2
- package/src/preview/host-ui-runtime.ts +56 -12
- package/src/ui-engine/font-assets.ts +13 -0
- package/src/ui-engine/layout-engine.ts +19 -6
- package/src/ui-engine/model.ts +10 -5
- package/src/ui-engine/runtime-header/antialiasing.ts +52 -32
- package/src/ui-engine/runtime-header/blend-bodies.ts +4 -4
- package/src/ui-engine/runtime-header/canvas-helpers.ts +42 -69
- package/src/ui-engine/runtime-header/canvas-scrollbar.ts +22 -10
- package/src/ui-engine/runtime-header/color-mono-refresh.ts +10 -10
- package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +566 -0
- package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +26 -10
- package/src/ui-engine/runtime-header/display-shim.ts +8 -8
- package/src/ui-engine/runtime-header/forward-decls.ts +52 -10
- package/src/ui-engine/runtime-header/image-drawing.ts +154 -84
- package/src/ui-engine/runtime-header/init-press-input.ts +20 -5
- package/src/ui-engine/runtime-header/keyboard.ts +62 -18
- package/src/ui-engine/runtime-header/node-decoration.ts +8 -9
- package/src/ui-engine/runtime-header/node-draw-body.ts +1402 -0
- package/src/ui-engine/runtime-header/paint-order-coords.ts +48 -18
- package/src/ui-engine/runtime-header/paint-rects-repair.ts +38 -17
- package/src/ui-engine/runtime-header/scroll-physics.ts +15 -18
- package/src/ui-engine/runtime-header/state-bindings-nav.ts +23 -13
- package/src/ui-engine/runtime-header/structs.ts +12 -10
- package/src/ui-engine/runtime-header/text-rendering.ts +132 -71
- package/src/ui-engine/runtime-header/tick/bindings-phase.ts +29 -10
- package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +336 -749
- package/src/ui-engine/runtime-header/tick/flush-phase.ts +7 -3
- package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +19 -3
- package/src/ui-engine/runtime-header/tick/transitions-phase.ts +31 -24
- package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +46 -41
- package/src/ui-engine/runtime-header/types-defines.ts +23 -3
- package/src/ui-engine/runtime-header.ts +17 -1
- package/src/ui-engine/transpile-ui.ts +2 -2
- package/src/ui-engine/ua-stylesheet.ts +46 -3
- package/src/ui-engine/ui-lowering.ts +19 -26
- package/src/ui-engine/ui-registry.ts +1 -7
- package/dist/ui-engine/scroll-memory-diagnostics.d.ts +0 -16
- package/dist/ui-engine/scroll-memory-diagnostics.js +0 -58
- package/src/ui-engine/scroll-memory-diagnostics.ts +0 -79
|
@@ -5,9 +5,13 @@ export function emitTickFlushPhase() {
|
|
|
5
5
|
return `
|
|
6
6
|
}
|
|
7
7
|
// ── Framebuffer bulk push ────────────────────────────────────────────────
|
|
8
|
-
// When a framebuffer was used this frame,
|
|
9
|
-
//
|
|
10
|
-
|
|
8
|
+
// When a framebuffer was used this frame, publish only its changed bounds.
|
|
9
|
+
// Local touch updates therefore avoid a full-screen SPI burst (which appears
|
|
10
|
+
// as a brightness dip on panels without a synchronized frame latch).
|
|
11
|
+
// Repairs performed before the dirty-node pass (for example transform
|
|
12
|
+
// geometry cleanup) may update the retained buffer without leaving a node
|
|
13
|
+
// dirty. The dirty-bounds accumulator is the authoritative publish signal.
|
|
14
|
+
if (__ui_fb && (__ui_fb_frame_dirty || __ui_fb_dirty)) {
|
|
11
15
|
ui_push_framebuffer();
|
|
12
16
|
}
|
|
13
17
|
ui_display_use_default_target();
|
|
@@ -9,7 +9,23 @@ export function emitTickScrollCanvasPhase() {
|
|
|
9
9
|
ui_push_buffered_scroll_canvas(bufferedScrollCanvas, bufferedScrollRepaintCanvas,
|
|
10
10
|
bufferedScrollNode, bufferedScrollVX, bufferedScrollVY,
|
|
11
11
|
bufferedScrollRepaintY, bufferedScrollRepaintH, __ui_draw_target);
|
|
12
|
-
} else if (bufferedScrollNode >= 0 &&
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
} else if (bufferedScrollNode >= 0 && bufferedScrollBands) {
|
|
13
|
+
// Band render fallback: the main loop didn't trigger it at the owner's
|
|
14
|
+
// z-slot (e.g. the owner was filtered out after dispatch). Render now so
|
|
15
|
+
// the subtree is never left unpainted. ui_render_scroll_bands sets
|
|
16
|
+
// lastPaintedScrollY itself on success; only the failure fallback (band
|
|
17
|
+
// canvas wouldn't allocate) needs to record the scrollY here so the next
|
|
18
|
+
// frame's delta is correct.
|
|
19
|
+
if (!ui_render_scroll_bands(static_cast<uint16_t>(bufferedScrollNode))) {
|
|
20
|
+
// No band canvas means there is no coherent frame to submit. Retain the
|
|
21
|
+
// previous viewport rather than drawing the scrollbar/direct subtree to
|
|
22
|
+
// the live SPI target, which would reintroduce tearing.
|
|
23
|
+
if (__ui_scroll_render_locked) __ui_scroll_render_locked[static_cast<uint16_t>(bufferedScrollNode)] = 1;
|
|
24
|
+
__ui_nodes[bufferedScrollNode].dirty = 0;
|
|
25
|
+
}
|
|
26
|
+
} else if (bufferedScrollNode >= 0 && bufferedScrollDirectFull) {
|
|
27
|
+
// The direct-full path is intentionally disabled for tear-sensitive scroll
|
|
28
|
+
// rendering. Keep the retained pixels when no compositor is available.
|
|
29
|
+
if (__ui_scroll_render_locked) __ui_scroll_render_locked[static_cast<uint16_t>(bufferedScrollNode)] = 1;
|
|
30
|
+
__ui_nodes[bufferedScrollNode].dirty = 0;`;
|
|
15
31
|
}
|
|
@@ -10,9 +10,10 @@ export function emitTickTransitionsPhase() {
|
|
|
10
10
|
__ui_trans[i].elapsed += deltaMs;
|
|
11
11
|
uint16_t k = __ui_trans[i].durationMs == 0
|
|
12
12
|
? 100
|
|
13
|
-
:
|
|
13
|
+
: static_cast<uint16_t>(static_cast<uint32_t>(__ui_trans[i].elapsed > __ui_trans[i].durationMs
|
|
14
|
+
? __ui_trans[i].durationMs : __ui_trans[i].elapsed) * 100 / __ui_trans[i].durationMs);
|
|
14
15
|
if (__ui_trans[i].durationMs > 0 && __ui_trans[i].durationMs <= UI_TRANSITION_SNAP_MS) k = 100;
|
|
15
|
-
uint32_t v = UI_LERP_COLOR(__ui_trans[i].prevValue, __ui_trans[i].targetValue, (
|
|
16
|
+
uint32_t v = UI_LERP_COLOR(__ui_trans[i].prevValue, __ui_trans[i].targetValue, static_cast<uint8_t>(k));
|
|
16
17
|
if (__ui_trans[i].prop == PROP_FG) {
|
|
17
18
|
__ui_nodes[__ui_trans[i].node].fg = v;
|
|
18
19
|
} else {
|
|
@@ -44,14 +45,20 @@ export function emitTickTransitionsPhase() {
|
|
|
44
45
|
ui_keyframe_set_has_scroll_sensitive_geometry(__ui_anims[i].keyframeSet)) {
|
|
45
46
|
continue;
|
|
46
47
|
}
|
|
47
|
-
__ui_anims[i].elapsed += (
|
|
48
|
+
__ui_anims[i].elapsed += static_cast<uint32_t>(deltaMs);
|
|
48
49
|
uint32_t elapsedNoDelay = __ui_anims[i].elapsed;
|
|
49
50
|
if (elapsedNoDelay < __ui_anims[i].delayMs) continue;
|
|
50
51
|
elapsedNoDelay -= __ui_anims[i].delayMs;
|
|
51
52
|
// Check iteration limit (finite).
|
|
52
53
|
uint8_t completing = 0;
|
|
53
54
|
if (__ui_anims[i].iterations > 0) {
|
|
54
|
-
|
|
55
|
+
// Saturate the multiplication so a long duration × iteration count
|
|
56
|
+
// cannot wrap and complete immediately after ~49 days of uptime.
|
|
57
|
+
uint32_t totalDuration = static_cast<uint32_t>(__ui_anims[i].iterations) * static_cast<uint32_t>(__ui_anims[i].durationMs);
|
|
58
|
+
if (__ui_anims[i].durationMs != 0 &&
|
|
59
|
+
static_cast<uint32_t>(__ui_anims[i].iterations) > 0xFFFFFFFFUL / static_cast<uint32_t>(__ui_anims[i].durationMs)) {
|
|
60
|
+
totalDuration = 0xFFFFFFFFUL;
|
|
61
|
+
}
|
|
55
62
|
if (elapsedNoDelay >= totalDuration) {
|
|
56
63
|
elapsedNoDelay = totalDuration;
|
|
57
64
|
completing = 1;
|
|
@@ -61,7 +68,7 @@ export function emitTickTransitionsPhase() {
|
|
|
61
68
|
uint8_t pct = 100;
|
|
62
69
|
if (!completing && __ui_anims[i].durationMs > 0) {
|
|
63
70
|
uint32_t cycleMs = elapsedNoDelay % __ui_anims[i].durationMs;
|
|
64
|
-
pct =
|
|
71
|
+
pct = static_cast<uint8_t>(static_cast<uint32_t>(cycleMs) * 100 / __ui_anims[i].durationMs);
|
|
65
72
|
}
|
|
66
73
|
// Find surrounding keyframe stops.
|
|
67
74
|
if (__ui_anims[i].keyframeSet >= __ui_keyframe_set_count) continue;
|
|
@@ -77,7 +84,7 @@ export function emitTickTransitionsPhase() {
|
|
|
77
84
|
const UIKeyframeStop* sHi = &ks->stops[hi];
|
|
78
85
|
// Lerp factor between lo and hi.
|
|
79
86
|
uint8_t range = sHi->percent - sLo->percent;
|
|
80
|
-
uint8_t lerpK = range > 0 ?
|
|
87
|
+
uint8_t lerpK = range > 0 ? static_cast<uint8_t>(static_cast<uint16_t>(pct - sLo->percent) * 100 / range) : 0;
|
|
81
88
|
// Shape the lerp by the animation's timing function (ease-in-out, etc.).
|
|
82
89
|
// CSS attaches it to the animation and applies it between stops.
|
|
83
90
|
lerpK = ui_ease_lerp_k(__ui_anims[i].timingFunction, lerpK);
|
|
@@ -95,7 +102,7 @@ export function emitTickTransitionsPhase() {
|
|
|
95
102
|
}
|
|
96
103
|
if ((sLo->props & UI_KF_OPACITY) && (sHi->props & UI_KF_OPACITY)) {
|
|
97
104
|
uint8_t newOp = range > 0
|
|
98
|
-
?
|
|
105
|
+
? static_cast<uint8_t>(static_cast<int16_t>(sLo->opacity) + (static_cast<int16_t>(sHi->opacity) - static_cast<int16_t>(sLo->opacity)) * lerpK / 100)
|
|
99
106
|
: sLo->opacity;
|
|
100
107
|
if (newOp != __ui_nodes[n].opacity) { __ui_nodes[n].opacity = newOp; changed = 1; }
|
|
101
108
|
}
|
|
@@ -108,10 +115,10 @@ export function emitTickTransitionsPhase() {
|
|
|
108
115
|
uint8_t hasSizeFrame = (sLo->props & UI_KF_SIZE) && (sHi->props & UI_KF_SIZE);
|
|
109
116
|
if (hasSizeFrame) {
|
|
110
117
|
nextWidth = range > 0
|
|
111
|
-
?
|
|
118
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->width) + (static_cast<int32_t>(sHi->width) - static_cast<int32_t>(sLo->width)) * lerpK / 100)
|
|
112
119
|
: sLo->width;
|
|
113
120
|
nextHeight = range > 0
|
|
114
|
-
?
|
|
121
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->height) + (static_cast<int32_t>(sHi->height) - static_cast<int32_t>(sLo->height)) * lerpK / 100)
|
|
115
122
|
: sLo->height;
|
|
116
123
|
if (nextWidth < 0) nextWidth = 0;
|
|
117
124
|
if (nextHeight < 0) nextHeight = 0;
|
|
@@ -122,25 +129,25 @@ export function emitTickTransitionsPhase() {
|
|
|
122
129
|
}
|
|
123
130
|
if ((sLo->props & UI_KF_TRANSFORM) && (sHi->props & UI_KF_TRANSFORM)) {
|
|
124
131
|
int16_t pxX = range > 0
|
|
125
|
-
?
|
|
132
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->transformOffsetX) + (static_cast<int32_t>(sHi->transformOffsetX) - static_cast<int32_t>(sLo->transformOffsetX)) * lerpK / 100)
|
|
126
133
|
: sLo->transformOffsetX;
|
|
127
134
|
int16_t pxY = range > 0
|
|
128
|
-
?
|
|
135
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->transformOffsetY) + (static_cast<int32_t>(sHi->transformOffsetY) - static_cast<int32_t>(sLo->transformOffsetY)) * lerpK / 100)
|
|
129
136
|
: sLo->transformOffsetY;
|
|
130
137
|
int16_t pctX = range > 0
|
|
131
|
-
?
|
|
138
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->translatePctX) + (static_cast<int32_t>(sHi->translatePctX) - static_cast<int32_t>(sLo->translatePctX)) * lerpK / 100)
|
|
132
139
|
: sLo->translatePctX;
|
|
133
140
|
int16_t pctY = range > 0
|
|
134
|
-
?
|
|
141
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->translatePctY) + (static_cast<int32_t>(sHi->translatePctY) - static_cast<int32_t>(sLo->translatePctY)) * lerpK / 100)
|
|
135
142
|
: sLo->translatePctY;
|
|
136
143
|
int16_t scaleX = range > 0
|
|
137
|
-
?
|
|
144
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->scaleX) + (static_cast<int32_t>(sHi->scaleX) - static_cast<int32_t>(sLo->scaleX)) * lerpK / 100)
|
|
138
145
|
: sLo->scaleX;
|
|
139
146
|
int16_t scaleY = range > 0
|
|
140
|
-
?
|
|
147
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->scaleY) + (static_cast<int32_t>(sHi->scaleY) - static_cast<int32_t>(sLo->scaleY)) * lerpK / 100)
|
|
141
148
|
: sLo->scaleY;
|
|
142
149
|
nextRotateDeg = range > 0
|
|
143
|
-
?
|
|
150
|
+
? static_cast<int16_t>(static_cast<int32_t>(sLo->rotateDeg) + (static_cast<int32_t>(sHi->rotateDeg) - static_cast<int32_t>(sLo->rotateDeg)) * lerpK / 100)
|
|
144
151
|
: sLo->rotateDeg;
|
|
145
152
|
if (scaleX < 0) scaleX = 0;
|
|
146
153
|
if (scaleY < 0) scaleY = 0;
|
|
@@ -148,14 +155,14 @@ export function emitTickTransitionsPhase() {
|
|
|
148
155
|
int16_t refH = hasSizeFrame ? nextHeight : __ui_anims[i].baseHeight;
|
|
149
156
|
if (refW <= 0) refW = __ui_nodes[n].box.w;
|
|
150
157
|
if (refH <= 0) refH = __ui_nodes[n].box.h;
|
|
151
|
-
int16_t originPxX =
|
|
152
|
-
int16_t originPxY =
|
|
153
|
-
int16_t scaledW =
|
|
154
|
-
int16_t scaledH =
|
|
155
|
-
int16_t scaleOffsetX = originPxX -
|
|
156
|
-
int16_t scaleOffsetY = originPxY -
|
|
157
|
-
nextTransformX = pxX +
|
|
158
|
-
nextTransformY = pxY +
|
|
158
|
+
int16_t originPxX = static_cast<int16_t>(static_cast<int32_t>(refW) * __ui_anims[i].originX / 100);
|
|
159
|
+
int16_t originPxY = static_cast<int16_t>(static_cast<int32_t>(refH) * __ui_anims[i].originY / 100);
|
|
160
|
+
int16_t scaledW = static_cast<int16_t>(static_cast<int32_t>(refW) * scaleX / 100);
|
|
161
|
+
int16_t scaledH = static_cast<int16_t>(static_cast<int32_t>(refH) * scaleY / 100);
|
|
162
|
+
int16_t scaleOffsetX = originPxX - static_cast<int16_t>(static_cast<int32_t>(originPxX) * scaleX / 100);
|
|
163
|
+
int16_t scaleOffsetY = originPxY - static_cast<int16_t>(static_cast<int32_t>(originPxY) * scaleY / 100);
|
|
164
|
+
nextTransformX = pxX + static_cast<int16_t>(static_cast<int32_t>(refW) * pctX / 100) + scaleOffsetX;
|
|
165
|
+
nextTransformY = pxY + static_cast<int16_t>(static_cast<int32_t>(refH) * pctY / 100) + scaleOffsetY;
|
|
159
166
|
nextWidth = scaledW < 0 ? 0 : scaledW;
|
|
160
167
|
nextHeight = scaledH < 0 ? 0 : scaledH;
|
|
161
168
|
if (nextTransformX != __ui_nodes[n].transformOffsetX ||
|
|
@@ -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;
|
|
@@ -91,15 +92,15 @@ static int16_t ui_hit_test(int16_t tx, int16_t ty) {
|
|
|
91
92
|
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
92
93
|
if (!ui_is_effectively_visible(i)) continue;
|
|
93
94
|
if (__ui_nodes[i].screenId != __ui_active_screen) continue;
|
|
94
|
-
int16_t drawX = ui_draw_x_for_node((
|
|
95
|
-
int16_t drawY = ui_draw_y_for_node((
|
|
95
|
+
int16_t drawX = ui_draw_x_for_node(static_cast<uint16_t>(i));
|
|
96
|
+
int16_t drawY = ui_draw_y_for_node(static_cast<uint16_t>(i));
|
|
96
97
|
if (tx >= drawX && tx < drawX + __ui_nodes[i].box.w &&
|
|
97
98
|
ty >= drawY && ty < drawY + __ui_nodes[i].box.h) {
|
|
98
99
|
// The node's box contains the tap. For nodes inside a scroll container,
|
|
99
100
|
// the tap point (not the whole box) must lie within the visible viewport:
|
|
100
101
|
// a tall wrapped paragraph can overflow below the fold yet still have a
|
|
101
102
|
// tappable link segment in its visible portion.
|
|
102
|
-
if (ui_is_point_clipped_by_scroll((
|
|
103
|
+
if (ui_is_point_clipped_by_scroll(static_cast<uint16_t>(i), tx, ty)) continue;
|
|
103
104
|
// Skip nodes without any click handler — they're containers, not targets.
|
|
104
105
|
// Exceptions: NODE_RANGE (horizontal drag), NODE_INPUT (opens keyboard),
|
|
105
106
|
// NODE_LIST (virtualized item tap), and NODE_BUTTON — the last so a button
|
|
@@ -120,7 +121,7 @@ static int16_t ui_hit_test(int16_t tx, int16_t ty) {
|
|
|
120
121
|
|
|
121
122
|
// Dispatch a handler from the given table if registered for the node.
|
|
122
123
|
static void ui_dispatch(void (**table)(), uint16_t count, int16_t node) {
|
|
123
|
-
if (node >= 0 && (
|
|
124
|
+
if (node >= 0 && static_cast<uint16_t>(node) < count && table[node]) {
|
|
124
125
|
table[node]();
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -164,28 +165,13 @@ static void ui_touch_down(int16_t tx, int16_t ty) {
|
|
|
164
165
|
// One owner per gesture; the double-delta bug class (node in both a container
|
|
165
166
|
// and a list) is gone because there's no second mechanism.
|
|
166
167
|
#if UI_SCROLL_HAS_TOUCH
|
|
167
|
-
|
|
168
|
-
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
169
|
-
if (!__ui_nodes[i].scrollable || !ui_is_effectively_visible(i)) continue;
|
|
170
|
-
if (__ui_nodes[i].screenId != __ui_active_screen) continue;
|
|
171
|
-
// Only scrollable if content overflows the viewport.
|
|
172
|
-
if (__ui_nodes[i].contentHeight <= __ui_nodes[i].box.h) continue;
|
|
173
|
-
int16_t drawX = ui_draw_x_for_node((uint16_t)i);
|
|
174
|
-
int16_t drawY = ui_draw_y_for_node((uint16_t)i);
|
|
175
|
-
if (tx >= drawX && tx < drawX + __ui_nodes[i].box.w &&
|
|
176
|
-
ty >= drawY && ty < drawY + __ui_nodes[i].box.h) {
|
|
177
|
-
if (bestScroll < 0 || ui_node_draws_before(bestScroll, i)) bestScroll = i;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
__ui_scroll_node = bestScroll;
|
|
168
|
+
__ui_scroll_node = ui_scroll_node_at(tx, ty);
|
|
181
169
|
#else
|
|
182
170
|
(void)tx; (void)ty;
|
|
183
171
|
#endif
|
|
184
172
|
if (node >= 0) {
|
|
185
|
-
uint8_t handledTouchTarget = 0;
|
|
186
173
|
if (__ui_nodes[node].kind == NODE_BUTTON) {
|
|
187
|
-
ui_set_pressed((
|
|
188
|
-
handledTouchTarget = 1;
|
|
174
|
+
ui_set_pressed(static_cast<uint16_t>(node), 1);
|
|
189
175
|
}
|
|
190
176
|
// Track range nodes for horizontal drag
|
|
191
177
|
if (__ui_nodes[node].kind == NODE_RANGE) {
|
|
@@ -198,20 +184,22 @@ static void ui_touch_down(int16_t tx, int16_t ty) {
|
|
|
198
184
|
int16_t rMax = __ui_nodes[node].rangeMax;
|
|
199
185
|
int16_t range = rMax - rMin;
|
|
200
186
|
if (range <= 0) range = 100;
|
|
201
|
-
int16_t relX = tx - ui_draw_x_for_node((
|
|
187
|
+
int16_t relX = tx - ui_draw_x_for_node(static_cast<uint16_t>(node)) - 4;
|
|
202
188
|
int16_t usable = __ui_nodes[node].box.w - 8;
|
|
203
189
|
if (usable <= 0) usable = 1;
|
|
204
|
-
int16_t nextVal = rMin + ((
|
|
190
|
+
int16_t nextVal = rMin + (static_cast<int32_t>(relX) * range) / usable;
|
|
205
191
|
nextVal = constrain(nextVal, rMin, rMax);
|
|
206
192
|
if (nextVal != __ui_nodes[node].value) {
|
|
207
193
|
__ui_nodes[node].value = nextVal;
|
|
208
194
|
ui_mark_dirty(node);
|
|
209
195
|
}
|
|
210
|
-
handledTouchTarget = 1;
|
|
211
196
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
197
|
+
// Only controls with a visual state change need a dirty repaint on touch-down:
|
|
198
|
+
// buttons were marked by ui_set_pressed() above and ranges were marked when
|
|
199
|
+
// their value changed. Links, inputs, checks, radios, selects, and list
|
|
200
|
+
// containers do not have a pressed state; repainting them here is redundant
|
|
201
|
+
// and can expose a clear/redraw flash on direct SPI targets. They repaint
|
|
202
|
+
// after the click/value change (or when scrolling actually begins).
|
|
215
203
|
}
|
|
216
204
|
}
|
|
217
205
|
|
|
@@ -240,21 +228,29 @@ static void ui_touch_up() {
|
|
|
240
228
|
int16_t clickedNode = __ui_touch_node;
|
|
241
229
|
if (elapsed < UI_TOUCH_HOLD_MS) {
|
|
242
230
|
if (__ui_nodes[clickedNode].kind == NODE_INPUT) {
|
|
243
|
-
ui_open_keyboard_for_input((
|
|
231
|
+
ui_open_keyboard_for_input(static_cast<uint16_t>(clickedNode));
|
|
244
232
|
}
|
|
245
233
|
ui_dispatch(__ui_click_handlers, __ui_click_handler_count, __ui_touch_node);
|
|
246
234
|
// Rich-text inline link: if the tapped node has link runs, find which link
|
|
247
235
|
// segment the tap falls within and navigate to its target screen. Copies
|
|
248
236
|
// the list-item subdivision precedent with measured run rects.
|
|
249
237
|
if (__ui_nodes[clickedNode].runCount > 0) {
|
|
250
|
-
int16_t ndx = __ui_last_touch_x - ui_draw_x_for_node((
|
|
251
|
-
int16_t ndy = __ui_last_touch_y - ui_draw_y_for_node((
|
|
252
|
-
int8_t target = ui_rich_link_hit((
|
|
253
|
-
if (target >= 0) ui_navigate((
|
|
238
|
+
int16_t ndx = __ui_last_touch_x - ui_draw_x_for_node(static_cast<uint16_t>(clickedNode));
|
|
239
|
+
int16_t ndy = __ui_last_touch_y - ui_draw_y_for_node(static_cast<uint16_t>(clickedNode));
|
|
240
|
+
int8_t target = ui_rich_link_hit(static_cast<uint16_t>(clickedNode), ndx, ndy);
|
|
241
|
+
if (target >= 0) ui_navigate(static_cast<uint8_t>(target));
|
|
254
242
|
}
|
|
255
243
|
}
|
|
256
244
|
ui_dispatch(__ui_release_handlers, __ui_click_handler_count, __ui_touch_node);
|
|
257
|
-
|
|
245
|
+
// Built-in check/radio/select handlers mutate the node value during click
|
|
246
|
+
// dispatch and need one repaint. Buttons are already dirty from releasing
|
|
247
|
+
// :pressed; links, lists, inputs, and ordinary callbacks are either handled
|
|
248
|
+
// by navigation/keyboard state or observed by bindings on the next tick.
|
|
249
|
+
if (__ui_nodes[clickedNode].kind == NODE_CHECK ||
|
|
250
|
+
__ui_nodes[clickedNode].kind == NODE_RADIO ||
|
|
251
|
+
__ui_nodes[clickedNode].kind == NODE_SELECT) {
|
|
252
|
+
ui_mark_dirty(static_cast<uint16_t>(clickedNode));
|
|
253
|
+
}
|
|
258
254
|
}
|
|
259
255
|
// Release the pressed button's :pressed state unconditionally — even when a
|
|
260
256
|
// drag/scroll hijacked the gesture (the click above is correctly gated on
|
|
@@ -262,13 +258,15 @@ static void ui_touch_up() {
|
|
|
262
258
|
// otherwise a touch-down on a button followed by a scroll leaves it stuck).
|
|
263
259
|
if (__ui_touch_node >= 0 && __ui_touch_node < __ui_node_count &&
|
|
264
260
|
__ui_nodes[__ui_touch_node].kind == NODE_BUTTON && __ui_nodes[__ui_touch_node].value != 0) {
|
|
265
|
-
ui_set_pressed((
|
|
261
|
+
ui_set_pressed(static_cast<uint16_t>(__ui_touch_node), 0);
|
|
266
262
|
}
|
|
267
263
|
// Resume any \`await ui.onTap()\` awaiter. Runs for EVERY completed tap —
|
|
268
264
|
// including holds (released above) and taps on empty space (__ui_touch_node
|
|
269
265
|
// == -1), which is what makes "wake on any touch" work for display-sleep.
|
|
270
266
|
// Placed AFTER the click/release dispatch so onClick always fires first.
|
|
271
|
-
|
|
267
|
+
// Note: explicit '+ 1' instead of '++' — GCC 13+ (IDF v6) deprecates '++'
|
|
268
|
+
// on volatile-qualified types under -Werror=volatile.
|
|
269
|
+
__ui_tap_seq = __ui_tap_seq + 1;
|
|
272
270
|
__ui_tap_node = __ui_touch_node;
|
|
273
271
|
// Virtualized list item tap: if the touch was inside a list, compute the item
|
|
274
272
|
// index from the touch Y. Use total movement (not drag flag) to distinguish
|
|
@@ -280,9 +278,9 @@ static void ui_touch_up() {
|
|
|
280
278
|
int16_t relY = __ui_last_touch_y - drawY;
|
|
281
279
|
int16_t totalMove = abs(__ui_last_touch_y - __ui_touch_down_y_pos);
|
|
282
280
|
uint16_t ih = __ui_nodes[n].listItemHeight > 0 ? __ui_nodes[n].listItemHeight : 24;
|
|
283
|
-
if (totalMove <
|
|
281
|
+
if (totalMove < static_cast<int16_t>(ih / 2) &&
|
|
284
282
|
relY >= 0 && relY < __ui_nodes[n].box.h) {
|
|
285
|
-
uint16_t itemIdx =
|
|
283
|
+
uint16_t itemIdx = static_cast<uint16_t>((relY + __ui_nodes[n].scrollY) / ih);
|
|
286
284
|
if (itemIdx < __ui_nodes[n].listCount) {
|
|
287
285
|
__ui_nodes[n].listTapFn(itemIdx);
|
|
288
286
|
}
|
|
@@ -346,16 +344,16 @@ static inline void ui_handle_touch(int16_t tx, int16_t ty) {
|
|
|
346
344
|
int16_t rMax = __ui_nodes[__ui_range_node].rangeMax;
|
|
347
345
|
int16_t range = rMax - rMin;
|
|
348
346
|
if (range <= 0) range = 100;
|
|
349
|
-
int16_t relX = tx - ui_draw_x_for_node((
|
|
347
|
+
int16_t relX = tx - ui_draw_x_for_node(static_cast<uint16_t>(__ui_range_node)) - 4;
|
|
350
348
|
int16_t usable = __ui_nodes[__ui_range_node].box.w - 8;
|
|
351
349
|
if (usable <= 0) usable = 1;
|
|
352
|
-
int16_t newVal = rMin + ((
|
|
350
|
+
int16_t newVal = rMin + (static_cast<int32_t>(relX) * range) / usable;
|
|
353
351
|
newVal = constrain(newVal, rMin, rMax);
|
|
354
352
|
if (newVal != __ui_nodes[__ui_range_node].value) {
|
|
355
353
|
__ui_nodes[__ui_range_node].value = newVal;
|
|
356
354
|
ui_mark_dirty(__ui_range_node);
|
|
357
355
|
// Fire the onChange callback (if any) — every value change during drag.
|
|
358
|
-
if (__ui_range_node < (
|
|
356
|
+
if (__ui_range_node < static_cast<int16_t>(__ui_rangechange_handler_count) &&
|
|
359
357
|
__ui_rangechange_handlers[__ui_range_node]) {
|
|
360
358
|
__ui_rangechange_handlers[__ui_range_node]();
|
|
361
359
|
}
|
|
@@ -373,10 +371,17 @@ static inline void ui_handle_touch(int16_t tx, int16_t ty) {
|
|
|
373
371
|
ui_apply_scroll_delta(__ui_scroll_node, dy);
|
|
374
372
|
__ui_drag_start_y = ty;
|
|
375
373
|
#if UI_SCROLL_DEBUG
|
|
374
|
+
#if defined(ESP32) && defined(ARDUINO)
|
|
376
375
|
Serial.printf("scroll dy=%d sy=%d ov=%d virt=%d\\n",
|
|
377
376
|
dy, __ui_nodes[__ui_scroll_node].scrollY,
|
|
378
377
|
__ui_nodes[__ui_scroll_node].overscrollPx,
|
|
379
|
-
(
|
|
378
|
+
static_cast<int>(__ui_nodes[__ui_scroll_node].virtualized));
|
|
379
|
+
#else
|
|
380
|
+
printk("scroll dy=%d sy=%d ov=%d virt=%d\\n",
|
|
381
|
+
dy, __ui_nodes[__ui_scroll_node].scrollY,
|
|
382
|
+
__ui_nodes[__ui_scroll_node].overscrollPx,
|
|
383
|
+
static_cast<int>(__ui_nodes[__ui_scroll_node].virtualized));
|
|
384
|
+
#endif
|
|
380
385
|
#endif
|
|
381
386
|
}
|
|
382
387
|
}
|
|
@@ -7,7 +7,8 @@ export function emitTypesDefines() {
|
|
|
7
7
|
#ifndef __TC_UI_RUNTIME
|
|
8
8
|
#define __TC_UI_RUNTIME
|
|
9
9
|
#include <stdint.h>
|
|
10
|
-
#include <
|
|
10
|
+
#include <cstring>
|
|
11
|
+
#include <new>
|
|
11
12
|
#define UI_TEXT_BUF 32 // max stored UI text chars, excluding the trailing NUL
|
|
12
13
|
#define UI_TEXT_LINE_BUF 96
|
|
13
14
|
#define UI_WS_NORMAL 0
|
|
@@ -17,6 +18,17 @@ export function emitTypesDefines() {
|
|
|
17
18
|
#ifndef UI_MAX_BUFFERED_PAINT_PIXELS
|
|
18
19
|
#define UI_MAX_BUFFERED_PAINT_PIXELS 20000
|
|
19
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
|
|
20
32
|
#ifndef UI_USE_FULL_FRAMEBUFFER
|
|
21
33
|
#define UI_USE_FULL_FRAMEBUFFER 0
|
|
22
34
|
#endif
|
|
@@ -69,8 +81,16 @@ export function emitTypesDefines() {
|
|
|
69
81
|
#ifndef UI_SCROLL_DEBUG
|
|
70
82
|
#define UI_SCROLL_DEBUG 0
|
|
71
83
|
#endif
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
// Band renderer: height (px) of the horizontal band canvas used to composite
|
|
85
|
+
// scroll subtrees tear-free when no viewport canvas fits (no PSRAM / over
|
|
86
|
+
// budget). Each band is vw × UI_STRIP_BAND_HEIGHT. Must be tall enough that a
|
|
87
|
+
// single line of AA text (glyph height ~lineHeight, typically 16-22px at ts=2)
|
|
88
|
+
// fits within one band — if a glyph straddles a band boundary, its anti-
|
|
89
|
+
// aliased edge pixels blend toward the wrong bg in the adjacent band, visible
|
|
90
|
+
// as a clipped/faded text bottom. 32 ensures most fonts fit; at 480px wide
|
|
91
|
+
// that's ~30KB (fits SRAM on most ESP32 targets).
|
|
92
|
+
#ifndef UI_STRIP_BAND_HEIGHT
|
|
93
|
+
#define UI_STRIP_BAND_HEIGHT 32
|
|
74
94
|
#endif
|
|
75
95
|
#if defined(ESP32) || defined(ESP8266)
|
|
76
96
|
#include <Esp.h>
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface EmitRuntimeHeaderOptions {
|
|
2
|
+
/**
|
|
3
|
+
* True when a native display adapter (AVR, ESP32) is in use. Kept for
|
|
4
|
+
* backwards compatibility — the CuttlefishGFX slice is now emitted
|
|
5
|
+
* separately via emitCuttlefishGfx() so it can land BEFORE display adapter
|
|
6
|
+
* declarations that instantiate CuttlefishGFX by value.
|
|
7
|
+
*/
|
|
8
|
+
nativeDisplayActive?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function emitRuntimeHeader(opts?: EmitRuntimeHeaderOptions): string;
|
|
@@ -35,12 +35,17 @@ import { emitTouchKeyboardFwd } from "./runtime-header/touch-keyboard-fwd.js";
|
|
|
35
35
|
import { emitBlendBodies } from "./runtime-header/blend-bodies.js";
|
|
36
36
|
import { emitTextRendering } from "./runtime-header/text-rendering.js";
|
|
37
37
|
import { emitNodeDecoration } from "./runtime-header/node-decoration.js";
|
|
38
|
+
import { emitNodeDrawBody } from "./runtime-header/node-draw-body.js";
|
|
38
39
|
import { emitTickMotionHelpers } from "./runtime-header/tick-motion-helpers.js";
|
|
39
40
|
import { emitTick } from "./runtime-header/tick.js";
|
|
40
41
|
import { emitAntialiasing } from "./runtime-header/antialiasing.js";
|
|
41
42
|
import { emitKeyboard } from "./runtime-header/keyboard.js";
|
|
42
43
|
import { emitGuardClose } from "./runtime-header/guard-close.js";
|
|
43
|
-
export function emitRuntimeHeader() {
|
|
44
|
+
export function emitRuntimeHeader(opts) {
|
|
45
|
+
// Note: the CuttlefishGFX slice (emitCuttlefishGfx) is emitted separately
|
|
46
|
+
// by ui-emitter.ts BEFORE the display adapter declaration. It is NOT
|
|
47
|
+
// emitted here — passing nativeDisplayActive has no effect.
|
|
48
|
+
void opts;
|
|
44
49
|
return [
|
|
45
50
|
emitTypesDefines(),
|
|
46
51
|
emitStructs(),
|
|
@@ -60,6 +65,7 @@ export function emitRuntimeHeader() {
|
|
|
60
65
|
emitBlendBodies(),
|
|
61
66
|
emitTextRendering(),
|
|
62
67
|
emitNodeDecoration(),
|
|
68
|
+
emitNodeDrawBody(),
|
|
63
69
|
emitTickMotionHelpers(),
|
|
64
70
|
emitTick(),
|
|
65
71
|
emitAntialiasing(),
|
|
@@ -13,7 +13,7 @@ import { parseHtml } from "./html-parser.js";
|
|
|
13
13
|
import { parseCss, parseFontFaces, parseKeyframes } from "./css-parser.js";
|
|
14
14
|
import { resolveStyles } from "./style-resolver.js";
|
|
15
15
|
import { selectEngine } from "./select-engine.js";
|
|
16
|
-
import {
|
|
16
|
+
import { measureWithFonts } from "./layout-engine.js";
|
|
17
17
|
import { lowerUIToCpp } from "./ui-lowering.js";
|
|
18
18
|
import { buildUIFontAssets } from "./font-assets.js";
|
|
19
19
|
import { buildKeyframeSets } from "./keyframes.js";
|
|
@@ -27,7 +27,7 @@ export function transpileUI(html, css, opts) {
|
|
|
27
27
|
// Select layout engine: Yoga for flexbox, BlockLayout as fallback.
|
|
28
28
|
const engine = selectEngine(styled);
|
|
29
29
|
const viewport = { x: 0, y: 0, w: opts.viewport.width, h: opts.viewport.height };
|
|
30
|
-
const boxes = engine.arrange(styled, viewport,
|
|
30
|
+
const boxes = engine.arrange(styled, viewport, measureWithFonts(fontAssets));
|
|
31
31
|
const keyframeSets = buildKeyframeSets(rawKeyframes, opts.colorFormat);
|
|
32
32
|
return lowerUIToCpp(styled, boxes, opts.colorFormat, opts.storage, [], rules, undefined, fontAssets, [], new Map(), keyframeSets);
|
|
33
33
|
}
|
|
@@ -6,9 +6,15 @@
|
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
import { parseCss } from "./css-parser.js";
|
|
8
8
|
const UA_CSS = `
|
|
9
|
+
/* Browser-like light defaults: dark text on a near-white background.
|
|
10
|
+
A dark theme overrides these via user CSS (e.g. screen { color: #f0f0f0;
|
|
11
|
+
background: #1a1a1a }). Without these, screen fg defaults to white
|
|
12
|
+
(0xFFFF at the model level), making text invisible on light backgrounds. */
|
|
9
13
|
screen {
|
|
10
14
|
display: flex;
|
|
11
15
|
flex-direction: column;
|
|
16
|
+
color: #1a1a1a;
|
|
17
|
+
background: #ffffff;
|
|
12
18
|
}
|
|
13
19
|
body {
|
|
14
20
|
display: flex;
|
|
@@ -20,14 +26,41 @@ view {
|
|
|
20
26
|
display: flex;
|
|
21
27
|
flex-direction: column;
|
|
22
28
|
}
|
|
29
|
+
/* Scrollable content area — the standard pattern for multi-screen apps.
|
|
30
|
+
align-items:center + gap give readable card-style layouts out of the box. */
|
|
31
|
+
.scrollBody {
|
|
32
|
+
overflow: scroll;
|
|
33
|
+
flex: 1;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 10px;
|
|
36
|
+
}
|
|
37
|
+
/* Header bar (back link + title). flex-direction:row is the expected layout;
|
|
38
|
+
without it the back link and title stack vertically. */
|
|
39
|
+
.screenHeader {
|
|
40
|
+
flex-direction: row;
|
|
41
|
+
align-items: center;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
}
|
|
23
44
|
button {
|
|
24
|
-
padding:
|
|
45
|
+
padding: 10px 16px;
|
|
25
46
|
border: 1px solid;
|
|
47
|
+
min-height: 48px;
|
|
26
48
|
text-align: center;
|
|
27
49
|
}
|
|
28
50
|
input {
|
|
29
|
-
padding:
|
|
51
|
+
padding: 8px;
|
|
52
|
+
border: 1px solid;
|
|
53
|
+
}
|
|
54
|
+
select {
|
|
55
|
+
padding: 10px 12px;
|
|
30
56
|
border: 1px solid;
|
|
57
|
+
min-height: 48px;
|
|
58
|
+
}
|
|
59
|
+
check, radio {
|
|
60
|
+
min-height: 48px;
|
|
61
|
+
}
|
|
62
|
+
range {
|
|
63
|
+
height: 40px;
|
|
31
64
|
}
|
|
32
65
|
list {
|
|
33
66
|
overflow: scroll;
|
|
@@ -39,13 +72,23 @@ a {
|
|
|
39
72
|
label {
|
|
40
73
|
text-align: left;
|
|
41
74
|
}
|
|
75
|
+
/* h3 is non-bold by default: the runtime bumps textSize for bold text
|
|
76
|
+
(roughly doubling per-char advance), which wraps multi-word captions
|
|
77
|
+
like "width / height / min / max" to 3 lines. Normal weight keeps
|
|
78
|
+
them readable. Users can override with font-weight:bold if needed. */
|
|
42
79
|
h1 { font-size: 24px; font-weight: bold; }
|
|
43
80
|
h2 { font-size: 20px; font-weight: bold; }
|
|
44
|
-
h3 { font-size: 18px; font-weight:
|
|
81
|
+
h3 { font-size: 18px; font-weight: normal; }
|
|
45
82
|
h4 { font-size: 16px; font-weight: bold; }
|
|
46
83
|
h5 { font-size: 14px; }
|
|
47
84
|
h6 { font-size: 12px; }
|
|
48
85
|
p { font-size: 16px; }
|
|
86
|
+
/* Keyboard structural defaults (the OSK is runtime-generated, not
|
|
87
|
+
user-authored HTML). Border keeps keys visually separated. Colors
|
|
88
|
+
are design choices left to user CSS. */
|
|
89
|
+
.ui-key {
|
|
90
|
+
border: 1px solid;
|
|
91
|
+
}
|
|
49
92
|
`;
|
|
50
93
|
let UA_RULES = null;
|
|
51
94
|
/** Get the parsed UA default rules. Lazily computed, cached. */
|
|
@@ -21,13 +21,11 @@ export interface LoweredUI {
|
|
|
21
21
|
imageTables: string;
|
|
22
22
|
/** C++ keyframe data arrays + animation table. */
|
|
23
23
|
keyframeTables: string;
|
|
24
|
-
/** Compile-time warnings for scroll viewports that exceed the canvas budget. */
|
|
25
|
-
scrollMemoryDiagnostics: Diagnostic[];
|
|
26
24
|
/** Layout-time diagnostics (viewport overflow, text overflow). Populated by
|
|
27
25
|
* lowerOnMount after the boxes are computed; empty until then. */
|
|
28
26
|
diagnostics: Diagnostic[];
|
|
29
27
|
}
|
|
30
28
|
type ColorFormat = "rgb565" | "rgb666" | "rgb888" | "mono";
|
|
31
29
|
type Storage = "progmem" | "flash";
|
|
32
|
-
export declare function lowerUIToCpp(root: StyledNode, boxes: Box[], colorFormat: ColorFormat, storage: Storage, keyboards?: KeyboardTemplate[], rules?: CSSRule[], display?: DisplayProfile, fontAssets?: UIFontAssetModel[], allScreens?: StyledNode[], imageAssetIds?: Map<string, number>, keyframeSets?: KeyframeSetModel[]
|
|
30
|
+
export declare function lowerUIToCpp(root: StyledNode, boxes: Box[], colorFormat: ColorFormat, storage: Storage, keyboards?: KeyboardTemplate[], rules?: CSSRule[], display?: DisplayProfile, fontAssets?: UIFontAssetModel[], allScreens?: StyledNode[], imageAssetIds?: Map<string, number>, keyframeSets?: KeyframeSetModel[]): LoweredUI;
|
|
33
31
|
export {};
|