@typecad/ui 1.0.0-alpha.6 → 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.
Files changed (86) hide show
  1. package/README.md +6 -0
  2. package/dist/engine-index.js +2 -2
  3. package/dist/preview/host-ui-runtime.d.ts +1 -0
  4. package/dist/preview/host-ui-runtime.js +56 -11
  5. package/dist/ui-engine/font-assets.d.ts +8 -0
  6. package/dist/ui-engine/font-assets.js +13 -0
  7. package/dist/ui-engine/layout-engine.js +19 -6
  8. package/dist/ui-engine/model.d.ts +1 -1
  9. package/dist/ui-engine/model.js +10 -4
  10. package/dist/ui-engine/runtime-header/antialiasing.js +52 -32
  11. package/dist/ui-engine/runtime-header/blend-bodies.js +4 -4
  12. package/dist/ui-engine/runtime-header/canvas-helpers.js +42 -69
  13. package/dist/ui-engine/runtime-header/canvas-scrollbar.js +22 -10
  14. package/dist/ui-engine/runtime-header/color-mono-refresh.js +10 -10
  15. package/dist/ui-engine/runtime-header/cuttlefish-gfx.d.ts +1 -0
  16. package/dist/ui-engine/runtime-header/cuttlefish-gfx.js +563 -0
  17. package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +26 -10
  18. package/dist/ui-engine/runtime-header/display-shim.js +8 -8
  19. package/dist/ui-engine/runtime-header/forward-decls.js +52 -10
  20. package/dist/ui-engine/runtime-header/image-drawing.js +154 -84
  21. package/dist/ui-engine/runtime-header/init-press-input.js +20 -5
  22. package/dist/ui-engine/runtime-header/keyboard.js +62 -18
  23. package/dist/ui-engine/runtime-header/node-decoration.js +8 -9
  24. package/dist/ui-engine/runtime-header/node-draw-body.d.ts +1 -0
  25. package/dist/ui-engine/runtime-header/node-draw-body.js +1402 -0
  26. package/dist/ui-engine/runtime-header/paint-order-coords.js +48 -18
  27. package/dist/ui-engine/runtime-header/paint-rects-repair.js +38 -17
  28. package/dist/ui-engine/runtime-header/scroll-physics.js +15 -18
  29. package/dist/ui-engine/runtime-header/state-bindings-nav.js +23 -13
  30. package/dist/ui-engine/runtime-header/structs.js +12 -10
  31. package/dist/ui-engine/runtime-header/text-rendering.js +132 -71
  32. package/dist/ui-engine/runtime-header/tick/bindings-phase.js +29 -10
  33. package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +336 -749
  34. package/dist/ui-engine/runtime-header/tick/flush-phase.js +7 -3
  35. package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +19 -3
  36. package/dist/ui-engine/runtime-header/tick/transitions-phase.js +31 -24
  37. package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +46 -41
  38. package/dist/ui-engine/runtime-header/types-defines.js +23 -3
  39. package/dist/ui-engine/runtime-header.d.ts +10 -1
  40. package/dist/ui-engine/runtime-header.js +7 -1
  41. package/dist/ui-engine/transpile-ui.js +2 -2
  42. package/dist/ui-engine/ua-stylesheet.js +46 -3
  43. package/dist/ui-engine/ui-lowering.d.ts +1 -3
  44. package/dist/ui-engine/ui-lowering.js +18 -24
  45. package/dist/ui-engine/ui-registry.js +1 -6
  46. package/package.json +2 -2
  47. package/src/engine-index.ts +2 -2
  48. package/src/preview/host-ui-runtime.ts +56 -12
  49. package/src/ui-engine/font-assets.ts +13 -0
  50. package/src/ui-engine/layout-engine.ts +19 -6
  51. package/src/ui-engine/model.ts +10 -5
  52. package/src/ui-engine/runtime-header/antialiasing.ts +52 -32
  53. package/src/ui-engine/runtime-header/blend-bodies.ts +4 -4
  54. package/src/ui-engine/runtime-header/canvas-helpers.ts +42 -69
  55. package/src/ui-engine/runtime-header/canvas-scrollbar.ts +22 -10
  56. package/src/ui-engine/runtime-header/color-mono-refresh.ts +10 -10
  57. package/src/ui-engine/runtime-header/cuttlefish-gfx.ts +566 -0
  58. package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +26 -10
  59. package/src/ui-engine/runtime-header/display-shim.ts +8 -8
  60. package/src/ui-engine/runtime-header/forward-decls.ts +52 -10
  61. package/src/ui-engine/runtime-header/image-drawing.ts +154 -84
  62. package/src/ui-engine/runtime-header/init-press-input.ts +20 -5
  63. package/src/ui-engine/runtime-header/keyboard.ts +62 -18
  64. package/src/ui-engine/runtime-header/node-decoration.ts +8 -9
  65. package/src/ui-engine/runtime-header/node-draw-body.ts +1402 -0
  66. package/src/ui-engine/runtime-header/paint-order-coords.ts +48 -18
  67. package/src/ui-engine/runtime-header/paint-rects-repair.ts +38 -17
  68. package/src/ui-engine/runtime-header/scroll-physics.ts +15 -18
  69. package/src/ui-engine/runtime-header/state-bindings-nav.ts +23 -13
  70. package/src/ui-engine/runtime-header/structs.ts +12 -10
  71. package/src/ui-engine/runtime-header/text-rendering.ts +132 -71
  72. package/src/ui-engine/runtime-header/tick/bindings-phase.ts +29 -10
  73. package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +336 -749
  74. package/src/ui-engine/runtime-header/tick/flush-phase.ts +7 -3
  75. package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +19 -3
  76. package/src/ui-engine/runtime-header/tick/transitions-phase.ts +31 -24
  77. package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +46 -41
  78. package/src/ui-engine/runtime-header/types-defines.ts +23 -3
  79. package/src/ui-engine/runtime-header.ts +17 -1
  80. package/src/ui-engine/transpile-ui.ts +2 -2
  81. package/src/ui-engine/ua-stylesheet.ts +46 -3
  82. package/src/ui-engine/ui-lowering.ts +19 -26
  83. package/src/ui-engine/ui-registry.ts +1 -7
  84. package/dist/ui-engine/scroll-memory-diagnostics.d.ts +0 -16
  85. package/dist/ui-engine/scroll-memory-diagnostics.js +0 -58
  86. package/src/ui-engine/scroll-memory-diagnostics.ts +0 -79
