diff --git a/hello b/hello index c63acbc..d07d3df 100755 Binary files a/hello and b/hello differ diff --git a/hello.c b/hello.c index 4d4e87c..aa02370 100644 --- a/hello.c +++ b/hello.c @@ -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;