@typecad/ui 1.0.0-alpha.13 → 1.0.0-alpha.15
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 +1457 -1469
- package/dist/cli.js +22 -19
- package/dist/preview/host-ui-runtime.js +0 -1
- package/dist/ui-engine/model.js +7 -1
- package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -115
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -182
- package/dist/ui-engine/runtime-header/forward-decls.js +227 -216
- package/dist/ui-engine/runtime-header/init-press-input.js +138 -138
- package/dist/ui-engine/runtime-header/keyboard.js +676 -676
- package/dist/ui-engine/runtime-header/node-draw-body.js +1658 -1656
- package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -259
- package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -736
- package/dist/ui-engine/runtime-header/scroll-physics.js +4 -4
- package/dist/ui-engine/runtime-header/structs.js +228 -228
- package/dist/ui-engine/runtime-header/text-rendering.js +888 -888
- package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -118
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +896 -896
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -24
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +11 -11
- package/dist/ui-engine/runtime-header/types-defines.js +110 -110
- package/dist/ui-engine/shadcn-kit.d.ts +1 -1
- package/dist/ui-engine/shadcn-kit.js +4 -0
- package/dist/ui-engine/ui-lowering.d.ts +1 -1
- package/dist/ui-engine/ui-lowering.js +14 -5
- package/dist/ui-engine/ui-registry.js +9 -1
- package/dist/wizard/display-catalog.d.ts +0 -3
- package/dist/wizard/display-catalog.js +3 -12
- package/dist/wizard/index.d.ts +2 -0
- package/dist/wizard/index.js +1 -0
- package/dist/wizard/integration-wizard.d.ts +3 -0
- package/dist/wizard/integration-wizard.js +69 -20
- package/dist/wizard/package-writer.d.ts +20 -0
- package/dist/wizard/package-writer.js +79 -0
- package/package.json +4 -4
- package/src/cli.ts +90 -87
- package/src/preview/host-ui-runtime.ts +0 -1
- package/src/ui-engine/model.ts +6 -1
- package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -121
- package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -188
- package/src/ui-engine/runtime-header/forward-decls.ts +238 -227
- package/src/ui-engine/runtime-header/init-press-input.ts +144 -144
- package/src/ui-engine/runtime-header/keyboard.ts +689 -689
- package/src/ui-engine/runtime-header/node-draw-body.ts +1683 -1681
- package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -265
- package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -742
- package/src/ui-engine/runtime-header/scroll-physics.ts +4 -4
- package/src/ui-engine/runtime-header/structs.ts +234 -234
- package/src/ui-engine/runtime-header/text-rendering.ts +894 -894
- package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -124
- package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -902
- package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -30
- package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +11 -11
- package/src/ui-engine/runtime-header/types-defines.ts +116 -116
- package/src/ui-engine/shadcn-kit.ts +4 -0
- package/src/ui-engine/ui-lowering.ts +12 -4
- package/src/ui-engine/ui-registry.ts +9 -1
- package/src/wizard/display-catalog.ts +261 -273
- package/src/wizard/index.ts +46 -38
- package/src/wizard/integration-wizard.ts +679 -619
- package/src/wizard/package-writer.ts +98 -0
|
@@ -116,7 +116,7 @@ static inline uint8_t ui_scroll_release(int16_t node) {
|
|
|
116
116
|
__ui_nodes[node].settling = 1;
|
|
117
117
|
__ui_settle_from_overscroll = __ui_nodes[node].overscrollPx;
|
|
118
118
|
__ui_settle_from_scrollY = 0;
|
|
119
|
-
__ui_settle_start_ms =
|
|
119
|
+
__ui_settle_start_ms = __tc_now_ms();
|
|
120
120
|
changed = 1;
|
|
121
121
|
} else {
|
|
122
122
|
int16_t sy = __ui_nodes[node].scrollY;
|
|
@@ -126,13 +126,13 @@ static inline uint8_t ui_scroll_release(int16_t node) {
|
|
|
126
126
|
__ui_nodes[node].settling = 1;
|
|
127
127
|
__ui_settle_from_scrollY = sy; // positive → snap toward 0
|
|
128
128
|
__ui_settle_from_overscroll = 0;
|
|
129
|
-
__ui_settle_start_ms =
|
|
129
|
+
__ui_settle_start_ms = __tc_now_ms();
|
|
130
130
|
changed = 1;
|
|
131
131
|
} else if (maxS > 0 && sy < maxS && sy >= maxS - snap) {
|
|
132
132
|
__ui_nodes[node].settling = 1;
|
|
133
133
|
__ui_settle_from_scrollY = sy - maxS; // negative → snap toward max
|
|
134
134
|
__ui_settle_from_overscroll = 0;
|
|
135
|
-
__ui_settle_start_ms =
|
|
135
|
+
__ui_settle_start_ms = __tc_now_ms();
|
|
136
136
|
changed = 1;
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -151,7 +151,7 @@ static inline void ui_scroll_advance_settle(uint16_t node, uint16_t deltaMs) {
|
|
|
151
151
|
__ui_nodes[node].settling = 0;
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
|
-
uint32_t elapsed =
|
|
154
|
+
uint32_t elapsed = __tc_now_ms() - __ui_settle_start_ms;
|
|
155
155
|
uint16_t dur = static_cast<uint16_t>(UI_SCROLL_SETTLE_MS);
|
|
156
156
|
// ease-out: k = 1 - (1 - t)^2, t in [0,1]
|
|
157
157
|
uint32_t t = elapsed >= dur ? 100 : (elapsed * 100) / dur;
|
|
@@ -1,234 +1,234 @@
|
|
|
1
|
-
// Slice of the C++ runtime header (original source lines 90-303).
|
|
2
|
-
// Enums (UINodeKind, UIProperty) and all struct definitions + extern table decls.
|
|
3
|
-
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
-
export function emitStructs(): string {
|
|
5
|
-
return `
|
|
6
|
-
enum UINodeKind { NODE_FILL, NODE_TEXT, NODE_BUTTON, NODE_CHECK, NODE_RADIO, NODE_PROGRESS, NODE_RANGE, NODE_INPUT, NODE_IMG, NODE_LIST, NODE_CANVAS, NODE_SELECT };
|
|
7
|
-
enum UIProperty { PROP_BG, PROP_FG, PROP_TEXT, PROP_VISIBLE, PROP_BORDER_COLOR, PROP_VALUE };
|
|
8
|
-
|
|
9
|
-
struct UIRect { int16_t x, y, w, h; };
|
|
10
|
-
struct UIFontGlyph {
|
|
11
|
-
uint16_t codepoint;
|
|
12
|
-
int8_t xOffset;
|
|
13
|
-
int8_t yOffset;
|
|
14
|
-
uint8_t width;
|
|
15
|
-
uint8_t height;
|
|
16
|
-
uint8_t advance;
|
|
17
|
-
uint16_t dataOffset; // 4-bit alpha pixel offset
|
|
18
|
-
};
|
|
19
|
-
struct UIFontFace {
|
|
20
|
-
uint8_t id;
|
|
21
|
-
uint8_t glyphCount;
|
|
22
|
-
uint8_t lineHeight;
|
|
23
|
-
uint8_t baseline;
|
|
24
|
-
const UIFontGlyph* glyphs;
|
|
25
|
-
const uint8_t* alpha;
|
|
26
|
-
};
|
|
27
|
-
struct UINode {
|
|
28
|
-
UIRect box;
|
|
29
|
-
uint32_t bg;
|
|
30
|
-
uint32_t fg;
|
|
31
|
-
UINodeKind kind;
|
|
32
|
-
const char* text;
|
|
33
|
-
char textBuffer[UI_TEXT_BUF + 1]; // dynamic text — read only when hasTextBinding == 1
|
|
34
|
-
uint8_t hasTextBinding; // set by ui_init when a PROP_TEXT binding targets this node
|
|
35
|
-
const uint8_t* font;
|
|
36
|
-
uint8_t hasBg;
|
|
37
|
-
uint8_t textAlign; // 0=left, 1=center, 2=right
|
|
38
|
-
uint8_t textSize; // GFX text size: 1-4
|
|
39
|
-
uint8_t lineHeight; // px per text line (0 = font default)
|
|
40
|
-
int8_t letterSpacing; // px between chars (0 = default advance)
|
|
41
|
-
uint8_t fontAntialias; // 1 = smooth text edges when UI_AA is available
|
|
42
|
-
uint8_t fontFace; // 0 = classic GFX bitmap font; otherwise UIFontFace id
|
|
43
|
-
uint32_t borderColor; // resolved color for the border (0 = use fg)
|
|
44
|
-
uint8_t borderStyle; // 0=none, 1=solid, 2=dashed
|
|
45
|
-
uint8_t borderWidth; // px, 0=none (uniform fallback)
|
|
46
|
-
uint8_t borderTopWidth; // per-side; equals borderWidth when uniform
|
|
47
|
-
uint8_t borderRightWidth;
|
|
48
|
-
uint8_t borderBottomWidth;
|
|
49
|
-
uint8_t borderLeftWidth;
|
|
50
|
-
uint8_t hasPerSideBorder; // 1 when any per-side width differs from borderWidth
|
|
51
|
-
uint8_t borderRadius; // px, 0=square
|
|
52
|
-
uint8_t paddingTop;
|
|
53
|
-
uint8_t paddingRight;
|
|
54
|
-
uint8_t paddingBottom;
|
|
55
|
-
uint8_t paddingLeft;
|
|
56
|
-
uint8_t gradientEnabled; // 0=none, 1=vertical, 2=horizontal
|
|
57
|
-
uint32_t gradientColor1;
|
|
58
|
-
uint32_t gradientColor2;
|
|
59
|
-
uint32_t outlineColor;
|
|
60
|
-
uint8_t outlineStyle; // 0=none, 1=solid, 2=dashed
|
|
61
|
-
uint8_t outlineWidth;
|
|
62
|
-
int16_t zIndex; // effective draw layer; higher layers draw later
|
|
63
|
-
int16_t transformOffsetX; // draw-only transform: translate(...)
|
|
64
|
-
int16_t transformOffsetY;
|
|
65
|
-
int16_t rotateDeg;
|
|
66
|
-
int8_t pressedOffsetX; // draw-only :pressed offset, no Yoga relayout
|
|
67
|
-
int8_t pressedOffsetY;
|
|
68
|
-
uint8_t shadowCount; // 0-4 active shadows
|
|
69
|
-
int8_t shadowOffsetX[4];
|
|
70
|
-
int8_t shadowOffsetY[4];
|
|
71
|
-
uint8_t shadowBlur[4];
|
|
72
|
-
uint32_t shadowColor[4];
|
|
73
|
-
uint8_t shadowAlpha[4];
|
|
74
|
-
uint8_t shadowInset[4]; // 0=outset, 1=inset
|
|
75
|
-
uint8_t textShadowCount;
|
|
76
|
-
int8_t textShadowOffsetX;
|
|
77
|
-
int8_t textShadowOffsetY;
|
|
78
|
-
uint8_t textShadowBlur;
|
|
79
|
-
uint32_t textShadowColor;
|
|
80
|
-
uint8_t textShadowAlpha;
|
|
81
|
-
uint8_t underline; // text-decoration: 0=none,1=underline,2=line-through,3=both
|
|
82
|
-
uint8_t textOverflow; // text-overflow: 0=clip, 1=ellipsis (truncate + ...)
|
|
83
|
-
uint8_t nowrap; // 1 = no text wrapping (white-space: nowrap/pre)
|
|
84
|
-
uint8_t whiteSpaceMode; // 0=normal, 1=nowrap, 2=pre, 3=pre-line
|
|
85
|
-
uint8_t visible; // 0=hidden, 1=visible
|
|
86
|
-
uint8_t opacity; // 0-100
|
|
87
|
-
uint32_t clearColor; // ancestor's background — used to wipe transparent text before redraw
|
|
88
|
-
int16_t lastTextWidth;
|
|
89
|
-
int16_t lastTextHeight;
|
|
90
|
-
uint32_t layoutCacheKey; // 0 = invalid; non-zero hashes layout inputs
|
|
91
|
-
uint16_t layoutMetricsW; // cached ui_text_layout_metrics width
|
|
92
|
-
uint16_t layoutMetricsH; // cached ui_text_layout_metrics height
|
|
93
|
-
// scroll (unified: containers and virtualized lists share these)
|
|
94
|
-
uint8_t scrollable; // 1 = children offset by scrollY, clipped to this box
|
|
95
|
-
uint8_t virtualized; // 1 = children produced by list*Fn callbacks (<list>)
|
|
96
|
-
int16_t scrollY; // committed offset (always in [0, maxScroll]); draw subtracts it
|
|
97
|
-
int16_t contentHeight; // total child height (clamp bound + scrollbar ratio)
|
|
98
|
-
int16_t overscrollPx; // elastic excursion past a boundary (0 in-bounds; +top, -bottom)
|
|
99
|
-
uint8_t settling; // 1 while a bounce-back/snap animation runs
|
|
100
|
-
int16_t lastPaintedScrollY; // scrollY at last container repaint (Mode B shift delta)
|
|
101
|
-
uint16_t listCount; // virtualized: current item count (refreshed each frame)
|
|
102
|
-
uint16_t (*listCountFn)(void);
|
|
103
|
-
void (*listItemFn)(uint16_t idx, char* buf, uint8_t size);
|
|
104
|
-
void (*listTapFn)(uint16_t idx); // nullptr if no tap handler
|
|
105
|
-
uint16_t parent; // 0xFFFF = root/no parent (UI_NO_PARENT)
|
|
106
|
-
uint16_t subtreeEnd; // exclusive pre-order end index
|
|
107
|
-
uint8_t screenId; // which <screen> this node belongs to (for navigation)
|
|
108
|
-
uint8_t imgDataId; // index into __ui_images[] (255 = no image)
|
|
109
|
-
uint8_t objectFit; // 0=none, 1=fill, 2=contain, 3=cover, 4=scale-down
|
|
110
|
-
uint16_t listItemHeight; // px per item for <list> (0 = not a list)
|
|
111
|
-
int16_t rangeMin; // for <range>: minimum value
|
|
112
|
-
int16_t rangeMax; // for <range>: maximum value
|
|
113
|
-
int16_t maxlen; // for <input>: max character length (0 = UI_TEXT_BUF)
|
|
114
|
-
uint16_t canvasW; // canvas buffer width (for <canvas>)
|
|
115
|
-
uint16_t canvasH; // canvas buffer height (for <canvas>)
|
|
116
|
-
// Rich-text runs (runCount > 0 for text nodes with mixed inline content).
|
|
117
|
-
// The node references a contiguous slice of the global run / segment / line
|
|
118
|
-
// arrays; geometry is precomputed at transpile time (runs are static-only).
|
|
119
|
-
uint8_t runCount; // number of runs in this node (0 = plain single-string text)
|
|
120
|
-
uint8_t richLineCount; // number of wrapped lines
|
|
121
|
-
uint16_t runStart; // first index into __ui_runs[]
|
|
122
|
-
uint16_t richSegStart; // first index into __ui_rich_segs[]
|
|
123
|
-
uint16_t richSegCount; // total segments across all lines
|
|
124
|
-
uint16_t richLineStart; // first index into __ui_rich_lines[]
|
|
125
|
-
// runtime slot
|
|
126
|
-
uint8_t dirty;
|
|
127
|
-
int16_t value; // unified element
|
|
128
|
-
uint8_t disabled; // HTML disabled attr: no taps/keyboard, dimmed draw state
|
|
129
|
-
uint8_t optionCount; // <select>: number of options
|
|
130
|
-
void (*optionTextFn)(uint8_t idx, char* buf, uint8_t size); // option text by index
|
|
131
|
-
int8_t drawerSide; // <drawer>/<toast>: 0=bottom 1=top 2=left 3=right; 4=<dialog> center; -1 = none
|
|
132
|
-
uint16_t toastDuration; // <toast duration>: ms before auto-close (0 = manual)
|
|
133
|
-
uint32_t checkedBg; // :checked background (RGB565) — switch track / checkbox face / radio dot / select selected row
|
|
134
|
-
uint32_t checkedFg; // :checked color (RGB565) — knob / checkmark / selected-row text
|
|
135
|
-
uint8_t hasCheckedBg; // 1 when checkedBg was authored (0 = swap not wired)
|
|
136
|
-
uint8_t hasCheckedFg; // 1 when checkedFg was authored
|
|
137
|
-
int8_t flowAxis; // visibility reflow: 0 none, 1 column, 2 row (ui_reflow_visibility)
|
|
138
|
-
uint8_t flowGap; // visibility reflow: main-axis gap between in-flow children
|
|
139
|
-
uint8_t flowFlags; // bit0 auto height, bit1 auto width, bit2 out-of-flow
|
|
140
|
-
};
|
|
141
|
-
// Rich-text run: one piece of styled inline text within a node's run list.
|
|
142
|
-
struct UIRichRun {
|
|
143
|
-
const char* text;
|
|
144
|
-
uint32_t fg;
|
|
145
|
-
uint8_t textSize;
|
|
146
|
-
uint8_t fontFace;
|
|
147
|
-
uint8_t underline; // 0=none,1=underline,2=line-through,3=both
|
|
148
|
-
int8_t letterSpacing;
|
|
149
|
-
int8_t linkTarget; // resolved screen index, -1 = not a link
|
|
150
|
-
};
|
|
151
|
-
// One laid-out segment of a run on one line (precomputed geometry).
|
|
152
|
-
struct UIRichSeg {
|
|
153
|
-
uint8_t runIndex; // index into the node's runs (0..runCount-1)
|
|
154
|
-
const char* text;
|
|
155
|
-
int16_t x; // offset from the line's left edge (pre-alignment)
|
|
156
|
-
uint16_t w; // measured width
|
|
157
|
-
uint8_t line; // which line (0..richLineCount-1) this segment is on
|
|
158
|
-
};
|
|
159
|
-
// One wrapped line of rich text (precomputed).
|
|
160
|
-
struct UIRichLine {
|
|
161
|
-
int16_t y; // top y relative to the node's text top
|
|
162
|
-
uint16_t h; // line height (tallest run on this line)
|
|
163
|
-
int16_t baseline; // baseline y (for mixed-size baseline alignment)
|
|
164
|
-
uint16_t w; // total line width (for alignment)
|
|
165
|
-
};
|
|
166
|
-
struct UITransition {
|
|
167
|
-
uint16_t node;
|
|
168
|
-
UIProperty prop;
|
|
169
|
-
uint16_t durationMs;
|
|
170
|
-
// The :pressed and base-state target colors. ui_on_press arms toward
|
|
171
|
-
// pressedTarget; ui_on_release arms toward baseTarget.
|
|
172
|
-
uint32_t pressedTarget;
|
|
173
|
-
uint32_t baseTarget;
|
|
174
|
-
// runtime
|
|
175
|
-
uint32_t elapsed;
|
|
176
|
-
uint32_t prevValue;
|
|
177
|
-
uint32_t targetValue;
|
|
178
|
-
uint8_t active;
|
|
179
|
-
};
|
|
180
|
-
struct UIBinding {
|
|
181
|
-
uint16_t node;
|
|
182
|
-
UIProperty prop;
|
|
183
|
-
uint32_t (*fn)(void); // for color/numeric bindings
|
|
184
|
-
void (*textFn)(char* buf, uint8_t size); // for text bindings (PROP_TEXT): fills buf
|
|
185
|
-
uint32_t lastValue; // numeric binding cache; avoids redundant dirty work
|
|
186
|
-
uint8_t initialized; // first evaluation establishes the baseline
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
// Color lerp for transitions (rgb565). For mono, this collapses to a snap.
|
|
190
|
-
static inline uint16_t lerp_color(uint16_t a, uint16_t b, uint8_t k100) {
|
|
191
|
-
if (k100 >= 100) return b;
|
|
192
|
-
// Lerp in 888 internally for smoother color transitions (keyframe animation,
|
|
193
|
-
// :pressed transitions). Unpack 565→888, lerp at 8-bit, re-quantize to 565.
|
|
194
|
-
uint8_t ar5 = (a >> 11) & 0x1f, ag6 = (a >> 5) & 0x3f, ab5 = a & 0x1f;
|
|
195
|
-
uint8_t br5 = (b >> 11) & 0x1f, bg6 = (b >> 5) & 0x3f, bb5 = b & 0x1f;
|
|
196
|
-
uint16_t ar8 = (ar5 << 3) | (ar5 >> 2), ag8 = (ag6 << 2) | (ag6 >> 4), ab8 = (ab5 << 3) | (ab5 >> 2);
|
|
197
|
-
uint16_t br8 = (br5 << 3) | (br5 >> 2), bg8 = (bg6 << 2) | (bg6 >> 4), bb8 = (bb5 << 3) | (bb5 >> 2);
|
|
198
|
-
int16_t r = static_cast<int16_t>(ar8 + static_cast<int16_t>((br8 - ar8) * k100 / 100));
|
|
199
|
-
int16_t g = static_cast<int16_t>(ag8 + static_cast<int16_t>((bg8 - ag8) * k100 / 100));
|
|
200
|
-
int16_t bl = static_cast<int16_t>(ab8 + static_cast<int16_t>((bb8 - ab8) * k100 / 100));
|
|
201
|
-
return (static_cast<uint16_t>((r >> 3) & 0x1f) << 11) | (static_cast<uint16_t>((g >> 2) & 0x3f) << 5) | static_cast<uint16_t>((bl >> 3) & 0x1f);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// RGB888 lerp — for transitions on RGB888/RGB666 targets (Phase 2+). Unused in
|
|
205
|
-
// Phase 1; the 565 lerp_color above remains the active path for TFT targets,
|
|
206
|
-
// whose node colors are still emitted as 565 values stored in uint32_t fields.
|
|
207
|
-
static inline uint32_t lerp_color_888(uint32_t a, uint32_t b, uint8_t k100) {
|
|
208
|
-
if (k100 >= 100) return b;
|
|
209
|
-
uint8_t ar = (a >> 16) & 0xff, ag = (a >> 8) & 0xff, ab = a & 0xff;
|
|
210
|
-
uint8_t br = (b >> 16) & 0xff, bg = (b >> 8) & 0xff, bb = b & 0xff;
|
|
211
|
-
int16_t r = ar + static_cast<int16_t>((static_cast<int16_t>(br) - static_cast<int16_t>(ar)) * k100 / 100);
|
|
212
|
-
int16_t g = ag + static_cast<int16_t>((static_cast<int16_t>(bg) - static_cast<int16_t>(ag)) * k100 / 100);
|
|
213
|
-
int16_t bl = ab + static_cast<int16_t>((static_cast<int16_t>(bb) - static_cast<int16_t>(ab)) * k100 / 100);
|
|
214
|
-
return (static_cast<uint32_t>(r & 0xff) << 16) | (static_cast<uint32_t>(g & 0xff) << 8) | static_cast<uint32_t>(bl & 0xff);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Declared by the lowering output (the tables). Matches the mutable (non-const)
|
|
218
|
-
// definitions: ui_tick updates node bg/dirty and transition elapsed/active.
|
|
219
|
-
extern UINode __ui_nodes[];
|
|
220
|
-
extern UITransition __ui_trans[];
|
|
221
|
-
extern UIBinding __ui_bindings[];
|
|
222
|
-
extern const UIFontFace __ui_font_faces[];
|
|
223
|
-
// Rich-text run / segment / line tables (parallel arrays; nodes reference
|
|
224
|
-
// contiguous slices via runStart/richSegStart/richLineStart + counts).
|
|
225
|
-
extern UIRichRun __ui_runs[];
|
|
226
|
-
extern UIRichSeg __ui_rich_segs[];
|
|
227
|
-
extern UIRichLine __ui_rich_lines[];
|
|
228
|
-
extern const uint16_t __ui_node_count;
|
|
229
|
-
extern const uint16_t __ui_trans_count;
|
|
230
|
-
extern const uint16_t __ui_binding_count;
|
|
231
|
-
extern const uint16_t __ui_run_count;
|
|
232
|
-
extern const uint16_t __ui_rich_seg_count;
|
|
233
|
-
extern const uint16_t __ui_rich_line_count;`;
|
|
234
|
-
}
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 90-303).
|
|
2
|
+
// Enums (UINodeKind, UIProperty) and all struct definitions + extern table decls.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitStructs(): string {
|
|
5
|
+
return `
|
|
6
|
+
enum UINodeKind { NODE_FILL, NODE_TEXT, NODE_BUTTON, NODE_CHECK, NODE_RADIO, NODE_PROGRESS, NODE_RANGE, NODE_INPUT, NODE_IMG, NODE_LIST, NODE_CANVAS, NODE_SELECT };
|
|
7
|
+
enum UIProperty { PROP_BG, PROP_FG, PROP_TEXT, PROP_VISIBLE, PROP_BORDER_COLOR, PROP_VALUE };
|
|
8
|
+
|
|
9
|
+
struct UIRect { int16_t x, y, w, h; };
|
|
10
|
+
struct UIFontGlyph {
|
|
11
|
+
uint16_t codepoint;
|
|
12
|
+
int8_t xOffset;
|
|
13
|
+
int8_t yOffset;
|
|
14
|
+
uint8_t width;
|
|
15
|
+
uint8_t height;
|
|
16
|
+
uint8_t advance;
|
|
17
|
+
uint16_t dataOffset; // 4-bit alpha pixel offset
|
|
18
|
+
};
|
|
19
|
+
struct UIFontFace {
|
|
20
|
+
uint8_t id;
|
|
21
|
+
uint8_t glyphCount;
|
|
22
|
+
uint8_t lineHeight;
|
|
23
|
+
uint8_t baseline;
|
|
24
|
+
const UIFontGlyph* glyphs;
|
|
25
|
+
const uint8_t* alpha;
|
|
26
|
+
};
|
|
27
|
+
struct UINode {
|
|
28
|
+
UIRect box;
|
|
29
|
+
uint32_t bg;
|
|
30
|
+
uint32_t fg;
|
|
31
|
+
UINodeKind kind;
|
|
32
|
+
const char* text;
|
|
33
|
+
char textBuffer[UI_TEXT_BUF + 1]; // dynamic text — read only when hasTextBinding == 1
|
|
34
|
+
uint8_t hasTextBinding; // set by ui_init when a PROP_TEXT binding targets this node
|
|
35
|
+
const uint8_t* font;
|
|
36
|
+
uint8_t hasBg;
|
|
37
|
+
uint8_t textAlign; // 0=left, 1=center, 2=right
|
|
38
|
+
uint8_t textSize; // GFX text size: 1-4
|
|
39
|
+
uint8_t lineHeight; // px per text line (0 = font default)
|
|
40
|
+
int8_t letterSpacing; // px between chars (0 = default advance)
|
|
41
|
+
uint8_t fontAntialias; // 1 = smooth text edges when UI_AA is available
|
|
42
|
+
uint8_t fontFace; // 0 = classic GFX bitmap font; otherwise UIFontFace id
|
|
43
|
+
uint32_t borderColor; // resolved color for the border (0 = use fg)
|
|
44
|
+
uint8_t borderStyle; // 0=none, 1=solid, 2=dashed
|
|
45
|
+
uint8_t borderWidth; // px, 0=none (uniform fallback)
|
|
46
|
+
uint8_t borderTopWidth; // per-side; equals borderWidth when uniform
|
|
47
|
+
uint8_t borderRightWidth;
|
|
48
|
+
uint8_t borderBottomWidth;
|
|
49
|
+
uint8_t borderLeftWidth;
|
|
50
|
+
uint8_t hasPerSideBorder; // 1 when any per-side width differs from borderWidth
|
|
51
|
+
uint8_t borderRadius; // px, 0=square
|
|
52
|
+
uint8_t paddingTop;
|
|
53
|
+
uint8_t paddingRight;
|
|
54
|
+
uint8_t paddingBottom;
|
|
55
|
+
uint8_t paddingLeft;
|
|
56
|
+
uint8_t gradientEnabled; // 0=none, 1=vertical, 2=horizontal
|
|
57
|
+
uint32_t gradientColor1;
|
|
58
|
+
uint32_t gradientColor2;
|
|
59
|
+
uint32_t outlineColor;
|
|
60
|
+
uint8_t outlineStyle; // 0=none, 1=solid, 2=dashed
|
|
61
|
+
uint8_t outlineWidth;
|
|
62
|
+
int16_t zIndex; // effective draw layer; higher layers draw later
|
|
63
|
+
int16_t transformOffsetX; // draw-only transform: translate(...)
|
|
64
|
+
int16_t transformOffsetY;
|
|
65
|
+
int16_t rotateDeg;
|
|
66
|
+
int8_t pressedOffsetX; // draw-only :pressed offset, no Yoga relayout
|
|
67
|
+
int8_t pressedOffsetY;
|
|
68
|
+
uint8_t shadowCount; // 0-4 active shadows
|
|
69
|
+
int8_t shadowOffsetX[4];
|
|
70
|
+
int8_t shadowOffsetY[4];
|
|
71
|
+
uint8_t shadowBlur[4];
|
|
72
|
+
uint32_t shadowColor[4];
|
|
73
|
+
uint8_t shadowAlpha[4];
|
|
74
|
+
uint8_t shadowInset[4]; // 0=outset, 1=inset
|
|
75
|
+
uint8_t textShadowCount;
|
|
76
|
+
int8_t textShadowOffsetX;
|
|
77
|
+
int8_t textShadowOffsetY;
|
|
78
|
+
uint8_t textShadowBlur;
|
|
79
|
+
uint32_t textShadowColor;
|
|
80
|
+
uint8_t textShadowAlpha;
|
|
81
|
+
uint8_t underline; // text-decoration: 0=none,1=underline,2=line-through,3=both
|
|
82
|
+
uint8_t textOverflow; // text-overflow: 0=clip, 1=ellipsis (truncate + ...)
|
|
83
|
+
uint8_t nowrap; // 1 = no text wrapping (white-space: nowrap/pre)
|
|
84
|
+
uint8_t whiteSpaceMode; // 0=normal, 1=nowrap, 2=pre, 3=pre-line
|
|
85
|
+
uint8_t visible; // 0=hidden, 1=visible
|
|
86
|
+
uint8_t opacity; // 0-100
|
|
87
|
+
uint32_t clearColor; // ancestor's background — used to wipe transparent text before redraw
|
|
88
|
+
int16_t lastTextWidth;
|
|
89
|
+
int16_t lastTextHeight;
|
|
90
|
+
uint32_t layoutCacheKey; // 0 = invalid; non-zero hashes layout inputs
|
|
91
|
+
uint16_t layoutMetricsW; // cached ui_text_layout_metrics width
|
|
92
|
+
uint16_t layoutMetricsH; // cached ui_text_layout_metrics height
|
|
93
|
+
// scroll (unified: containers and virtualized lists share these)
|
|
94
|
+
uint8_t scrollable; // 1 = children offset by scrollY, clipped to this box
|
|
95
|
+
uint8_t virtualized; // 1 = children produced by list*Fn callbacks (<list>)
|
|
96
|
+
int16_t scrollY; // committed offset (always in [0, maxScroll]); draw subtracts it
|
|
97
|
+
int16_t contentHeight; // total child height (clamp bound + scrollbar ratio)
|
|
98
|
+
int16_t overscrollPx; // elastic excursion past a boundary (0 in-bounds; +top, -bottom)
|
|
99
|
+
uint8_t settling; // 1 while a bounce-back/snap animation runs
|
|
100
|
+
int16_t lastPaintedScrollY; // scrollY at last container repaint (Mode B shift delta)
|
|
101
|
+
uint16_t listCount; // virtualized: current item count (refreshed each frame)
|
|
102
|
+
uint16_t (*listCountFn)(void);
|
|
103
|
+
void (*listItemFn)(uint16_t idx, char* buf, uint8_t size);
|
|
104
|
+
void (*listTapFn)(uint16_t idx); // nullptr if no tap handler
|
|
105
|
+
uint16_t parent; // 0xFFFF = root/no parent (UI_NO_PARENT)
|
|
106
|
+
uint16_t subtreeEnd; // exclusive pre-order end index
|
|
107
|
+
uint8_t screenId; // which <screen> this node belongs to (for navigation)
|
|
108
|
+
uint8_t imgDataId; // index into __ui_images[] (255 = no image)
|
|
109
|
+
uint8_t objectFit; // 0=none, 1=fill, 2=contain, 3=cover, 4=scale-down
|
|
110
|
+
uint16_t listItemHeight; // px per item for <list> (0 = not a list)
|
|
111
|
+
int16_t rangeMin; // for <range>: minimum value
|
|
112
|
+
int16_t rangeMax; // for <range>: maximum value
|
|
113
|
+
int16_t maxlen; // for <input>: max character length (0 = UI_TEXT_BUF)
|
|
114
|
+
uint16_t canvasW; // canvas buffer width (for <canvas>)
|
|
115
|
+
uint16_t canvasH; // canvas buffer height (for <canvas>)
|
|
116
|
+
// Rich-text runs (runCount > 0 for text nodes with mixed inline content).
|
|
117
|
+
// The node references a contiguous slice of the global run / segment / line
|
|
118
|
+
// arrays; geometry is precomputed at transpile time (runs are static-only).
|
|
119
|
+
uint8_t runCount; // number of runs in this node (0 = plain single-string text)
|
|
120
|
+
uint8_t richLineCount; // number of wrapped lines
|
|
121
|
+
uint16_t runStart; // first index into __ui_runs[]
|
|
122
|
+
uint16_t richSegStart; // first index into __ui_rich_segs[]
|
|
123
|
+
uint16_t richSegCount; // total segments across all lines
|
|
124
|
+
uint16_t richLineStart; // first index into __ui_rich_lines[]
|
|
125
|
+
// runtime slot
|
|
126
|
+
uint8_t dirty;
|
|
127
|
+
int16_t value; // unified element
|
|
128
|
+
uint8_t disabled; // HTML disabled attr: no taps/keyboard, dimmed draw state
|
|
129
|
+
uint8_t optionCount; // <select>: number of options
|
|
130
|
+
void (*optionTextFn)(uint8_t idx, char* buf, uint8_t size); // option text by index
|
|
131
|
+
int8_t drawerSide; // <drawer>/<toast>: 0=bottom 1=top 2=left 3=right; 4=<dialog> center; -1 = none
|
|
132
|
+
uint16_t toastDuration; // <toast duration>: ms before auto-close (0 = manual)
|
|
133
|
+
uint32_t checkedBg; // :checked background (RGB565) — switch track / checkbox face / radio dot / select selected row
|
|
134
|
+
uint32_t checkedFg; // :checked color (RGB565) — knob / checkmark / selected-row text
|
|
135
|
+
uint8_t hasCheckedBg; // 1 when checkedBg was authored (0 = swap not wired)
|
|
136
|
+
uint8_t hasCheckedFg; // 1 when checkedFg was authored
|
|
137
|
+
int8_t flowAxis; // visibility reflow: 0 none, 1 column, 2 row (ui_reflow_visibility)
|
|
138
|
+
uint8_t flowGap; // visibility reflow: main-axis gap between in-flow children
|
|
139
|
+
uint8_t flowFlags; // bit0 auto height, bit1 auto width, bit2 out-of-flow
|
|
140
|
+
};
|
|
141
|
+
// Rich-text run: one piece of styled inline text within a node's run list.
|
|
142
|
+
struct UIRichRun {
|
|
143
|
+
const char* text;
|
|
144
|
+
uint32_t fg;
|
|
145
|
+
uint8_t textSize;
|
|
146
|
+
uint8_t fontFace;
|
|
147
|
+
uint8_t underline; // 0=none,1=underline,2=line-through,3=both
|
|
148
|
+
int8_t letterSpacing;
|
|
149
|
+
int8_t linkTarget; // resolved screen index, -1 = not a link
|
|
150
|
+
};
|
|
151
|
+
// One laid-out segment of a run on one line (precomputed geometry).
|
|
152
|
+
struct UIRichSeg {
|
|
153
|
+
uint8_t runIndex; // index into the node's runs (0..runCount-1)
|
|
154
|
+
const char* text;
|
|
155
|
+
int16_t x; // offset from the line's left edge (pre-alignment)
|
|
156
|
+
uint16_t w; // measured width
|
|
157
|
+
uint8_t line; // which line (0..richLineCount-1) this segment is on
|
|
158
|
+
};
|
|
159
|
+
// One wrapped line of rich text (precomputed).
|
|
160
|
+
struct UIRichLine {
|
|
161
|
+
int16_t y; // top y relative to the node's text top
|
|
162
|
+
uint16_t h; // line height (tallest run on this line)
|
|
163
|
+
int16_t baseline; // baseline y (for mixed-size baseline alignment)
|
|
164
|
+
uint16_t w; // total line width (for alignment)
|
|
165
|
+
};
|
|
166
|
+
struct UITransition {
|
|
167
|
+
uint16_t node;
|
|
168
|
+
UIProperty prop;
|
|
169
|
+
uint16_t durationMs;
|
|
170
|
+
// The :pressed and base-state target colors. ui_on_press arms toward
|
|
171
|
+
// pressedTarget; ui_on_release arms toward baseTarget.
|
|
172
|
+
uint32_t pressedTarget;
|
|
173
|
+
uint32_t baseTarget;
|
|
174
|
+
// runtime
|
|
175
|
+
uint32_t elapsed;
|
|
176
|
+
uint32_t prevValue;
|
|
177
|
+
uint32_t targetValue;
|
|
178
|
+
uint8_t active;
|
|
179
|
+
};
|
|
180
|
+
struct UIBinding {
|
|
181
|
+
uint16_t node;
|
|
182
|
+
UIProperty prop;
|
|
183
|
+
uint32_t (*fn)(void); // for color/numeric bindings
|
|
184
|
+
void (*textFn)(char* buf, uint8_t size); // for text bindings (PROP_TEXT): fills buf
|
|
185
|
+
uint32_t lastValue; // numeric binding cache; avoids redundant dirty work
|
|
186
|
+
uint8_t initialized; // first evaluation establishes the baseline
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Color lerp for transitions (rgb565). For mono, this collapses to a snap.
|
|
190
|
+
static inline uint16_t lerp_color(uint16_t a, uint16_t b, uint8_t k100) {
|
|
191
|
+
if (k100 >= 100) return b;
|
|
192
|
+
// Lerp in 888 internally for smoother color transitions (keyframe animation,
|
|
193
|
+
// :pressed transitions). Unpack 565→888, lerp at 8-bit, re-quantize to 565.
|
|
194
|
+
uint8_t ar5 = (a >> 11) & 0x1f, ag6 = (a >> 5) & 0x3f, ab5 = a & 0x1f;
|
|
195
|
+
uint8_t br5 = (b >> 11) & 0x1f, bg6 = (b >> 5) & 0x3f, bb5 = b & 0x1f;
|
|
196
|
+
uint16_t ar8 = (ar5 << 3) | (ar5 >> 2), ag8 = (ag6 << 2) | (ag6 >> 4), ab8 = (ab5 << 3) | (ab5 >> 2);
|
|
197
|
+
uint16_t br8 = (br5 << 3) | (br5 >> 2), bg8 = (bg6 << 2) | (bg6 >> 4), bb8 = (bb5 << 3) | (bb5 >> 2);
|
|
198
|
+
int16_t r = static_cast<int16_t>(ar8 + static_cast<int16_t>((br8 - ar8) * k100 / 100));
|
|
199
|
+
int16_t g = static_cast<int16_t>(ag8 + static_cast<int16_t>((bg8 - ag8) * k100 / 100));
|
|
200
|
+
int16_t bl = static_cast<int16_t>(ab8 + static_cast<int16_t>((bb8 - ab8) * k100 / 100));
|
|
201
|
+
return (static_cast<uint16_t>((r >> 3) & 0x1f) << 11) | (static_cast<uint16_t>((g >> 2) & 0x3f) << 5) | static_cast<uint16_t>((bl >> 3) & 0x1f);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// RGB888 lerp — for transitions on RGB888/RGB666 targets (Phase 2+). Unused in
|
|
205
|
+
// Phase 1; the 565 lerp_color above remains the active path for TFT targets,
|
|
206
|
+
// whose node colors are still emitted as 565 values stored in uint32_t fields.
|
|
207
|
+
static inline uint32_t lerp_color_888(uint32_t a, uint32_t b, uint8_t k100) {
|
|
208
|
+
if (k100 >= 100) return b;
|
|
209
|
+
uint8_t ar = (a >> 16) & 0xff, ag = (a >> 8) & 0xff, ab = a & 0xff;
|
|
210
|
+
uint8_t br = (b >> 16) & 0xff, bg = (b >> 8) & 0xff, bb = b & 0xff;
|
|
211
|
+
int16_t r = ar + static_cast<int16_t>((static_cast<int16_t>(br) - static_cast<int16_t>(ar)) * k100 / 100);
|
|
212
|
+
int16_t g = ag + static_cast<int16_t>((static_cast<int16_t>(bg) - static_cast<int16_t>(ag)) * k100 / 100);
|
|
213
|
+
int16_t bl = ab + static_cast<int16_t>((static_cast<int16_t>(bb) - static_cast<int16_t>(ab)) * k100 / 100);
|
|
214
|
+
return (static_cast<uint32_t>(r & 0xff) << 16) | (static_cast<uint32_t>(g & 0xff) << 8) | static_cast<uint32_t>(bl & 0xff);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Declared by the lowering output (the tables). Matches the mutable (non-const)
|
|
218
|
+
// definitions: ui_tick updates node bg/dirty and transition elapsed/active.
|
|
219
|
+
extern UINode __ui_nodes[];
|
|
220
|
+
extern UITransition __ui_trans[];
|
|
221
|
+
extern UIBinding __ui_bindings[];
|
|
222
|
+
extern const UIFontFace __ui_font_faces[];
|
|
223
|
+
// Rich-text run / segment / line tables (parallel arrays; nodes reference
|
|
224
|
+
// contiguous slices via runStart/richSegStart/richLineStart + counts).
|
|
225
|
+
extern UIRichRun __ui_runs[];
|
|
226
|
+
extern UIRichSeg __ui_rich_segs[];
|
|
227
|
+
extern UIRichLine __ui_rich_lines[];
|
|
228
|
+
extern const uint16_t __ui_node_count;
|
|
229
|
+
extern const uint16_t __ui_trans_count;
|
|
230
|
+
extern const uint16_t __ui_binding_count;
|
|
231
|
+
extern const uint16_t __ui_run_count;
|
|
232
|
+
extern const uint16_t __ui_rich_seg_count;
|
|
233
|
+
extern const uint16_t __ui_rich_line_count;`;
|
|
234
|
+
}
|