feat(sdk): 绘制期通用clip + view递归/on_event接线 (agent-195) — ①栈式clip rect(g_clip_stack[16]), 所有写像素原语过clip, meow_widget_draw push/pop控件矩形(含W_CUSTOM, 根治越界脏区), IME/模态顶层全屏不受影响 ②view enter/leave递归children + meow_view_dispatch_event(z降序子>父命中即消费); hello App层显式驱动退役

meow_ui.a→da4d3a7d; hello→c655ba43; 宿主4套件全PASS(含clip越界断言+view递归断言)
出入: W_SLIDER拇指在max处被裁(既有几何瑕疵可见化,待修); on_draw祖先已进入即画
This commit is contained in:
MeowOS committed 2026-08-31 05:24:43 +08:00
1 parent b2e7cc8c70
commit 32a6a8ed1e
14 files changed
+257 -44

No files matched your search

+97 -4
View File
@@ -62,6 +62,48 @@ static int g_dirty[/*MUI_DIRTY_MAX*/12][4]; /* [x,y,w,h] */
static int g_ndirty = 0;
static int g_dirty_full = 1;
/* ---- 绘制期裁剪(clip rect,§3;默认全屏)----
* 栈式嵌套:push 与当前 clip 求交后压栈,pop 恢复。写像素原语(put_px / put_px_blend /
* fill_rect / fill_rect_alpha / round / circle / ring / blit_icon / blit_rgba / text)
* 统一过 g_clip;顶层(g_clip_n==0)= 全屏(g_xres×g_yres),故 IME/模态的全屏 scrim
* 直绘不受裁剪。 */
#define MUI_CLIP_MAX 16
static int g_clip_stack[MUI_CLIP_MAX][4]; /* [x0,y0,x1,y1](闭开区间) */
static int g_clip_n = 0;
static void clip_cur(int out[4]) { /* 当前 clip 边界(无 clip = 全屏) */
if (g_clip_n > 0) {
out[0] = g_clip_stack[g_clip_n - 1][0]; out[1] = g_clip_stack[g_clip_n - 1][1];
out[2] = g_clip_stack[g_clip_n - 1][2]; out[3] = g_clip_stack[g_clip_n - 1][3];
} else { out[0] = 0; out[1] = 0; out[2] = g_xres; out[3] = g_yres; }
}
static int clip_contains(int x, int y)
{
if (g_clip_n == 0) return x >= 0 && x < g_xres && y >= 0 && y < g_yres;
return x >= g_clip_stack[g_clip_n - 1][0] && x < g_clip_stack[g_clip_n - 1][2] &&
y >= g_clip_stack[g_clip_n - 1][1] && y < g_clip_stack[g_clip_n - 1][3];
}
void meow_gfx_clip_push(int x, int y, int w, int h)
{
if (!g_init_ok || w <= 0 || h <= 0) return;
int c[4]; clip_cur(c);
int ix0 = x > c[0] ? x : c[0];
int iy0 = y > c[1] ? y : c[1];
int ix1 = (x + w) < c[2] ? (x + w) : c[2];
int iy1 = (y + h) < c[3] ? (y + h) : c[3];
if (ix1 < ix0) ix1 = ix0;
if (iy1 < iy0) iy1 = iy0;
if (g_clip_n >= MUI_CLIP_MAX) return; /* 栈满:忽略本次 push(保持当前 clip) */
g_clip_stack[g_clip_n][0] = ix0; g_clip_stack[g_clip_n][1] = iy0;
g_clip_stack[g_clip_n][2] = ix1; g_clip_stack[g_clip_n][3] = iy1;
g_clip_n++;
}
void meow_gfx_clip_pop(void)
{
if (g_clip_n > 0) g_clip_n--;
}
static char *g_dump_path = NULL;
/* ---- 状态栏「上收出屏只留提示线」(collapsed,基座)----
@@ -158,6 +200,17 @@ static void dirty_add(int x, int y, int w, int h)
if (x + w > g_xres) w = g_xres - x;
if (y + h > g_yres) h = g_yres - y;
if (w <= 0 || h <= 0) return;
/* 绘制期裁剪:脏区也不越 clip(顶层 clip=全屏 → 无操作)。 */
if (g_clip_n > 0) {
int *c = g_clip_stack[g_clip_n - 1];
int x1 = x + w, y1 = y + h;
if (x < c[0]) x = c[0];
if (y < c[1]) y = c[1];
if (x1 > c[2]) x1 = c[2];
if (y1 > c[3]) y1 = c[3];
if (x1 <= x || y1 <= y) return;
w = x1 - x; h = y1 - y;
}
for (int i = 0; i < g_ndirty; i++) {
if (rect_hit(g_dirty[i][0], g_dirty[i][1], g_dirty[i][2], g_dirty[i][3], x, y, w, h)) {
int nx1 = g_dirty[i][0] < x ? g_dirty[i][0] : x;
@@ -237,6 +290,7 @@ void meow_gfx_blit_icon(int idx, int x, int y, int ink_h, uint32_t fg, int cy)
for (int dx = 0; dx < t_w; dx++) {
int tx = x0 + dx;
if (tx < 0 || tx >= g_xres) continue;
if (!clip_contains(tx, ty)) continue;
int sx = minx + (dx * ink_w) / t_w;
int a = src[sy * SB_ICON_SIZE + sx];
if (a < 8) continue; /* 透明像素跳过 */
@@ -265,7 +319,7 @@ static uint16_t px_read_rgb565(int x, int y)
static void put_px(int x, int y, uint32_t color)
{
if (x < 0 || x >= g_xres || y < 0 || y >= g_yres) return;
if (!clip_contains(x, y)) return;
if (g_bpp == 16) {
px_write_rgb565(x, y, rgb565(color));
} else {
@@ -276,7 +330,7 @@ static void put_px(int x, int y, uint32_t color)
static void put_px_blend(int x, int y, uint32_t color, int alpha)
{
if (x < 0 || x >= g_xres || y < 0 || y >= g_yres) return;
if (!clip_contains(x, y)) return;
uint16_t fg = rgb565(color);
if (g_bpp == 16) {
uint16_t bg = px_read_rgb565(x, y);
@@ -300,6 +354,10 @@ static void put_px_blend(int x, int y, uint32_t color, int alpha)
void meow_ui_clear(uint32_t color)
{
if (!g_init_ok) return;
if (g_clip_n > 0) { /* 绘制期裁剪:清当前 clip 区(顶层 clip=全屏 → 走快速整刷) */
meow_ui_fill_rect(0, 0, g_xres, g_yres, color);
return;
}
/* 快速整刷(16bit 用半字填充,可 memset 当色值由 32bit 拼接掩码) */
if (g_bpp == 16) {
uint16_t c16 = rgb565(color);
@@ -327,6 +385,16 @@ void meow_ui_fill_rect(int x, int y, int w, int h, uint32_t color)
if (x + w > g_xres) w = g_xres - x;
if (y + h > g_yres) h = g_yres - y;
if (w <= 0 || h <= 0) return;
if (g_clip_n > 0) { /* 绘制期裁剪:与当前 clip 求交(顶层 clip=全屏 → 无操作) */
int *c = g_clip_stack[g_clip_n - 1];
int x1 = x + w, y1 = y + h;
if (x < c[0]) x = c[0];
if (y < c[1]) y = c[1];
if (x1 > c[2]) x1 = c[2];
if (y1 > c[3]) y1 = c[3];
if (x1 <= x || y1 <= y) return;
w = x1 - x; h = y1 - y;
}
if (g_bpp == 16) {
uint16_t c16 = rgb565(color);
for (int ry = y; ry < y + h; ry++) {
@@ -534,6 +602,16 @@ void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alp
if (x + w > g_xres) w = g_xres - x;
if (y + h > g_yres) h = g_yres - y;
if (w <= 0 || h <= 0) return;
if (g_clip_n > 0) { /* 绘制期裁剪:与当前 clip 求交(顶层 clip=全屏 → 无操作) */
int *c = g_clip_stack[g_clip_n - 1];
int x1 = x + w, y1 = y + h;
if (x < c[0]) x = c[0];
if (y < c[1]) y = c[1];
if (x1 > c[2]) x1 = c[2];
if (y1 > c[3]) y1 = c[3];
if (x1 <= x || y1 <= y) return;
w = x1 - x; h = y1 - y;
}
for (int ry = y; ry < y + h; ry++)
for (int rx = x; rx < x + w; rx++) put_px_blend(rx, ry, color, alpha);
dirty_add(x, y, w, h);
@@ -677,13 +755,28 @@ static void text_draw(int x, int y, const char *s, int size, uint32_t color)
{
if (!g_init_ok || !s) return;
if (g_mfont_ready && g_bpp == 16) {
meow_font_drawtext((uint16_t *)g_fb, x, y, s, rgb565(color), size);
int w = meow_font_width_text(s, size);
int hh = meow_font_line_height(size);
if (g_clip_n > 0) {
int *c = g_clip_stack[g_clip_n - 1];
if (x + w <= c[0] || x >= c[2] || y + hh <= c[1] || y >= c[3]) return; /* 与 clip 无交 */
if (!(x >= c[0] && x + w <= c[2] && y >= c[1] && y + hh <= c[3])) {
/* 部分相交:用「偏移 fb 子矩形 + 临时 fb 几何」做裁剪(meow_font 只按全屏剪)。
* 把 fb 基址指向 clip 左上角、fb_w/h 设为 clip 尺寸、原点平移到 clip 坐标,
* 这样 meow_font 的逐字形裁剪天然落在 clip 内;画完恢复全屏几何。 */
uint16_t *fb = (uint16_t *)(g_fb + (size_t)c[1] * g_line + (size_t)c[0] * 2);
meow_font_set_fb((unsigned)(c[2] - c[0]), (unsigned)(c[3] - c[1]), (unsigned)g_line);
meow_font_drawtext(fb, x - c[0], y - c[1], s, rgb565(color), size);
meow_font_set_fb((unsigned)g_xres, (unsigned)g_yres, (unsigned)g_line);
dirty_add(x, y, w, hh);
return;
}
}
meow_font_drawtext((uint16_t *)g_fb, x, y, s, rgb565(color), size);
dirty_add(x, y, w, hh);
} else {
int sc = fallback_scale(size);
draw_text5x7(x, y, s, sc, color);
draw_text5x7(x, y, s, sc, color); /* 走 put_px,自动过 clip */
dirty_add(x, y, (int)strlen(s) * 6 * sc, 7 * sc);
}
}