/* * meow_ui_draw.c — 绘制物注册表 / z 序 / 区域重画(§6.2 / SDK_Z_ORDER_DESIGN §2)。 * * 非保留模型下,把「清底 + 按 z 重画重叠区完整 z 栈」下沉到 SDK: * - 控件(meow_widget)创建即自动注册(create 末尾调 meow_draw_widget_register), * meow_widget_free 自动注销;rect 实时读 w->x/y/w/h; * - App 直绘的非控件内容显式 meow_draw_custom_register(声明 bbox + 绘制回调); * - z 自动推导(子>父、同层注册先序);显式 set_z 粘滞、置顶。 * 显式 z 存于本注册表(按 w 反查 entry),**不改 struct meow_widget**(零 ABI 破坏)。 */ #include "meow_ui.h" #include "meow_ui_internal.h" #include "meow_ui_view.h" #include #include #define MEOW_DRAW_MAX 256 #define MEOW_ITEM_VIEW 2 /* 内部 kinds(不进公共枚举):meow_view 绘制物 */ typedef struct draw_entry { int kind; /* MEOW_ITEM_WIDGET / MEOW_ITEM_CUSTOM / MEOW_ITEM_VIEW */ meow_widget *w; /* WIDGET:绘制其 meow_widget_draw(w) */ meow_draw_fn draw_cb; /* CUSTOM:绘制回调 */ void *ctx; /* CUSTOM: 传给 draw_cb; VIEW: (meow_view*)v */ int rx, ry, rw, rh; /* CUSTOM bbox(WIDGET 读 w->x/y/w/h,VIEW 读 v->x/y/w/h) */ int z; /* 生效 z(显式=其值,否则=自动推导) */ int z_explicit; /* 1=显式(粘滞) */ int id; /* CUSTOM id(0=无效) */ int seq; /* 全局注册序(z 同值时稳定先序) */ struct meow_view *view; /* WIDGET:所属 view(z 深度源)+1 */ } draw_entry; static draw_entry g_e[MEOW_DRAW_MAX]; static int g_n = 0; static int g_seq = 0; /* 全局注册序(单调递增) */ static int g_next_id = 1; /* CUSTOM id 起点(0=无效) */ static uint32_t g_page_bg = 0; static int g_page_bg_set = 0; /* ---- 内部访问器(widget.c 提供;跨 TU 用 meow_ui_internal.h 声明)---- */ static int w_is_layout(const meow_widget *w) { return meow_widget_is_layout(w); } /* ---- 查找 ---- */ static draw_entry *e_find_widget(const meow_widget *w) { for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_WIDGET && g_e[i].w == w) return &g_e[i]; return NULL; } static draw_entry *e_find_view(const meow_view *v) { for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_VIEW && g_e[i].ctx == (void *)v) return &g_e[i]; return NULL; } static draw_entry *e_find_id(int id) { for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_CUSTOM && g_e[i].id == id) return &g_e[i]; return NULL; } /* ---- 深度:view 树深度 ---- */ static int view_depth(const meow_view *v) { int d = 0; const meow_view *p = v ? v->parent : NULL; while (p) { d++; if (d > MEOW_Z_DEPTH_MAX) break; p = p->parent; } return d; } /* ---- 深度:widget 所属嵌套深度(view 树为主;否则 W_LAYOUT children 反推;否则 0)---- */ static int widget_nest_depth(meow_widget *w, int depth) { if (depth > MEOW_Z_DEPTH_MAX) return MEOW_Z_DEPTH_MAX; draw_entry *e = e_find_widget(w); if (e && e->view) return view_depth(e->view) + 1; /* 视图树深度源(更确定) */ /* 注册表反推:w 是否经 meow_layout_add 挂在某布局下(此时布局自身已注册为 WIDGET)。 */ for (int i = 0; i < g_n; i++) { if (g_e[i].kind != MEOW_ITEM_WIDGET) continue; meow_widget *lw = g_e[i].w; if (!lw || !w_is_layout(lw)) continue; int nc = meow_widget_nchild(lw); for (int j = 0; j < nc; j++) if (meow_widget_child_at(lw, j) == w) return widget_nest_depth(lw, depth + 1) + 1; /* 子层 >= 父层+1 */ } return 0; } /* 计算 auto z(显式不重算——粘滞):depth*STRIDE + 层内 seq(注册先序,折叠 MEOW_Z_PER_LEVEL_MAX)。 */ static void e_compute_auto(draw_entry *e) { if (e->z_explicit) return; int depth = 0; if (e->kind == MEOW_ITEM_WIDGET && e->w) depth = widget_nest_depth(e->w, 0); else if (e->kind == MEOW_ITEM_VIEW && e->ctx) depth = view_depth((const meow_view *)e->ctx); /* CUSTOM:z 恒显式(register 传入),不进 auto 分支 */ int cnt = 0; for (int i = 0; i < g_n; i++) { draw_entry *o = &g_e[i]; if (o == e || o->z_explicit) continue; if (o->seq >= e->seq) continue; if (o->z / MEOW_Z_STRIDE == depth) cnt++; } if (cnt > MEOW_Z_PER_LEVEL_MAX) cnt = MEOW_Z_PER_LEVEL_MAX; e->z = depth * MEOW_Z_STRIDE + cnt; } /* ============================================================ */ /* 控件自动注册 / 注销(create 末尾 / meow_widget_free 调用) */ /* ============================================================ */ void meow_draw_widget_register(meow_widget *w) { if (!w || e_find_widget(w)) return; /* 幂等 */ if (g_n >= MEOW_DRAW_MAX) return; /* 满:静默(骨架级) */ draw_entry *e = &g_e[g_n++]; memset(e, 0, sizeof *e); e->kind = MEOW_ITEM_WIDGET; e->w = w; e->seq = g_seq++; e_compute_auto(e); } void meow_draw_widget_unregister(meow_widget *w) { if (!w) return; int idx = -1; for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_WIDGET && g_e[i].w == w) { idx = i; break; } if (idx < 0) return; g_e[idx] = g_e[--g_n]; /* 交换移除(seq 保留,排序稳定) */ } int meow_draw_widget_registered(const meow_widget *w) { return w ? e_find_widget(w) != NULL : 0; } void meow_draw_widget_set_view(meow_widget *w, struct meow_view *v) { draw_entry *e = e_find_widget(w); if (!e) return; e->view = v; e_compute_auto(e); } /* ============================================================ */ /* 显式 z(widget) */ /* ============================================================ */ void meow_widget_set_z(meow_widget *w, int z) { if (!w || z < 0) return; draw_entry *e = e_find_widget(w); if (!e) return; e->z_explicit = 1; e->z = z; } int meow_widget_z(const meow_widget *w) { if (!w) return 0; draw_entry *e = e_find_widget((meow_widget *)w); if (!e) return 0; if (e->z_explicit) return e->z; e_compute_auto(e); return e->z; } void meow_widget_clear_z(meow_widget *w) { if (!w) return; draw_entry *e = e_find_widget(w); if (!e) return; e->z_explicit = 0; e_compute_auto(e); } /* ============================================================ */ /* CUSTOM(App 直绘)注册 / 注销 / 改 z */ /* ============================================================ */ int meow_draw_custom_register(int z, int x, int y, int w, int h, meow_draw_fn cb, void *ctx) { if (!cb || w <= 0 || h <= 0) return 0; if (g_n >= MEOW_DRAW_MAX) return 0; draw_entry *e = &g_e[g_n++]; memset(e, 0, sizeof *e); e->kind = MEOW_ITEM_CUSTOM; e->draw_cb = cb; e->ctx = ctx; e->rx = x; e->ry = y; e->rw = w; e->rh = h; e->z = z < 0 ? 0 : z; e->z_explicit = 1; e->id = g_next_id++; e->seq = g_seq++; return e->id; } void meow_draw_unregister(int id) { if (id <= 0) return; int idx = -1; for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_CUSTOM && g_e[i].id == id) { idx = i; break; } if (idx < 0) return; g_e[idx] = g_e[--g_n]; } int meow_draw_set_z(int id, int z) { if (id <= 0 || z < 0) return -1; draw_entry *e = e_find_id(id); if (!e) return -1; e->z = z; e->z_explicit = 1; return 0; } /* ============================================================ */ /* view 绘制物注册 / 注销 */ /* ============================================================ */ void meow_draw_view_register(struct meow_view *v) { if (!v || e_find_view(v)) return; if (g_n >= MEOW_DRAW_MAX) return; draw_entry *e = &g_e[g_n++]; memset(e, 0, sizeof *e); e->kind = MEOW_ITEM_VIEW; e->ctx = (void *)v; e->seq = g_seq++; e_compute_auto(e); } void meow_draw_view_unregister(struct meow_view *v) { if (!v) return; int idx = -1; for (int i = 0; i < g_n; i++) if (g_e[i].kind == MEOW_ITEM_VIEW && g_e[i].ctx == (void *)v) { idx = i; break; } if (idx < 0) return; g_e[idx] = g_e[--g_n]; } int meow_draw_view_entered(const struct meow_view *v) { /* 子>父:view 或其任意祖先已进入即视为「可绘制」——配合 view_enter/leave 递归 * (meow_ui_view.c §A.4),父 on_enter 重绘时子视图(尚未单独进入)也要经 on_draw 画出; * 且子随父进出("子视图随父进出"),祖先已进入 ⇒ 子树已进入,可绘制。 */ const struct meow_view *cur = v; while (cur) { if (meow_view_get_state(cur) & MEOW_VIEW_STATE_ENTERED) return 1; cur = meow_view_parent(cur); } return 0; } void meow_draw_view_set_z(struct meow_view *v, int z) { draw_entry *e = e_find_view(v); if (!e) return; if (z <= 0) { e->z_explicit = 0; e_compute_auto(e); } else { e->z_explicit = 1; e->z = z; } } /* ============================================================ */ /* page bg / 区域重画 / 整帧 */ /* ============================================================ */ void meow_ui_set_page_bg(uint32_t color) { g_page_bg = color; g_page_bg_set = 1; } uint32_t meow_ui_page_bg(void) { return g_page_bg_set ? g_page_bg : meow_theme_get()->bg; } static int rect_hit(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) { return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by; } static int entry_rect(draw_entry *e, int out[4]) { if (e->kind == MEOW_ITEM_WIDGET && e->w) { meow_widget_rect(e->w, out); } else if (e->kind == MEOW_ITEM_VIEW && e->ctx) { meow_view *v = (meow_view *)e->ctx; out[0] = v->x; out[1] = v->y; out[2] = v->w; out[3] = v->h; } else { out[0] = e->rx; out[1] = e->ry; out[2] = e->rw; out[3] = e->rh; } return out[2] > 0 && out[3] > 0; } static void draw_one(draw_entry *e) { switch (e->kind) { case MEOW_ITEM_WIDGET: meow_widget_draw(e->w); break; case MEOW_ITEM_CUSTOM: e->draw_cb(e->ctx); break; case MEOW_ITEM_VIEW: { meow_view *v = (meow_view *)e->ctx; if (v->hooks.on_draw) v->hooks.on_draw(v, meow_theme_get(), v->ctx); break; } default: break; } } static void paint(int full, int x, int y, int w, int h) { uint32_t bg = meow_ui_page_bg(); if (full) { meow_ui_clear(bg); } else { if (w <= 0 || h <= 0) return; meow_ui_fill_rect(x, y, w, h, bg); } /* 刷新 auto z + 组装按 (z,seq) 升序的绘制序(owner==active 过滤 WIDGET;view 须已进入)。 */ draw_entry *order[MEOW_DRAW_MAX]; int nn = 0; int active = meow_ui_activity_active(); for (int i = 0; i < g_n; i++) { draw_entry *e = &g_e[i]; e_compute_auto(e); if (e->kind == MEOW_ITEM_WIDGET && e->w && meow_widget_owner(e->w) != active) continue; if (e->kind == MEOW_ITEM_VIEW && !meow_draw_view_entered((meow_view *)e->ctx)) continue; order[nn++] = e; } /* 稳定插入排序:(z 升序,同 z 按 seq 升序=注册先序)。 */ for (int i = 1; i < nn; i++) { draw_entry *key = order[i]; int j = i - 1; while (j >= 0 && (order[j]->z > key->z || (order[j]->z == key->z && order[j]->seq > key->seq))) { order[j + 1] = order[j]; j--; } order[j + 1] = key; } if (full) { for (int i = 0; i < nn; i++) draw_one(order[i]); meow_ui_flush(); } else { int r[4]; /* 区域重画(meow_ui_invalidate):把绘制 clip 收敛到本次失效矩形,只画「真正相交且可见」的 * 部分——大绘制物(整页 card/布局)仅擦边相交时不再整块重画,而是裁到矩形内,避免 overdraw。 * 控件内部还会再 push 自身矩形(嵌套求交 = 矩形∩控件,语义不变:越界仍被裁)。 */ meow_gfx_clip_push(x, y, w, h); for (int i = 0; i < nn; i++) { if (!entry_rect(order[i], r)) continue; if (rect_hit(r[0], r[1], r[2], r[3], x, y, w, h)) draw_one(order[i]); } meow_gfx_clip_pop(); meow_ui_flush_region(x, y, w, h); } } void meow_ui_invalidate(int x, int y, int w, int h) { if (w <= 0 || h <= 0) return; paint(0, x, y, w, h); } void meow_ui_paint_full(void) { paint(1, 0, 0, 0, 0); }