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:
1 parent
fbc412e96a
commit
08c70aa14c
13 files changed
+872
-96
No files matched your search
Binary file not shown.
+73
-79
@@ -140,6 +140,31 @@ static meow_widget *g_dlc; static rect_t r_list; /* LazyColumn */
|
|||||||
static meow_dialog *g_dlg;
|
static meow_dialog *g_dlg;
|
||||||
static meow_sheet *g_sheet;
|
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 redraw(void);
|
||||||
static void demo_rebuild_to(int scroll);
|
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)
|
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;
|
if (g_dtitle_n < D_TITLE_MAX) {
|
||||||
g_dtitle[g_dtitle_n].s = s; g_dtitle_n++; }
|
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 项虚拟化) */
|
/* LazyColumn 数据源(100 项虚拟化) */
|
||||||
@@ -231,12 +264,15 @@ static int demo_list_src(int idx, char *label, int len, void *ctx)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 释放当前全部内容控件(含 Card 的独立子按钮);chrome 不在其列。 */
|
/* 释放当前全部内容控件(含 Card 的独立子按钮)与 CUSTOM 绘制物;chrome 不在其列。 */
|
||||||
static void demo_free_content(void)
|
static void demo_free_content(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < g_dslot_n; i++) meow_widget_free(g_dslot[i].w);
|
for (int i = 0; i < g_dslot_n; i++) meow_widget_free(g_dslot[i].w);
|
||||||
g_dslot_n = 0;
|
g_dslot_n = 0;
|
||||||
if (g_dcard_btn) { meow_widget_free(g_dcard_btn); g_dcard_btn = NULL; }
|
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;
|
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;
|
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_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;
|
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;
|
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
|
#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)
|
static void demo_paint(void)
|
||||||
{
|
{
|
||||||
const meow_theme *th = meow_theme_get();
|
const meow_theme *th = meow_theme_get();
|
||||||
int sb = meow_ui_statusbar_height();
|
meow_ui_set_page_bg(th->bg); /* 页面底 = 主题 bg(区域/整帧重画清底用) */
|
||||||
|
meow_ui_paint_full(); /* 整帧按 z 序重画 */
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 重建内容到指定 scroll(clamp 到 [0, max_scroll]);进入/滚动共用 */
|
/* 重建内容到指定 scroll(clamp 到 [0, max_scroll]);进入/滚动共用 */
|
||||||
@@ -369,51 +395,14 @@ static void demo_rebuild_to(int scroll)
|
|||||||
demo_paint();
|
demo_paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 两矩形是否相交(P1:局部重绘时判定哪些控件落在该区) */
|
/* 局部刷新统一走 SDK meow_ui_invalidate(清底 + 按 z 重画相交绘制物 + 上屏);
|
||||||
static int d_rect_overlap(rect_t a, rect_t b)
|
* 旧 d_paint_region/d_redraw/d_rect_overlap(App 层 z 栈重画)已删除、下沉到 SDK(§6.2)。
|
||||||
{
|
* 局部刷新一控件:整区清底 + 重画重叠 z 栈由注册表完成。 */
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void d_toggle_sel(meow_widget *w, rect_t r)
|
static void d_toggle_sel(meow_widget *w, rect_t r)
|
||||||
{
|
{
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
meow_widget_set_selected(w, !meow_widget_selected(w));
|
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=已消费 */
|
/* Tap:落点在内容控件上,返回 1=已消费 */
|
||||||
@@ -423,29 +412,29 @@ static int demo_content_tap(int x, int y)
|
|||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
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_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_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; 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; 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_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_dslider, x, y)) { demo_slider_drag(x); return 1; }
|
||||||
if (meow_widget_hit(g_dtf, x, y)) {
|
if (meow_widget_hit(g_dtf, x, y)) {
|
||||||
meow_textfield_activate(g_dtf); /* 阻塞 IME,返回后刷新 + 状态回写 */
|
meow_textfield_activate(g_dtf); /* 阻塞 IME,返回后刷新 + 状态回写 */
|
||||||
strncpy(g_ds.tf, meow_textfield_text(g_dtf), sizeof g_ds.tf - 1);
|
strncpy(g_ds.tf, meow_textfield_text(g_dtf), sizeof g_ds.tf - 1);
|
||||||
g_ds.tf[sizeof g_ds.tf - 1] = 0;
|
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;
|
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 (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) {
|
if (g_dtab) {
|
||||||
int t = meow_tabbar_hit(g_dtab, x, y);
|
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_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); d_redraw(g_dbtn_sheet, r_sheet); 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)) {
|
if (meow_widget_hit(g_dlc, x, y)) {
|
||||||
g_demo_focus = 1;
|
g_demo_focus = 1;
|
||||||
int li = meow_list_tap_at(g_dlc, x, y); /* M2.71-bug8:命中行→置选中并高亮 */
|
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 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
char lb[16]; snprintf(lb, sizeof lb, "+%d", g_demo_fab);
|
||||||
meow_widget_free(g_fab);
|
meow_widget_free(g_fab);
|
||||||
g_fab = meow_fab_create(r_fab.x, r_fab.y, 56, lb);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (g_nav) {
|
if (g_nav) {
|
||||||
int idx = meow_navigationbar_hit(g_nav, x, y);
|
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;
|
if (demo_content_tap(x, y)) return;
|
||||||
}
|
}
|
||||||
@@ -481,8 +471,8 @@ static void demo_tick(uint64_t now)
|
|||||||
g_demo_prog_last = now;
|
g_demo_prog_last = now;
|
||||||
g_ds.prog = (g_ds.prog + 3) % 101;
|
g_ds.prog = (g_ds.prog + 3) % 101;
|
||||||
g_demo_prog = g_ds.prog;
|
g_demo_prog = g_ds.prog;
|
||||||
meow_progress_set(g_dprl, g_demo_prog); d_redraw(g_dprl, r_prl);
|
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); d_redraw(g_dprc, r_prc);
|
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) */
|
/* 按触碰 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;
|
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;
|
g_ds.slider = frac * 100 / r_slider.w;
|
||||||
meow_slider_set(g_dslider, g_ds.slider);
|
meow_slider_set(g_dslider, g_ds.slider);
|
||||||
d_redraw(g_dslider, r_slider);
|
meow_ui_invalidate(r_slider.x, r_slider.y, r_slider.w, r_slider.h);
|
||||||
d_paint_region(r_slider_txt); /* 重画 slider 值文本(z 序一致) */
|
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 态跳过。
|
/* 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_slider) { demo_slider_drag(x); return; }
|
||||||
if (g_drag_list) {
|
if (g_drag_list) {
|
||||||
int dy = y - g_drag_list_last_y; g_drag_list_last_y = y;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (g_drag_page) {
|
if (g_drag_page) {
|
||||||
@@ -546,7 +536,7 @@ static void demo_swipe(int dir, int dist)
|
|||||||
if (g_demo_focus && g_dlc) {
|
if (g_demo_focus && g_dlc) {
|
||||||
meow_list_scroll_by(g_dlc, del);
|
meow_list_scroll_by(g_dlc, del);
|
||||||
g_ds.list = meow_list_scroll(g_dlc);
|
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 {
|
} else {
|
||||||
demo_rebuild_to(g_demo_scroll + del);
|
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_add_item(g_nav, "More");
|
||||||
meow_navigationbar_set_selected(g_nav, 0);
|
meow_navigationbar_set_selected(g_nav, 0);
|
||||||
r_fab = RX(406, 616, 56, 56); g_fab = meow_fab_create(406, 616, 56, "+");
|
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);
|
demo_build_at(0);
|
||||||
meow_ui_activity_pop();
|
meow_ui_activity_pop();
|
||||||
g_demo_scroll = 0;
|
g_demo_scroll = 0;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ AR="${AR:-/usr/bin/ar}" # 系统 GNU ar 即可归档 mipsel ELF 对象(架
|
|||||||
rm -f meow_ui.a *.o
|
rm -f meow_ui.a *.o
|
||||||
|
|
||||||
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
||||||
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config stb_image"
|
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view stb_image"
|
||||||
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
||||||
for f in $OBJS; do
|
for f in $OBJS; do
|
||||||
echo "== cc $f =="
|
echo "== cc $f =="
|
||||||
|
|||||||
@@ -210,6 +210,58 @@ void meow_ui_global_remove(int id);
|
|||||||
/* ③ 系统级控件:状态栏/通知中心/左缘返回滑条/电源菜单等全局叠加层——仅 SDK 内部接口,
|
/* ③ 系统级控件:状态栏/通知中心/左缘返回滑条/电源菜单等全局叠加层——仅 SDK 内部接口,
|
||||||
* 不向用户 App 开放任何公共悬浮/叠加层 API。既有状态栏/返回滑条逻辑(§3.1)不动。 */
|
* 不向用户 App 开放任何公共悬浮/叠加层 API。既有状态栏/返回滑条逻辑(§3.1)不动。 */
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* §6.2 绘制物注册表 / z 序 / 区域重画(合并 SDK_Z_ORDER_DESIGN,源:2026-08-31)
|
||||||
|
* ------------------------------------------------------------
|
||||||
|
* 非保留模型(§5.8.7)下,把「清底 + 按 z 重画重叠区完整 z 栈」下沉到 SDK,让所有 App
|
||||||
|
* 自动获得正确的局部重画(根治 P1:下层动态控件局部重绘会把重叠区上层 chrome 抹掉)。
|
||||||
|
* - 控件(meow_widget)创建即自动注册进绘制物注册表;rect 实时读 w->x/y/w/h;
|
||||||
|
* - App 直绘的非控件内容(meow_ui_text/fill_rect 等)须显式 meow_draw_custom_register
|
||||||
|
* 注册(声明 bbox + 绘制回调),否则区域重画会漏画(非保留模型固有代价);
|
||||||
|
* - z 自动推导(子>父、同层注册先序);显式 meow_widget_set_z(999/MEOW_Z_TOP) 置顶(粘滞)。
|
||||||
|
* 用法:meow_ui_invalidate(x,y,w,h) 局部重画(清底+按 z 升序重画所有相交绘制物+上屏),
|
||||||
|
* 不整帧;meow_ui_paint_full() 整帧按 z 序重画。默认底=meow_theme bg(set_page_bg 覆盖)。
|
||||||
|
* 兼容:新 API 全部 opt-in;不调用本节的既有 App(widget/activity/flush 均不动)行为完全不变。 */
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
/* 绘制物种类:控件(自动注册)/ App 直绘内容(显式注册)。 */
|
||||||
|
typedef enum { MEOW_ITEM_WIDGET = 0, MEOW_ITEM_CUSTOM = 1 } meow_draw_kind;
|
||||||
|
typedef void (*meow_draw_fn)(void *ctx); /* CUSTOM 绘制回调(ctx 由 App 持有) */
|
||||||
|
|
||||||
|
/* ---- 层级常量(保证"子>父" + 值域远小于置顶值)---- */
|
||||||
|
#define MEOW_Z_STRIDE 16 /* 每层容器嵌套的 z 步进(子层至少 +16) */
|
||||||
|
#define MEOW_Z_DEPTH_MAX 7 /* 自动推导最大嵌套深度(0..6,>7 折叠) */
|
||||||
|
#define MEOW_Z_PER_LEVEL_MAX 15 /* 每层最多 16 槽(seq 0..15,超出折叠按注册序) */
|
||||||
|
#define MEOW_Z_AUTO_MAX (MEOW_Z_STRIDE * MEOW_Z_DEPTH_MAX + MEOW_Z_PER_LEVEL_MAX) /* 127 */
|
||||||
|
#define MEOW_Z_TOP 1000 /* 惯例"置顶"值;≥(MEOW_Z_AUTO_MAX+1)=128 即超一切自动值 */
|
||||||
|
|
||||||
|
/* 控件显式置层:z 为任意非负整数(0..INT_MAX,无上限),越大越上;z>所有其它控件即恒在最上。
|
||||||
|
* 惯例设 999(或 MEOW_Z_TOP)即"置顶"。显式 z 存于绘制注册表(按 w 反查 entry,不改
|
||||||
|
* struct meow_widget——零 ABI 破坏)且**粘滞**:不被后续自动推导覆盖;clear_z 才回退。 */
|
||||||
|
void meow_widget_set_z(meow_widget *w, int z);
|
||||||
|
int meow_widget_z(const meow_widget *w); /* 当前生效 z(显式=其值,否则=自动推导) */
|
||||||
|
void meow_widget_clear_z(meow_widget *w); /* 清除显式 z,回退自动推导 */
|
||||||
|
|
||||||
|
/* ---- 非控件直绘内容注册为绘制物(CUSTOM)----
|
||||||
|
* App 声明 bbox + 绘制回调 + 显式 z(任意非负;999=置顶);区域重画/整帧重画会画到它。
|
||||||
|
* 返回 id(供 meow_draw_unregister / meow_draw_set_z);注册表满返回 0。
|
||||||
|
* 生命周期契约:App 持有 ctx;widget 类内容不必注册(自动);离开页面前 unregister。 */
|
||||||
|
int meow_draw_custom_register(int z, int x, int y, int w, int h,
|
||||||
|
meow_draw_fn cb, void *ctx);
|
||||||
|
void meow_draw_unregister(int id); /* 注销(id 失效,勿再用) */
|
||||||
|
int meow_draw_set_z(int id, int z); /* 改 custom 显式 z;无效 id 返回 -1 */
|
||||||
|
|
||||||
|
/* 页面背景色(区域重画/整帧清底用);默认 meow_theme bg。 */
|
||||||
|
void meow_ui_set_page_bg(uint32_t color);
|
||||||
|
uint32_t meow_ui_page_bg(void);
|
||||||
|
|
||||||
|
/* 声明某区域内容已变化 → 清底(page_bg) + 按 z 升序重画所有相交绘制物 + 上屏。
|
||||||
|
* 局部(只画相交绘制物,完整 bbox——见 SDK_Z_ORDER_DESIGN §5),不整帧、不冲状态栏。 */
|
||||||
|
void meow_ui_invalidate(int x, int y, int w, int h);
|
||||||
|
|
||||||
|
/* 整帧按 z 序重画全部(set_page_bg 清底 + 全注册表按 z 升序 + 上屏)。 */
|
||||||
|
void meow_ui_paint_full(void);
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §3.1 全局状态栏 / 全屏(A-0,SDK 系统级组件) */
|
/* §3.1 全局状态栏 / 全屏(A-0,SDK 系统级组件) */
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
|
|||||||
@@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
return v ? meow_view_get_state(v) & MEOW_VIEW_STATE_ENTERED : 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];
|
||||||
|
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_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);
|
||||||
|
}
|
||||||
@@ -184,6 +184,31 @@ void meow_widget_touch_refresh(void);
|
|||||||
void meow_ui_global_render(void);
|
void meow_ui_global_render(void);
|
||||||
int meow_ui_global_hit(int x, int y);
|
int meow_ui_global_hit(int x, int y);
|
||||||
|
|
||||||
|
/* ---- 绘制物注册表(meow_ui_draw.c,§6.2 绘制物注册表/z序/区域重画)----
|
||||||
|
* 内部协作接口:widget.c 在 create 末尾自动注册、meow_widget_free 自动注销;view.c 在
|
||||||
|
* meow_view_add_widget/meow_view_free 挂/摘 widget 与 view 的 z 深度源;live_btn 收敛查询
|
||||||
|
* 是否已注册(已注册→走 invalidate 区域重画,否则回退单控件 flush)。 */
|
||||||
|
struct meow_view; /* 仅前向声明;完整类型在 meow_ui_view.h */
|
||||||
|
|
||||||
|
void meow_draw_widget_register(struct meow_widget *w); /* create 末尾:自动注册(幂等) */
|
||||||
|
void meow_draw_widget_unregister(struct meow_widget *w); /* meow_widget_free:自动注销 */
|
||||||
|
int meow_draw_widget_registered(const struct meow_widget *w);/* 是否在注册表(live_btn 收敛用) */
|
||||||
|
void meow_draw_widget_set_view(struct meow_widget *w, struct meow_view *v); /* 挂 view:重算 auto z */
|
||||||
|
void meow_draw_view_register(struct meow_view *v); /* view create:注册绘制物(on_draw 用) */
|
||||||
|
void meow_draw_view_unregister(struct meow_view *v); /* view free:注销 */
|
||||||
|
int meow_draw_view_entered(const struct meow_view *v); /* view 是否已进入(绘制过滤参考) */
|
||||||
|
void meow_draw_view_set_z(struct meow_view *v, int z); /* view 显式 z(z<=0=清除回退自动) */
|
||||||
|
|
||||||
|
/* 控件布局深度反推(meow_ui_draw.c 用;widget.c 实现,读 struct meow_widget 内部字段)。
|
||||||
|
* 让绘制注册表在「无 meow_view 时」仍能从 W_LAYOUT children 反推子>父深度。 */
|
||||||
|
int meow_widget_is_layout(const struct meow_widget *w); /* 1 = W_LAYOUT */
|
||||||
|
int meow_widget_nchild(const struct meow_widget *w); /* 布局子项数 */
|
||||||
|
const struct meow_widget *meow_widget_child_at(const struct meow_widget *w, int idx);
|
||||||
|
|
||||||
|
/* 控件几何/归属访问器(meow_ui_draw.c 用:绘制物 rect 实时读 + owner 过滤)。 */
|
||||||
|
int meow_widget_owner(const struct meow_widget *w); /* 创建时绑定的 Activity */
|
||||||
|
void meow_widget_rect(const struct meow_widget *w, int out[4]); /* x,y,w,h */
|
||||||
|
|
||||||
/* ---- IME(meow_ui_ime.c)---- */
|
/* ---- IME(meow_ui_ime.c)---- */
|
||||||
/* 当前是否显示软键盘。 */
|
/* 当前是否显示软键盘。 */
|
||||||
int meow_ime_active(void);
|
int meow_ime_active(void);
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* meow_ui_view.c — meow_view 视图/页面框架骨架(§A 视图数据结构/嵌套/生命周期/页面导航)。
|
||||||
|
*
|
||||||
|
* meow_view 是**薄壳**:容器 + 生命周期 + 事件路由;叶子仍是 meow_widget(不改)。绘制走
|
||||||
|
* z 序绘制物注册表(on_draw 回调,非保留——不缓存像素)。opt-in:不调 meow_view_* 的 App
|
||||||
|
* 完全照旧(widget/activity/flush 不动)。页面模型 = 定案 b(顶层页切走 activity 栈,
|
||||||
|
* page_push/pop/replace 包装;不做页内子导航栈,sub_push/pop 为预留扩展位 a 桩)。
|
||||||
|
*/
|
||||||
|
#include "meow_ui.h"
|
||||||
|
#include "meow_ui_internal.h"
|
||||||
|
#include "meow_ui_view.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MEOW_VIEW_BY_ID_MAX 32
|
||||||
|
|
||||||
|
static meow_view *g_view_by_id[MEOW_VIEW_BY_ID_MAX]; /* id → 顶层页 view(page_push/pop 查找) */
|
||||||
|
static meow_view *g_top_view = NULL; /* 当前进入的顶层页 view(生命周期跟踪) */
|
||||||
|
|
||||||
|
static void run_fn(meow_view_fn f, meow_view *v)
|
||||||
|
{
|
||||||
|
if (f) f(v, v->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 登记/清除 id→view 映射(幂等)。 */
|
||||||
|
static void view_map_set(meow_view *v)
|
||||||
|
{
|
||||||
|
if (!v) return;
|
||||||
|
int id = v->id;
|
||||||
|
if (id >= 0 && id < MEOW_VIEW_BY_ID_MAX) g_view_by_id[id] = v;
|
||||||
|
}
|
||||||
|
static void view_map_clear(meow_view *v)
|
||||||
|
{
|
||||||
|
if (!v) return;
|
||||||
|
int id = v->id;
|
||||||
|
if (id >= 0 && id < MEOW_VIEW_BY_ID_MAX && g_view_by_id[id] == v) g_view_by_id[id] = NULL;
|
||||||
|
}
|
||||||
|
static meow_view *view_map_get(int id)
|
||||||
|
{
|
||||||
|
return (id >= 0 && id < MEOW_VIEW_BY_ID_MAX) ? g_view_by_id[id] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 进入一个 view(置 ENTERED + on_enter)。 */
|
||||||
|
static void view_enter(meow_view *v)
|
||||||
|
{
|
||||||
|
if (!v || (v->state & MEOW_VIEW_STATE_ENTERED)) return;
|
||||||
|
v->state |= MEOW_VIEW_STATE_ENTERED;
|
||||||
|
run_fn(v->hooks.on_enter, v);
|
||||||
|
}
|
||||||
|
/* 离开一个 view(清 ENTERED + on_leave;默认不销毁子 view/widget——弹回零重建)。 */
|
||||||
|
static void view_leave(meow_view *v)
|
||||||
|
{
|
||||||
|
if (!v || !(v->state & MEOW_VIEW_STATE_ENTERED)) return;
|
||||||
|
v->state &= ~MEOW_VIEW_STATE_ENTERED;
|
||||||
|
run_fn(v->hooks.on_leave, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* 生命周期 */
|
||||||
|
/* ============================================================ */
|
||||||
|
meow_view *meow_view_create(int id, meow_view_type type,
|
||||||
|
const meow_view_hooks *hooks, void *ctx)
|
||||||
|
{
|
||||||
|
meow_view *v = (meow_view *)calloc(1, sizeof *v);
|
||||||
|
if (!v) return NULL;
|
||||||
|
v->id = id;
|
||||||
|
v->type = (type == MEOW_VIEW_CONTAINER) ? MEOW_VIEW_CONTAINER : MEOW_VIEW_ACTIVITY;
|
||||||
|
v->x = v->y = v->w = v->h = 0;
|
||||||
|
v->z = 0;
|
||||||
|
v->state = MEOW_VIEW_STATE_CREATED;
|
||||||
|
if (hooks) v->hooks = *hooks;
|
||||||
|
v->ctx = ctx;
|
||||||
|
view_map_set(v);
|
||||||
|
meow_draw_view_register(v); /* 登记为绘制物(on_draw 经 z 序重画触发) */
|
||||||
|
run_fn(v->hooks.on_create, v);
|
||||||
|
if (v->hooks.on_layout) run_fn(v->hooks.on_layout, v); /* 布局:create 后跑一次 */
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void meow_view_free(meow_view *v)
|
||||||
|
{
|
||||||
|
if (!v) return;
|
||||||
|
if (v->state & MEOW_VIEW_STATE_ENTERED) view_leave(v);
|
||||||
|
run_fn(v->hooks.on_destroy, v); /* 释放视图态资源 */
|
||||||
|
view_map_clear(v);
|
||||||
|
meow_draw_view_unregister(v); /* 注销 z 序绘制物 */
|
||||||
|
for (int i = 0; i < v->nwidgets; i++) /* 叶子控件 */
|
||||||
|
meow_widget_free(v->widgets[i]);
|
||||||
|
v->nwidgets = 0;
|
||||||
|
for (int i = 0; i < v->nchildren; i++) /* 子 view 递归 */
|
||||||
|
meow_view_free(v->children[i]);
|
||||||
|
v->nchildren = 0;
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* 嵌套(组合视图树) */
|
||||||
|
/* ============================================================ */
|
||||||
|
int meow_view_add_child(meow_view *parent, meow_view *child)
|
||||||
|
{
|
||||||
|
if (!parent || !child || child == parent) return -1;
|
||||||
|
for (int i = 0; i < parent->nchildren; i++)
|
||||||
|
if (parent->children[i] == child) return -1; /* 去重 */
|
||||||
|
if (parent->nchildren >= MEOW_VIEW_MAX_CHILD) return -1;
|
||||||
|
parent->children[parent->nchildren++] = child;
|
||||||
|
child->parent = parent;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int meow_view_add_widget(meow_view *v, meow_widget *w)
|
||||||
|
{
|
||||||
|
if (!v || !w) return -1;
|
||||||
|
for (int i = 0; i < v->nwidgets; i++)
|
||||||
|
if (v->widgets[i] == w) return -1;
|
||||||
|
if (v->nwidgets >= MEOW_VIEW_MAX_WIDGET) return -1;
|
||||||
|
v->widgets[v->nwidgets++] = w;
|
||||||
|
meow_draw_widget_set_view(w, v); /* z 深度源 = view 树;重算 auto z */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void meow_view_set_z(meow_view *v, int z)
|
||||||
|
{
|
||||||
|
if (!v) return;
|
||||||
|
v->z = (z < 0) ? 0 : z;
|
||||||
|
meow_draw_view_set_z(v, v->z);
|
||||||
|
}
|
||||||
|
int meow_view_z(const meow_view *v)
|
||||||
|
{
|
||||||
|
return v ? v->z : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* 页面导航(包装 activity 栈——唯一驱动 on_enter/on_leave) */
|
||||||
|
/* ============================================================ */
|
||||||
|
void meow_view_page_push(int id)
|
||||||
|
{
|
||||||
|
meow_view *cur = g_top_view;
|
||||||
|
meow_view *next = view_map_get(id);
|
||||||
|
if (cur && cur != next) view_leave(cur);
|
||||||
|
meow_ui_activity_push(id);
|
||||||
|
view_enter(next);
|
||||||
|
g_top_view = next ? next : cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void meow_view_page_pop(void)
|
||||||
|
{
|
||||||
|
meow_view *cur = g_top_view;
|
||||||
|
view_leave(cur);
|
||||||
|
meow_ui_activity_pop();
|
||||||
|
meow_view *next = view_map_get(meow_ui_activity_active());
|
||||||
|
view_enter(next);
|
||||||
|
g_top_view = next ? next : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 说明(诚实):replace 假定目标页已由 App 先 meow_view_create 指定 id 建好;本批不销毁旧页
|
||||||
|
* 对象(保留弹回),仅 leave+enter 切换——与设计「leave+destroy 当前」的差异见汇报。 */
|
||||||
|
void meow_view_page_replace(int id)
|
||||||
|
{
|
||||||
|
meow_view *cur = g_top_view;
|
||||||
|
meow_view *next = view_map_get(id);
|
||||||
|
if (cur && cur != next) view_leave(cur);
|
||||||
|
view_enter(next);
|
||||||
|
g_top_view = next ? next : cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 页内子导航(预留扩展位 a 桩:本批不实现,仅返回占位)---- */
|
||||||
|
int meow_view_sub_push(meow_view *v, meow_view *sub)
|
||||||
|
{
|
||||||
|
(void)v; (void)sub;
|
||||||
|
return 0; /* 预留:将来在 ACTIVITY view 内维护子栈 */
|
||||||
|
}
|
||||||
|
meow_view *meow_view_sub_pop(meow_view *v)
|
||||||
|
{
|
||||||
|
(void)v;
|
||||||
|
return NULL; /* 预留 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* 坐标 / 查询 */
|
||||||
|
/* ============================================================ */
|
||||||
|
int meow_view_screen_x(const meow_view *v)
|
||||||
|
{
|
||||||
|
int x = v ? v->x : 0;
|
||||||
|
const meow_view *p = v ? v->parent : NULL;
|
||||||
|
while (p) { x += p->x; p = p->parent; }
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
int meow_view_screen_y(const meow_view *v)
|
||||||
|
{
|
||||||
|
int y = v ? v->y : 0;
|
||||||
|
const meow_view *p = v ? v->parent : NULL;
|
||||||
|
while (p) { y += p->y; p = p->parent; }
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
meow_view *meow_view_parent(const meow_view *v) { return v ? v->parent : NULL; }
|
||||||
|
int meow_view_get_state(const meow_view *v) { return v ? (int)v->state : 0; }
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* meow_ui_view.h — SDK 视图/页面框架(meow_view,嵌套容器 + 生命周期 + 事件路由)。
|
||||||
|
*
|
||||||
|
* 源:devdocs/plan/SDK_VIEW_FRAMEWORK_DESIGN.md §A。本文件为机制 ABI(结构 + 生命周期钩子 +
|
||||||
|
* 页面导航包装),与 z 序绘制物注册表(meow_ui_draw.c,§C/§6.2)协同:
|
||||||
|
* - meow_view 是**薄壳**:容器 + 生命周期 + 事件路由;叶子仍是 meow_widget(不改)。
|
||||||
|
* - on_draw 是回调,view 不缓存像素(非保留);重绘由 meow_ui_invalidate 触发。
|
||||||
|
* - opt-in:不调用 meow_view_* 的 App 完全照旧(widget/activity/flush 不动)。
|
||||||
|
* - z 深度源 = view 树(parent/children 深度);叶子 widget 深度 = 所属 view 深度 + 1。
|
||||||
|
*
|
||||||
|
* 页面模型(定案 b,预留 a):顶层页切换仍由 activity 栈(meow_view_page_push/pop/replace 包装),
|
||||||
|
* 不做页内子导航栈;meow_view_sub_push/pop 为将来扩展位(仅在一个 ACTIVITY view 内维护子栈)。
|
||||||
|
*/
|
||||||
|
#ifndef MEOW_UI_VIEW_H
|
||||||
|
#define MEOW_UI_VIEW_H
|
||||||
|
|
||||||
|
#include "meow_ui.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct meow_view meow_view;
|
||||||
|
|
||||||
|
typedef enum { MEOW_VIEW_ACTIVITY = 0, MEOW_VIEW_CONTAINER = 1 } meow_view_type;
|
||||||
|
typedef enum {
|
||||||
|
MEOW_VIEW_STATE_CREATED = 1u << 0,
|
||||||
|
MEOW_VIEW_STATE_ENTERED = 1u << 1,
|
||||||
|
MEOW_VIEW_STATE_DIRTY = 1u << 2,
|
||||||
|
} meow_view_state;
|
||||||
|
|
||||||
|
/* 生命周期/事件钩子(on_create→on_enter→(事件循环)→on_leave→on_destroy + on_layout)。
|
||||||
|
* 均以 view 自身 + ctx(=视图控制器,业务-UI 绑定点)为参。可 NULL。 */
|
||||||
|
typedef void (*meow_view_fn)(meow_view *v, void *ctx);
|
||||||
|
typedef int (*meow_view_ev_fn)(meow_view *v, int ev, int a, int b, void *ctx);
|
||||||
|
typedef void (*meow_view_draw_fn)(meow_view *v, const meow_theme *th, void *ctx);
|
||||||
|
|
||||||
|
typedef struct meow_view_hooks {
|
||||||
|
meow_view_fn on_create; /* 建 view 后跑一次(分配视图态/初始布局) */
|
||||||
|
meow_view_fn on_enter; /* 页面进入(push/replace 后;回页面自动恢复零重建) */
|
||||||
|
meow_view_fn on_leave; /* 页面离开(pop/replace 前;默认不销毁子 view/widget) */
|
||||||
|
meow_view_fn on_destroy; /* meow_view_free 释放(递归)时跑 */
|
||||||
|
meow_view_fn on_layout; /* 布局(on_create/page_push 后跑一次,算子控件绝对坐标) */
|
||||||
|
meow_view_draw_fn on_draw; /* 绘制回调(非保留;由 meow_ui_invalidate 触发) */
|
||||||
|
meow_view_ev_fn on_event; /* 事件路由(可 NULL;先发后代按 z 降序,命中即消费) */
|
||||||
|
} meow_view_hooks;
|
||||||
|
|
||||||
|
#define MEOW_VIEW_MAX_CHILD 16
|
||||||
|
#define MEOW_VIEW_MAX_WIDGET 32
|
||||||
|
|
||||||
|
struct meow_view {
|
||||||
|
int type; /* MEOW_VIEW_ACTIVITY / MEOW_VIEW_CONTAINER */
|
||||||
|
int id; /* 页面/视图 id(App 命名的稳定值;= page_push 用的 id) */
|
||||||
|
int x, y, w, h; /* 自身坐标(相对父内容原点;子 view 默认占满,叠放由 z 排) */
|
||||||
|
meow_view *parent;
|
||||||
|
meow_view *children[MEOW_VIEW_MAX_CHILD];
|
||||||
|
int nchildren;
|
||||||
|
meow_widget *widgets[MEOW_VIEW_MAX_WIDGET]; /* 叶子控件(直接挂本 view) */
|
||||||
|
int nwidgets;
|
||||||
|
int z; /* 显式 z(meow_view_set_z);0=未设(由子/注册表推导) */
|
||||||
|
unsigned state; /* meow_view_state 位掩码 */
|
||||||
|
meow_view_hooks hooks;
|
||||||
|
void *ctx; /* 视图控制器(biz-UI 绑定点) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---- 生命周期 ---- */
|
||||||
|
meow_view *meow_view_create(int id, meow_view_type type,
|
||||||
|
const meow_view_hooks *hooks, void *ctx);
|
||||||
|
void meow_view_free(meow_view *v); /* 递归 on_destroy + widget_free 叶子 + 注销 z 序 */
|
||||||
|
|
||||||
|
/* ---- 嵌套(组合视图树)---- */
|
||||||
|
int meow_view_add_child(meow_view *parent, meow_view *child); /* 任意深挂子 view;0/负=结果 */
|
||||||
|
int meow_view_add_widget(meow_view *v, meow_widget *w); /* 挂叶子控件(登记 z 深度源) */
|
||||||
|
void meow_view_set_z(meow_view *v, int z); /* 显式 z(999 置顶);影响其绘制物 z */
|
||||||
|
int meow_view_z(const meow_view *v);
|
||||||
|
|
||||||
|
/* ---- 页面导航(包装 activity 栈,唯一驱动 on_enter/on_leave——单一入口,App 不再分别调)----
|
||||||
|
* 顶层页切换走 activity 栈;页内子导航为预留(见设计定案 b)。 */
|
||||||
|
void meow_view_page_push(int id); /* activity_push + 旧top on_leave + 新页 on_enter */
|
||||||
|
void meow_view_page_pop(void); /* 旧top on_leave + activity_pop + 新top on_enter */
|
||||||
|
void meow_view_page_replace(int id); /* 旧top on_leave + 新页 on_enter(目标页须已 create) */
|
||||||
|
|
||||||
|
/* ---- 页内子导航(预留扩展位 a;本批为空实现/桩,仅在 ACTIVITY view 内维护子栈)---- */
|
||||||
|
int meow_view_sub_push(meow_view *v, meow_view *sub); /* 预留;返回 0(未实现于本批) */
|
||||||
|
meow_view *meow_view_sub_pop(meow_view *v); /* 预留;返回 NULL(未实现于本批) */
|
||||||
|
|
||||||
|
/* ---- 坐标:view 相对父内容原点的累计(父坐标链求和 → 屏幕绝对坐标)---- */
|
||||||
|
int meow_view_screen_x(const meow_view *v);
|
||||||
|
int meow_view_screen_y(const meow_view *v);
|
||||||
|
|
||||||
|
/* ---- 查询 ---- */
|
||||||
|
meow_view *meow_view_parent(const meow_view *v);
|
||||||
|
int meow_view_get_state(const meow_view *v); /* MEOW_VIEW_STATE_* 位掩码 */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* MEOW_UI_VIEW_H */
|
||||||
@@ -211,10 +211,16 @@ static meow_widget *live_btn_hit(int x, int y)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 重绘并局部刷新一个按钮区(绘制内部调 meow_gfx_fill_round 已标脏;flush_region 合区+上屏)。 */
|
/* 重绘并局部刷新一个按钮区。
|
||||||
|
* §6.2 收敛:若按钮已注册绘制物 → 走 meow_ui_invalidate(清底 + 按 z 重画重叠区完整 z 栈),
|
||||||
|
* 避免按钮压上层 chrome 时被单控件 flush 抹掉(P1);未注册则回退单控件绘制+区域上屏。 */
|
||||||
static void live_btn_redraw(meow_widget *w)
|
static void live_btn_redraw(meow_widget *w)
|
||||||
{
|
{
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
|
if (meow_draw_widget_registered(w)) {
|
||||||
|
meow_ui_invalidate(w->x, w->y, w->w, w->h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
meow_widget_draw(w);
|
meow_widget_draw(w);
|
||||||
meow_ui_flush_region(w->x, w->y, w->w, w->h);
|
meow_ui_flush_region(w->x, w->y, w->w, w->h);
|
||||||
}
|
}
|
||||||
@@ -275,6 +281,7 @@ meow_widget *meow_btn_create(int x, int y, int w, int h, const char *label)
|
|||||||
t->state = MEOW_WS_ENABLED; /* §5.8.3:默认 ENABLED */
|
t->state = MEOW_WS_ENABLED; /* §5.8.3:默认 ENABLED */
|
||||||
if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
||||||
live_btn_register(t);
|
live_btn_register(t);
|
||||||
|
meow_draw_widget_register(t); /* §6.2 自动注册(创建即注册,App 零调用) */
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +293,7 @@ meow_widget *meow_slider_create(int x, int y, int w, int min, int max, int val)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->min = min; t->max = (max > min) ? max : min + 1; t->val = (val < min) ? min : (val > t->max) ? t->max : val;
|
t->min = min; t->max = (max > min) ? max : min + 1; t->val = (val < min) ? min : (val > t->max) ? t->max : val;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +306,7 @@ meow_widget *meow_switch_create(int x, int y, int on)
|
|||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->on = on ? 1 : 0;
|
t->on = on ? 1 : 0;
|
||||||
if (t->on) t->state |= MEOW_WS_SELECTED; /* §5.8.3:开关 on → selected */
|
if (t->on) t->state |= MEOW_WS_SELECTED; /* §5.8.3:开关 on → selected */
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,12 +319,14 @@ meow_widget *meow_list_create(int x, int y, int w, int h, int count,
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void meow_widget_free(meow_widget *w)
|
void meow_widget_free(meow_widget *w)
|
||||||
{
|
{
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
|
meow_draw_widget_unregister(w); /* §6.2:绘制物注册表自动注销(stale id 失效勿用) */
|
||||||
live_btn_unregister(w);
|
live_btn_unregister(w);
|
||||||
free(w);
|
free(w);
|
||||||
}
|
}
|
||||||
@@ -334,6 +345,7 @@ meow_widget *meow_widget_custom_create(int x, int y, int w, int h,
|
|||||||
t->render_cb = render_cb;
|
t->render_cb = render_cb;
|
||||||
t->hit_cb = hit_cb;
|
t->hit_cb = hit_cb;
|
||||||
t->ctx = ctx;
|
t->ctx = ctx;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +358,7 @@ meow_widget *meow_row_create(int x, int y, int w, int h, int spacing)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->spacing = spacing > 0 ? spacing : 0;
|
t->spacing = spacing > 0 ? spacing : 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
meow_widget *meow_column_create(int x, int y, int w, int h, int spacing)
|
meow_widget *meow_column_create(int x, int y, int w, int h, int spacing)
|
||||||
@@ -356,6 +369,7 @@ meow_widget *meow_column_create(int x, int y, int w, int h, int spacing)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->spacing = spacing > 0 ? spacing : 0;
|
t->spacing = spacing > 0 ? spacing : 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
meow_widget *meow_box_create(int x, int y, int w, int h)
|
meow_widget *meow_box_create(int x, int y, int w, int h)
|
||||||
@@ -366,6 +380,7 @@ meow_widget *meow_box_create(int x, int y, int w, int h)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->spacing = 0;
|
t->spacing = 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
meow_widget *meow_layout_spacer(int w, int h)
|
meow_widget *meow_layout_spacer(int w, int h)
|
||||||
@@ -375,6 +390,7 @@ meow_widget *meow_layout_spacer(int w, int h)
|
|||||||
t->type = W_SPACER; t->x = 0; t->y = 0; t->w = w > 0 ? w : 0; t->h = h > 0 ? h : 0;
|
t->type = W_SPACER; t->x = 0; t->y = 0; t->w = w > 0 ? w : 0; t->h = h > 0 ? h : 0;
|
||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,6 +437,24 @@ void meow_layout_arrange(meow_widget *layout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 布局深度反推访问器(meow_ui_draw.c 用,读本 TU 的 struct meow_widget 内部字段)---- */
|
||||||
|
int meow_widget_is_layout(const meow_widget *w)
|
||||||
|
{ return w && w->type == W_LAYOUT; }
|
||||||
|
int meow_widget_nchild(const meow_widget *w)
|
||||||
|
{ return (w && w->type == W_LAYOUT) ? w->nchildren : 0; }
|
||||||
|
const meow_widget *meow_widget_child_at(const meow_widget *w, int idx)
|
||||||
|
{ return (w && w->type == W_LAYOUT && idx >= 0 && idx < w->nchildren) ? w->children[idx] : NULL; }
|
||||||
|
|
||||||
|
/* ---- 几何/归属访问器(meow_ui_draw.c 用:绘制物 rect 实时读 + owner 过滤)---- */
|
||||||
|
int meow_widget_owner(const meow_widget *w)
|
||||||
|
{ return w ? w->owner : 0; }
|
||||||
|
void meow_widget_rect(const meow_widget *w, int out[4])
|
||||||
|
{
|
||||||
|
if (!out) return;
|
||||||
|
if (!w) { out[0] = out[1] = out[2] = out[3] = 0; return; }
|
||||||
|
out[0] = w->x; out[1] = w->y; out[2] = w->w; out[3] = w->h;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §5.8.6 batch2 Material 组件子集 API(create/setter/getter/hit) */
|
/* §5.8.6 batch2 Material 组件子集 API(create/setter/getter/hit) */
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
@@ -460,6 +494,7 @@ meow_widget *meow_textfield_create(int x, int y, int w, int h, const char *place
|
|||||||
t->buf = buf; t->buflen = buf ? (int)strlen(buf) : 0;
|
t->buf = buf; t->buflen = buf ? (int)strlen(buf) : 0;
|
||||||
t->maxlen = (maxlen > 0 && maxlen <= 256) ? maxlen : 256;
|
t->maxlen = (maxlen > 0 && maxlen <= 256) ? maxlen : 256;
|
||||||
t->ime_mode = mode;
|
t->ime_mode = mode;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
void meow_textfield_set_placeholder(meow_widget *w, const char *placeholder)
|
void meow_textfield_set_placeholder(meow_widget *w, const char *placeholder)
|
||||||
@@ -515,6 +550,7 @@ meow_widget *meow_card_create(int x, int y, int w, int h)
|
|||||||
t->type = W_CARD; t->x = x; t->y = y; t->w = w; t->h = h;
|
t->type = W_CARD; t->x = x; t->y = y; t->w = w; t->h = h;
|
||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
void meow_card_set_content(meow_widget *card, meow_widget *child)
|
void meow_card_set_content(meow_widget *card, meow_widget *child)
|
||||||
@@ -535,6 +571,7 @@ meow_widget *meow_divider_create(int x, int y, int len, int vertical)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->variant = vertical ? 1 : 0;
|
t->variant = vertical ? 1 : 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,6 +584,7 @@ meow_widget *meow_badge_create(int cx, int cy)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->value = 0; /* 红点 */
|
t->value = 0; /* 红点 */
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
void meow_badge_set(meow_widget *w, int count)
|
void meow_badge_set(meow_widget *w, int count)
|
||||||
@@ -564,6 +602,7 @@ meow_widget *meow_checkbox_create(int x, int y)
|
|||||||
t->type = W_CHECKBOX; t->x = x; t->y = y; t->w = 34; t->h = 34;
|
t->type = W_CHECKBOX; t->x = x; t->y = y; t->w = 34; t->h = 34;
|
||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
meow_widget *meow_radio_create(int x, int y)
|
meow_widget *meow_radio_create(int x, int y)
|
||||||
@@ -573,6 +612,7 @@ meow_widget *meow_radio_create(int x, int y)
|
|||||||
t->type = W_RADIO; t->x = x; t->y = y; t->w = 34; t->h = 34;
|
t->type = W_RADIO; t->x = x; t->y = y; t->w = 34; t->h = 34;
|
||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,6 +626,7 @@ meow_widget *meow_progress_create(int x, int y, int w, int h, int value)
|
|||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->variant = 0; /* 线性 */
|
t->variant = 0; /* 线性 */
|
||||||
t->value = value < 0 ? -1 : (value > 100 ? 100 : value);
|
t->value = value < 0 ? -1 : (value > 100 ? 100 : value);
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
meow_widget *meow_progress_circular_create(int cx, int cy, int r, int value)
|
meow_widget *meow_progress_circular_create(int cx, int cy, int r, int value)
|
||||||
@@ -603,6 +644,7 @@ meow_widget *meow_progress_circular_create(int cx, int cy, int r, int value)
|
|||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->variant = 1; /* 圆形 */
|
t->variant = 1; /* 圆形 */
|
||||||
t->value = value < 0 ? -1 : (value > 100 ? 100 : value);
|
t->value = value < 0 ? -1 : (value > 100 ? 100 : value);
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
void meow_progress_set(meow_widget *w, int value)
|
void meow_progress_set(meow_widget *w, int value)
|
||||||
@@ -621,6 +663,7 @@ meow_widget *meow_fab_create(int x, int y, int size, const char *label)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,6 +677,7 @@ meow_widget *meow_topappbar_create(int x, int y, int w, int h, const char *title
|
|||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->back_on = 0; t->nitems = 0;
|
t->back_on = 0; t->nitems = 0;
|
||||||
if (title) { strncpy(t->label, title, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
if (title) { strncpy(t->label, title, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
void meow_topappbar_set_title(meow_widget *w, const char *title)
|
void meow_topappbar_set_title(meow_widget *w, const char *title)
|
||||||
@@ -682,6 +726,7 @@ meow_widget *meow_navigationbar_create(int x, int y, int w, int h)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->nitems = 0; t->selected = 0;
|
t->nitems = 0; t->selected = 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
int meow_navigationbar_add_item(meow_widget *w, const char *label)
|
int meow_navigationbar_add_item(meow_widget *w, const char *label)
|
||||||
@@ -721,6 +766,7 @@ meow_widget *meow_tabbar_create(int x, int y, int w, int h)
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->nitems = 0; t->selected = 0;
|
t->nitems = 0; t->selected = 0;
|
||||||
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
int meow_tabbar_add_tab(meow_widget *w, const char *label)
|
int meow_tabbar_add_tab(meow_widget *w, const char *label)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
|
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
|
* meow_ui_draw.c meow_ui_view.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \
|
* gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
|
* meow_ui_draw.c meow_ui_view.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
||||||
* 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕)
|
* 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,12 +18,13 @@
|
|||||||
* -o test_p1p2p3_repro test_p1p2p3_repro.c test_host_stub.c \
|
* -o test_p1p2p3_repro test_p1p2p3_repro.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
* meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \
|
||||||
|
* meow_ui_view.c stb_image.c \
|
||||||
* -I. -I../hello_app -I../meow_launcherd -pthread -lm
|
* -I. -I../hello_app -I../meow_launcherd -pthread -lm
|
||||||
* 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕)
|
* 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕)
|
||||||
*
|
*
|
||||||
* 修复前(无 P1/P2/P3 修法)预期输出:RESULT: 4 FAIL(S);
|
* 覆盖(批次① z 序下沉后):P1c 显式 z 置顶(set_z(g_fab,999)+invalidate(r_prc) 不抹 FAB——
|
||||||
* 修复后:RESULT: ALL PASS。
|
* 显式 z 不依赖绘制先后)+ P2/P3 与迁移前一致。预期 RESULT: ALL PASS。
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
#include "meow_ui_internal.h"
|
#include "meow_ui_internal.h"
|
||||||
@@ -74,13 +75,15 @@ int main(void)
|
|||||||
|
|
||||||
int fails = 0;
|
int fails = 0;
|
||||||
|
|
||||||
/* ================= P1:局部重绘不盖浮层(FAB) =================
|
/* ================= P1 / P1c:局部重绘不盖浮层(FAB,须显式置顶) =================
|
||||||
* 场景:scroll=0 时圆形进度(413..453,605..645) 与 FAB(406..462,616..672) 重叠。
|
* 场景:scroll=0 时圆形进度 r_prc(413..453,605..645) 与 FAB(406..462,616..672) 重叠。
|
||||||
* demo_paint 先画内容后画 chrome → 场景正确 FAB 在上。随后「局部重绘进度条」:
|
* demo_paint 整帧后 FAB 在上(demo_init set_z(g_fab,999) 显式置顶)。随后「局部重绘进度条」:
|
||||||
* 旧(清底+只画进度条+flush 其矩形)→ FAB 重叠区被清掉;
|
* 旧(清底+只画进度条+flush 其矩形)→ FAB 重叠区被清掉;
|
||||||
* 新(清底+重画重叠区内所有控件=hello d_redraw/d_paint_region)→ FAB 保持。 */
|
* 新(SDK meow_ui_invalidate:清底 + 按 z 重画重叠区完整 z 栈)→ FAB 保持。
|
||||||
|
* P1c:set_z(g_fab,999) 后 invalidate(r_prc),断言 FAB 重叠点(434,622) 仍=demo_paint 后值
|
||||||
|
* (显式 z 不依赖绘制先后——置顶在重绘前显式给出,下层重绘不抹上层)。 */
|
||||||
demo_paint();
|
demo_paint();
|
||||||
int fx = r_fab.x + 28, fy = r_fab.y + 6; /* FAB 内、远离 "+" 文本处 */
|
int fx = r_fab.x + 28, fy = r_fab.y + 6; /* FAB 内、远离 "+" 文本处 → (434,622) */
|
||||||
int s0r, s0g, s0b; rd_px(fx, fy, &s0r, &s0g, &s0b);
|
int s0r, s0g, s0b; rd_px(fx, fy, &s0r, &s0g, &s0b);
|
||||||
printf("P1 scene (demo_paint) FAB-overlap "); pr_px("scene", fx, fy);
|
printf("P1 scene (demo_paint) FAB-overlap "); pr_px("scene", fx, fy);
|
||||||
if (is_bg(s0r, s0g, s0b))
|
if (is_bg(s0r, s0g, s0b))
|
||||||
@@ -98,15 +101,16 @@ int main(void)
|
|||||||
if (is_bg(obr, obg, obb)) printf(" [BUG-CONFIRMED] old path erased FAB overlap (bg)\n");
|
if (is_bg(obr, obg, obb)) printf(" [BUG-CONFIRMED] old path erased FAB overlap (bg)\n");
|
||||||
else printf(" [note] old path did NOT erase FAB here (color %02X%02X%02X)\n", obr, obg, obb);
|
else printf(" [note] old path did NOT erase FAB here (color %02X%02X%02X)\n", obr, obg, obb);
|
||||||
|
|
||||||
/* 新式局部重绘(真实 hello d_redraw → d_paint_region,重画重叠栈)*/
|
/* P1c:显式置顶 + SDK 局部重画(invalidate 按 z 重画重叠栈) */
|
||||||
demo_paint(); /* 还原场景 */
|
demo_paint(); /* 还原场景 */
|
||||||
|
meow_widget_set_z(g_fab, 999); /* 重新显式置顶(P1c 要求) */
|
||||||
meow_progress_set(g_dprc, 30);
|
meow_progress_set(g_dprc, 30);
|
||||||
d_redraw(g_dprc, r_prc); /* hello 的局部重绘入口 */
|
meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h);
|
||||||
int nbr, nbg, nbb; rd_px(fx, fy, &nbr, &nbg, &nbb);
|
int nbr, nbg, nbb; rd_px(fx, fy, &nbr, &nbg, &nbb);
|
||||||
printf("P1 new-partial (d_redraw stack) "); pr_px("new", fx, fy);
|
printf("P1c set_z(999)+invalidate(r_prc) "); pr_px("p1c", fx, fy);
|
||||||
if (near(s0r, nbr) && near(s0g, nbg) && near(s0b, nbb))
|
if (near(s0r, nbr) && near(s0g, nbg) && near(s0b, nbb))
|
||||||
printf(" P1-PASS FAB preserved over live progress redraw\n");
|
printf(" P1-PASS explicit z:FAB preserved over live progress redraw\n");
|
||||||
else { printf(" P1-FAIL FAB not preserved (scene %02X%02X%02X vs new %02X%02X%02X)\n",
|
else { printf(" P1-FAIL FAB not preserved (scene %02X%02X%02X vs p1c %02X%02X%02X)\n",
|
||||||
s0r, s0g, s0b, nbr, nbg, nbb); fails++; }
|
s0r, s0g, s0b, nbr, nbg, nbb); fails++; }
|
||||||
|
|
||||||
/* ================= P2:列表焦点按本次触摸绑定/释放 =================
|
/* ================= P2:列表焦点按本次触摸绑定/释放 =================
|
||||||
@@ -128,7 +132,7 @@ int main(void)
|
|||||||
printf("P3 list rect = (%d,%d,%d,%d)\n", r_list.x, r_list.y, r_list.w, r_list.h);
|
printf("P3 list rect = (%d,%d,%d,%d)\n", r_list.x, r_list.y, r_list.w, r_list.h);
|
||||||
/* 顶部泄漏:选中行0 + scroll=20 → 行0 ry=top-20,填充越顶泄漏 */
|
/* 顶部泄漏:选中行0 + scroll=20 → 行0 ry=top-20,填充越顶泄漏 */
|
||||||
meow_list_set_selected(g_dlc, 0); meow_list_set_scroll(g_dlc, 20);
|
meow_list_set_selected(g_dlc, 0); meow_list_set_scroll(g_dlc, 20);
|
||||||
d_redraw(g_dlc, r_list);
|
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h);
|
||||||
int ux = r_list.x + 10, uy = r_list.y - 5; /* 列表顶上方 5px(标题间隙) */
|
int ux = r_list.x + 10, uy = r_list.y - 5; /* 列表顶上方 5px(标题间隙) */
|
||||||
int ur, ug, ub; rd_px(ux, uy, &ur, &ug, &ub);
|
int ur, ug, ub; rd_px(ux, uy, &ur, &ug, &ub);
|
||||||
printf("P3 top-leak "); pr_px("above-top", ux, uy);
|
printf("P3 top-leak "); pr_px("above-top", ux, uy);
|
||||||
@@ -136,7 +140,7 @@ int main(void)
|
|||||||
else { printf(" P3-top-FAIL leaked into title gap\n"); fails++; }
|
else { printf(" P3-top-FAIL leaked into title gap\n"); fails++; }
|
||||||
/* 底部泄漏:选中行4 + scroll=20 → 行4 ry=590..630 越底泄漏 */
|
/* 底部泄漏:选中行4 + scroll=20 → 行4 ry=590..630 越底泄漏 */
|
||||||
meow_list_set_selected(g_dlc, 4); meow_list_set_scroll(g_dlc, 20);
|
meow_list_set_selected(g_dlc, 4); meow_list_set_scroll(g_dlc, 20);
|
||||||
d_redraw(g_dlc, r_list);
|
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h);
|
||||||
int dx = r_list.x + 10, dy_ = r_list.y + r_list.h + 5; /* 列表底下方 5px */
|
int dx = r_list.x + 10, dy_ = r_list.y + r_list.h + 5; /* 列表底下方 5px */
|
||||||
int dr, dg, db; rd_px(dx, dy_, &dr, &dg, &db);
|
int dr, dg, db; rd_px(dx, dy_, &dr, &dg, &db);
|
||||||
printf("P3 bot-leak "); pr_px("below-bottom", dx, dy_);
|
printf("P3 bot-leak "); pr_px("below-bottom", dx, dy_);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
* gcc -Wall -o test_sdk_fixes test_sdk_fixes.c test_host_stub.c \
|
* gcc -Wall -o test_sdk_fixes test_sdk_fixes.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
|
* meow_ui_draw.c meow_ui_view.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
Reference in new issue
Block a user