@typecad/ui 1.0.0-alpha.7 → 1.0.0-alpha.9
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Slice of the C++ runtime header (original source lines 753-901).
|
|
2
|
-
// Persistent canvas release/create/get/shift/repair
|
|
2
|
+
// Persistent canvas release/create/get/shift/repair helpers.
|
|
3
3
|
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
4
|
export function emitCanvasHelpers() {
|
|
5
5
|
return `
|
|
@@ -10,6 +10,7 @@ static inline void ui_release_canvas_state() {
|
|
|
10
10
|
__ui_list_canvas_node = -1;
|
|
11
11
|
display_deleteCanvas(__ui_node_canvas); __ui_node_canvas = nullptr;
|
|
12
12
|
display_deleteCanvas(__ui_repair_canvas); __ui_repair_canvas = nullptr;
|
|
13
|
+
display_deleteCanvas(__ui_band_canvas); __ui_band_canvas = nullptr;
|
|
13
14
|
display_deleteCanvas(__ui_kb_canvas); __ui_kb_canvas = nullptr;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -23,7 +24,18 @@ static inline CuttlefishCanvas16* ui_create_canvas_best(int16_t w, int16_t h) {
|
|
|
23
24
|
#if defined(ESP32) && defined(BOARD_HAS_PSRAM)
|
|
24
25
|
if (psramFound()) {
|
|
25
26
|
CuttlefishCanvas16* c = display_createCanvasPsram(w, h);
|
|
26
|
-
if (c && display_canvasBuffer(c))
|
|
27
|
+
if (c && display_canvasBuffer(c)) {
|
|
28
|
+
static uint8_t psram_logged = 0;
|
|
29
|
+
if (!psram_logged) {
|
|
30
|
+
psram_logged = 1;
|
|
31
|
+
#if defined(ESP32) && defined(ARDUINO)
|
|
32
|
+
Serial.printf("[psram] canvas %dx%d allocated in PSRAM (free=%u)\n", w, h, ESP.getFreePsram());
|
|
33
|
+
#else
|
|
34
|
+
printf("[psram] canvas %dx%d allocated in PSRAM\n", w, h);
|
|
35
|
+
#endif
|
|
36
|
+
}
|
|
37
|
+
return c;
|
|
38
|
+
}
|
|
27
39
|
// PSRAM allocation failed (rare — fragmented PSRAM) → fall through to SRAM.
|
|
28
40
|
}
|
|
29
41
|
#endif
|
|
@@ -31,63 +43,18 @@ static inline CuttlefishCanvas16* ui_create_canvas_best(int16_t w, int16_t h) {
|
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
static inline CuttlefishCanvas16* ui_get_container_canvas(int16_t w, int16_t h) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
static inline const char* __ui_scroll_node_id(uint16_t idx);
|
|
47
|
-
|
|
48
|
-
// Emit a one-time Serial warning when scroll rendering cannot be accurate due
|
|
49
|
-
// to heap limits. reason: 0=canvas alloc failed, 1=viewport exceeds budget,
|
|
50
|
-
// 2=Mode C strip fallback (reduced accuracy).
|
|
51
|
-
static inline void ui_warn_scroll_memory(uint16_t nodeIdx, uint8_t reason) {
|
|
52
|
-
if (nodeIdx >= __ui_node_count) return;
|
|
53
|
-
if (!__ui_scroll_mem_warned) return;
|
|
54
|
-
if (__ui_scroll_mem_warned[nodeIdx]) return;
|
|
55
|
-
__ui_scroll_mem_warned[nodeIdx] = 1;
|
|
56
|
-
|
|
57
|
-
int16_t vw = __ui_nodes[nodeIdx].box.w;
|
|
58
|
-
int16_t vh = __ui_nodes[nodeIdx].box.h;
|
|
59
|
-
uint32_t need = (uint32_t)(vw > 0 ? vw : 0) * (uint32_t)(vh > 0 ? vh : 0) * 2u;
|
|
60
|
-
const char* id = __ui_scroll_node_id(nodeIdx);
|
|
61
|
-
const char* label = (id && id[0]) ? id : "scroll viewport";
|
|
62
|
-
const char* reasonText = "scroll canvas allocation failed";
|
|
63
|
-
if (reason == 1) reasonText = "scroll viewport exceeds compile-time canvas budget";
|
|
64
|
-
else if (reason == 2) reasonText = "using Mode C strip fallback (smooth scroll canvas unavailable)";
|
|
65
|
-
|
|
66
|
-
#if defined(ESP32) && defined(ARDUINO)
|
|
67
|
-
uint32_t freeHeap = ESP.getFreeHeap();
|
|
68
|
-
uint32_t maxAlloc = ESP.getMaxAllocHeap();
|
|
69
|
-
Serial.printf(
|
|
70
|
-
"[cuttlefish] WARNING: #%s (%dx%d) needs %lu bytes for accurate scroll — %s. "
|
|
71
|
-
"heap free=%lu max_alloc=%lu budget=%d. "
|
|
72
|
-
"Shrink the scroll viewport in CSS, trim fonts/images, or use PSRAM.\\n",
|
|
73
|
-
label, vw, vh, (unsigned long)need, reasonText,
|
|
74
|
-
(unsigned long)freeHeap, (unsigned long)maxAlloc, UI_SCROLL_CANVAS_BUDGET_BYTES);
|
|
75
|
-
#elif defined(ESP8266) && defined(ARDUINO)
|
|
76
|
-
uint32_t freeHeap = ESP.getFreeHeap();
|
|
77
|
-
Serial.printf(
|
|
78
|
-
"[cuttlefish] WARNING: #%s (%dx%d) needs %lu bytes for accurate scroll — %s. "
|
|
79
|
-
"heap free=%lu budget=%d. "
|
|
80
|
-
"Shrink the scroll viewport in CSS, trim fonts/images, or reduce UI footprint.\\n",
|
|
81
|
-
label, vw, vh, (unsigned long)need, reasonText,
|
|
82
|
-
(unsigned long)freeHeap, UI_SCROLL_CANVAS_BUDGET_BYTES);
|
|
83
|
-
#else
|
|
84
|
-
// Non-Arduino target (e.g. SDL native): no Serial, so use standard-C printf.
|
|
85
|
-
// The native framework forces <cstdio> so printf is available here.
|
|
86
|
-
printf(
|
|
87
|
-
"[cuttlefish] WARNING: #%s (%dx%d) needs %lu bytes for accurate scroll — %s. "
|
|
88
|
-
"budget=%d. Shrink the scroll viewport in CSS or trim UI assets.\\n",
|
|
89
|
-
label, vw, vh, (unsigned long)need, reasonText, UI_SCROLL_CANVAS_BUDGET_BYTES);
|
|
90
|
-
#endif
|
|
46
|
+
// Intentionally returns nullptr: scroll containers always use the band
|
|
47
|
+
// renderer (ui_render_scroll_bands), not the Mode B viewport canvas.
|
|
48
|
+
// Mode B holds the whole viewport in one large canvas and pushes it in a
|
|
49
|
+
// single transaction every frame — on SPI TFTs that full-viewport push
|
|
50
|
+
// (especially from PSRAM) visibly flashes on child state changes like a
|
|
51
|
+
// button press. The band renderer composites into a small ~10KB SRAM canvas
|
|
52
|
+
// strip-by-strip, pushing each band only after it's complete — tear-free and
|
|
53
|
+
// flash-free regardless of target memory. PSRAM still benefits the other
|
|
54
|
+
// canvases (list, keyboard, repair); only the scroll viewport deliberately
|
|
55
|
+
// bypasses it for visual quality.
|
|
56
|
+
(void)w; (void)h;
|
|
57
|
+
return nullptr;
|
|
91
58
|
}
|
|
92
59
|
|
|
93
60
|
// Shift the canvas buffer vertically by deltaY (cheap memmove of existing
|
|
@@ -118,16 +85,16 @@ static inline void ui_shift_container_canvas(CuttlefishCanvas16* canvas, int16_t
|
|
|
118
85
|
// band at the TOP. (Matches the proven pre-rewrite direction.)
|
|
119
86
|
if (deltaY > 0) {
|
|
120
87
|
for (int16_t row = 0; row < h - shift; row++) {
|
|
121
|
-
memmove(pixels + (
|
|
122
|
-
pixels +
|
|
123
|
-
(
|
|
88
|
+
memmove(pixels + static_cast<int32_t>(row) * stride,
|
|
89
|
+
pixels + static_cast<int32_t>(row + shift) * stride,
|
|
90
|
+
static_cast<size_t>(contentW) * sizeof(UI_COLOR_T));
|
|
124
91
|
}
|
|
125
92
|
if (exposedY) *exposedY = h - shift;
|
|
126
93
|
} else {
|
|
127
94
|
for (int16_t row = h - shift - 1; row >= 0; row--) {
|
|
128
|
-
memmove(pixels +
|
|
129
|
-
pixels + (
|
|
130
|
-
(
|
|
95
|
+
memmove(pixels + static_cast<int32_t>(row + shift) * stride,
|
|
96
|
+
pixels + static_cast<int32_t>(row) * stride,
|
|
97
|
+
static_cast<size_t>(contentW) * sizeof(UI_COLOR_T));
|
|
131
98
|
}
|
|
132
99
|
if (exposedY) *exposedY = 0;
|
|
133
100
|
}
|
|
@@ -13,12 +13,16 @@ static inline void ui_push_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, in
|
|
|
13
13
|
// via __ui_gfx (so the single bulk push at frame end captures everything).
|
|
14
14
|
// Otherwise write straight to the display in one SPI transaction.
|
|
15
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);
|
|
16
20
|
if (w == stride) {
|
|
17
21
|
ui_display_draw_rgb_bitmap(x, y, pixels, w, h);
|
|
18
22
|
return;
|
|
19
23
|
}
|
|
20
24
|
for (int16_t row = 0; row < h; row++) {
|
|
21
|
-
ui_display_draw_rgb_bitmap(x, y + row, pixels + (
|
|
25
|
+
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
22
26
|
}
|
|
23
27
|
return;
|
|
24
28
|
}
|
|
@@ -26,12 +30,12 @@ static inline void ui_push_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, in
|
|
|
26
30
|
display_setAddrWindow(x, y, w, h);
|
|
27
31
|
if (w == stride) {
|
|
28
32
|
// Full-width: contiguous in buffer, single write.
|
|
29
|
-
display_writePixels(pixels, (
|
|
33
|
+
display_writePixels(pixels, static_cast<uint32_t>(w) * h);
|
|
30
34
|
display_endWrite();
|
|
31
35
|
return;
|
|
32
36
|
}
|
|
33
37
|
for (int16_t row = 0; row < h; row++) {
|
|
34
|
-
display_writePixels(pixels + (
|
|
38
|
+
display_writePixels(pixels + static_cast<int32_t>(row) * stride, w);
|
|
35
39
|
}
|
|
36
40
|
display_endWrite();
|
|
37
41
|
}
|
|
@@ -45,7 +49,7 @@ static inline void ui_draw_canvas_rect(CuttlefishCanvas16* canvas, int16_t x, in
|
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
51
|
for (int16_t row = 0; row < h; row++) {
|
|
48
|
-
ui_display_draw_rgb_bitmap(x, y + row, pixels + (
|
|
52
|
+
ui_display_draw_rgb_bitmap(x, y + row, pixels + static_cast<int32_t>(row) * stride, w, 1);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -67,10 +71,14 @@ static inline void ui_push_buffered_scroll_canvas(CuttlefishCanvas16* bufferedSc
|
|
|
67
71
|
ui_draw_canvas_rect(bufferedScrollRepaintCanvas, 0, bufferedScrollRepaintY, vw, bufferedScrollRepaintH);
|
|
68
72
|
}
|
|
69
73
|
int16_t tx = vw - 4;
|
|
70
|
-
uint16_t thumbH = (
|
|
74
|
+
uint16_t thumbH = static_cast<uint32_t>(vh) * vh / __ui_nodes[si].contentHeight;
|
|
71
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);
|
|
72
80
|
int16_t maxScroll = __ui_nodes[si].contentHeight - vh;
|
|
73
|
-
uint16_t thumbY =
|
|
81
|
+
uint16_t thumbY = static_cast<uint32_t>(vh - thumbH) * __ui_nodes[si].scrollY / (maxScroll > 0 ? maxScroll : 1);
|
|
74
82
|
UI_COLOR_T dimFg = (UI_COLOR_T)((__ui_nodes[si].fg >> 1) & UI_DIM_MASK);
|
|
75
83
|
ui_display_fill_rect(tx, 0, 3, vh, dimFg);
|
|
76
84
|
ui_display_fill_rect(tx, thumbY, 3, thumbH, __ui_nodes[si].fg);
|
|
@@ -87,18 +95,22 @@ static inline void ui_push_buffered_scroll_canvas(CuttlefishCanvas16* bufferedSc
|
|
|
87
95
|
|
|
88
96
|
// Draw a scroll container's scrollbar directly on the display (Mode C).
|
|
89
97
|
static inline void ui_draw_scrollbar_direct(int16_t si, int16_t vox, int16_t voy) {
|
|
90
|
-
if (si < 0 || si >= (
|
|
98
|
+
if (si < 0 || si >= static_cast<int16_t>(__ui_node_count)) return;
|
|
91
99
|
int16_t vw = __ui_nodes[si].box.w;
|
|
92
100
|
int16_t vh = __ui_nodes[si].box.h;
|
|
93
101
|
if (__ui_nodes[si].contentHeight <= vh) return;
|
|
94
102
|
int16_t tx = vox + vw - 4;
|
|
95
|
-
uint16_t thumbH = (
|
|
103
|
+
uint16_t thumbH = static_cast<uint32_t>(vh) * vh / __ui_nodes[si].contentHeight;
|
|
96
104
|
if (thumbH < 8) thumbH = 8;
|
|
105
|
+
// Clamp to vh so (vh - thumbH) below can't underflow on a degenerate sub-8px
|
|
106
|
+
// viewport (which would cast a negative value to a huge uint32_t and place the
|
|
107
|
+
// thumb off-screen). Matches the guard in ui_render_scroll_bands.
|
|
108
|
+
if (thumbH > static_cast<uint16_t>(vh)) thumbH = static_cast<uint16_t>(vh);
|
|
97
109
|
int16_t maxScroll = __ui_nodes[si].contentHeight - vh;
|
|
98
|
-
uint16_t thumbY =
|
|
110
|
+
uint16_t thumbY = static_cast<uint32_t>(vh - thumbH) * __ui_nodes[si].scrollY / (maxScroll > 0 ? maxScroll : 1);
|
|
99
111
|
UI_COLOR_T dimFg = (UI_COLOR_T)((__ui_nodes[si].fg >> 1) & UI_DIM_MASK);
|
|
100
112
|
ui_display_fill_rect(tx, voy, 3, vh, dimFg);
|
|
101
|
-
ui_display_fill_rect(tx,
|
|
113
|
+
ui_display_fill_rect(tx, static_cast<int16_t>(voy + thumbY), 3, thumbH, __ui_nodes[si].fg);
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
// Per-node dirty marker (called by press handlers and binding evaluation).`;
|
|
@@ -39,11 +39,11 @@ static inline uint32_t ui_blend888(uint32_t fg, uint32_t bg, uint8_t opacity);
|
|
|
39
39
|
static inline uint16_t lerp_color(uint16_t a, uint16_t b, uint8_t k100);
|
|
40
40
|
static inline uint32_t lerp_color_888(uint32_t a, uint32_t b, uint8_t k100);
|
|
41
41
|
#if UI_COLOR_DEPTH == 888
|
|
42
|
-
#define ui_blend(fg, bg, op) ui_blend888(
|
|
43
|
-
#define UI_LERP_COLOR(a, b, k) lerp_color_888(
|
|
42
|
+
#define ui_blend(fg, bg, op) ui_blend888(static_cast<uint32_t>(fg), static_cast<uint32_t>(bg), (op))
|
|
43
|
+
#define UI_LERP_COLOR(a, b, k) lerp_color_888(static_cast<uint32_t>(a), static_cast<uint32_t>(b), (k))
|
|
44
44
|
#else
|
|
45
|
-
#define ui_blend(fg, bg, op) ui_blend565(
|
|
46
|
-
#define UI_LERP_COLOR(a, b, k) lerp_color(
|
|
45
|
+
#define ui_blend(fg, bg, op) ui_blend565(static_cast<uint16_t>(fg), static_cast<uint16_t>(bg), (op))
|
|
46
|
+
#define UI_LERP_COLOR(a, b, k) lerp_color(static_cast<uint16_t>(a), static_cast<uint16_t>(b), (k))
|
|
47
47
|
#endif
|
|
48
48
|
|
|
49
49
|
// ── 1-bit mono snap (UI_NATIVE_MONO) ─────────────────────────────────────────
|
|
@@ -57,7 +57,7 @@ static inline uint32_t ui_snap_mono(uint32_t c) {
|
|
|
57
57
|
uint8_t r = (c >> 16) & 0xff, g = (c >> 8) & 0xff, b = c & 0xff;
|
|
58
58
|
// Match the transpile-time toMono threshold: (0.299r + 0.587g + 0.114b)/255 >= 0.27.
|
|
59
59
|
// Integer form: 299r+587g+114b >= 68850 (= 0.27*255*1000). Verified 0 mismatches.
|
|
60
|
-
return (
|
|
60
|
+
return (static_cast<uint32_t>(299 * r + 587 * g + 114 * b) >= 68850u) ? 0xffffffu : 0x000000u;
|
|
61
61
|
}
|
|
62
62
|
// Snap an RGB565 value to 1-bit mono. Mono panels run at UI_COLOR_DEPTH 565, so
|
|
63
63
|
// node fields hold 565 values; reconstruct 8-bit channels then apply the threshold.
|
|
@@ -68,10 +68,10 @@ static inline uint16_t ui_snap_mono565(uint16_t c) {
|
|
|
68
68
|
if (c == 0x0001u || c == 0xffffu) return 0xffffu;
|
|
69
69
|
uint8_t r5 = (c >> 11) & 0x1f, g6 = (c >> 5) & 0x3f, b5 = c & 0x1f;
|
|
70
70
|
uint8_t r = (r5 << 3) | (r5 >> 2), g = (g6 << 2) | (g6 >> 4), b = (b5 << 3) | (b5 >> 2);
|
|
71
|
-
return (
|
|
71
|
+
return (static_cast<uint32_t>(299 * r + 587 * g + 114 * b) >= 68850u) ? 0xffffu : 0x0000u;
|
|
72
72
|
}
|
|
73
|
-
#define UI_MAYBE_SNAP_MONO(c) (ui_snap_mono(
|
|
74
|
-
#define UI_MAYBE_SNAP_MONO565(c) (ui_snap_mono565(
|
|
73
|
+
#define UI_MAYBE_SNAP_MONO(c) (ui_snap_mono(static_cast<uint32_t>(c)))
|
|
74
|
+
#define UI_MAYBE_SNAP_MONO565(c) (ui_snap_mono565(static_cast<uint16_t>(c)))
|
|
75
75
|
#else
|
|
76
76
|
#define UI_MAYBE_SNAP_MONO(c) (c)
|
|
77
77
|
#define UI_MAYBE_SNAP_MONO565(c) (c)
|
|
@@ -115,7 +115,7 @@ static inline uint16_t ui_snap_mono565(uint16_t c) {
|
|
|
115
115
|
const UIRect16& r = __ui_refresh_rects[i];
|
|
116
116
|
if (r.x < x0) x0 = r.x;
|
|
117
117
|
if (r.y < y0) y0 = r.y;
|
|
118
|
-
int16_t rx1 =
|
|
118
|
+
int16_t rx1 = static_cast<int16_t>(r.x + r.w), ry1 = static_cast<int16_t>(r.y + r.h);
|
|
119
119
|
if (rx1 > x1) x1 = rx1;
|
|
120
120
|
if (ry1 > y1) y1 = ry1;
|
|
121
121
|
}
|
|
@@ -124,7 +124,7 @@ static inline uint16_t ui_snap_mono565(uint16_t c) {
|
|
|
124
124
|
if (x1 > display_width()) x1 = display_width();
|
|
125
125
|
if (y1 > display_height()) y1 = display_height();
|
|
126
126
|
if (x1 > x0 && y1 > y0) {
|
|
127
|
-
display_partial_refresh(x0, y0,
|
|
127
|
+
display_partial_refresh(x0, y0, static_cast<int16_t>(x1 - x0), static_cast<int16_t>(y1 - y0));
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
#elif defined(UI_BATCH_SPI_WRITES)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// Slice of the C++ runtime header. Defines the CuttlefishGFX class — the
|
|
3
|
-
// shared geometry/canvas/text base used by native
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// shared geometry/canvas/text base used by native display adapters that
|
|
4
|
+
// instantiate CuttlefishGFX by value. NOT emitted on macro-alias paths
|
|
5
|
+
// (Adafruit `CuttlefishCanvas16==GFXcanvas16`, SDL
|
|
6
|
+
// `CuttlefishCanvas16==SdlGfxCanvas`), which own the canvas type.
|
|
6
7
|
//
|
|
7
8
|
// ──── BSD-3-Clause attribution ────────────────────────────────────────────
|
|
8
9
|
// The geometry algorithm implementations emitted by this slice (drawLine,
|
|
@@ -53,13 +54,16 @@ export function emitCuttlefishGfx(active) {
|
|
|
53
54
|
const fontArray = renderGlcdfontArray("cuttlefish_glcdfont", "unsigned char");
|
|
54
55
|
return `
|
|
55
56
|
// ── CuttlefishGFX (native display GFX base) ────────────────────────────────
|
|
56
|
-
// Emitted only
|
|
57
|
+
// Emitted only for native adapters that instantiate CuttlefishGFX by value;
|
|
58
|
+
// suppressed on macro-alias paths (Adafruit CuttlefishCanvas16==GFXcanvas16,
|
|
59
|
+
// SDL CuttlefishCanvas16==SdlGfxCanvas). Gated in ui-emitter.ts.
|
|
57
60
|
#ifndef CUTTLEFISH_GFX_DEFINED
|
|
58
61
|
#define CUTTLEFISH_GFX_DEFINED
|
|
59
62
|
|
|
60
63
|
#include <stdint.h>
|
|
61
|
-
#include <
|
|
62
|
-
#include <
|
|
64
|
+
#include <cstdlib>
|
|
65
|
+
#include <cstring>
|
|
66
|
+
#include <new> // std::nothrow for canvas buffer allocation
|
|
63
67
|
|
|
64
68
|
// ── Panel-ops interface ────────────────────────────────────────────────────
|
|
65
69
|
// Each native adapter fills a CuttlefishPanelOps with function pointers that
|
|
@@ -118,7 +122,7 @@ class CuttlefishGFX {
|
|
|
118
122
|
// Text
|
|
119
123
|
virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size);
|
|
120
124
|
virtual void write(uint8_t c);
|
|
121
|
-
void print(const char* s) { while (*s) write((
|
|
125
|
+
void print(const char* s) { while (*s) write(static_cast<uint8_t>(*s++)); }
|
|
122
126
|
void setCursor(int16_t x, int16_t y) { cursor_x_ = x; cursor_y_ = y; }
|
|
123
127
|
void setTextColor(uint16_t c) { textcolor_ = c; }
|
|
124
128
|
void setTextColor(uint16_t c, uint16_t bg) { textcolor_ = c; textbgcolor_ = bg; }
|
|
@@ -150,9 +154,18 @@ class CuttlefishGFX {
|
|
|
150
154
|
// display_deleteCanvas (the runtime reuses persistent canvas slots — see
|
|
151
155
|
// AGENTS.md: __ui_container_canvas, __ui_repair_canvas, __ui_list_canvas,
|
|
152
156
|
// __ui_node_canvas).
|
|
153
|
-
class CuttlefishCanvas16 : public CuttlefishGFX {
|
|
157
|
+
class CuttlefishCanvas16 final : public CuttlefishGFX {
|
|
154
158
|
public:
|
|
159
|
+
// Noncopyable (owns a heap buffer; a value-copy would double-free).
|
|
160
|
+
CuttlefishCanvas16(const CuttlefishCanvas16&) = delete;
|
|
161
|
+
CuttlefishCanvas16& operator=(const CuttlefishCanvas16&) = delete;
|
|
162
|
+
// Owns its buffer: mallocs w*h*2 bytes and frees it in the dtor.
|
|
155
163
|
CuttlefishCanvas16(int16_t w, int16_t h);
|
|
164
|
+
// Adopts an externally-allocated buffer (e.g. PSRAM via display_createCanvasPsram).
|
|
165
|
+
// If takeOwnership is true, the dtor frees the buffer with free() (works for both
|
|
166
|
+
// SRAM malloc and the ESP unified heap, which includes PSRAM). If false, the
|
|
167
|
+
// caller owns the buffer's lifetime.
|
|
168
|
+
CuttlefishCanvas16(int16_t w, int16_t h, uint16_t* externalBuffer, uint8_t takeOwnership = 0);
|
|
156
169
|
virtual ~CuttlefishCanvas16();
|
|
157
170
|
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
|
|
158
171
|
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
|
@@ -171,13 +184,16 @@ class CuttlefishCanvas16 : public CuttlefishGFX {
|
|
|
171
184
|
private:
|
|
172
185
|
uint16_t* buffer_;
|
|
173
186
|
int16_t canvas_w_, canvas_h_;
|
|
187
|
+
uint8_t owns_buffer_; // 1 = dtor frees buffer_ (malloc'd), 0 = externally owned
|
|
174
188
|
};
|
|
175
189
|
|
|
176
190
|
// ── 1-bit mono canvas (SSD1309/SSD1680 backing stores) ──────────────────────
|
|
177
191
|
// Mirrors Adafruit_GFXcanvasMono. (w+7)/8 bytes per row. The buffer is the
|
|
178
192
|
// panel backing store on SSD1309 — flush via display_partial_refresh.
|
|
179
|
-
class CuttlefishCanvasMono : public CuttlefishGFX {
|
|
193
|
+
class CuttlefishCanvasMono final : public CuttlefishGFX {
|
|
180
194
|
public:
|
|
195
|
+
CuttlefishCanvasMono(const CuttlefishCanvasMono&) = delete;
|
|
196
|
+
CuttlefishCanvasMono& operator=(const CuttlefishCanvasMono&) = delete;
|
|
181
197
|
CuttlefishCanvasMono(int16_t w, int16_t h);
|
|
182
198
|
virtual ~CuttlefishCanvasMono();
|
|
183
199
|
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
|
|
@@ -370,8 +386,8 @@ void CuttlefishGFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
|
|
370
386
|
if (a > b) { int16_t t = a; a = b; b = t; }
|
|
371
387
|
drawFastHLine(a, y, b - a + 1, color);
|
|
372
388
|
}
|
|
373
|
-
sa = (
|
|
374
|
-
sb = (
|
|
389
|
+
sa = static_cast<int32_t>(dx12) * (last - y1);
|
|
390
|
+
sb = static_cast<int32_t>(dx02) * (last - y0);
|
|
375
391
|
for (; y <= y2; y++) {
|
|
376
392
|
a = x1 + sa / dy12;
|
|
377
393
|
b = x0 + sb / dy02;
|
|
@@ -389,7 +405,7 @@ void CuttlefishGFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t* bitmap,
|
|
|
389
405
|
if (!bitmap || w <= 0 || h <= 0) return;
|
|
390
406
|
for (int16_t j = 0; j < h; j++) {
|
|
391
407
|
for (int16_t i = 0; i < w; i++) {
|
|
392
|
-
drawPixel(x + i, y + j, bitmap[(
|
|
408
|
+
drawPixel(x + i, y + j, bitmap[static_cast<int32_t>(j) * w + i]);
|
|
393
409
|
}
|
|
394
410
|
}
|
|
395
411
|
}
|
|
@@ -403,7 +419,7 @@ void CuttlefishGFX::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t col
|
|
|
403
419
|
return;
|
|
404
420
|
if (c >= 176) c++; // Adafruit '±' fixup
|
|
405
421
|
for (int8_t i = 0; i < 5; i++) {
|
|
406
|
-
uint8_t line = cuttlefish_glcdfont[(
|
|
422
|
+
uint8_t line = cuttlefish_glcdfont[static_cast<size_t>(c) * 5 + i];
|
|
407
423
|
for (int8_t j = 0; j < 8; j++, line >>= 1) {
|
|
408
424
|
if (line & 1) {
|
|
409
425
|
if (size == 1) drawPixel(x + i, y + j, color);
|
|
@@ -439,22 +455,36 @@ void CuttlefishGFX::write(uint8_t c) {
|
|
|
439
455
|
|
|
440
456
|
CuttlefishCanvas16::CuttlefishCanvas16(int16_t w, int16_t h)
|
|
441
457
|
: CuttlefishGFX(nullptr, nullptr),
|
|
442
|
-
buffer_(nullptr), canvas_w_(w), canvas_h_(h) {
|
|
458
|
+
buffer_(nullptr), canvas_w_(w), canvas_h_(h), owns_buffer_(1) {
|
|
443
459
|
if ((w > 0) && (h > 0)) {
|
|
444
|
-
size_t bytes = (
|
|
445
|
-
|
|
460
|
+
size_t bytes = static_cast<size_t>(w) * static_cast<size_t>(h) * sizeof(uint16_t);
|
|
461
|
+
// malloc (not new): on targets with CONFIG_REQUIRES_FULL_LIBCPP but without
|
|
462
|
+
// CONFIG_CPP_EXCEPTIONS, operator new throws std::bad_alloc on OOM and the
|
|
463
|
+
// nothrow wrapper's internal catch can't unwind → std::terminate → abort.
|
|
464
|
+
// malloc returns NULL on failure with no exception path, which is exactly
|
|
465
|
+
// what the canvas-failure self-heal logic expects.
|
|
466
|
+
buffer_ = static_cast<uint16_t*>(malloc(bytes));
|
|
446
467
|
if (buffer_) memset(buffer_, 0, bytes);
|
|
447
468
|
}
|
|
448
469
|
}
|
|
449
470
|
|
|
471
|
+
CuttlefishCanvas16::CuttlefishCanvas16(int16_t w, int16_t h, uint16_t* externalBuffer, uint8_t takeOwnership)
|
|
472
|
+
: CuttlefishGFX(nullptr, nullptr),
|
|
473
|
+
buffer_(externalBuffer), canvas_w_(w), canvas_h_(h), owns_buffer_(takeOwnership) {
|
|
474
|
+
// Zero the buffer so the canvas starts clean whether or not we own it.
|
|
475
|
+
if (externalBuffer && (w > 0) && (h > 0)) {
|
|
476
|
+
memset(externalBuffer, 0, static_cast<size_t>(w) * static_cast<size_t>(h) * sizeof(uint16_t));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
450
480
|
CuttlefishCanvas16::~CuttlefishCanvas16() {
|
|
451
|
-
if (buffer_) free(buffer_);
|
|
481
|
+
if (buffer_ && owns_buffer_) free(buffer_);
|
|
452
482
|
}
|
|
453
483
|
|
|
454
484
|
void CuttlefishCanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|
455
485
|
if (!buffer_) return;
|
|
456
486
|
if ((x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return;
|
|
457
|
-
buffer_[(
|
|
487
|
+
buffer_[static_cast<size_t>(y) * static_cast<size_t>(canvas_w_) + static_cast<size_t>(x)] = color;
|
|
458
488
|
}
|
|
459
489
|
|
|
460
490
|
void CuttlefishCanvas16::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
|
@@ -466,23 +496,23 @@ void CuttlefishCanvas16::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, ui
|
|
|
466
496
|
// Cull before the inner loop (AGENTS.md: clip before expensive work).
|
|
467
497
|
if (x2 <= x1 || y2 <= y1) return;
|
|
468
498
|
for (int16_t j = y1; j < y2; j++) {
|
|
469
|
-
uint16_t* row = buffer_ + (
|
|
499
|
+
uint16_t* row = buffer_ + static_cast<size_t>(j) * static_cast<size_t>(canvas_w_);
|
|
470
500
|
for (int16_t i = x1; i < x2; i++) row[i] = color;
|
|
471
501
|
}
|
|
472
502
|
}
|
|
473
503
|
|
|
474
504
|
uint16_t CuttlefishCanvas16::getPixel(int16_t x, int16_t y) const {
|
|
475
505
|
if (!buffer_ || (x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return 0;
|
|
476
|
-
return buffer_[(
|
|
506
|
+
return buffer_[static_cast<size_t>(y) * static_cast<size_t>(canvas_w_) + static_cast<size_t>(x)];
|
|
477
507
|
}
|
|
478
508
|
|
|
479
509
|
CuttlefishCanvasMono::CuttlefishCanvasMono(int16_t w, int16_t h)
|
|
480
510
|
: CuttlefishGFX(nullptr, nullptr),
|
|
481
511
|
buffer_(nullptr), canvas_w_(w), canvas_h_(h) {
|
|
482
512
|
if ((w > 0) && (h > 0)) {
|
|
483
|
-
size_t row_bytes = ((
|
|
484
|
-
size_t bytes = row_bytes * (
|
|
485
|
-
buffer_ = (
|
|
513
|
+
size_t row_bytes = (static_cast<size_t>(w) + 7u) / 8u;
|
|
514
|
+
size_t bytes = row_bytes * static_cast<size_t>(h);
|
|
515
|
+
buffer_ = static_cast<uint8_t*>(malloc(bytes));
|
|
486
516
|
if (buffer_) memset(buffer_, 0, bytes);
|
|
487
517
|
}
|
|
488
518
|
}
|
|
@@ -494,8 +524,8 @@ CuttlefishCanvasMono::~CuttlefishCanvasMono() {
|
|
|
494
524
|
void CuttlefishCanvasMono::drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|
495
525
|
if (!buffer_) return;
|
|
496
526
|
if ((x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return;
|
|
497
|
-
size_t row_bytes = ((
|
|
498
|
-
uint8_t* row = buffer_ + (
|
|
527
|
+
size_t row_bytes = (static_cast<size_t>(canvas_w_) + 7u) / 8u;
|
|
528
|
+
uint8_t* row = buffer_ + static_cast<size_t>(y) * row_bytes;
|
|
499
529
|
uint8_t mask = 0x80u >> (x & 7);
|
|
500
530
|
if (color) row[x >> 3] |= mask;
|
|
501
531
|
else row[x >> 3] &= ~mask;
|
|
@@ -511,8 +541,8 @@ void CuttlefishCanvasMono::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
|
|
511
541
|
uint8_t fill = color ? 0xFFu : 0x00u;
|
|
512
542
|
for (int16_t j = y1; j < y2; j++) {
|
|
513
543
|
for (int16_t i = x1; i < x2; i++) {
|
|
514
|
-
size_t row_bytes = ((
|
|
515
|
-
uint8_t* row = buffer_ + (
|
|
544
|
+
size_t row_bytes = (static_cast<size_t>(canvas_w_) + 7u) / 8u;
|
|
545
|
+
uint8_t* row = buffer_ + static_cast<size_t>(j) * row_bytes;
|
|
516
546
|
uint8_t mask = 0x80u >> (i & 7);
|
|
517
547
|
if (color) row[i >> 3] |= mask;
|
|
518
548
|
else row[i >> 3] &= ~mask;
|
|
@@ -523,8 +553,8 @@ void CuttlefishCanvasMono::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
|
|
523
553
|
|
|
524
554
|
uint16_t CuttlefishCanvasMono::getPixel(int16_t x, int16_t y) const {
|
|
525
555
|
if (!buffer_ || (x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return 0;
|
|
526
|
-
size_t row_bytes = ((
|
|
527
|
-
const uint8_t* row = buffer_ + (
|
|
556
|
+
size_t row_bytes = (static_cast<size_t>(canvas_w_) + 7u) / 8u;
|
|
557
|
+
const uint8_t* row = buffer_ + static_cast<size_t>(y) * row_bytes;
|
|
528
558
|
return (row[x >> 3] & (0x80u >> (x & 7))) ? 0xFFFFu : 0x0000u;
|
|
529
559
|
}
|
|
530
560
|
|
|
@@ -64,7 +64,10 @@ static inline void ui_mark_subtree_dirty_local(uint16_t scrollNode) {
|
|
|
64
64
|
|
|
65
65
|
// Mode C strip-only: direct-partial scroll when no viewport canvas fits and the
|
|
66
66
|
// scroll delta is small. Fills only the exposed strip on the display, then marks
|
|
67
|
-
//
|
|
67
|
+
// only the descendants that intersect that strip dirty for direct draw — mirroring
|
|
68
|
+
// the Mode B canvas repair path. Never clears the whole viewport, and never marks
|
|
69
|
+
// the whole subtree dirty (AGENTS.md: keep scroll drag invalidation small — a
|
|
70
|
+
// 1-pixel drag must not repaint every visible child).
|
|
68
71
|
static inline void ui_scroll_direct_prepare(uint16_t s, int16_t* outVX, int16_t* outVY) {
|
|
69
72
|
int16_t vw = __ui_nodes[s].box.w;
|
|
70
73
|
int16_t vh = __ui_nodes[s].box.h;
|
|
@@ -73,18 +76,31 @@ static inline void ui_scroll_direct_prepare(uint16_t s, int16_t* outVX, int16_t*
|
|
|
73
76
|
UI_COLOR_T scrollBg = __ui_nodes[s].hasBg ? __ui_nodes[s].bg : __ui_nodes[s].clearColor;
|
|
74
77
|
int16_t deltaY = __ui_nodes[s].scrollY - __ui_nodes[s].lastPaintedScrollY;
|
|
75
78
|
int16_t absDelta = deltaY < 0 ? -deltaY : deltaY;
|
|
76
|
-
int16_t stripY = deltaY > 0 ?
|
|
77
|
-
ui_display_fill_rect(vox,
|
|
79
|
+
int16_t stripY = deltaY > 0 ? static_cast<int16_t>(vh - absDelta) : 0;
|
|
80
|
+
ui_display_fill_rect(vox, static_cast<int16_t>(voy + stripY), vw, absDelta, scrollBg);
|
|
81
|
+
// Only descendants whose paint rect intersects the exposed strip need
|
|
82
|
+
// repainting; the rest keep their last-painted pixels (the strip background
|
|
83
|
+
// fill already covered the vacated band). Clear stale dirty flags on the
|
|
84
|
+
// others so a flag set by a prior frame (or a sibling promotion) doesn't
|
|
85
|
+
// trigger a needless repaint.
|
|
86
|
+
UIRect exposed = { vox, static_cast<int16_t>(voy + stripY), vw, absDelta };
|
|
78
87
|
for (uint16_t c = s + 1; c < __ui_nodes[s].subtreeEnd; c++) {
|
|
79
88
|
if (!ui_is_effectively_visible(c) || __ui_nodes[c].screenId != __ui_active_screen) {
|
|
80
89
|
__ui_nodes[c].dirty = 0;
|
|
81
90
|
continue;
|
|
82
91
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
UIRect cr;
|
|
93
|
+
ui_node_current_paint_rect(c, &cr);
|
|
94
|
+
if (cr.w > 0 && cr.h > 0 &&
|
|
95
|
+
ui_rects_intersect(cr.x, cr.y, cr.w, cr.h, exposed.x, exposed.y, exposed.w, exposed.h)) {
|
|
96
|
+
__ui_nodes[c].dirty = 1;
|
|
97
|
+
if (__ui_nodes[c].kind == NODE_PROGRESS || __ui_nodes[c].kind == NODE_RANGE) {
|
|
98
|
+
__ui_nodes[c].lastTextWidth = -1;
|
|
99
|
+
}
|
|
100
|
+
__ui_nodes[c].lastTextHeight = 0;
|
|
101
|
+
} else {
|
|
102
|
+
__ui_nodes[c].dirty = 0;
|
|
86
103
|
}
|
|
87
|
-
__ui_nodes[c].lastTextHeight = 0;
|
|
88
104
|
}
|
|
89
105
|
__ui_nodes[s].dirty = 0;
|
|
90
106
|
if (outVX) *outVX = vox;
|
|
@@ -96,13 +112,13 @@ static inline int16_t ui_overflow_scroll_compositor(uint16_t nodeIdx) {
|
|
|
96
112
|
if (nodeIdx >= __ui_node_count) return -1;
|
|
97
113
|
if (__ui_nodes[nodeIdx].scrollable && !__ui_nodes[nodeIdx].virtualized &&
|
|
98
114
|
__ui_nodes[nodeIdx].contentHeight > __ui_nodes[nodeIdx].box.h) {
|
|
99
|
-
return (
|
|
115
|
+
return static_cast<int16_t>(nodeIdx);
|
|
100
116
|
}
|
|
101
117
|
uint16_t p = __ui_nodes[nodeIdx].parent;
|
|
102
118
|
while (p != UI_NO_PARENT && p < __ui_node_count) {
|
|
103
119
|
if (__ui_nodes[p].scrollable && !__ui_nodes[p].virtualized &&
|
|
104
120
|
__ui_nodes[p].contentHeight > __ui_nodes[p].box.h) {
|
|
105
|
-
return (
|
|
121
|
+
return static_cast<int16_t>(p);
|
|
106
122
|
}
|
|
107
123
|
p = __ui_nodes[p].parent;
|
|
108
124
|
}
|
|
@@ -151,7 +167,7 @@ static inline void ui_mark_scroll_view_dirty(uint16_t scrollNode) {
|
|
|
151
167
|
static inline int16_t ui_scroll_ancestor_for_node(uint16_t nodeIdx) {
|
|
152
168
|
uint16_t p = __ui_nodes[nodeIdx].parent;
|
|
153
169
|
while (p != UI_NO_PARENT && p < __ui_node_count) {
|
|
154
|
-
if (__ui_nodes[p].scrollable) return (
|
|
170
|
+
if (__ui_nodes[p].scrollable) return static_cast<int16_t>(p);
|
|
155
171
|
p = __ui_nodes[p].parent;
|
|
156
172
|
}
|
|
157
173
|
return -1;
|
|
@@ -26,10 +26,10 @@ static inline int16_t ui_clamp_i16(int16_t value, int16_t lo, int16_t hi) {
|
|
|
26
26
|
return value;
|
|
27
27
|
}
|
|
28
28
|
static inline void ui_display_target_bounds(int16_t* left, int16_t* top, int16_t* right, int16_t* bottom) {
|
|
29
|
-
if (left) *left =
|
|
30
|
-
if (top) *top =
|
|
31
|
-
if (right) *right =
|
|
32
|
-
if (bottom) *bottom =
|
|
29
|
+
if (left) *left = static_cast<int16_t>(-__ui_draw_off_x);
|
|
30
|
+
if (top) *top = static_cast<int16_t>(-__ui_draw_off_y);
|
|
31
|
+
if (right) *right = static_cast<int16_t>(ui_display_target_width() - __ui_draw_off_x);
|
|
32
|
+
if (bottom) *bottom = static_cast<int16_t>(ui_display_target_height() - __ui_draw_off_y);
|
|
33
33
|
}
|
|
34
34
|
static inline uint8_t ui_clip_rect_to_display_target(int16_t* x, int16_t* y, int16_t* w, int16_t* h) {
|
|
35
35
|
if (!x || !y || !w || !h || *w <= 0 || *h <= 0) return 0;
|
|
@@ -37,15 +37,15 @@ static inline uint8_t ui_clip_rect_to_display_target(int16_t* x, int16_t* y, int
|
|
|
37
37
|
ui_display_target_bounds(&left, &top, &right, &bottom);
|
|
38
38
|
int16_t x0 = *x > left ? *x : left;
|
|
39
39
|
int16_t y0 = *y > top ? *y : top;
|
|
40
|
-
int16_t x1 =
|
|
41
|
-
int16_t y1 =
|
|
40
|
+
int16_t x1 = static_cast<int16_t>(*x + *w);
|
|
41
|
+
int16_t y1 = static_cast<int16_t>(*y + *h);
|
|
42
42
|
if (x1 > right) x1 = right;
|
|
43
43
|
if (y1 > bottom) y1 = bottom;
|
|
44
44
|
if (x0 >= x1 || y0 >= y1) return 0;
|
|
45
45
|
*x = x0;
|
|
46
46
|
*y = y0;
|
|
47
|
-
*w =
|
|
48
|
-
*h =
|
|
47
|
+
*w = static_cast<int16_t>(x1 - x0);
|
|
48
|
+
*h = static_cast<int16_t>(y1 - y0);
|
|
49
49
|
return 1;
|
|
50
50
|
}
|
|
51
51
|
static inline void ui_display_draw_pixel(int16_t x, int16_t y, UI_COLOR_T color) {
|