@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
|
@@ -3,21 +3,40 @@
|
|
|
3
3
|
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
4
|
export function emitBlendBodies(): string {
|
|
5
5
|
return `
|
|
6
|
+
// Blend LUTs (LVGL draw-unit trick, memory-frugal variant): two 256-entry
|
|
7
|
+
// per-channel tables rebuilt only when the opacity level CHANGES. Blends
|
|
8
|
+
// typically run per-pixel at a fixed opacity (skeleton pulse frame, one
|
|
9
|
+
// shadow pass, a glyph's coverage step), so the table amortizes to one
|
|
10
|
+
// rebuild per pass and every pixel becomes three array lookups instead of
|
|
11
|
+
// three multiply-divide rounds. Total cost: 513 bytes of static RAM.
|
|
12
|
+
static uint8_t __ui_blend_lut_fg[256];
|
|
13
|
+
static uint8_t __ui_blend_lut_bg[256];
|
|
14
|
+
static uint8_t __ui_blend_lut_opacity = 255; // 255 = never built (valid range 0..100)
|
|
15
|
+
static inline void ui_blend_lut_build(uint8_t opacity) {
|
|
16
|
+
if (__ui_blend_lut_opacity == opacity) return;
|
|
17
|
+
for (int16_t v = 0; v < 256; v++) {
|
|
18
|
+
__ui_blend_lut_fg[v] = static_cast<uint8_t>((v * opacity) / 100);
|
|
19
|
+
__ui_blend_lut_bg[v] = static_cast<uint8_t>((v * (100 - opacity)) / 100);
|
|
20
|
+
}
|
|
21
|
+
__ui_blend_lut_opacity = opacity;
|
|
22
|
+
}
|
|
23
|
+
|
|
6
24
|
static inline uint16_t ui_blend565(uint16_t fg, uint16_t bg, uint8_t opacity) {
|
|
7
25
|
if (opacity >= 100) return fg;
|
|
8
26
|
if (opacity == 0) return bg;
|
|
9
|
-
|
|
27
|
+
ui_blend_lut_build(opacity);
|
|
28
|
+
// Blend in 888 internally for higher precision: unpack 565->888 (replicating
|
|
10
29
|
// high bits), blend at 8-bit, then re-quantize to 565. This produces smoother
|
|
11
|
-
// intermediate values for AA text edges, opacity, shadows, and gradients
|
|
30
|
+
// intermediate values for AA text edges, opacity, shadows, and gradients --
|
|
12
31
|
// the 565-channel blend (32 red levels) was too coarse and showed banding.
|
|
13
32
|
uint8_t fr = (fg >> 11) & 0x1F, fg5 = (fg >> 5) & 0x3F, fb = fg & 0x1F;
|
|
14
33
|
uint8_t br = (bg >> 11) & 0x1F, bg5 = (bg >> 5) & 0x3F, bb = bg & 0x1F;
|
|
15
|
-
// Unpack to 8-bit (5-bit
|
|
34
|
+
// Unpack to 8-bit (5-bit -> 8-bit: (v << 3) | (v >> 2)).
|
|
16
35
|
uint16_t fr8 = (fr << 3) | (fr >> 2), fg8 = (fg5 << 2) | (fg5 >> 4), fb8 = (fb << 3) | (fb >> 2);
|
|
17
36
|
uint16_t br8 = (br << 3) | (br >> 2), bg8 = (bg5 << 2) | (bg5 >> 4), bb8 = (bb << 3) | (bb >> 2);
|
|
18
|
-
uint16_t r = static_cast<uint16_t>(
|
|
19
|
-
uint16_t g = static_cast<uint16_t>(
|
|
20
|
-
uint16_t b = static_cast<uint16_t>(
|
|
37
|
+
uint16_t r = static_cast<uint16_t>(__ui_blend_lut_fg[fr8] + __ui_blend_lut_bg[br8]);
|
|
38
|
+
uint16_t g = static_cast<uint16_t>(__ui_blend_lut_fg[fg8] + __ui_blend_lut_bg[bg8]);
|
|
39
|
+
uint16_t b = static_cast<uint16_t>(__ui_blend_lut_fg[fb8] + __ui_blend_lut_bg[bb8]);
|
|
21
40
|
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
|
22
41
|
}
|
|
23
42
|
|
|
@@ -28,11 +47,12 @@ static inline uint16_t ui_blend565(uint16_t fg, uint16_t bg, uint8_t opacity) {
|
|
|
28
47
|
static inline uint32_t ui_blend888(uint32_t fg, uint32_t bg, uint8_t opacity) {
|
|
29
48
|
if (opacity >= 100) return fg;
|
|
30
49
|
if (opacity == 0) return bg;
|
|
50
|
+
ui_blend_lut_build(opacity);
|
|
31
51
|
uint8_t fr = (fg >> 16) & 0xff, fg8 = (fg >> 8) & 0xff, fb = fg & 0xff;
|
|
32
52
|
uint8_t br = (bg >> 16) & 0xff, bg8 = (bg >> 8) & 0xff, bb = bg & 0xff;
|
|
33
|
-
uint8_t r = (fr
|
|
34
|
-
uint8_t g = (fg8
|
|
35
|
-
uint8_t b = (fb
|
|
53
|
+
uint8_t r = static_cast<uint8_t>(__ui_blend_lut_fg[fr] + __ui_blend_lut_bg[br]);
|
|
54
|
+
uint8_t g = static_cast<uint8_t>(__ui_blend_lut_fg[fg8] + __ui_blend_lut_bg[bg8]);
|
|
55
|
+
uint8_t b = static_cast<uint8_t>(__ui_blend_lut_fg[fb] + __ui_blend_lut_bg[bb]);
|
|
36
56
|
return (static_cast<uint32_t>(r) << 16) | (static_cast<uint32_t>(g) << 8) | b;
|
|
37
57
|
}
|
|
38
58
|
`;
|
|
@@ -29,13 +29,16 @@ static inline CuttlefishCanvas16* ui_create_canvas_best(int16_t w, int16_t h) {
|
|
|
29
29
|
if (!psram_logged) {
|
|
30
30
|
psram_logged = 1;
|
|
31
31
|
#if defined(ESP32) && defined(ARDUINO)
|
|
32
|
-
Serial.printf("[psram] canvas %dx%d allocated in PSRAM (free=%u)
|
|
32
|
+
Serial.printf("[psram] canvas %dx%d allocated in PSRAM (free=%u)\\n", w, h, ESP.getFreePsram());
|
|
33
33
|
#else
|
|
34
|
-
printf("[psram] canvas %dx%d allocated in PSRAM
|
|
34
|
+
printf("[psram] canvas %dx%d allocated in PSRAM\\n", w, h);
|
|
35
35
|
#endif
|
|
36
36
|
}
|
|
37
37
|
return c;
|
|
38
38
|
}
|
|
39
|
+
// Object allocated but its pixel buffer failed — free the object before
|
|
40
|
+
// falling through to SRAM so it isn't leaked.
|
|
41
|
+
display_deleteCanvas(c);
|
|
39
42
|
// PSRAM allocation failed (rare — fragmented PSRAM) → fall through to SRAM.
|
|
40
43
|
}
|
|
41
44
|
#endif
|
|
@@ -1,117 +1,121 @@
|
|
|
1
|
-
// Slice of the C++ runtime header (original source lines 1449-1547).
|
|
2
|
-
// Canvas push/draw helpers, buffered scroll canvas push, scrollbar direct.
|
|
3
|
-
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
-
export function emitCanvasScrollbar(): string {
|
|
5
|
-
return `
|
|
6
|
-
static inline void ui_push_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
7
|
-
if (!canvas || !display_canvasBuffer(canvas)) return;
|
|
8
|
-
UI_COLOR_T* pixels = display_canvasBuffer(canvas);
|
|
9
|
-
int16_t stride = display_canvasWidth(canvas);
|
|
10
|
-
// The canvas is viewport-sized: buffer row 0 = the first row of the viewport.
|
|
11
|
-
// The display destination is (x, y) but the source buffer starts at (0, 0).
|
|
12
|
-
// When a full-screen framebuffer is the active draw target, composite into it
|
|
13
|
-
// via __ui_gfx (so the single bulk push at frame end captures everything).
|
|
14
|
-
// Otherwise write straight to the display in one SPI transaction.
|
|
15
|
-
if (__ui_fb) {
|
|
16
|
-
// The framebuffer is the composition target. Track this publish so a
|
|
17
|
-
// geometry repair or scroll-canvas repair that does not leave a node dirty
|
|
18
|
-
// still reaches the panel during the frame-end flush.
|
|
19
|
-
ui_fb_add_rect(x, y, w, h);
|
|
20
|
-
if (w == stride) {
|
|
21
|
-
ui_display_draw_rgb_bitmap(x, y, pixels, w, h);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
for (int16_t row = 0; row < h; row++) {
|
|
25
|
-
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
26
|
-
}
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
display_startWrite();
|
|
30
|
-
display_setAddrWindow(x, y, w, h);
|
|
31
|
-
if (w == stride) {
|
|
32
|
-
// Full-width: contiguous in buffer, single write.
|
|
33
|
-
display_writePixels(pixels, static_cast<uint32_t>(w) * h);
|
|
34
|
-
display_endWrite();
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
for (int16_t row = 0; row < h; row++) {
|
|
38
|
-
display_writePixels(pixels + static_cast<int32_t>(row) * stride, w);
|
|
39
|
-
}
|
|
40
|
-
display_endWrite();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static inline void ui_draw_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
44
|
-
if (!canvas || !display_canvasBuffer(canvas)) return;
|
|
45
|
-
UI_COLOR_T* pixels = display_canvasBuffer(canvas);
|
|
46
|
-
int16_t stride = display_canvasWidth(canvas);
|
|
47
|
-
if (w == stride && h == display_canvasHeight(canvas)) {
|
|
48
|
-
ui_display_draw_rgb_bitmap(x, y, pixels, w, h);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
for (int16_t row = 0; row < h; row++) {
|
|
52
|
-
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static inline void ui_push_buffered_scroll_canvas(CuttlefishCanvas16* bufferedScrollCanvas,
|
|
57
|
-
CuttlefishCanvas16* bufferedScrollRepaintCanvas,
|
|
58
|
-
int16_t bufferedScrollNode,
|
|
59
|
-
int16_t bufferedScrollVX,
|
|
60
|
-
int16_t bufferedScrollVY,
|
|
61
|
-
int16_t bufferedScrollRepaintY,
|
|
62
|
-
int16_t bufferedScrollRepaintH,
|
|
63
|
-
CuttlefishDisplayTarget* drawTarget) {
|
|
64
|
-
if (bufferedScrollNode < 0 || !bufferedScrollCanvas || !display_canvasBuffer(bufferedScrollCanvas)) return;
|
|
65
|
-
// Draw scrollbar into the canvas (canvas-local coords: 0,0 = viewport top-left).
|
|
66
|
-
ui_display_set_target(bufferedScrollCanvas);
|
|
67
|
-
int16_t si = bufferedScrollNode;
|
|
68
|
-
int16_t vw = __ui_nodes[si].box.w;
|
|
69
|
-
int16_t vh = __ui_nodes[si].box.h;
|
|
70
|
-
if (bufferedScrollRepaintCanvas && bufferedScrollRepaintH > 0) {
|
|
71
|
-
ui_draw_canvas_rect(bufferedScrollRepaintCanvas, 0, bufferedScrollRepaintY, vw, bufferedScrollRepaintH);
|
|
72
|
-
}
|
|
73
|
-
int16_t tx = vw - 4;
|
|
74
|
-
uint16_t thumbH = static_cast<uint32_t>(vh) * vh / __ui_nodes[si].contentHeight;
|
|
75
|
-
if (thumbH < 8) thumbH = 8;
|
|
76
|
-
// Clamp to vh so (vh - thumbH) below can't underflow on a degenerate sub-8px
|
|
77
|
-
// viewport (which would cast a negative value to a huge uint32_t and place the
|
|
78
|
-
// thumb off-screen). Matches the guard in ui_render_scroll_bands.
|
|
79
|
-
if (thumbH > static_cast<uint16_t>(vh)) thumbH = static_cast<uint16_t>(vh);
|
|
80
|
-
int16_t maxScroll = __ui_nodes[si].contentHeight - vh;
|
|
81
|
-
uint16_t thumbY = static_cast<uint32_t>(vh - thumbH) * __ui_nodes[si].scrollY / (maxScroll > 0 ? maxScroll : 1);
|
|
82
|
-
UI_COLOR_T dimFg = (UI_COLOR_T)((__ui_nodes[si].fg >> 1) & UI_DIM_MASK);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
int16_t
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 1449-1547).
|
|
2
|
+
// Canvas push/draw helpers, buffered scroll canvas push, scrollbar direct.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitCanvasScrollbar(): string {
|
|
5
|
+
return `
|
|
6
|
+
static inline void ui_push_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
7
|
+
if (!canvas || !display_canvasBuffer(canvas)) return;
|
|
8
|
+
UI_COLOR_T* pixels = display_canvasBuffer(canvas);
|
|
9
|
+
int16_t stride = display_canvasWidth(canvas);
|
|
10
|
+
// The canvas is viewport-sized: buffer row 0 = the first row of the viewport.
|
|
11
|
+
// The display destination is (x, y) but the source buffer starts at (0, 0).
|
|
12
|
+
// When a full-screen framebuffer is the active draw target, composite into it
|
|
13
|
+
// via __ui_gfx (so the single bulk push at frame end captures everything).
|
|
14
|
+
// Otherwise write straight to the display in one SPI transaction.
|
|
15
|
+
if (__ui_fb) {
|
|
16
|
+
// The framebuffer is the composition target. Track this publish so a
|
|
17
|
+
// geometry repair or scroll-canvas repair that does not leave a node dirty
|
|
18
|
+
// still reaches the panel during the frame-end flush.
|
|
19
|
+
ui_fb_add_rect(x, y, w, h);
|
|
20
|
+
if (w == stride) {
|
|
21
|
+
ui_display_draw_rgb_bitmap(x, y, pixels, w, h);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
for (int16_t row = 0; row < h; row++) {
|
|
25
|
+
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
display_startWrite();
|
|
30
|
+
display_setAddrWindow(x, y, w, h);
|
|
31
|
+
if (w == stride) {
|
|
32
|
+
// Full-width: contiguous in buffer, single write.
|
|
33
|
+
display_writePixels(pixels, static_cast<uint32_t>(w) * h);
|
|
34
|
+
display_endWrite();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (int16_t row = 0; row < h; row++) {
|
|
38
|
+
display_writePixels(pixels + static_cast<int32_t>(row) * stride, w);
|
|
39
|
+
}
|
|
40
|
+
display_endWrite();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static inline void ui_draw_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
44
|
+
if (!canvas || !display_canvasBuffer(canvas)) return;
|
|
45
|
+
UI_COLOR_T* pixels = display_canvasBuffer(canvas);
|
|
46
|
+
int16_t stride = display_canvasWidth(canvas);
|
|
47
|
+
if (w == stride && h == display_canvasHeight(canvas)) {
|
|
48
|
+
ui_display_draw_rgb_bitmap(x, y, pixels, w, h);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
for (int16_t row = 0; row < h; row++) {
|
|
52
|
+
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static inline void ui_push_buffered_scroll_canvas(CuttlefishCanvas16* bufferedScrollCanvas,
|
|
57
|
+
CuttlefishCanvas16* bufferedScrollRepaintCanvas,
|
|
58
|
+
int16_t bufferedScrollNode,
|
|
59
|
+
int16_t bufferedScrollVX,
|
|
60
|
+
int16_t bufferedScrollVY,
|
|
61
|
+
int16_t bufferedScrollRepaintY,
|
|
62
|
+
int16_t bufferedScrollRepaintH,
|
|
63
|
+
CuttlefishDisplayTarget* drawTarget) {
|
|
64
|
+
if (bufferedScrollNode < 0 || !bufferedScrollCanvas || !display_canvasBuffer(bufferedScrollCanvas)) return;
|
|
65
|
+
// Draw scrollbar into the canvas (canvas-local coords: 0,0 = viewport top-left).
|
|
66
|
+
ui_display_set_target(bufferedScrollCanvas);
|
|
67
|
+
int16_t si = bufferedScrollNode;
|
|
68
|
+
int16_t vw = __ui_nodes[si].box.w;
|
|
69
|
+
int16_t vh = __ui_nodes[si].box.h;
|
|
70
|
+
if (bufferedScrollRepaintCanvas && bufferedScrollRepaintH > 0) {
|
|
71
|
+
ui_draw_canvas_rect(bufferedScrollRepaintCanvas, 0, bufferedScrollRepaintY, vw, bufferedScrollRepaintH);
|
|
72
|
+
}
|
|
73
|
+
int16_t tx = vw - 4;
|
|
74
|
+
uint16_t thumbH = static_cast<uint32_t>(vh) * vh / __ui_nodes[si].contentHeight;
|
|
75
|
+
if (thumbH < 8) thumbH = 8;
|
|
76
|
+
// Clamp to vh so (vh - thumbH) below can't underflow on a degenerate sub-8px
|
|
77
|
+
// viewport (which would cast a negative value to a huge uint32_t and place the
|
|
78
|
+
// thumb off-screen). Matches the guard in ui_render_scroll_bands.
|
|
79
|
+
if (thumbH > static_cast<uint16_t>(vh)) thumbH = static_cast<uint16_t>(vh);
|
|
80
|
+
int16_t maxScroll = __ui_nodes[si].contentHeight - vh;
|
|
81
|
+
uint16_t thumbY = static_cast<uint32_t>(vh - thumbH) * __ui_nodes[si].scrollY / (maxScroll > 0 ? maxScroll : 1);
|
|
82
|
+
UI_COLOR_T dimFg = (UI_COLOR_T)((__ui_nodes[si].fg >> 1) & UI_DIM_MASK);
|
|
83
|
+
// Track covers the FULL reserved gutter (4px) so child decorations that
|
|
84
|
+
// poke past the content area (e.g. outset shadows, offset up to +6px)
|
|
85
|
+
// can't leave 1px ticks in the uncovered edge column. Thumb stays 3px.
|
|
86
|
+
ui_display_fill_rect(tx, 0, 4, vh, dimFg);
|
|
87
|
+
ui_display_fill_rect(tx, thumbY, 3, thumbH, __ui_nodes[si].fg);
|
|
88
|
+
// Record the scrollY this canvas now reflects, so the next scroll frame can
|
|
89
|
+
// compute its shift delta (Mode B) from scrollY - lastPaintedScrollY.
|
|
90
|
+
__ui_nodes[si].lastPaintedScrollY = __ui_nodes[si].scrollY;
|
|
91
|
+
// Push the canvas to the draw target at the viewport position (the
|
|
92
|
+
// framebuffer when active, else the display directly).
|
|
93
|
+
ui_display_set_target(drawTarget);
|
|
94
|
+
ui_push_canvas_rect(bufferedScrollCanvas,
|
|
95
|
+
bufferedScrollVX, bufferedScrollVY,
|
|
96
|
+
vw, vh);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Draw a scroll container's scrollbar directly on the display (Mode C).
|
|
100
|
+
static inline void ui_draw_scrollbar_direct(int16_t si, int16_t vox, int16_t voy) {
|
|
101
|
+
if (si < 0 || si >= static_cast<int16_t>(__ui_node_count)) return;
|
|
102
|
+
int16_t vw = __ui_nodes[si].box.w;
|
|
103
|
+
int16_t vh = __ui_nodes[si].box.h;
|
|
104
|
+
if (__ui_nodes[si].contentHeight <= vh) return;
|
|
105
|
+
int16_t tx = vox + vw - 4;
|
|
106
|
+
uint16_t thumbH = static_cast<uint32_t>(vh) * vh / __ui_nodes[si].contentHeight;
|
|
107
|
+
if (thumbH < 8) thumbH = 8;
|
|
108
|
+
// Clamp to vh so (vh - thumbH) below can't underflow on a degenerate sub-8px
|
|
109
|
+
// viewport (which would cast a negative value to a huge uint32_t and place the
|
|
110
|
+
// thumb off-screen). Matches the guard in ui_render_scroll_bands.
|
|
111
|
+
if (thumbH > static_cast<uint16_t>(vh)) thumbH = static_cast<uint16_t>(vh);
|
|
112
|
+
int16_t maxScroll = __ui_nodes[si].contentHeight - vh;
|
|
113
|
+
uint16_t thumbY = static_cast<uint32_t>(vh - thumbH) * __ui_nodes[si].scrollY / (maxScroll > 0 ? maxScroll : 1);
|
|
114
|
+
UI_COLOR_T dimFg = (UI_COLOR_T)((__ui_nodes[si].fg >> 1) & UI_DIM_MASK);
|
|
115
|
+
// Full 4px gutter track (see the Mode B variant above).
|
|
116
|
+
ui_display_fill_rect(tx, voy, 4, vh, dimFg);
|
|
117
|
+
ui_display_fill_rect(tx, static_cast<int16_t>(voy + thumbY), 3, thumbH, __ui_nodes[si].fg);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Per-node dirty marker (called by press handlers and binding evaluation).`;
|
|
121
|
+
}
|
|
@@ -347,6 +347,17 @@ void CuttlefishGFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t
|
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
void CuttlefishGFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) {
|
|
350
|
+
if (w <= 0 || h <= 0) return;
|
|
351
|
+
if (r <= 0) {
|
|
352
|
+
drawRect(x, y, w, h, color);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
// CSS border-radius semantics: radii larger than half the shorter side
|
|
356
|
+
// collapse to a pill/box (the preview host-gfx clamps identically). Kit
|
|
357
|
+
// styles lower border-radius:9999px to r=255; without this clamp the
|
|
358
|
+
// corner arcs overgrow the box instead of forming a true pill.
|
|
359
|
+
const int16_t halfMin = static_cast<int16_t>((w < h ? w : h) / 2);
|
|
360
|
+
if (r > halfMin) r = halfMin;
|
|
350
361
|
drawFastHLine(x + r, y, w - 2 * r, color); // Top
|
|
351
362
|
drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
|
|
352
363
|
drawFastVLine(x, y + r, h - 2 * r, color); // Left
|
|
@@ -358,7 +369,17 @@ void CuttlefishGFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, in
|
|
|
358
369
|
}
|
|
359
370
|
|
|
360
371
|
void CuttlefishGFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) {
|
|
372
|
+
if (w <= 0 || h <= 0) return;
|
|
373
|
+
if (r <= 0) {
|
|
374
|
+
fillRect(x, y, w, h, color);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const int16_t halfMin = static_cast<int16_t>((w < h ? w : h) / 2);
|
|
378
|
+
if (r > halfMin) r = halfMin;
|
|
361
379
|
fillRect(x + r, y, w - 2 * r, h, color);
|
|
380
|
+
// h - 2*r - 1 stays unclamped: for a perfect pill (h == 2r) it is -1 and the
|
|
381
|
+
// helper's +1+delta lands the arc lines exactly on the box (the preview
|
|
382
|
+
// host-gfx passes the same unclamped value).
|
|
362
383
|
fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
|
|
363
384
|
fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
|
|
364
385
|
}
|