@@ -0,0 +1,563 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Slice of the C++ runtime header. Defines the CuttlefishGFX class — the
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.
7
+ //
8
+ // ──── BSD-3-Clause attribution ────────────────────────────────────────────
9
+ // The geometry algorithm implementations emitted by this slice (drawLine,
10
+ // drawCircle, drawCircleHelper, fillCircleHelper, drawRoundRect,
11
+ // fillRoundRect, drawTriangle, fillTriangle, drawChar, and the glyph loop
12
+ // in write()) are ported from Adafruit's Adafruit_GFX library:
13
+ //
14
+ // Adafruit_GFX.cpp / Adafruit_GFX.h
15
+ // Copyright (c) 2013 Adafruit Industries. All rights reserved.
16
+ // Licensed under BSD-3-Clause.
17
+ // Upstream: https://github.com/adafruit/Adafruit-GFX-Library
18
+ //
19
+ // Redistribution and use in source and binary forms, with or without
20
+ // modification, are permitted provided that the following conditions are met:
21
+ //
22
+ // - Redistributions of source code must retain the above copyright notice,
23
+ // this list of conditions and the following disclaimer.
24
+ // - Redistributions in binary form must reproduce the above copyright notice,
25
+ // this list of conditions and the following disclaimer in the documentation
26
+ // and/or other materials provided with the distribution.
27
+ //
28
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
+ // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32
+ // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33
+ // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34
+ // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35
+ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36
+ // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
+ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
+ // POSSIBILITY OF SUCH DAMAGE.
39
+ // ──── End BSD-3-Clause attribution ────────────────────────────────────────
40
+ //
41
+ // Pixel output of the ported algorithms is byte-for-byte identical to
42
+ // Adafruit_GFX because the runtime's text layout and the AGENTS.md
43
+ // scroll/canvas invariants depend on it.
44
+ //
45
+ // AGENTS.md rendering guardrails: canvas ops reuse persistent buffers,
46
+ // use memmove-shift repair strips for scroll (handled in scroll slices that
47
+ // consume getBuffer()), never allocate per-frame.
48
+ // ---------------------------------------------------------------------------
49
+ import { renderGlcdfontArray } from "@typecad/cuttlefish/api/shared";
50
+ export function emitCuttlefishGfx(active) {
51
+ if (!active)
52
+ return "";
53
+ // The font array (shared with the SDL adapter).
54
+ const fontArray = renderGlcdfontArray("cuttlefish_glcdfont", "unsigned char");
55
+ return `
56
+ // ── CuttlefishGFX (native display GFX base) ────────────────────────────────
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.
60
+ #ifndef CUTTLEFISH_GFX_DEFINED
61
+ #define CUTTLEFISH_GFX_DEFINED
62
+
63
+ #include <stdint.h>
64
+ #include <cstdlib>
65
+ #include <cstring>
66
+ #include <new> // std::nothrow for canvas buffer allocation
67
+
68
+ // ── Panel-ops interface ────────────────────────────────────────────────────
69
+ // Each native adapter fills a CuttlefishPanelOps with function pointers that
70
+ // drive its specific bus + panel. CuttlefishGFX calls through these; it never
71
+ // touches hardware directly. Pointers marked "may be nullptr" must be null-
72
+ // checked by callers.
73
+ struct CuttlefishPanelOps {
74
+ void (*startWrite)(void* ctx); // assert CS, take bus lock (may be nullptr)
75
+ void (*endWrite)(void* ctx); // release CS / bus lock (may be nullptr)
76
+ void (*setAddrWindow)(void* ctx, int16_t x, int16_t y, int16_t w, int16_t h);
77
+ void (*writePixels)(void* ctx, const uint16_t* px, uint32_t n);
78
+ void (*writePixel)(void* ctx, int16_t x, int16_t y, uint16_t c); // direct mode
79
+ void (*fillRect)(void* ctx, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t c);
80
+ int16_t (*width)(void* ctx);
81
+ int16_t (*height)(void* ctx);
82
+ // For SSD1309/SSD1680 only — flush a backing-store buffer to the panel.
83
+ // May be nullptr on direct-mode panels.
84
+ void (*flush)(void* ctx, int16_t x, int16_t y, int16_t w, int16_t h);
85
+ };
86
+
87
+ // ── Color snap (mono displays) ─────────────────────────────────────────────
88
+ // Same logic as the Adafruit SSD1309 adapter: any nonzero 565 → white.
89
+ static inline uint16_t ssd_mono(uint16_t c) { return c ? 0xFFFFu : 0x0000u; }
90
+
91
+ // ── 5x7 font (Adafruit glcdfont, BSD-3-Clause — see file header) ──────────
92
+ // 256 glyphs × 5 bytes per glyph. Indexed as cuttlefish_glcdfont[ch * 5 + col].
93
+ ${fontArray}
94
+
95
+ // ── CuttlefishGFX base class ───────────────────────────────────────────────
96
+ class CuttlefishGFX {
97
+ public:
98
+ CuttlefishGFX(const CuttlefishPanelOps* ops, void* ctx)
99
+ : ops_(ops), ctx_(ctx),
100
+ cursor_x_(0), cursor_y_(0),
101
+ textcolor_(0xFFFFu), textbgcolor_(0x0000u),
102
+ textsize_(1), wrap_(true) {}
103
+ virtual ~CuttlefishGFX() {}
104
+
105
+ // Geometry — match Adafruit_GFX signatures exactly.
106
+ virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
107
+ virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
108
+ virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
109
+ virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
110
+ virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
111
+ virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
112
+ virtual void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color);
113
+ virtual void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color);
114
+ virtual void drawCircle(int16_t x, int16_t y, int16_t r, uint16_t color);
115
+ virtual void fillCircle(int16_t x, int16_t y, int16_t r, uint16_t color);
116
+ virtual void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
117
+ virtual void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
118
+
119
+ // Bitmaps — match Adafruit_GFX signatures.
120
+ virtual void drawRGBBitmap(int16_t x, int16_t y, const uint16_t* bitmap, int16_t w, int16_t h);
121
+
122
+ // Text
123
+ virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size);
124
+ virtual void write(uint8_t c);
125
+ void print(const char* s) { while (*s) write(static_cast<uint8_t>(*s++)); }
126
+ void setCursor(int16_t x, int16_t y) { cursor_x_ = x; cursor_y_ = y; }
127
+ void setTextColor(uint16_t c) { textcolor_ = c; }
128
+ void setTextColor(uint16_t c, uint16_t bg) { textcolor_ = c; textbgcolor_ = bg; }
129
+ void setTextSize(uint8_t s) { textsize_ = (s > 0) ? s : 1; }
130
+ void setTextWrap(bool w) { wrap_ = w; }
131
+
132
+ // virtual so CuttlefishCanvas16/Mono overrides route through their stored
133
+ // canvas dimensions instead of trying to deref the null ops_.
134
+ virtual int16_t width() const { return (ops_ && ops_->width) ? ops_->width(ctx_) : 0; }
135
+ virtual int16_t height() const { return (ops_ && ops_->height) ? ops_->height(ctx_) : 0; }
136
+ int16_t getCursorX() const { return cursor_x_; }
137
+ int16_t getCursorY() const { return cursor_y_; }
138
+
139
+ // Adafruit circle helpers — public because drawRoundRect/fillRoundRect call them.
140
+ void drawCircleHelper(int16_t x, int16_t y, int16_t r, uint8_t cornername, uint16_t color);
141
+ void fillCircleHelper(int16_t x, int16_t y, int16_t r, uint8_t cornername, int16_t delta, uint16_t color);
142
+
143
+ protected:
144
+ const CuttlefishPanelOps* ops_;
145
+ void* ctx_;
146
+ int16_t cursor_x_, cursor_y_;
147
+ uint16_t textcolor_, textbgcolor_;
148
+ uint8_t textsize_;
149
+ bool wrap_;
150
+ };
151
+
152
+ // ── RGB565 canvas (offscreen; for AA text + scroll compositing) ─────────────
153
+ // Mirrors Adafruit_GFXcanvas16. Allocates w*h*2 bytes; consumer must free via
154
+ // display_deleteCanvas (the runtime reuses persistent canvas slots — see
155
+ // AGENTS.md: __ui_container_canvas, __ui_repair_canvas, __ui_list_canvas,
156
+ // __ui_node_canvas).
157
+ class CuttlefishCanvas16 final : public CuttlefishGFX {
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.
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);
169
+ virtual ~CuttlefishCanvas16();
170
+ virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
171
+ virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
172
+ // Override width()/height() — the base implementation reads ops_->width,
173
+ // which is null for canvases (constructed with CuttlefishGFX(nullptr, nullptr)).
174
+ // Without these overrides, any code path that calls width()/height() on a
175
+ // canvas target (text wrapping, scroll clipping, ui_display_target_bounds)
176
+ // dereferences null.
177
+ virtual int16_t width() const { return canvas_w_; }
178
+ virtual int16_t height() const { return canvas_h_; }
179
+ uint16_t* getBuffer() const { return buffer_; }
180
+ uint16_t getPixel(int16_t x, int16_t y) const;
181
+ void fillScreen(uint16_t color) { fillRect(0, 0, canvas_w_, canvas_h_, color); }
182
+ int16_t canvasWidth() const { return canvas_w_; }
183
+ int16_t canvasHeight() const { return canvas_h_; }
184
+ private:
185
+ uint16_t* buffer_;
186
+ int16_t canvas_w_, canvas_h_;
187
+ uint8_t owns_buffer_; // 1 = dtor frees buffer_ (malloc'd), 0 = externally owned
188
+ };
189
+
190
+ // ── 1-bit mono canvas (SSD1309/SSD1680 backing stores) ──────────────────────
191
+ // Mirrors Adafruit_GFXcanvasMono. (w+7)/8 bytes per row. The buffer is the
192
+ // panel backing store on SSD1309 — flush via display_partial_refresh.
193
+ class CuttlefishCanvasMono final : public CuttlefishGFX {
194
+ public:
195
+ CuttlefishCanvasMono(const CuttlefishCanvasMono&) = delete;
196
+ CuttlefishCanvasMono& operator=(const CuttlefishCanvasMono&) = delete;
197
+ CuttlefishCanvasMono(int16_t w, int16_t h);
198
+ virtual ~CuttlefishCanvasMono();
199
+ virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
200
+ virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
201
+ // Override width()/height() — see CuttlefishCanvas16 for rationale.
202
+ virtual int16_t width() const { return canvas_w_; }
203
+ virtual int16_t height() const { return canvas_h_; }
204
+ uint8_t* getBuffer() const { return buffer_; }
205
+ uint16_t getPixel(int16_t x, int16_t y) const;
206
+ void fillScreen(uint16_t color) { fillRect(0, 0, canvas_w_, canvas_h_, color); }
207
+ int16_t canvasWidth() const { return canvas_w_; }
208
+ int16_t canvasHeight() const { return canvas_h_; }
209
+ private:
210
+ uint8_t* buffer_; // (w+7)/8 bytes per row × h rows
211
+ int16_t canvas_w_, canvas_h_;
212
+ };
213
+
214
+ // ───────────────────────────────────────────────────────────────────────────
215
+ // Implementations. Ported verbatim from Adafruit_GFX.cpp.
216
+ // ───────────────────────────────────────────────────────────────────────────
217
+
218
+ void CuttlefishGFX::drawPixel(int16_t x, int16_t y, uint16_t color) {
219
+ // Dispatch through ops_->writePixel when present (live panel); otherwise
220
+ // rely on subclasses (CuttlefishCanvas16/Mono) overriding drawPixel to
221
+ // write into their buffers. The null check on ops_ is required because
222
+ // canvases construct their base with CuttlefishGFX(nullptr, nullptr).
223
+ if (ops_ && ops_->writePixel) ops_->writePixel(ctx_, x, y, color);
224
+ }
225
+
226
+ void CuttlefishGFX::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
227
+ // Dispatch through the virtual fillRect so canvases (which override it)
228
+ // route into their buffer. Do NOT call the panel op directly here —
229
+ // canvases construct their base with a null panel-ops struct.
230
+ fillRect(x, y, 1, h, color);
231
+ }
232
+
233
+ void CuttlefishGFX::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
234
+ fillRect(x, y, w, 1, color);
235
+ }
236
+
237
+ void CuttlefishGFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
238
+ drawFastHLine(x, y, w, color);
239
+ drawFastHLine(x, y + h - 1, w, color);
240
+ drawFastVLine(x, y, h, color);
241
+ drawFastVLine(x + w - 1, y, h, color);
242
+ }
243
+
244
+ void CuttlefishGFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
245
+ // Live panel fast-path: bypass the per-pixel virtual call and ask the
246
+ // panel to fill directly. Canvases override this method to write into
247
+ // their buffer (so they never reach this base path).
248
+ if (ops_ && ops_->fillRect) ops_->fillRect(ctx_, x, y, w, h, color);
249
+ }
250
+
251
+ // Bresenham line — Adafruit_GFX.cpp drawLine, unchanged.
252
+ void CuttlefishGFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) {
253
+ int16_t steep = abs(y1 - y0) > abs(x1 - x0);
254
+ if (steep) {
255
+ int16_t t = x0; x0 = y0; y0 = t;
256
+ t = x1; x1 = y1; y1 = t;
257
+ }
258
+ if (x0 > x1) {
259
+ int16_t t = x0; x0 = x1; x1 = t;
260
+ t = y0; y0 = y1; y1 = t;
261
+ }
262
+ int16_t dx = x1 - x0, dy = abs(y1 - y0);
263
+ int16_t err = dx / 2;
264
+ int16_t ystep = (y0 < y1) ? 1 : -1;
265
+ for (; x0 <= x1; x0++) {
266
+ if (steep) drawPixel(y0, x0, color);
267
+ else drawPixel(x0, y0, color);
268
+ err -= dy;
269
+ if (err < 0) { y0 += ystep; err += dx; }
270
+ }
271
+ }
272
+
273
+ // Midpoint circle — Adafruit_GFX.cpp drawCircle, unchanged.
274
+ void CuttlefishGFX::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) {
275
+ if (r <= 0) { drawPixel(x0, y0, color); return; }
276
+ int16_t f = 1 - r, ddF_x = 1, ddF_y = -2 * r;
277
+ int16_t x = 0, y = r;
278
+ drawPixel(x0, y0 + r, color);
279
+ drawPixel(x0, y0 - r, color);
280
+ drawPixel(x0 + r, y0, color);
281
+ drawPixel(x0 - r, y0, color);
282
+ while (x < y) {
283
+ if (f >= 0) { y--; ddF_y += 2; f += ddF_y; }
284
+ x++; ddF_x += 2; f += ddF_x;
285
+ drawPixel(x0 + x, y0 + y, color);
286
+ drawPixel(x0 - x, y0 + y, color);
287
+ drawPixel(x0 + x, y0 - y, color);
288
+ drawPixel(x0 - x, y0 - y, color);
289
+ drawPixel(x0 + y, y0 + x, color);
290
+ drawPixel(x0 - y, y0 + x, color);
291
+ drawPixel(x0 + y, y0 - x, color);
292
+ drawPixel(x0 - y, y0 - x, color);
293
+ }
294
+ }
295
+
296
+ void CuttlefishGFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color) {
297
+ if (r <= 0) return;
298
+ int16_t f = 1 - r, ddF_x = 1, ddF_y = -2 * r;
299
+ int16_t x = 0, y = r;
300
+ while (x < y) {
301
+ if (f >= 0) { y--; ddF_y += 2; f += ddF_y; }
302
+ x++; ddF_x += 2; f += ddF_x;
303
+ if (cornername & 0x4) {
304
+ drawPixel(x0 + x, y0 + y, color);
305
+ drawPixel(x0 + y, y0 + x, color);
306
+ }
307
+ if (cornername & 0x2) {
308
+ drawPixel(x0 + x, y0 - y, color);
309
+ drawPixel(x0 + y, y0 - x, color);
310
+ }
311
+ if (cornername & 0x8) {
312
+ drawPixel(x0 - y, y0 + x, color);
313
+ drawPixel(x0 - x, y0 + y, color);
314
+ }
315
+ if (cornername & 0x1) {
316
+ drawPixel(x0 - y, y0 - x, color);
317
+ drawPixel(x0 - x, y0 - y, color);
318
+ }
319
+ }
320
+ }
321
+
322
+ void CuttlefishGFX::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) {
323
+ if (r <= 0) { drawPixel(x0, y0, color); return; }
324
+ drawFastVLine(x0, y0 - r, 2 * r + 1, color);
325
+ fillCircleHelper(x0, y0, r, 3, 0, color);
326
+ }
327
+
328
+ void CuttlefishGFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color) {
329
+ if (r <= 0) return;
330
+ int16_t f = 1 - r, ddF_x = 1, ddF_y = -2 * r;
331
+ int16_t x = 0, y = r;
332
+ while (x < y) {
333
+ if (f >= 0) { y--; ddF_y += 2; f += ddF_y; }
334
+ x++; ddF_x += 2; f += ddF_x;
335
+ if (cornername & 0x1) {
336
+ drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color);
337
+ drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color);
338
+ }
339
+ if (cornername & 0x2) {
340
+ drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color);
341
+ drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color);
342
+ }
343
+ }
344
+ }
345
+
346
+ void CuttlefishGFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) {
347
+ drawFastHLine(x + r, y, w - 2 * r, color); // Top
348
+ drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
349
+ drawFastVLine(x, y + r, h - 2 * r, color); // Left
350
+ drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
351
+ drawCircleHelper(x + r, y + r, r, 1, color);
352
+ drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
353
+ drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
354
+ drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
355
+ }
356
+
357
+ void CuttlefishGFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) {
358
+ fillRect(x + r, y, w - 2 * r, h, color);
359
+ fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
360
+ fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
361
+ }
362
+
363
+ void CuttlefishGFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
364
+ drawLine(x0, y0, x1, y1, color);
365
+ drawLine(x1, y1, x2, y2, color);
366
+ drawLine(x2, y2, x0, y0, color);
367
+ }
368
+
369
+ void CuttlefishGFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
370
+ int16_t a, b, y, last;
371
+ // Sort coordinates by Y order ascending.
372
+ if (y0 > y1) { int16_t t = y0; y0 = y1; y1 = t; t = x0; x0 = x1; x1 = t; }
373
+ if (y1 > y2) { int16_t t = y1; y1 = y2; y2 = t; t = x1; x1 = x2; x2 = t; }
374
+ if (y0 > y1) { int16_t t = y0; y0 = y1; y1 = t; t = x0; x0 = x1; x1 = t; }
375
+ if (y0 == y2) { drawFastHLine(x0, y0, x1 - x0, color); return; }
376
+ int16_t dx01 = x1 - x0, dy01 = y1 - y0;
377
+ int16_t dx02 = x2 - x0, dy02 = y2 - y0;
378
+ int16_t dx12 = x2 - x1, dy12 = y2 - y1;
379
+ int32_t sa = 0, sb = 0;
380
+ last = (y1 == y2) ? y1 : y1 - 1;
381
+ for (y = y0; y <= last; y++) {
382
+ a = x0 + sa / dy01;
383
+ b = x0 + sb / dy02;
384
+ sa += dx01;
385
+ sb += dx02;
386
+ if (a > b) { int16_t t = a; a = b; b = t; }
387
+ drawFastHLine(a, y, b - a + 1, color);
388
+ }
389
+ sa = static_cast<int32_t>(dx12) * (last - y1);
390
+ sb = static_cast<int32_t>(dx02) * (last - y0);
391
+ for (; y <= y2; y++) {
392
+ a = x1 + sa / dy12;
393
+ b = x0 + sb / dy02;
394
+ sa += dx12;
395
+ sb += dx02;
396
+ if (a > b) { int16_t t = a; a = b; b = t; }
397
+ drawFastHLine(a, y, b - a + 1, color);
398
+ }
399
+ }
400
+
401
+ // RGB565 bitmap — Adafruit_GFX.cpp drawRGBBitmap, adapted to call writePixel
402
+ // through the panel ops (no memory-backed variant; the Adafruit mem-version
403
+ // is unused by the cuttlefish runtime).
404
+ void CuttlefishGFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t* bitmap, int16_t w, int16_t h) {
405
+ if (!bitmap || w <= 0 || h <= 0) return;
406
+ for (int16_t j = 0; j < h; j++) {
407
+ for (int16_t i = 0; i < w; i++) {
408
+ drawPixel(x + i, y + j, bitmap[static_cast<int32_t>(j) * w + i]);
409
+ }
410
+ }
411
+ }
412
+
413
+ // Glyph rendering — Adafruit_GFX.cpp drawChar, unchanged algorithm.
414
+ void CuttlefishGFX::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) {
415
+ if ((x >= width()) || // Clip right
416
+ (y >= height()) || // Clip bottom
417
+ ((x + 5 * size - 1) < 0) || // Clip left
418
+ ((y + 8 * size - 1) < 0)) // Clip top
419
+ return;
420
+ if (c >= 176) c++; // Adafruit '±' fixup
421
+ for (int8_t i = 0; i < 5; i++) {
422
+ uint8_t line = cuttlefish_glcdfont[static_cast<size_t>(c) * 5 + i];
423
+ for (int8_t j = 0; j < 8; j++, line >>= 1) {
424
+ if (line & 1) {
425
+ if (size == 1) drawPixel(x + i, y + j, color);
426
+ else fillRect(x + i * size, y + j * size, size, size, color);
427
+ } else if (bg != color) {
428
+ if (size == 1) drawPixel(x + i, y + j, bg);
429
+ else fillRect(x + i * size, y + j * size, size, size, bg);
430
+ }
431
+ }
432
+ }
433
+ if (bg != color) {
434
+ if (size == 1) drawFastVLine(x + 5, y, 8, bg);
435
+ else fillRect(x + 5 * size, y, size, 8 * size, bg);
436
+ }
437
+ }
438
+
439
+ void CuttlefishGFX::write(uint8_t c) {
440
+ if (c == '\\n') {
441
+ cursor_x_ = 0;
442
+ cursor_y_ += textsize_ * 8;
443
+ } else if (c != '\\r') {
444
+ int16_t w = 6 * textsize_;
445
+ if (wrap_ && ((cursor_x_ + w) > width())) {
446
+ cursor_x_ = 0;
447
+ cursor_y_ += textsize_ * 8;
448
+ }
449
+ drawChar(cursor_x_, cursor_y_, c, textcolor_, textbgcolor_, textsize_);
450
+ cursor_x_ += w;
451
+ }
452
+ }
453
+
454
+ // ── Canvas implementations ─────────────────────────────────────────────────
455
+
456
+ CuttlefishCanvas16::CuttlefishCanvas16(int16_t w, int16_t h)
457
+ : CuttlefishGFX(nullptr, nullptr),
458
+ buffer_(nullptr), canvas_w_(w), canvas_h_(h), owns_buffer_(1) {
459
+ if ((w > 0) && (h > 0)) {
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));
467
+ if (buffer_) memset(buffer_, 0, bytes);
468
+ }
469
+ }
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
+
480
+ CuttlefishCanvas16::~CuttlefishCanvas16() {
481
+ if (buffer_ && owns_buffer_) free(buffer_);
482
+ }
483
+
484
+ void CuttlefishCanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
485
+ if (!buffer_) return;
486
+ if ((x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return;
487
+ buffer_[static_cast<size_t>(y) * static_cast<size_t>(canvas_w_) + static_cast<size_t>(x)] = color;
488
+ }
489
+
490
+ void CuttlefishCanvas16::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
491
+ if (!buffer_) return;
492
+ int16_t x1 = (x < 0) ? 0 : x;
493
+ int16_t y1 = (y < 0) ? 0 : y;
494
+ int16_t x2 = x + w; if (x2 > canvas_w_) x2 = canvas_w_;
495
+ int16_t y2 = y + h; if (y2 > canvas_h_) y2 = canvas_h_;
496
+ // Cull before the inner loop (AGENTS.md: clip before expensive work).
497
+ if (x2 <= x1 || y2 <= y1) return;
498
+ for (int16_t j = y1; j < y2; j++) {
499
+ uint16_t* row = buffer_ + static_cast<size_t>(j) * static_cast<size_t>(canvas_w_);
500
+ for (int16_t i = x1; i < x2; i++) row[i] = color;
501
+ }
502
+ }
503
+
504
+ uint16_t CuttlefishCanvas16::getPixel(int16_t x, int16_t y) const {
505
+ if (!buffer_ || (x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return 0;
506
+ return buffer_[static_cast<size_t>(y) * static_cast<size_t>(canvas_w_) + static_cast<size_t>(x)];
507
+ }
508
+
509
+ CuttlefishCanvasMono::CuttlefishCanvasMono(int16_t w, int16_t h)
510
+ : CuttlefishGFX(nullptr, nullptr),
511
+ buffer_(nullptr), canvas_w_(w), canvas_h_(h) {
512
+ if ((w > 0) && (h > 0)) {
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));
516
+ if (buffer_) memset(buffer_, 0, bytes);
517
+ }
518
+ }
519
+
520
+ CuttlefishCanvasMono::~CuttlefishCanvasMono() {
521
+ if (buffer_) free(buffer_);
522
+ }
523
+
524
+ void CuttlefishCanvasMono::drawPixel(int16_t x, int16_t y, uint16_t color) {
525
+ if (!buffer_) return;
526
+ if ((x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return;
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;
529
+ uint8_t mask = 0x80u >> (x & 7);
530
+ if (color) row[x >> 3] |= mask;
531
+ else row[x >> 3] &= ~mask;
532
+ }
533
+
534
+ void CuttlefishCanvasMono::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
535
+ if (!buffer_) return;
536
+ int16_t x1 = (x < 0) ? 0 : x;
537
+ int16_t y1 = (y < 0) ? 0 : y;
538
+ int16_t x2 = x + w; if (x2 > canvas_w_) x2 = canvas_w_;
539
+ int16_t y2 = y + h; if (y2 > canvas_h_) y2 = canvas_h_;
540
+ if (x2 <= x1 || y2 <= y1) return;
541
+ uint8_t fill = color ? 0xFFu : 0x00u;
542
+ for (int16_t j = y1; j < y2; j++) {
543
+ for (int16_t i = x1; i < x2; i++) {
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;
546
+ uint8_t mask = 0x80u >> (i & 7);
547
+ if (color) row[i >> 3] |= mask;
548
+ else row[i >> 3] &= ~mask;
549
+ }
550
+ }
551
+ (void)fill;
552
+ }
553
+
554
+ uint16_t CuttlefishCanvasMono::getPixel(int16_t x, int16_t y) const {
555
+ if (!buffer_ || (x < 0) || (y < 0) || (x >= canvas_w_) || (y >= canvas_h_)) return 0;
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;
558
+ return (row[x >> 3] & (0x80u >> (x & 7))) ? 0xFFFFu : 0x0000u;
559
+ }
560
+
561
+ #endif // CUTTLEFISH_GFX_DEFINED
562
+ `;
563
+ }
@@ -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
- // visible descendants dirty for direct draw — never clears the whole viewport.
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 ? (int16_t)(vh - absDelta) : 0;
77
- ui_display_fill_rect(vox, (int16_t)(voy + stripY), vw, absDelta, scrollBg);
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
- __ui_nodes[c].dirty = 1;
84
- if (__ui_nodes[c].kind == NODE_PROGRESS || __ui_nodes[c].kind == NODE_RANGE) {
85
- __ui_nodes[c].lastTextWidth = -1;
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 (int16_t)nodeIdx;
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 (int16_t)p;
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 (int16_t)p;
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 = (int16_t)(-__ui_draw_off_x);
30
- if (top) *top = (int16_t)(-__ui_draw_off_y);
31
- if (right) *right = (int16_t)(ui_display_target_width() - __ui_draw_off_x);
32
- if (bottom) *bottom = (int16_t)(ui_display_target_height() - __ui_draw_off_y);
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 = (int16_t)(*x + *w);
41
- int16_t y1 = (int16_t)(*y + *h);
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 = (int16_t)(x1 - x0);
48
- *h = (int16_t)(y1 - y0);
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) {