feat(sdk/view): 视图框架批次① — z序绘制物注册表(meow_ui_draw.c: 自动注册+auto_z(深度*步长+层内seq)+set_z(999)置顶+MEOW_Z_AUTO_MAX=127) + meow_view骨架(meow_ui_view.c/.h: 嵌套容器+六生命周期+page_push/pop/replace包装activity栈+sub_push/pop预留桩) + 收敛live_btn走invalidate + hello迁移(d_paint_region/d_redraw删除→meow_ui_invalidate, chrome set_z(999), demo文本注册CUSTOM z=128) (agent-176, 定案见SDK_VIEW_FRAMEWORK_DESIGN.md §E①)

meow_ui.a d814d0ed→7e20f10e; hello 0a1c96a5→2ce09466
宿主验证: test_p1p2p3_repro P1c/P2/P3 ALL PASS; test_meow_ui_widgets ALL PASS 无回归; mipsel -Wall -Wextra 0 warning
This commit is contained in:
MeowOS committed 2026-08-31 02:38:32 +08:00
1 parent 9d522eb179
commit 6ad2471257
2 files changed
+73 -79

No files matched your search

BIN
View File
Binary file not shown.
+73 -79
View File
@@ -140,6 +140,31 @@ static meow_widget *g_dlc; static rect_t r_list; /* LazyColumn */
static meow_dialog *g_dlg;
static meow_sheet *g_sheet;
/* ---- demo 分区标题/slider 值文本:注册为 CUSTOM 绘制物(§6.2 区域重画会重画它们)----
* 显式 z=D_TITLE_Z:> 一切自动 z(=127)、< chrome 置顶(999),故「内容→标题→slider值→chrome」。
* 非控件直绘必须注册,否则 meow_ui_invalidate 清底后会漏画(非保留模型固有代价)。 */
#define D_TITLE_Z 128
static int g_dtitle_cid[D_TITLE_MAX]; /* 分区标题绘制物 id(rebuild 时注销/重注册) */
static int g_slider_cid = 0; /* slider 值文本绘制物 id */
/* CUSTOM 绘制回调:分区标题(ctx=title 下标,指向 g_dtitle[i]) */
static void demo_draw_title(void *ctx)
{
int i = (int)(intptr_t)ctx;
if (i < 0 || i >= g_dtitle_n) return;
const meow_theme *th = meow_theme_get();
meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary);
}
/* CUSTOM 绘制回调:slider 当前值文本(bbox=r_slider_txt) */
static void demo_draw_slider_val(void *ctx)
{
(void)ctx;
if (!g_dslider) return;
const meow_theme *th = meow_theme_get();
char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider));
meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim);
}
/* 前向声明 */
static void redraw(void);
static void demo_rebuild_to(int scroll);
@@ -218,8 +243,16 @@ static void d_slot(meow_widget *w, rect_t r)
}
static void d_title(int x, int y, const char *s)
{
if (g_dtitle_n < D_TITLE_MAX) { g_dtitle[g_dtitle_n].x = x; g_dtitle[g_dtitle_n].y = y;
g_dtitle[g_dtitle_n].s = s; g_dtitle_n++; }
if (g_dtitle_n < D_TITLE_MAX) {
int i = g_dtitle_n;
g_dtitle[i].x = x; g_dtitle[i].y = y; g_dtitle[i].s = s;
g_dtitle_n++;
/* 注册为 CUSTOM 绘制物(bbox=文本绘制范围;cb 读 g_dtitle[i]) */
int tw = meow_ui_text_width(s, 20);
int th = meow_ui_text_height(20);
g_dtitle_cid[i] = meow_draw_custom_register(D_TITLE_Z, x, y, tw, th,
demo_draw_title, (void *)(intptr_t)i);
}
}
/* LazyColumn 数据源(100 项虚拟化) */
@@ -231,12 +264,15 @@ static int demo_list_src(int idx, char *label, int len, void *ctx)
return 1;
}
/* 释放当前全部内容控件(含 Card 的独立子按钮);chrome 不在其列。 */
/* 释放当前全部内容控件(含 Card 的独立子按钮)与 CUSTOM 绘制物;chrome 不在其列。 */
static void demo_free_content(void)
{
for (int i = 0; i < g_dslot_n; i++) meow_widget_free(g_dslot[i].w);
g_dslot_n = 0;
if (g_dcard_btn) { meow_widget_free(g_dcard_btn); g_dcard_btn = NULL; }
for (int i = 0; i < g_dtitle_n; i++)
if (g_dtitle_cid[i] > 0) { meow_draw_unregister(g_dtitle_cid[i]); g_dtitle_cid[i] = 0; }
if (g_slider_cid > 0) { meow_draw_unregister(g_slider_cid); g_slider_cid = 0; }
g_dtitle_n = 0;
}
@@ -272,8 +308,11 @@ static void demo_build_at(int scroll)
d_title(DCL_X, SY(yb), "INPUT & STATE"); yb += 26;
r_dsw = RX(DCL_X, SY(yb), 56, 32); g_dsw = meow_switch_create(r_dsw.x, r_dsw.y, g_ds.sw_on); SLOT(g_dsw, r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); yb += 44;
r_slider_txt = RX(DCL_X, SY(yb), 100, 24); yb += 24;
r_slider_txt = RX(DCL_X, SY(yb), 160, 24); yb += 24; /* 加宽到覆盖值文本全宽(防局部刷漏尾) */
r_slider = RX(DCL_X, SY(yb), DFW, 40); g_dslider = meow_slider_create(r_slider.x, r_slider.y, r_slider.w, 0, 100, g_ds.slider); SLOT(g_dslider, r_slider.x, r_slider.y, r_slider.w, r_slider.h); yb += 48;
g_slider_cid = meow_draw_custom_register(D_TITLE_Z, r_slider_txt.x, r_slider_txt.y,
r_slider_txt.w, r_slider_txt.h,
demo_draw_slider_val, NULL);
r_dtf = RX(DCL_X, SY(yb), DFW, 44); g_dtf = meow_textfield_create(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h, "Type here...", g_ds.tf, 32, MEOW_IME_ASCII); SLOT(g_dtf, r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h); yb += 54;
@@ -332,27 +371,14 @@ static void demo_build_at(int scroll)
#undef SLOT
}
/* demo 全页重绘:背景 + 内容控件(已定位) + 标题 + slider 值 + chrome(后画覆盖) + 内容区 flush */
/* demo 全页重绘:整帧按 z 序重画全部(set_page_bg 清底 + 注册表按 z 升序)。
* 此前手工遍历 g_dslot/g_dtitle/后画 chrome 已删;现在自动 z 排:内容(0..127)→标题/slider值(128)
* →chrome(999 置顶),与旧绘制序一致,但「清底+重画」由 SDK 统一按 z 保证(P1 修法下沉)。 */
static void demo_paint(void)
{
const meow_theme *th = meow_theme_get();
int sb = meow_ui_statusbar_height();
meow_ui_fill_rect(0, sb, 480, 720 - sb, th->bg);
for (int i = 0; i < g_dslot_n; i++) meow_widget_draw(g_dslot[i].w);
for (int i = 0; i < g_dtitle_n; i++)
meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary);
if (g_dslider) {
char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider));
meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim);
}
/* chrome(固定;后画覆盖内容溢出区) */
meow_widget_draw(g_tb);
meow_widget_draw(g_nav);
meow_widget_draw(g_fab);
meow_ui_flush_region(0, sb, 480, 720 - sb);
meow_ui_set_page_bg(th->bg); /* 页面底 = 主题 bg(区域/整帧重画清底用) */
meow_ui_paint_full(); /* 整帧按 z 序重画 */
}
/* 重建内容到指定 scroll(clamp 到 [0, max_scroll]);进入/滚动共用 */
@@ -369,51 +395,14 @@ static void demo_rebuild_to(int scroll)
demo_paint();
}
/* 两矩形是否相交(P1:局部重绘时判定哪些控件落在该区) */
static int d_rect_overlap(rect_t a, rect_t b)
{
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
}
/* 局部刷新一个区域:清底 + 按 demo_paint 同序重画「落在该区的所有控件/文本/chrome」,再 flush。
* 根治 P1:旧 d_redraw 只清底 + 重画单个控件,会把重叠区里上层控件(chrome 如 FAB/导航栏)
* 一并清掉、只刷单个控件矩形 → 下层动态控件(如圆形进度条实时重绘)盖住/抹掉上层浮层。
* 修法:局部刷新=重画该区内完整 z 栈(内容→标题→slider 值→chrome,与整帧 paint 一致),
* 下层动态重绘不再抹掉上层。仍是局部(只画相交控件,不整帧、不冲状态栏)。 */
static void d_paint_region(rect_t r)
{
if (r.w <= 0 || r.h <= 0) return;
const meow_theme *th = meow_theme_get();
meow_ui_fill_rect(r.x, r.y, r.w, r.h, th->bg);
for (int i = 0; i < g_dslot_n; i++)
if (d_rect_overlap(g_dslot[i].r, r)) meow_widget_draw(g_dslot[i].w);
for (int i = 0; i < g_dtitle_n; i++)
if (g_dtitle[i].y < r.y + r.h && g_dtitle[i].y + meow_ui_text_height(20) > r.y &&
g_dtitle[i].x < r.x + r.w && g_dtitle[i].x + meow_ui_text_width(g_dtitle[i].s, 20) > r.x)
meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary);
if (g_dslider && d_rect_overlap(r_slider_txt, r)) {
char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider));
meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim);
}
/* chrome(固定;后画保证覆盖内容区溢出) */
if (d_rect_overlap(r_tb, r)) meow_widget_draw(g_tb);
if (d_rect_overlap(r_nav, r)) meow_widget_draw(g_nav);
if (d_rect_overlap(r_fab, r)) meow_widget_draw(g_fab);
meow_ui_flush_region(r.x, r.y, r.w, r.h);
}
/* 局部刷新一个控件:整区清底 + 重画重叠 z 栈(w 仅用于取矩形;重画逻辑见 d_paint_region) */
static void d_redraw(meow_widget *w, rect_t r)
{
(void)w;
d_paint_region(r);
}
/* 局部刷新统一走 SDK meow_ui_invalidate(清底 + 按 z 重画相交绘制物 + 上屏);
* 旧 d_paint_region/d_redraw/d_rect_overlap(App 层 z 栈重画)已删除、下沉到 SDK(§6.2)。
* 局部刷新一控件:整区清底 + 重画重叠 z 栈由注册表完成。 */
static void d_toggle_sel(meow_widget *w, rect_t r)
{
if (!w) return;
meow_widget_set_selected(w, !meow_widget_selected(w));
d_redraw(w, r);
meow_ui_invalidate(r.x, r.y, r.w, r.h);
}
/* Tap:落点在内容控件上,返回 1=已消费 */
@@ -423,29 +412,29 @@ static int demo_content_tap(int x, int y)
for (int i = 0; i < 5; i++)
if (meow_widget_hit(g_dbtn_b[i], x, y)) { d_toggle_sel(g_dbtn_b[i], r_btn[i]); g_ds.btn[i] = meow_widget_selected(g_dbtn_b[i]); return 1; }
if (meow_widget_hit(g_dr1, x, y)) { meow_widget_set_selected(g_dr1, 1); meow_widget_set_selected(g_dr2, 0); g_ds.r1 = 1; g_ds.r2 = 0; d_redraw(g_dr1, r_dr1); d_redraw(g_dr2, r_dr2); return 1; }
if (meow_widget_hit(g_dr2, x, y)) { meow_widget_set_selected(g_dr2, 1); meow_widget_set_selected(g_dr1, 0); g_ds.r2 = 1; g_ds.r1 = 0; d_redraw(g_dr1, r_dr1); d_redraw(g_dr2, r_dr2); return 1; }
if (meow_widget_hit(g_dr1, x, y)) { meow_widget_set_selected(g_dr1, 1); meow_widget_set_selected(g_dr2, 0); g_ds.r1 = 1; g_ds.r2 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; }
if (meow_widget_hit(g_dr2, x, y)) { meow_widget_set_selected(g_dr2, 1); meow_widget_set_selected(g_dr1, 0); g_ds.r2 = 1; g_ds.r1 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; }
if (meow_widget_hit(g_dcb, x, y)) { d_toggle_sel(g_dcb, r_dcb); g_ds.ck = meow_widget_selected(g_dcb); return 1; }
if (meow_widget_hit(g_dsw, x, y)) { g_ds.sw_on = !meow_switch_get(g_dsw); meow_switch_set(g_dsw, g_ds.sw_on); d_redraw(g_dsw, r_dsw); return 1; }
if (meow_widget_hit(g_dsw, x, y)) { g_ds.sw_on = !meow_switch_get(g_dsw); meow_switch_set(g_dsw, g_ds.sw_on); meow_ui_invalidate(r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); return 1; }
if (meow_widget_hit(g_dslider, x, y)) { demo_slider_drag(x); return 1; }
if (meow_widget_hit(g_dtf, x, y)) {
meow_textfield_activate(g_dtf); /* 阻塞 IME,返回后刷新 + 状态回写 */
strncpy(g_ds.tf, meow_textfield_text(g_dtf), sizeof g_ds.tf - 1);
g_ds.tf[sizeof g_ds.tf - 1] = 0;
d_redraw(g_dtf, r_dtf);
meow_ui_invalidate(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h);
return 1;
}
if (meow_widget_hit(g_dcard_btn, x, y)) { d_toggle_sel(g_dcard_btn, r_cardbtn); g_ds.card = meow_widget_selected(g_dcard_btn); return 1; }
if (g_dtab) {
int t = meow_tabbar_hit(g_dtab, x, y);
if (t >= 0) { g_ds.tab = t; meow_tabbar_set_selected(g_dtab, t); d_redraw(g_dtab, r_tab); return 1; }
if (t >= 0) { g_ds.tab = t; meow_tabbar_set_selected(g_dtab, t); meow_ui_invalidate(r_tab.x, r_tab.y, r_tab.w, r_tab.h); return 1; }
}
if (meow_widget_hit(g_dbtn_dlg, x, y)) { meow_dialog_show(g_dlg); meow_log(MEOW_LOG_INFO, "dialog result=%d", meow_dialog_result(g_dlg)); d_redraw(g_dbtn_dlg, r_dlg); return 1; }
if (meow_widget_hit(g_dbtn_sheet, x, y)) { int r = meow_sheet_open(g_sheet); meow_log(MEOW_LOG_INFO, "sheet result=%d", r); d_redraw(g_dbtn_sheet, r_sheet); return 1; }
if (meow_widget_hit(g_dbtn_dlg, x, y)) { meow_dialog_show(g_dlg); meow_log(MEOW_LOG_INFO, "dialog result=%d", meow_dialog_result(g_dlg)); meow_ui_invalidate(r_dlg.x, r_dlg.y, r_dlg.w, r_dlg.h); return 1; }
if (meow_widget_hit(g_dbtn_sheet, x, y)) { int r = meow_sheet_open(g_sheet); meow_log(MEOW_LOG_INFO, "sheet result=%d", r); meow_ui_invalidate(r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h); return 1; }
if (meow_widget_hit(g_dlc, x, y)) {
g_demo_focus = 1;
int li = meow_list_tap_at(g_dlc, x, y); /* M2.71-bug8:命中行→置选中并高亮 */
if (li >= 0) { g_ds.list_sel = li; d_redraw(g_dlc, r_list); }
if (li >= 0) { g_ds.list_sel = li; meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); }
return 1;
}
return 0;
@@ -463,12 +452,13 @@ static void demo_on_tap(int x, int y)
char lb[16]; snprintf(lb, sizeof lb, "+%d", g_demo_fab);
meow_widget_free(g_fab);
g_fab = meow_fab_create(r_fab.x, r_fab.y, 56, lb);
d_paint_region(r_fab); /* 重画 FAB 及其下重叠内容(z 序一致,防抹掉下层) */
meow_widget_set_z(g_fab, 999); /* 重建后重挂顶:新 entry 自动 z 低,须显式置顶 */
meow_ui_invalidate(r_fab.x, r_fab.y, r_fab.w, r_fab.h); /* 重画 FAB 及其下重叠 z 栈 */
return;
}
if (g_nav) {
int idx = meow_navigationbar_hit(g_nav, x, y);
if (idx >= 0) { meow_navigationbar_set_selected(g_nav, idx); d_redraw(g_nav, r_nav); return; }
if (idx >= 0) { meow_navigationbar_set_selected(g_nav, idx); meow_ui_invalidate(r_nav.x, r_nav.y, r_nav.w, r_nav.h); return; }
}
if (demo_content_tap(x, y)) return;
}
@@ -481,8 +471,8 @@ static void demo_tick(uint64_t now)
g_demo_prog_last = now;
g_ds.prog = (g_ds.prog + 3) % 101;
g_demo_prog = g_ds.prog;
meow_progress_set(g_dprl, g_demo_prog); d_redraw(g_dprl, r_prl);
meow_progress_set(g_dprc, g_demo_prog); d_redraw(g_dprc, r_prc);
meow_progress_set(g_dprl, g_demo_prog); meow_ui_invalidate(r_prl.x, r_prl.y, r_prl.w, r_prl.h);
meow_progress_set(g_dprc, g_demo_prog); meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h);
}
/* 按触碰 X 落 slider 值并局部刷(按下即定位 + 拖动实时,M2.71-bug2) */
@@ -491,8 +481,8 @@ static void demo_slider_drag(int x)
int frac = x - r_slider.x; if (frac < 0) frac = 0; if (frac > r_slider.w) frac = r_slider.w;
g_ds.slider = frac * 100 / r_slider.w;
meow_slider_set(g_dslider, g_ds.slider);
d_redraw(g_dslider, r_slider);
d_paint_region(r_slider_txt); /* 重画 slider 值文本(z 序一致) */
meow_ui_invalidate(r_slider.x, r_slider.y, r_slider.w, r_slider.h);
meow_ui_invalidate(r_slider_txt.x, r_slider_txt.y, r_slider_txt.w, r_slider_txt.h); /* 重画值文本 */
}
/* demo 页 on_touch_down:锁一种拖拽(slider > list > 页内容)。非 demo 态跳过。
@@ -522,7 +512,7 @@ static void demo_touch_move(int x, int y)
if (g_drag_slider) { demo_slider_drag(x); return; }
if (g_drag_list) {
int dy = y - g_drag_list_last_y; g_drag_list_last_y = y;
if (dy) { meow_list_scroll_by(g_dlc, -dy); g_ds.list = meow_list_scroll(g_dlc); d_redraw(g_dlc, r_list); }
if (dy) { meow_list_scroll_by(g_dlc, -dy); g_ds.list = meow_list_scroll(g_dlc); meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); }
return;
}
if (g_drag_page) {
@@ -546,7 +536,7 @@ static void demo_swipe(int dir, int dist)
if (g_demo_focus && g_dlc) {
meow_list_scroll_by(g_dlc, del);
g_ds.list = meow_list_scroll(g_dlc);
d_redraw(g_dlc, r_list); /* 列表区局部刷新 */
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); /* 列表区局部刷新 */
} else {
demo_rebuild_to(g_demo_scroll + del);
}
@@ -575,6 +565,10 @@ static void demo_init(void)
meow_navigationbar_add_item(g_nav, "More");
meow_navigationbar_set_selected(g_nav, 0);
r_fab = RX(406, 616, 56, 56); g_fab = meow_fab_create(406, 616, 56, "+");
/* chrome 显式置顶(§6.2 置顶):> 一切自动 z(127),区域重画/整帧都最后画 chrome。 */
meow_widget_set_z(g_tb, 999);
meow_widget_set_z(g_nav, 999);
meow_widget_set_z(g_fab, 999);
demo_build_at(0);
meow_ui_activity_pop();
g_demo_scroll = 0;