@typecad/ui 1.0.0-alpha.7 → 1.0.0-alpha.8
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 +6 -0
- package/dist/engine-index.js +0 -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 +32 -65
- 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.js +59 -29
- 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 +48 -6
- 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 +19 -16
- package/dist/ui-engine/runtime-header/node-decoration.js +8 -8
- 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 -14
- 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 +299 -747
- 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 +42 -40
- package/dist/ui-engine/runtime-header/types-defines.js +23 -3
- package/dist/ui-engine/runtime-header.js +2 -0
- 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 +4 -23
- package/dist/ui-engine/ui-registry.js +1 -7
- package/package.json +2 -2
- package/src/engine-index.ts +0 -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 +32 -65
- 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 +59 -29
- 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 +48 -6
- 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 +19 -16
- package/src/ui-engine/runtime-header/node-decoration.ts +8 -8
- 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 -14
- 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 +299 -747
- 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 +42 -40
- package/src/ui-engine/runtime-header/types-defines.ts +23 -3
- package/src/ui-engine/runtime-header.ts +2 -0
- 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 +3 -25
- package/src/ui-engine/ui-registry.ts +1 -8
- 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
|
@@ -3,12 +3,54 @@
|
|
|
3
3
|
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
4
|
export function emitImageDrawing(): string {
|
|
5
5
|
return `
|
|
6
|
-
// ── Full-screen framebuffer (opt-in PSRAM
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
6
|
+
// ── Full-screen framebuffer (opt-in PSRAM composition path) ──────────────────
|
|
7
|
+
// Composes a complete frame off-screen so navigation and dirty-node updates do
|
|
8
|
+
// not expose intermediate clears/primitive writes. The panel still receives a
|
|
9
|
+
// sequential SPI transfer; without a TE/vblank signal this is a strong tearing
|
|
10
|
+
// reduction, not a strict hardware-level tear-free guarantee.
|
|
10
11
|
static CuttlefishCanvas16* __ui_fb = nullptr;
|
|
11
12
|
static uint8_t __ui_fb_tried = 0; // 0 = not yet attempted, 1 = alloc attempted
|
|
13
|
+
// Dirty bounds for the retained framebuffer. A local touch update should not
|
|
14
|
+
// retransmit the entire panel: the full-frame burst is long enough to look like
|
|
15
|
+
// a brightness dip on SPI TFTs even though the framebuffer itself is coherent.
|
|
16
|
+
static uint8_t __ui_fb_dirty = 0;
|
|
17
|
+
static int16_t __ui_fb_dirty_x0 = 0;
|
|
18
|
+
static int16_t __ui_fb_dirty_y0 = 0;
|
|
19
|
+
static int16_t __ui_fb_dirty_x1 = 0;
|
|
20
|
+
static int16_t __ui_fb_dirty_y1 = 0;
|
|
21
|
+
|
|
22
|
+
static inline void ui_fb_begin_frame() {
|
|
23
|
+
__ui_fb_dirty = 0;
|
|
24
|
+
__ui_fb_dirty_x0 = display_width();
|
|
25
|
+
__ui_fb_dirty_y0 = display_height();
|
|
26
|
+
__ui_fb_dirty_x1 = 0;
|
|
27
|
+
__ui_fb_dirty_y1 = 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static inline void ui_fb_add_rect(int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
31
|
+
if (w <= 0 || h <= 0) return;
|
|
32
|
+
int16_t x0 = x < 0 ? 0 : x;
|
|
33
|
+
int16_t y0 = y < 0 ? 0 : y;
|
|
34
|
+
int16_t x1 = x + w;
|
|
35
|
+
int16_t y1 = y + h;
|
|
36
|
+
int16_t dw = display_width();
|
|
37
|
+
int16_t dh = display_height();
|
|
38
|
+
if (x1 > dw) x1 = dw;
|
|
39
|
+
if (y1 > dh) y1 = dh;
|
|
40
|
+
if (x0 >= x1 || y0 >= y1) return;
|
|
41
|
+
if (!__ui_fb_dirty) {
|
|
42
|
+
__ui_fb_dirty_x0 = x0;
|
|
43
|
+
__ui_fb_dirty_y0 = y0;
|
|
44
|
+
__ui_fb_dirty_x1 = x1;
|
|
45
|
+
__ui_fb_dirty_y1 = y1;
|
|
46
|
+
__ui_fb_dirty = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (x0 < __ui_fb_dirty_x0) __ui_fb_dirty_x0 = x0;
|
|
50
|
+
if (y0 < __ui_fb_dirty_y0) __ui_fb_dirty_y0 = y0;
|
|
51
|
+
if (x1 > __ui_fb_dirty_x1) __ui_fb_dirty_x1 = x1;
|
|
52
|
+
if (y1 > __ui_fb_dirty_y1) __ui_fb_dirty_y1 = y1;
|
|
53
|
+
}
|
|
12
54
|
|
|
13
55
|
// Get the framebuffer, allocating once (in PSRAM when available). Returns null
|
|
14
56
|
// when PSRAM is absent or the allocation failed — callers fall back to direct.
|
|
@@ -31,14 +73,42 @@ static inline CuttlefishCanvas16* ui_get_framebuffer() {
|
|
|
31
73
|
return __ui_fb;
|
|
32
74
|
}
|
|
33
75
|
|
|
34
|
-
// Push the
|
|
76
|
+
// Push only the changed framebuffer bounds. Rows are sent separately when the
|
|
77
|
+
// dirty union is narrower than the framebuffer because the source canvas has a
|
|
78
|
+
// wider stride than the panel window. Each row is complete before it reaches
|
|
79
|
+
// the panel, and the display adapter can synchronize each window to scanline.
|
|
35
80
|
static inline void ui_push_framebuffer() {
|
|
36
|
-
if (!__ui_fb || !display_canvasBuffer(__ui_fb)) return;
|
|
37
|
-
int16_t
|
|
38
|
-
int16_t
|
|
81
|
+
if (!__ui_fb || !display_canvasBuffer(__ui_fb) || !__ui_fb_dirty) return;
|
|
82
|
+
int16_t fw = display_canvasWidth(__ui_fb);
|
|
83
|
+
int16_t fh = display_canvasHeight(__ui_fb);
|
|
84
|
+
int16_t x = __ui_fb_dirty_x0;
|
|
85
|
+
int16_t y = __ui_fb_dirty_y0;
|
|
86
|
+
int16_t w = static_cast<int16_t>(__ui_fb_dirty_x1 - x);
|
|
87
|
+
int16_t h = static_cast<int16_t>(__ui_fb_dirty_y1 - y);
|
|
88
|
+
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x >= fw || y >= fh) return;
|
|
89
|
+
if (x + w > fw) w = static_cast<int16_t>(fw - x);
|
|
90
|
+
if (y + h > fh) h = static_cast<int16_t>(fh - y);
|
|
91
|
+
// Use the panel's native bulk-pixel path, not drawRGBBitmap(). The native
|
|
92
|
+
// CuttlefishGFX implementation of drawRGBBitmap is intentionally generic and
|
|
93
|
+
// emits one writePixel transaction per pixel; using it for a retained-frame
|
|
94
|
+
// flush turns a small local update into hundreds of visible SPI flashes.
|
|
95
|
+
UI_COLOR_T* pixels = display_canvasBuffer(__ui_fb);
|
|
39
96
|
display_startWrite();
|
|
40
|
-
|
|
41
|
-
|
|
97
|
+
if (x == 0 && w == fw) {
|
|
98
|
+
// Full-width rows are contiguous and can use one bulk write.
|
|
99
|
+
display_setAddrWindow(x, y, w, h);
|
|
100
|
+
display_writePixels(pixels + static_cast<int32_t>(y) * fw,
|
|
101
|
+
static_cast<uint32_t>(w) * h);
|
|
102
|
+
} else {
|
|
103
|
+
// Narrow dirty bounds require one row at a time because the source stride
|
|
104
|
+
// is fw while each destination window is only w pixels wide.
|
|
105
|
+
for (int16_t row = 0; row < h; row++) {
|
|
106
|
+
display_setAddrWindow(x, static_cast<int16_t>(y + row), w, 1);
|
|
107
|
+
display_writePixels(
|
|
108
|
+
pixels + static_cast<int32_t>(y + row) * fw + x,
|
|
109
|
+
static_cast<uint32_t>(w));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
42
112
|
display_endWrite();
|
|
43
113
|
}
|
|
44
114
|
|
|
@@ -82,8 +152,8 @@ static inline void ui_draw_image_with_fit(const UIImage* img, int16_t x, int16_t
|
|
|
82
152
|
offX = 0;
|
|
83
153
|
offY = 0;
|
|
84
154
|
} else if (fitMode == 2 || fitMode == 3 || fitMode == 4) {
|
|
85
|
-
int32_t scaleX = ((
|
|
86
|
-
int32_t scaleY = ((
|
|
155
|
+
int32_t scaleX = (static_cast<int32_t>(targetW) * 1000) / srcW;
|
|
156
|
+
int32_t scaleY = (static_cast<int32_t>(targetH) * 1000) / srcH;
|
|
87
157
|
if (scaleX < 1) scaleX = 1;
|
|
88
158
|
if (scaleY < 1) scaleY = 1;
|
|
89
159
|
int32_t scale = scaleX;
|
|
@@ -95,8 +165,8 @@ static inline void ui_draw_image_with_fit(const UIImage* img, int16_t x, int16_t
|
|
|
95
165
|
if (scaleY < scaleX) scale = scaleY;
|
|
96
166
|
if (scale > 1000) scale = 1000;
|
|
97
167
|
}
|
|
98
|
-
drawW =
|
|
99
|
-
drawH =
|
|
168
|
+
drawW = static_cast<int16_t>(static_cast<int32_t>(srcW) * scale / 1000);
|
|
169
|
+
drawH = static_cast<int16_t>(static_cast<int32_t>(srcH) * scale / 1000);
|
|
100
170
|
if (drawW < 1) drawW = 1;
|
|
101
171
|
if (drawH < 1) drawH = 1;
|
|
102
172
|
if (fitMode == 3) {
|
|
@@ -115,40 +185,40 @@ static inline void ui_draw_image_with_fit(const UIImage* img, int16_t x, int16_t
|
|
|
115
185
|
if (!ui_clip_rect_to_display_target(&clipX, &clipY, &clipW, &clipH)) return;
|
|
116
186
|
int16_t txStart = 0, txEnd = targetW, tyStart = 0, tyEnd = targetH;
|
|
117
187
|
if (q == 0) {
|
|
118
|
-
txStart = ui_clamp_i16(
|
|
119
|
-
txEnd = ui_clamp_i16(
|
|
120
|
-
tyStart = ui_clamp_i16(
|
|
121
|
-
tyEnd = ui_clamp_i16(
|
|
188
|
+
txStart = ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, targetW);
|
|
189
|
+
txEnd = ui_clamp_i16(static_cast<int16_t>(clipX + clipW - x), 0, targetW);
|
|
190
|
+
tyStart = ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, targetH);
|
|
191
|
+
tyEnd = ui_clamp_i16(static_cast<int16_t>(clipY + clipH - y), 0, targetH);
|
|
122
192
|
} else if (q == 1) {
|
|
123
|
-
txStart = ui_clamp_i16(
|
|
124
|
-
txEnd = ui_clamp_i16(
|
|
125
|
-
tyStart = ui_clamp_i16(
|
|
126
|
-
tyEnd = ui_clamp_i16(
|
|
193
|
+
txStart = ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, targetW);
|
|
194
|
+
txEnd = ui_clamp_i16(static_cast<int16_t>(clipY + clipH - y), 0, targetW);
|
|
195
|
+
tyStart = ui_clamp_i16(static_cast<int16_t>(x + targetH - (clipX + clipW)), 0, targetH);
|
|
196
|
+
tyEnd = ui_clamp_i16(static_cast<int16_t>(x + targetH - clipX), 0, targetH);
|
|
127
197
|
} else if (q == 2) {
|
|
128
|
-
txStart = ui_clamp_i16(
|
|
129
|
-
txEnd = ui_clamp_i16(
|
|
130
|
-
tyStart = ui_clamp_i16(
|
|
131
|
-
tyEnd = ui_clamp_i16(
|
|
198
|
+
txStart = ui_clamp_i16(static_cast<int16_t>(x + targetW - (clipX + clipW)), 0, targetW);
|
|
199
|
+
txEnd = ui_clamp_i16(static_cast<int16_t>(x + targetW - clipX), 0, targetW);
|
|
200
|
+
tyStart = ui_clamp_i16(static_cast<int16_t>(y + targetH - (clipY + clipH)), 0, targetH);
|
|
201
|
+
tyEnd = ui_clamp_i16(static_cast<int16_t>(y + targetH - clipY), 0, targetH);
|
|
132
202
|
} else {
|
|
133
|
-
txStart = ui_clamp_i16(
|
|
134
|
-
txEnd = ui_clamp_i16(
|
|
135
|
-
tyStart = ui_clamp_i16(
|
|
136
|
-
tyEnd = ui_clamp_i16(
|
|
203
|
+
txStart = ui_clamp_i16(static_cast<int16_t>(y + targetW - (clipY + clipH)), 0, targetW);
|
|
204
|
+
txEnd = ui_clamp_i16(static_cast<int16_t>(y + targetW - clipY), 0, targetW);
|
|
205
|
+
tyStart = ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, targetH);
|
|
206
|
+
tyEnd = ui_clamp_i16(static_cast<int16_t>(clipX + clipW - x), 0, targetH);
|
|
137
207
|
}
|
|
138
208
|
if (txStart >= txEnd || tyStart >= tyEnd) return;
|
|
139
209
|
for (int16_t ty = tyStart; ty < tyEnd; ty++) {
|
|
140
210
|
int16_t localY = ty - offY;
|
|
141
211
|
if (localY < 0 || localY >= drawH) continue;
|
|
142
|
-
int16_t srcY = ((
|
|
212
|
+
int16_t srcY = (static_cast<int32_t>(localY) * srcH) / drawH;
|
|
143
213
|
if (srcY < 0) srcY = 0;
|
|
144
214
|
if (srcY >= srcH) srcY = srcH - 1;
|
|
145
215
|
for (int16_t tx = txStart; tx < txEnd; tx++) {
|
|
146
216
|
int16_t localX = tx - offX;
|
|
147
217
|
if (localX < 0 || localX >= drawW) continue;
|
|
148
|
-
int16_t srcX = ((
|
|
218
|
+
int16_t srcX = (static_cast<int32_t>(localX) * srcW) / drawW;
|
|
149
219
|
if (srcX < 0) srcX = 0;
|
|
150
220
|
if (srcX >= srcW) srcX = srcW - 1;
|
|
151
|
-
UI_COLOR_T color = img->data[(
|
|
221
|
+
UI_COLOR_T color = img->data[static_cast<int32_t>(srcY) * srcW + srcX];
|
|
152
222
|
int16_t dx = tx;
|
|
153
223
|
int16_t dy = ty;
|
|
154
224
|
if (q == 1) {
|
|
@@ -177,43 +247,43 @@ static inline void ui_draw_scaled_image(const UIImage* img, int16_t x, int16_t y
|
|
|
177
247
|
if (!ui_clip_rect_to_display_target(&clipX, &clipY, &clipW, &clipH)) return;
|
|
178
248
|
int16_t dxStart = 0, dxEnd = drawW, dyStart = 0, dyEnd = drawH;
|
|
179
249
|
if (q == 0) {
|
|
180
|
-
dxStart = ui_clamp_i16(
|
|
181
|
-
dxEnd = ui_clamp_i16(
|
|
182
|
-
dyStart = ui_clamp_i16(
|
|
183
|
-
dyEnd = ui_clamp_i16(
|
|
250
|
+
dxStart = ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, drawW);
|
|
251
|
+
dxEnd = ui_clamp_i16(static_cast<int16_t>(clipX + clipW - x), 0, drawW);
|
|
252
|
+
dyStart = ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, drawH);
|
|
253
|
+
dyEnd = ui_clamp_i16(static_cast<int16_t>(clipY + clipH - y), 0, drawH);
|
|
184
254
|
} else if (q == 1) {
|
|
185
|
-
dxStart = ui_clamp_i16(
|
|
186
|
-
dxEnd = ui_clamp_i16(
|
|
187
|
-
dyStart = ui_clamp_i16(
|
|
188
|
-
dyEnd = ui_clamp_i16(
|
|
255
|
+
dxStart = ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, drawW);
|
|
256
|
+
dxEnd = ui_clamp_i16(static_cast<int16_t>(clipY + clipH - y), 0, drawW);
|
|
257
|
+
dyStart = ui_clamp_i16(static_cast<int16_t>(x + drawH - (clipX + clipW)), 0, drawH);
|
|
258
|
+
dyEnd = ui_clamp_i16(static_cast<int16_t>(x + drawH - clipX), 0, drawH);
|
|
189
259
|
} else if (q == 2) {
|
|
190
|
-
dxStart = ui_clamp_i16(
|
|
191
|
-
dxEnd = ui_clamp_i16(
|
|
192
|
-
dyStart = ui_clamp_i16(
|
|
193
|
-
dyEnd = ui_clamp_i16(
|
|
260
|
+
dxStart = ui_clamp_i16(static_cast<int16_t>(x + drawW - (clipX + clipW)), 0, drawW);
|
|
261
|
+
dxEnd = ui_clamp_i16(static_cast<int16_t>(x + drawW - clipX), 0, drawW);
|
|
262
|
+
dyStart = ui_clamp_i16(static_cast<int16_t>(y + drawH - (clipY + clipH)), 0, drawH);
|
|
263
|
+
dyEnd = ui_clamp_i16(static_cast<int16_t>(y + drawH - clipY), 0, drawH);
|
|
194
264
|
} else {
|
|
195
|
-
dxStart = ui_clamp_i16(
|
|
196
|
-
dxEnd = ui_clamp_i16(
|
|
197
|
-
dyStart = ui_clamp_i16(
|
|
198
|
-
dyEnd = ui_clamp_i16(
|
|
265
|
+
dxStart = ui_clamp_i16(static_cast<int16_t>(y + drawW - (clipY + clipH)), 0, drawW);
|
|
266
|
+
dxEnd = ui_clamp_i16(static_cast<int16_t>(y + drawW - clipY), 0, drawW);
|
|
267
|
+
dyStart = ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, drawH);
|
|
268
|
+
dyEnd = ui_clamp_i16(static_cast<int16_t>(clipX + clipW - x), 0, drawH);
|
|
199
269
|
}
|
|
200
270
|
if (dxStart >= dxEnd || dyStart >= dyEnd) return;
|
|
201
271
|
if (q == 0) {
|
|
202
272
|
// Simple case: no rotation, draw with scaling
|
|
203
273
|
if (drawW == img->w && drawH == img->h) {
|
|
204
|
-
int16_t rows =
|
|
205
|
-
int16_t cols =
|
|
274
|
+
int16_t rows = static_cast<int16_t>(dyEnd - dyStart);
|
|
275
|
+
int16_t cols = static_cast<int16_t>(dxEnd - dxStart);
|
|
206
276
|
for (int16_t row = 0; row < rows; row++) {
|
|
207
|
-
ui_display_draw_rgb_bitmap(
|
|
208
|
-
img->data +
|
|
277
|
+
ui_display_draw_rgb_bitmap(static_cast<int16_t>(x + dxStart), static_cast<int16_t>(y + dyStart + row),
|
|
278
|
+
img->data + static_cast<int32_t>(dyStart + row) * img->w + dxStart, cols, 1);
|
|
209
279
|
}
|
|
210
280
|
} else {
|
|
211
281
|
// Scale using nearest-neighbor
|
|
212
282
|
for (int16_t dy = dyStart; dy < dyEnd; dy++) {
|
|
213
|
-
int16_t srcY = ((
|
|
283
|
+
int16_t srcY = (static_cast<int32_t>(dy) * img->h) / drawH;
|
|
214
284
|
for (int16_t dx = dxStart; dx < dxEnd; dx++) {
|
|
215
|
-
int16_t srcX = ((
|
|
216
|
-
UI_COLOR_T color = img->data[(
|
|
285
|
+
int16_t srcX = (static_cast<int32_t>(dx) * img->w) / drawW;
|
|
286
|
+
UI_COLOR_T color = img->data[static_cast<int32_t>(srcY) * img->w + srcX];
|
|
217
287
|
ui_display_draw_pixel(x + dx, y + dy, color);
|
|
218
288
|
}
|
|
219
289
|
}
|
|
@@ -221,10 +291,10 @@ static inline void ui_draw_scaled_image(const UIImage* img, int16_t x, int16_t y
|
|
|
221
291
|
return;
|
|
222
292
|
}
|
|
223
293
|
for (int16_t dy = dyStart; dy < dyEnd; dy++) {
|
|
224
|
-
int16_t srcY = ((
|
|
294
|
+
int16_t srcY = (static_cast<int32_t>(dy) * img->h) / drawH;
|
|
225
295
|
for (int16_t dx = dxStart; dx < dxEnd; dx++) {
|
|
226
|
-
int16_t srcX = ((
|
|
227
|
-
UI_COLOR_T color = img->data[(
|
|
296
|
+
int16_t srcX = (static_cast<int32_t>(dx) * img->w) / drawW;
|
|
297
|
+
UI_COLOR_T color = img->data[static_cast<int32_t>(srcY) * img->w + srcX];
|
|
228
298
|
int16_t rdx = 0, rdy = 0;
|
|
229
299
|
if (q == 1) {
|
|
230
300
|
rdx = drawH - 1 - dy;
|
|
@@ -249,48 +319,48 @@ static inline void ui_draw_image_rotated(const UIImage* img, int16_t x, int16_t
|
|
|
249
319
|
int16_t clipH = (q == 1 || q == 3) ? img->w : img->h;
|
|
250
320
|
if (!ui_clip_rect_to_display_target(&clipX, &clipY, &clipW, &clipH)) return;
|
|
251
321
|
if (q == 0) {
|
|
252
|
-
int16_t sx0 = ui_clamp_i16(
|
|
253
|
-
int16_t sy0 = ui_clamp_i16(
|
|
254
|
-
int16_t sw = ui_clamp_i16(clipW, 0,
|
|
255
|
-
int16_t sh = ui_clamp_i16(clipH, 0,
|
|
322
|
+
int16_t sx0 = ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, static_cast<int16_t>(img->w));
|
|
323
|
+
int16_t sy0 = ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, static_cast<int16_t>(img->h));
|
|
324
|
+
int16_t sw = ui_clamp_i16(clipW, 0, static_cast<int16_t>(img->w - sx0));
|
|
325
|
+
int16_t sh = ui_clamp_i16(clipH, 0, static_cast<int16_t>(img->h - sy0));
|
|
256
326
|
for (int16_t row = 0; row < sh; row++) {
|
|
257
|
-
ui_display_draw_rgb_bitmap(
|
|
258
|
-
img->data +
|
|
327
|
+
ui_display_draw_rgb_bitmap(static_cast<int16_t>(x + sx0), static_cast<int16_t>(y + sy0 + row),
|
|
328
|
+
img->data + static_cast<int32_t>(sy0 + row) * img->w + sx0, sw, 1);
|
|
259
329
|
}
|
|
260
330
|
return;
|
|
261
331
|
}
|
|
262
332
|
uint16_t sxStart = 0, sxEnd = img->w, syStart = 0, syEnd = img->h;
|
|
263
333
|
if (q == 1) {
|
|
264
|
-
sxStart = (
|
|
265
|
-
sxEnd = (
|
|
266
|
-
syStart = (
|
|
267
|
-
syEnd = (
|
|
334
|
+
sxStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(clipY - y), 0, static_cast<int16_t>(img->w)));
|
|
335
|
+
sxEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(clipY + clipH - y), 0, static_cast<int16_t>(img->w)));
|
|
336
|
+
syStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(x + img->h - (clipX + clipW)), 0, static_cast<int16_t>(img->h)));
|
|
337
|
+
syEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(x + img->h - clipX), 0, static_cast<int16_t>(img->h)));
|
|
268
338
|
} else if (q == 2) {
|
|
269
|
-
sxStart = (
|
|
270
|
-
sxEnd = (
|
|
271
|
-
syStart = (
|
|
272
|
-
syEnd = (
|
|
339
|
+
sxStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(x + img->w - (clipX + clipW)), 0, static_cast<int16_t>(img->w)));
|
|
340
|
+
sxEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(x + img->w - clipX), 0, static_cast<int16_t>(img->w)));
|
|
341
|
+
syStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(y + img->h - (clipY + clipH)), 0, static_cast<int16_t>(img->h)));
|
|
342
|
+
syEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(y + img->h - clipY), 0, static_cast<int16_t>(img->h)));
|
|
273
343
|
} else {
|
|
274
|
-
sxStart = (
|
|
275
|
-
sxEnd = (
|
|
276
|
-
syStart = (
|
|
277
|
-
syEnd = (
|
|
344
|
+
sxStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(y + img->w - (clipY + clipH)), 0, static_cast<int16_t>(img->w)));
|
|
345
|
+
sxEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(y + img->w - clipY), 0, static_cast<int16_t>(img->w)));
|
|
346
|
+
syStart = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(clipX - x), 0, static_cast<int16_t>(img->h)));
|
|
347
|
+
syEnd = static_cast<uint16_t>(ui_clamp_i16(static_cast<int16_t>(clipX + clipW - x), 0, static_cast<int16_t>(img->h)));
|
|
278
348
|
}
|
|
279
349
|
if (sxStart >= sxEnd || syStart >= syEnd) return;
|
|
280
350
|
for (uint16_t sy = syStart; sy < syEnd; sy++) {
|
|
281
351
|
for (uint16_t sx = sxStart; sx < sxEnd; sx++) {
|
|
282
|
-
UI_COLOR_T color = img->data[(
|
|
352
|
+
UI_COLOR_T color = img->data[static_cast<uint32_t>(sy) * img->w + sx];
|
|
283
353
|
int16_t dx = 0;
|
|
284
354
|
int16_t dy = 0;
|
|
285
355
|
if (q == 1) {
|
|
286
|
-
dx =
|
|
287
|
-
dy = (
|
|
356
|
+
dx = static_cast<int16_t>(img->h - 1 - sy);
|
|
357
|
+
dy = static_cast<int16_t>(sx);
|
|
288
358
|
} else if (q == 2) {
|
|
289
|
-
dx =
|
|
290
|
-
dy =
|
|
359
|
+
dx = static_cast<int16_t>(img->w - 1 - sx);
|
|
360
|
+
dy = static_cast<int16_t>(img->h - 1 - sy);
|
|
291
361
|
} else {
|
|
292
|
-
dx = (
|
|
293
|
-
dy =
|
|
362
|
+
dx = static_cast<int16_t>(sy);
|
|
363
|
+
dy = static_cast<int16_t>(img->w - 1 - sx);
|
|
294
364
|
}
|
|
295
365
|
ui_display_draw_pixel(x + dx, y + dy, color);
|
|
296
366
|
}
|
|
@@ -13,15 +13,22 @@ static inline void ui_init(void) {
|
|
|
13
13
|
// containers start locked until the scroll-container loop proves their
|
|
14
14
|
// canvas fits.
|
|
15
15
|
if (!__ui_scroll_canvas_ok && __ui_node_count > 0) {
|
|
16
|
-
__ui_scroll_canvas_ok = (uint8_t
|
|
16
|
+
__ui_scroll_canvas_ok = new (std::nothrow) uint8_t[__ui_node_count]();
|
|
17
17
|
}
|
|
18
|
-
if (!
|
|
19
|
-
|
|
18
|
+
if (!__ui_scroll_render_locked && __ui_node_count > 0) {
|
|
19
|
+
__ui_scroll_render_locked = new (std::nothrow) uint8_t[__ui_node_count]();
|
|
20
20
|
}
|
|
21
21
|
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
22
22
|
__ui_nodes[i].dirty = 1;
|
|
23
23
|
__ui_nodes[i].lastTextHeight = 0;
|
|
24
24
|
__ui_nodes[i].layoutCacheKey = 0;
|
|
25
|
+
if (__ui_nodes[i].scrollable) {
|
|
26
|
+
// Force the first scroll-canvas composition to seed every pixel. After
|
|
27
|
+
// that, a dirty child can be repaired in place without repainting the
|
|
28
|
+
// entire viewport.
|
|
29
|
+
__ui_nodes[i].lastPaintedScrollY = static_cast<int16_t>(
|
|
30
|
+
__ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1));
|
|
31
|
+
}
|
|
25
32
|
if (__ui_nodes[i].kind == NODE_PROGRESS || __ui_nodes[i].kind == NODE_RANGE) {
|
|
26
33
|
__ui_nodes[i].lastTextWidth = -1;
|
|
27
34
|
}
|
|
@@ -32,6 +39,11 @@ static inline void ui_init(void) {
|
|
|
32
39
|
__ui_nodes[n].hasTextBinding = 1;
|
|
33
40
|
strncpy(__ui_nodes[n].textBuffer, __ui_nodes[n].text ? __ui_nodes[n].text : "", UI_TEXT_BUF);
|
|
34
41
|
__ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
|
|
42
|
+
} else if (__ui_bindings[i].fn) {
|
|
43
|
+
// Prime numeric binding caches once at setup; the first tick can then skip
|
|
44
|
+
// redundant assignments and dirty propagation when values are unchanged.
|
|
45
|
+
__ui_bindings[i].lastValue = __ui_bindings[i].fn();
|
|
46
|
+
__ui_bindings[i].initialized = 1;
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
// Seed virtualized-list runtime state. The fn pointers can't be baked into
|
|
@@ -52,7 +64,7 @@ static inline void ui_init(void) {
|
|
|
52
64
|
uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
|
|
53
65
|
uint16_t cnt = __ui_nodes[i].listCountFn();
|
|
54
66
|
__ui_nodes[i].listCount = cnt;
|
|
55
|
-
__ui_nodes[i].contentHeight =
|
|
67
|
+
__ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(cnt) * ih);
|
|
56
68
|
__ui_nodes[i].scrollY = 0;
|
|
57
69
|
__ui_nodes[i].overscrollPx = 0;
|
|
58
70
|
__ui_nodes[i].settling = 0;
|
|
@@ -61,6 +73,9 @@ static inline void ui_init(void) {
|
|
|
61
73
|
ui_build_draw_order();
|
|
62
74
|
ui_build_scroll_owner_table();
|
|
63
75
|
ui_refresh_active_screen_bg_node();
|
|
76
|
+
if (!__ui_scroll_candidates && __ui_node_count > 0) {
|
|
77
|
+
__ui_scroll_candidates = new (std::nothrow) UIScrollPaintCandidate[__ui_node_count];
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
// Debounce: ignore press/release events within 50ms of the last edge.
|
|
@@ -99,7 +114,7 @@ static inline void ui_on_release(uint16_t nodeIdx) {
|
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
// Pin-watch callback type: void fn(void)
|
|
102
|
-
|
|
117
|
+
using PinWatchCallback = void (*)(void);
|
|
103
118
|
|
|
104
119
|
struct UIPinWatch {
|
|
105
120
|
uint8_t pin;
|
|
@@ -49,7 +49,7 @@ static inline void ui_kb_insert(char c) {
|
|
|
49
49
|
if (__ui_kb_target >= 0) {
|
|
50
50
|
strncpy(__ui_nodes[__ui_kb_target].textBuffer, __ui_kb_buffer, UI_TEXT_BUF);
|
|
51
51
|
__ui_nodes[__ui_kb_target].textBuffer[UI_TEXT_BUF] = 0;
|
|
52
|
-
ui_mark_dirty((
|
|
52
|
+
ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
|
|
53
53
|
}
|
|
54
54
|
#endif
|
|
55
55
|
}
|
|
@@ -62,7 +62,7 @@ static inline void ui_kb_delete() {
|
|
|
62
62
|
if (__ui_kb_target >= 0) {
|
|
63
63
|
strncpy(__ui_nodes[__ui_kb_target].textBuffer, __ui_kb_buffer, UI_TEXT_BUF);
|
|
64
64
|
__ui_nodes[__ui_kb_target].textBuffer[UI_TEXT_BUF] = 0;
|
|
65
|
-
ui_mark_dirty((
|
|
65
|
+
ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
|
|
66
66
|
}
|
|
67
67
|
#endif
|
|
68
68
|
}
|
|
@@ -92,7 +92,7 @@ static inline void ui_kb_open(uint16_t nodeIdx, uint8_t inputPosition) {
|
|
|
92
92
|
__ui_kb_buffer[UI_TEXT_BUF] = 0;
|
|
93
93
|
__ui_kb_len = strlen(__ui_kb_buffer);
|
|
94
94
|
uint16_t ml = __ui_nodes[nodeIdx].maxlen;
|
|
95
|
-
__ui_kb_maxlen = (ml > 0 && ml <= UI_TEXT_BUF) ? (
|
|
95
|
+
__ui_kb_maxlen = (ml > 0 && ml <= UI_TEXT_BUF) ? static_cast<uint8_t>(ml) : UI_TEXT_BUF;
|
|
96
96
|
__ui_kb_shift = 0;
|
|
97
97
|
__ui_kb_bs_held = 0;
|
|
98
98
|
// Load the key set via the dispatch table.
|
|
@@ -113,7 +113,7 @@ static inline void ui_kb_open(uint16_t nodeIdx, uint8_t inputPosition) {
|
|
|
113
113
|
// keystroke. (The full-screen-flash concern above doesn't apply — there's no
|
|
114
114
|
// opaque overlay being skipped.) Seed the blink phase so the caret is ON for
|
|
115
115
|
// the first ~530ms (bit 0x20 set → visible), so focus feels immediate.
|
|
116
|
-
if (__ui_kb_target >= 0) ui_mark_dirty((
|
|
116
|
+
if (__ui_kb_target >= 0) ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
|
|
117
117
|
__ui_kb_blink = 0x20;
|
|
118
118
|
#endif
|
|
119
119
|
}
|
|
@@ -140,7 +140,7 @@ static inline void ui_kb_close() {
|
|
|
140
140
|
int16_t screenRoot = -1;
|
|
141
141
|
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
142
142
|
if (__ui_nodes[i].parent == UI_NO_PARENT && __ui_nodes[i].screenId == __ui_active_screen) {
|
|
143
|
-
screenRoot = (
|
|
143
|
+
screenRoot = static_cast<int16_t>(i);
|
|
144
144
|
break;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -156,7 +156,7 @@ static inline void ui_kb_close() {
|
|
|
156
156
|
// scroll clipping — safe here since these nodes are bounded in size, unlike
|
|
157
157
|
// the screen root.
|
|
158
158
|
for (uint16_t i = 0; i < __ui_node_count; i++) {
|
|
159
|
-
if ((
|
|
159
|
+
if (static_cast<int16_t>(i) == screenRoot) continue;
|
|
160
160
|
UIRect r;
|
|
161
161
|
ui_node_current_paint_rect(i, &r);
|
|
162
162
|
if (r.w > 0 && r.h > 0 &&
|
|
@@ -173,8 +173,8 @@ static inline void ui_kb_key_rect(uint8_t idx, UIRect* out) {
|
|
|
173
173
|
uint8_t col = idx % __ui_kb_cols;
|
|
174
174
|
uint8_t row = idx / __ui_kb_cols;
|
|
175
175
|
int16_t keysH = __ui_kb_box.h - UI_KB_TEXT_H; // key area height (below text row)
|
|
176
|
-
out->x = __ui_kb_box.x + (
|
|
177
|
-
out->y = __ui_kb_box.y + UI_KB_TEXT_H + (
|
|
176
|
+
out->x = __ui_kb_box.x + static_cast<int16_t>(col) * __ui_kb_box.w / __ui_kb_cols;
|
|
177
|
+
out->y = __ui_kb_box.y + UI_KB_TEXT_H + static_cast<int16_t>(row) * keysH / __ui_kb_rows;
|
|
178
178
|
out->w = __ui_kb_box.w / __ui_kb_cols;
|
|
179
179
|
out->h = keysH / __ui_kb_rows;
|
|
180
180
|
}
|
|
@@ -192,8 +192,8 @@ static inline void ui_kb_handle_touch(int16_t tx, int16_t ty) {
|
|
|
192
192
|
UIRect r;
|
|
193
193
|
ui_kb_key_rect(i, &r);
|
|
194
194
|
if (tx >= r.x && tx < r.x + r.w && ty >= r.y && ty < r.y + r.h) {
|
|
195
|
-
__ui_kb_pressed_key = (
|
|
196
|
-
__ui_kb_repaint_key = (
|
|
195
|
+
__ui_kb_pressed_key = static_cast<int8_t>(i); // remember for release
|
|
196
|
+
__ui_kb_repaint_key = static_cast<int8_t>(i);
|
|
197
197
|
__ui_kb_dirty = 2; // targeted: redraw just this key's highlight
|
|
198
198
|
// Backspace starts deleting immediately + arms auto-repeat.
|
|
199
199
|
if (k.special == 2) {
|
|
@@ -273,7 +273,7 @@ static inline void ui_kb_draw_key(uint8_t i) {
|
|
|
273
273
|
UI_COLOR_T border = ks.borderColor;
|
|
274
274
|
// Shift-active highlight: brighten the shift key's background — but only
|
|
275
275
|
// when not pressed, so the press inversion stays high-contrast.
|
|
276
|
-
if (k.special == 1 && __ui_kb_shift && (
|
|
276
|
+
if (k.special == 1 && __ui_kb_shift && static_cast<int8_t>(i) != __ui_kb_pressed_key) {
|
|
277
277
|
#if UI_COLOR_DEPTH == 888
|
|
278
278
|
bg = 0xBDEFFF;
|
|
279
279
|
#else
|
|
@@ -281,7 +281,7 @@ static inline void ui_kb_draw_key(uint8_t i) {
|
|
|
281
281
|
#endif
|
|
282
282
|
}
|
|
283
283
|
// Pressed key: invert colors for clear tap feedback.
|
|
284
|
-
if ((
|
|
284
|
+
if (static_cast<int8_t>(i) == __ui_kb_pressed_key) { UI_COLOR_T t = bg; bg = fg; fg = t; }
|
|
285
285
|
ui_display_fill_rect(r.x + 1, r.y + 1, r.w - 2, r.h - 2, bg);
|
|
286
286
|
ui_display_draw_rect(r.x + 1, r.y + 1, r.w - 2, r.h - 2, border);
|
|
287
287
|
ui_display_set_text_color(fg, bg);
|
|
@@ -295,14 +295,14 @@ static inline void ui_kb_draw_key(uint8_t i) {
|
|
|
295
295
|
case 3: labelStr = "OK"; break;
|
|
296
296
|
case 4: labelStr = __ui_kb_cols <= 4 ? "ABC" : "123"; break;
|
|
297
297
|
default:
|
|
298
|
-
single[0] = (__ui_kb_shift && k.ch >= 'a' && k.ch <= 'z') ?
|
|
298
|
+
single[0] = (__ui_kb_shift && k.ch >= 'a' && k.ch <= 'z') ? static_cast<char>(k.ch - 32) : k.ch;
|
|
299
299
|
single[1] = 0;
|
|
300
300
|
labelStr = single;
|
|
301
301
|
break;
|
|
302
302
|
}
|
|
303
303
|
// Center: textW = len * 6px, textH = 8px. Position inside the key rect.
|
|
304
304
|
uint8_t len = strlen(labelStr);
|
|
305
|
-
int16_t textW = (
|
|
305
|
+
int16_t textW = static_cast<int16_t>(len) * 6;
|
|
306
306
|
int16_t textH = 8;
|
|
307
307
|
int16_t cx = r.x + (r.w - textW) / 2;
|
|
308
308
|
int16_t cy = r.y + (r.h - textH) / 2;
|
|
@@ -338,11 +338,14 @@ static inline void ui_kb_draw() {
|
|
|
338
338
|
if (kw <= 0 || kh <= 0) return;
|
|
339
339
|
// (Re)allocate the keyboard canvas to exact size (see repair-canvas comment
|
|
340
340
|
// — stride mismatch corrupts the push when reusing a differently-sized canvas).
|
|
341
|
+
// ui_create_canvas_best prefers PSRAM when available (a full-width keyboard
|
|
342
|
+
// canvas can be ~30KB, too big for no-PSRAM internal SRAM) and falls back to
|
|
343
|
+
// SRAM — same policy as the list/scroll viewport canvases.
|
|
341
344
|
if (!__ui_kb_canvas || !display_canvasBuffer(__ui_kb_canvas) ||
|
|
342
345
|
display_canvasWidth(__ui_kb_canvas) != kw ||
|
|
343
346
|
display_canvasHeight(__ui_kb_canvas) != kh) {
|
|
344
347
|
display_deleteCanvas(__ui_kb_canvas);
|
|
345
|
-
__ui_kb_canvas =
|
|
348
|
+
__ui_kb_canvas = ui_create_canvas_best(kw, kh);
|
|
346
349
|
}
|
|
347
350
|
if (!__ui_kb_canvas || !display_canvasBuffer(__ui_kb_canvas)) {
|
|
348
351
|
// Canvas alloc failed — fall back to direct draw (slow but correct).
|
|
@@ -376,7 +379,7 @@ static inline void ui_kb_draw() {
|
|
|
376
379
|
ui_display_set_target(__kb_prev_target);
|
|
377
380
|
display_startWrite();
|
|
378
381
|
display_setAddrWindow(saveBoxX, saveBoxY, kw, kh);
|
|
379
|
-
display_writePixels(display_canvasBuffer(__ui_kb_canvas), (
|
|
382
|
+
display_writePixels(display_canvasBuffer(__ui_kb_canvas), static_cast<uint32_t>(kw) * kh);
|
|
380
383
|
display_endWrite();
|
|
381
384
|
}
|
|
382
385
|
`;
|
|
@@ -18,19 +18,19 @@ static inline void ui_draw_gradient_fill(uint16_t i, int16_t drawY) {
|
|
|
18
18
|
uint8_t dir = __ui_nodes[i].gradientEnabled; // 1=vertical, 2=horizontal
|
|
19
19
|
if (dir == 1) {
|
|
20
20
|
// Vertical: top=c1, bottom=c2. Draw row by row.
|
|
21
|
-
int16_t yStart =
|
|
22
|
-
int16_t yEnd =
|
|
21
|
+
int16_t yStart = static_cast<int16_t>(clipY - by);
|
|
22
|
+
int16_t yEnd = static_cast<int16_t>(clipY + clipH - by);
|
|
23
23
|
for (int16_t y = yStart; y < yEnd; y++) {
|
|
24
|
-
uint8_t op =
|
|
24
|
+
uint8_t op = static_cast<uint8_t>(static_cast<uint16_t>(y) * 100 / (bh > 1 ? bh - 1 : 1));
|
|
25
25
|
uint32_t col = ui_blend(c1, c2, op);
|
|
26
26
|
ui_display_draw_fast_hline(clipX, by + y, clipW, col);
|
|
27
27
|
}
|
|
28
28
|
} else {
|
|
29
29
|
// Horizontal: left=c1, right=c2. Draw column by column.
|
|
30
|
-
int16_t xStart =
|
|
31
|
-
int16_t xEnd =
|
|
30
|
+
int16_t xStart = static_cast<int16_t>(clipX - bx);
|
|
31
|
+
int16_t xEnd = static_cast<int16_t>(clipX + clipW - bx);
|
|
32
32
|
for (int16_t x = xStart; x < xEnd; x++) {
|
|
33
|
-
uint8_t op =
|
|
33
|
+
uint8_t op = static_cast<uint8_t>(static_cast<uint16_t>(x) * 100 / (bw > 1 ? bw - 1 : 1));
|
|
34
34
|
uint32_t col = ui_blend(c1, c2, op);
|
|
35
35
|
ui_display_draw_fast_vline(bx + x, clipY, clipH, col);
|
|
36
36
|
}
|
|
@@ -79,7 +79,7 @@ static inline void ui_draw_shadow(uint16_t i, int16_t drawY, uint8_t insetOnly)
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
for (int8_t pass = blur; pass >= 1; pass--) {
|
|
82
|
-
uint8_t opacity =
|
|
82
|
+
uint8_t opacity = static_cast<uint8_t>(static_cast<uint16_t>(baseAlpha) / (pass + 1));
|
|
83
83
|
uint32_t col = ui_blend(shadowCol, inset ? (__ui_nodes[i].hasBg ? __ui_nodes[i].bg : clearCol) : clearCol, opacity);
|
|
84
84
|
if (inset) {
|
|
85
85
|
// Inset: draw inside the element, shrinking inward by pass.
|
|
@@ -104,7 +104,7 @@ static inline void ui_draw_shadow(uint16_t i, int16_t drawY, uint8_t insetOnly)
|
|
|
104
104
|
int16_t sw = bw + 2 * pass;
|
|
105
105
|
int16_t sh_ = bh + 2 * pass;
|
|
106
106
|
if (radius > 0) {
|
|
107
|
-
uint8_t r = radius + (
|
|
107
|
+
uint8_t r = radius + static_cast<uint8_t>(pass);
|
|
108
108
|
if (r > sw / 2) r = sw / 2;
|
|
109
109
|
if (r > sh_ / 2) r = sh_ / 2;
|
|
110
110
|
ui_display_fill_round_rect(sx, sy, sw, sh_, r, col);
|