diff --git a/patch_v2/hello_app/app.c b/patch_v2/hello_app/app.c index 241e835..1d354cb 100644 --- a/patch_v2/hello_app/app.c +++ b/patch_v2/hello_app/app.c @@ -3,7 +3,7 @@ * 职责(SDK_VIEW_FRAMEWORK_DESIGN.md §B.2):main 只做初始化/建页/跑事件循环/清理;把 * meow_ui_run 的平铺输入回调(key/tap/swipe/tick/touch)路由到当前活动页(home/full/demo)。 * 页面切换统一走 meow_view_page_push/pop(活动栈 + on_enter/on_leave 的唯一驱动,App 不再 - * 分别调 activity_push/pop)。业务变化经 logic 监听器送回 UI(见 ui/home.c)。 + * 分别调 activity_push/pop)。业务变化经 logic 监听器送回 UI(见 ui/home/home.c)。 * * 契约(MEOW_APP_SDK.md §1/§3/§6):应用只调 meow_ui API。 */ diff --git a/patch_v2/hello_app/build_hello.sh b/patch_v2/hello_app/build_hello.sh index 908e32a..98edcb1 100755 --- a/patch_v2/hello_app/build_hello.sh +++ b/patch_v2/hello_app/build_hello.sh @@ -1,8 +1,10 @@ #!/bin/bash -# Build the hello app (SDK B1, 视图框架批次②文件拆分): 链 meow_ui.a(已内含 meow_font.o), +# Build the hello app (SDK B1, 视图框架批次③目录嵌套+视图深度化): 链 meow_ui.a(已内含 meow_font.o), # 额外链系统 libz.a(meow_font 的 inflate 依赖)+ -lpthread。静态 MIPS32r2 (musl sf)。 # 批次②:hello.c 拆为多文件(app.c + ui/home.c + ui/full.c + ui/demo.c + ui/common/chrome.c + -# logic/notify.c + logic/state.c),仅改列文件,编译期不改 SDK(patch_v2/sdk/ 零触及)。 +# logic/notify.c + logic/state.c)。 +# 批次③:ui/home、ui/demo 子目录化(ui/home/home.c + ui/demo/demo.c);demo 列表区块抽成 +# CONTAINER 子视图 ui/demo/list/list.c。仅改列文件,编译期不改 SDK(patch_v2/sdk/ 零触及)。 # mipsel -Wall -Wextra 0 warning。 set -e cd "$(dirname "$0")" @@ -10,7 +12,8 @@ ROOT="$HOME/Project/R3ProII" CC="$ROOT/.tools/zig-mipsel-cc" SYSROOT="$ROOT/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf" "$CC" -Os -static -Wall -Wextra -I../sdk -I. \ - app.c ui/home.c ui/full.c ui/demo.c ui/common/chrome.c logic/notify.c logic/state.c \ + app.c ui/home/home.c ui/full.c ui/demo/demo.c ui/demo/list/list.c ui/common/chrome.c \ + logic/notify.c logic/state.c \ ../sdk/meow_ui.a "$SYSROOT/lib/libz.a" -lpthread -o hello ls -la hello file hello diff --git a/patch_v2/hello_app/hello b/patch_v2/hello_app/hello index b051950..22181ab 100755 Binary files a/patch_v2/hello_app/hello and b/patch_v2/hello_app/hello differ diff --git a/patch_v2/hello_app/hello_internal.h b/patch_v2/hello_app/hello_internal.h index 15f8adc..7fd0b85 100644 --- a/patch_v2/hello_app/hello_internal.h +++ b/patch_v2/hello_app/hello_internal.h @@ -54,7 +54,7 @@ typedef struct { int _pad; } demo_ctrl; -/* ---- home 页(ui/home.c)---- */ +/* ---- home 页(ui/home/home.c)---- */ meow_view *home_view_create(void); /* 建 home view;on_create 建 home 控件 + 注册业务监听器 */ int home_on_tap(int x, int y);/* home 态命中分发:返回 1=已消费(含导航到 demo/full) */ @@ -63,7 +63,7 @@ meow_view *full_view_create(void); /* 建 full view(无控件;全屏文本 int full_is_active(void); /* 1=处于全屏态 */ void full_draw(void); /* 画全屏帧(clear accent + 文本 + flush) */ -/* ---- demo 页(ui/demo.c)---- */ +/* ---- demo 页(ui/demo/demo.c)---- */ meow_view *demo_view_create(void); /* 建 demo view;on_create 调 demo_init() 建 chrome+内容 */ int demo_is_active(void); /* 1=处于 demo 页 */ void demo_on_tap(int x, int y); @@ -78,19 +78,35 @@ void demo_init(void); void demo_paint(void); void demo_rebuild_to(int scroll); -/* ---- demo 视图态(设计定案 B:g_ds/g_drag_* /scroll 留 ui/demo.c,不迁 logic)---- +/* ---- demo 视图态(设计定案 B:g_ds 非列表字段/scroll/drag_page 留 ui/demo/demo.c,不迁 logic; + * 列表视图态批③ 迁 ui/demo/list/list.c——下列四项定义在 list.c,经本头 extern 跨 TU 共享)。---- * 暴露为 extern,供宿主测试对真实 demo 状态断言(P1/P2/P3)。 */ extern int g_demo; /* 1=处于 demo 演示页 */ -extern int g_demo_focus; /* 1=LazyColumn 聚焦 */ +extern int g_demo_focus; /* 1=LazyColumn 聚焦(list.c) */ extern int g_demo_scroll; /* 内容区滚动偏移 */ -extern int g_drag_list; /* 手指在列表:拖拽滚列表 */ +extern int g_drag_list; /* 手指在列表:拖拽滚列表(list.c) */ extern int g_drag_page; /* 手指在页内容:拖拽滚页面 */ -extern meow_widget *g_dlc; /* LazyColumn */ +extern meow_widget *g_dlc; /* LazyColumn(list.c) */ extern meow_widget *g_dprc; /* ProgressBar 圆形 */ extern rect_t r_prc; /* 圆形进度外接框 */ -extern rect_t r_list; /* 列表区几何 */ +extern rect_t r_list; /* 列表区几何(list.c) */ extern rect_t r_dr1, r_dr2; /* Radio 几何 */ +/* ---- 列表区 CONTAINER 子视图(ui/demo/list/list.c;批③ 视图深度化)---- + * demo 页把列表逻辑区块抽成 meow_view CONTAINER 子视图挂到 DEMO ACTIVITY view children, + * 承接列表交互(tap/down/move/swipe)、列表视图态与列表区块标题 on_draw 直绘。 + * 嵌套生命周期(list_view_enter/leave)由 demo 页 on_enter/on_leave 驱动(SDK 骨架不递归)。 */ +meow_view *list_view_create(void); /* 建 CONTAINER 子视图(须即 meow_view_add_child) */ +meow_view *list_view_get(void); /* 返回子视图(宿主测嵌套 on_enter/on_leave 断言) */ +void list_view_enter(void); /* 进入子视图(置 ENTERED + on_enter,幂等) */ +void list_view_leave(void); /* 离开子视图(清 ENTERED + on_leave,幂等) */ +void list_view_bind(meow_widget *w, rect_t list, rect_t title); /* 内容重建后绑控件+几何+恢复态 */ +void list_view_release(void); /* 内容释放后摘引用/几何 */ +int list_view_hit(int x, int y); /* tap 分发给列表区,命中即消费(含选中) */ +int list_view_down(int x, int y); /* touch_down 命中列表:置 focus+drag_list */ +int list_view_move(int y); /* touch_move 拖动列表:1=在列表拖动 */ +int list_view_swipe(int del); /* swipe:列表聚焦时滚列表,1=已消费 */ + /* ---- chrome(ui/common/chrome.c)---- */ extern meow_widget *g_tb; /* TopAppBar(chrome 固定) */ extern meow_widget *g_nav; /* NavigationBar(chrome 固定) */ diff --git a/patch_v2/hello_app/logic/logic.h b/patch_v2/hello_app/logic/logic.h index 4ca4ae1..f655ad2 100644 --- a/patch_v2/hello_app/logic/logic.h +++ b/patch_v2/hello_app/logic/logic.h @@ -13,6 +13,7 @@ /* 监听器事件类型(业务态变化 → 通知 UI) */ #define LOGIC_EV_TAPS 1 /* taps 计数变化 */ #define LOGIC_EV_SECS 2 /* secs 秒计数变化 */ +#define LOGIC_EV_PROG 3 /* demo 进度值变化(批③ 语义值上收) */ typedef void (*logic_listener_fn)(int ev, void *ctx); /* ctx = 监听器注册时给的视图控制器 */ @@ -21,6 +22,8 @@ int logic_taps_get(void); /* 返回累计 taps */ void logic_taps_bump(void); /* taps++,并触发监听器(若已注册) */ int logic_secs_get(void); /* 返回过去秒数 */ void logic_secs_add(int n); /* secs += n,并触发监听器(若已注册) */ +int logic_prog_get(void); /* 返回 demo 进度值 0..100(批③ 语义值上收) */ +void logic_prog_set(int p); /* 设置进度值(clamp 0..100),并触发监听器(若已注册) */ void logic_set_listener(logic_listener_fn cb, void *ctx); /* 注册业务→UI 推送监听器(可 NULL 注销) */ /* ---- 通知业务(logic/notify.c)---- */ diff --git a/patch_v2/hello_app/logic/state.c b/patch_v2/hello_app/logic/state.c index f676b0a..56c52ed 100644 --- a/patch_v2/hello_app/logic/state.c +++ b/patch_v2/hello_app/logic/state.c @@ -8,6 +8,7 @@ static int g_taps = 0; static int g_secs = 0; +static int g_prog = 0; /* demo 进度语义值 0..100(批③ 自 ui/demo/demo.c 上收) */ static logic_listener_fn g_listener = NULL; static void *g_listener_ctx = NULL; @@ -31,6 +32,18 @@ void logic_secs_add(int n) if (g_listener) g_listener(LOGIC_EV_SECS, g_listener_ctx); } +int logic_prog_get(void) +{ + return g_prog; +} +void logic_prog_set(int p) +{ + if (p < 0) p = 0; + if (p > 100) p = 100; + g_prog = p; + if (g_listener) g_listener(LOGIC_EV_PROG, g_listener_ctx); +} + void logic_set_listener(logic_listener_fn cb, void *ctx) { g_listener = cb; diff --git a/patch_v2/hello_app/ui/demo.c b/patch_v2/hello_app/ui/demo/demo.c similarity index 82% rename from patch_v2/hello_app/ui/demo.c rename to patch_v2/hello_app/ui/demo/demo.c index cb25477..ac6e6e7 100644 --- a/patch_v2/hello_app/ui/demo.c +++ b/patch_v2/hello_app/ui/demo/demo.c @@ -1,14 +1,17 @@ -/* ui/demo.c — 控件库 Demo 演示页(ACT_DEMO)view + 控制器。 +/* ui/demo/demo.c — 控件库 Demo 演示页(ACT_DEMO)view + 控制器(批次③ 目录嵌套后)。 * * 内容控件以绝对坐标创建,页滚动 = 按「base_y - scroll」重建内容(owner=ACT_DEMO 不变); - * 各控件跨重建状态存 g_ds(App 持有),重建后恢复。绘制走 batch① 郑序注册表:demo_paint 调 + * 各控件跨重建状态存 g_ds(App 持有),重建后恢复。绘制走批次① z 序注册表:demo_paint 调 * meow_ui_set_page_bg + meow_ui_paint_full(整帧按 z 重画:内容→标题/slider值→chrome 置顶), * 局部刷新统一 meow_ui_invalidate(清底+按 z 重画相交绘制物)。旧 d_paint_region/d_redraw/ - * d_rect_overlap(App 层郑栈重画)已删、下沉 SDK。 + * d_rect_overlap(App 层 z 栈重画)已删、下沉 SDK。 * - * 设计定案 B(SDK_VIEW_FRAMEWORK_DESIGN §B.3/F):demo 的 g_ds/g_drag_* /g_demo_scroll 等视图态 - * 留本文件(不迁 logic);UI→业务只经 logic_* / notify_*。页面进入/离开经 meow_view_page_push/pop - * 驱动 on_enter/on_leave(demo_page_enter/leave)。 + * 批次②③ 拆分/深度化(SDK_VIEW_FRAMEWORK_DESIGN §B.2/§B.4/§E③): + * - 列表区逻辑区块抽成 CONTAINER 子视图 ui/demo/list/list.c(挂到本页 ACTIVITY view children), + * 列表视图态(g_dlc/r_list/g_demo_focus/g_drag_list)随迁;本页只做页级分发(子>父)。 + * - 进度语义值 g_ds.prog 已上收 logic/state.c(logic_prog_get/set,经监听器)。 + * - 设计定案 B:其余视图态(demo 页 g_ds 非列表字段/g_demo_scroll/drag_page)留本文件(不迁 logic); + * UI→业务只经 logic_* / notify_*。页面进入/离开经 meow_view_page_push/pop 驱动。 */ #include "hello_internal.h" #include @@ -23,29 +26,31 @@ static demo_ctrl g_demo_ctrl; /* ---- demo 演示页状态 ---- */ int g_demo = 0; /* 1=处于 demo 演示页 */ int g_demo_scroll = 0; /* 内容区滚动偏移(base 空间 px) */ -int g_demo_focus = 0; /* 1=LazyColumn 聚焦(swipe 滚列表而非页面) */ static int g_demo_fab = 0; /* FAB 点击计数反馈 */ -static int g_demo_prog = 0; /* ProgressBar 动画当前值 0..100 */ static uint64_t g_demo_prog_last = 0; static int g_demo_ct = 0; /* 内容视口顶(屏y = statusbar+56+8) */ static int g_demo_cb = 0; /* 内容视口底(屏y =608,NavBar 上方留白) */ static int g_demo_content_h = 0;/* 内容总高(base 空间;决定 max_scroll) */ +/* 注:g_demo_focus/g_drag_list/g_dlc/r_list 已迁 ui/demo/list/list.c(列表视图态归列表区 + * CONTAINER 子视图),本文件仅经 hello_internal.h 的 extern 引用;g_demo_prog 已上收 logic/state.c。 */ -/* M2.71-bug2/6:拖动过程(跟手)状态。on_touch_down 锁一种拖拽,on_touch_move 实时更新。 */ +/* M2.71-bug2/6:拖动过程(跟手)状态。on_touch_down 锁一种拖拽,on_touch_move 实时更新。 + * g_drag_list(列表拖拽)/g_drag_list_last_y 归列表区 CONTAINER 子视图 list.c(extern 引用)。 + * 注:g_drag_page 仍为本页「页内容拖拽」标志。 */ static int g_drag_slider = 0; /* 手指按在 slider */ -int g_drag_list = 0; /* 手指按在 LazyColumn:拖拽滚列表 */ int g_drag_page = 0; /* 手指按在页内容(非 slider/list):拖拽滚页面 */ -static int g_drag_list_last_y = 0; /* 列表拖拽上一帧 y */ static int g_drag_page_last_y = 0; /* 页面拖拽上一帧 y */ static int g_drag_page_delta = 0; /* 页面拖拽累计位移(节流重建,≥8px 才重建一次) */ /* SDK 控件不透明:App 自记几何,用于局部 flush / 命中 / scroll 重建。 */ -/* demo 各控件跨重建保留的状态(app 持有;重建后按此恢复) */ +/* demo 各控件跨重建保留的状态(app 持有;重建后按此恢复)—— + * 列表态 list/list_sel 已迁 ui/demo/list/list.c(列表区 CONTAINER 子视图)持有; + * 进度语义值 prog 已上收 logic/state.c(logic_prog_*)。 */ static struct { int sw_on; int slider; char tf[32]; - int ck; int r1, r2; int btn[5]; int card; int tab; int list; int list_sel; int prog; -} g_ds = { .sw_on = 1, .slider = 40, .r1 = 1, .tab = 1, .list = 0, .list_sel = 0, .prog = 0 }; + int ck; int r1, r2; int btn[5]; int card; int tab; +} g_ds = { .sw_on = 1, .slider = 40, .r1 = 1, .tab = 1 }; /* demo 内容布局常量(base 空间) */ #define DCL_X 16 @@ -81,7 +86,7 @@ static meow_widget *g_dbadge; /* Badge */ static meow_widget *g_dtab; static rect_t r_tab; /* TabBar */ static meow_widget *g_dbtn_dlg; static rect_t r_dlg; /* 打开 Dialog 的按钮 */ static meow_widget *g_dbtn_sheet; static rect_t r_sheet;/* 打开 BottomSheet 的按钮 */ -meow_widget *g_dlc; rect_t r_list; /* LazyColumn */ +/* LazyColumn:g_dlc/r_list 已迁 list.c(列表区 CONTAINER 子视图),此处仅 extern 引用。 */ /* ---- demo 分区标题/slider 值文本:注册为 CUSTOM 绘制物(§6.2 区域重画会重画它们)---- * 显式 z=D_TITLE_Z:> 一切自动 z(=127)、< chrome 置顶(999)。非控件直绘必须注册,否则 @@ -146,6 +151,7 @@ static void demo_free_content(void) 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; + list_view_release(); /* 列表控件已在上方 g_dslot 释放;摘容器引用/几何 */ } /* 按 scroll 重建全部内容控件(owner=ACT_DEMO:调用方须已 push ACT_DEMO)。 @@ -197,11 +203,12 @@ static void demo_build_at(int scroll) meow_widget_set_selected(g_dr1, g_ds.r1); meow_widget_set_selected(g_dr2, g_ds.r2); - /* ---- ProgressBar(线性 + 圆形,on_tick 动画) ---- */ + /* ---- ProgressBar(线性 + 圆形,on_tick 动画)---- + * 进度语义值已上收 logic/state.c;重建从 logic_prog_get() 恢复。 */ d_title(DCL_X, SY(yb), "PROGRESS (animated)"); yb += 26; - r_prl = RX(DCL_X, SY(yb), DFW, 8); g_dprl = meow_progress_create(r_prl.x, r_prl.y, r_prl.w, r_prl.h, g_ds.prog); SLOT(g_dprl, r_prl.x, r_prl.y, r_prl.w, r_prl.h); yb += 16; + r_prl = RX(DCL_X, SY(yb), DFW, 8); g_dprl = meow_progress_create(r_prl.x, r_prl.y, r_prl.w, r_prl.h, logic_prog_get()); SLOT(g_dprl, r_prl.x, r_prl.y, r_prl.w, r_prl.h); yb += 16; r_prc = RX(DCL_X + 400 + 17 - 20, SY(yb) + 17 - 20, 40, 40); - g_dprc = meow_progress_circular_create(r_prc.x + 20, r_prc.y + 20, 17, g_ds.prog); + g_dprc = meow_progress_circular_create(r_prc.x + 20, r_prc.y + 20, 17, logic_prog_get()); SLOT(g_dprc, r_prc.x, r_prc.y, r_prc.w, r_prc.h); yb += 48; /* ---- Container(Card / Badge / TabBar) ---- */ @@ -228,12 +235,13 @@ static void demo_build_at(int scroll) r_sheet = RX(DCR_X, SY(yb), DCW, DBH); g_dbtn_sheet = meow_btn_create_variant(r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h, "SHEET", MEOW_BTN_OUTLINED); SLOT(g_dbtn_sheet, r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h); yb += DCH; - /* ---- LazyColumn(100 项列表滚动) ---- */ - d_title(DCL_X, SY(yb), "LIST (LazyColumn, tap+swipe)"); yb += 26; + /* ---- LazyColumn(100 项列表滚动) ---- + * 本区块标题改由列表区 CONTAINER 子视图(ui/demo/list/list.c)的 on_draw 绘制(注册表→ + * invalidate 链路);列表滚动/选中由 list_view_bind 从子视图持有态恢复(不再经 g_ds)。 */ + int list_title_y = SY(yb); yb += 26; /* 标题条(子视图 on_draw 直绘,几何计入容器) */ r_list = RX(DCL_X, SY(yb), DFW, 150); g_dlc = meow_lazycolumn_create(r_list.x, r_list.y, r_list.w, r_list.h, 40, 100, demo_list_src, NULL); SLOT(g_dlc, r_list.x, r_list.y, r_list.w, r_list.h); - meow_list_set_scroll(g_dlc, g_ds.list); - meow_list_set_selected(g_dlc, g_ds.list_sel); /* M2.71-bug8:跨重建保留选中行 */ + list_view_bind(g_dlc, r_list, RX(DCL_X, list_title_y, DFW, 26)); yb += 158; g_demo_content_h = yb; @@ -278,6 +286,9 @@ static int demo_content_tap(int x, int y) { g_demo_focus = 0; /* 默认切回页滚动;仅命中列表时改置 1 */ + /* 嵌套命中(子>父,§A.7 设计):列表区 CONTAINER 子视图先发,命中即消费。 */ + if (list_view_hit(x, y)) return 1; + 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; 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; } @@ -299,13 +310,7 @@ static int demo_content_tap(int x, int y) } 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; meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); } - return 1; - } - return 0; + return 0; /* 列表区分发已由顶部 list_view_hit 处理(子>父) */ } /* demo 页 on_tap 分发(chrome → 内容) */ @@ -331,16 +336,17 @@ void demo_on_tap(int x, int y) demo_content_tap(x, y); } -/* demo 页 on_tick:ProgressBar 动画(局部刷,~120ms 步进) */ +/* demo 页 on_tick:ProgressBar 动画(局部刷,~120ms 步进)。 + * 进度语义值已上收 logic/state.c(logic_prog_get/set),本处只驱动显示。 */ void demo_tick(uint64_t now) { if (g_demo_prog_last == 0) g_demo_prog_last = now; if (now - g_demo_prog_last < 120) return; 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); 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); + int p = logic_prog_get() + 3; if (p > 100) p -= 101; /* (v+3)%101,wrap 0..100 */ + logic_prog_set(p); + meow_progress_set(g_dprl, p); meow_ui_invalidate(r_prl.x, r_prl.y, r_prl.w, r_prl.h); + meow_progress_set(g_dprc, p); meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h); } /* 按触碰 X 落 slider 值并局部刷(按下即定位 + 拖动实时,M2.71-bug2) */ @@ -353,15 +359,14 @@ static void demo_slider_drag(int x) 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 页 on_touch_down:锁一种拖拽(slider > list > 页内容)。 + * 列表区走 list_view_down(子>父:命中列表区由列表 CONTAINER 子视图收口)。 */ void demo_touch_down(int x, int y) { g_drag_slider = 0; g_drag_list = 0; g_drag_page = 0; g_drag_page_delta = 0; if (!g_demo) return; if (meow_widget_hit(g_dslider, x, y)) { g_drag_slider = 1; demo_slider_drag(x); return; } - if (g_dlc && meow_widget_hit(g_dlc, x, y)) { - g_demo_focus = 1; g_drag_list = 1; g_drag_list_last_y = y; return; - } + if (list_view_down(x, y)) return; /* 列表区:置 focus+drag_list(list.c) */ g_demo_focus = 0; if (y >= g_demo_ct && y < g_demo_cb && x >= 0 && x < meow_ui_width()) { g_drag_page = 1; g_drag_page_last_y = y; @@ -373,11 +378,7 @@ void demo_touch_move(int x, int y) { if (!g_demo) return; 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); meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); } - return; - } + if (list_view_move(y)) return; /* 列表拖动(list.c) */ if (g_drag_page) { int dy = y - g_drag_page_last_y; g_drag_page_last_y = y; g_drag_page_delta += -dy; /* 手指上移(y 减) → scroll 增(显示更低内容),与 on_swipe 一致 */ @@ -395,13 +396,8 @@ void demo_swipe(int dir, int dist) if (dir != MEOW_SWIPE_UP && dir != MEOW_SWIPE_DOWN) return; if (g_drag_page || g_drag_list) return; /* 本次手势已实时跟手滚动过 */ int del = (dir == MEOW_SWIPE_UP) ? dist : -dist; /* 手指上移 → 偏移增大 */ - if (g_demo_focus && g_dlc) { - meow_list_scroll_by(g_dlc, del); - g_ds.list = meow_list_scroll(g_dlc); - meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); /* 列表区局部刷新 */ - } else { - demo_rebuild_to(g_demo_scroll + del); - } + if (list_view_swipe(del)) return; /* 列表聚焦:滚列表(list.c,子>父消费) */ + demo_rebuild_to(g_demo_scroll + del); } /* ---- demo 页 view(on_enter/on_leave/on_destroy 驱动进入/离开/释放)---- */ @@ -412,6 +408,7 @@ static void demo_page_enter(meow_view *v, void *ctx) ((demo_ctrl *)ctx)->active = 1; g_demo = 1; g_demo_focus = 0; + list_view_enter(); /* 先进入列表区子视图(其 on_draw 在下面 rebuild→paint 中经注册表触发) */ demo_rebuild_to(0); meow_log(MEOW_LOG_INFO, "demo enter scroll=0"); } @@ -421,6 +418,7 @@ static void demo_page_leave(meow_view *v, void *ctx) (void)v; ((demo_ctrl *)ctx)->active = 0; g_demo = 0; + list_view_leave(); /* 子离开先于父离开(嵌套顺序) */ } static void demo_page_destroy(meow_view *v, void *ctx) @@ -444,11 +442,15 @@ int demo_is_active(void) return g_demo; } -/* demo view:on_create 建 chrome+内容(一次,owner=ACT_DEMO);进入时 rebuild 到顶。 */ +/* demo view:on_create 建 chrome+内容(一次,owner=ACT_DEMO);进入时 rebuild 到顶。 + * 视图深度化:先挂列表区 CONTAINER 子视图到本 ACTIVITY view 的 children,再建内容。 + * 列表子视图 id 用非页面值,不占 g_view_by_id(见 list.c)。 */ static void demo_page_create(meow_view *v, void *ctx) { (void)v; ((demo_ctrl *)ctx)->view = v; + meow_view *lv = list_view_create(); + if (lv) meow_view_add_child(v, lv); demo_init(); } diff --git a/patch_v2/hello_app/ui/demo/list/list.c b/patch_v2/hello_app/ui/demo/list/list.c new file mode 100644 index 0000000..e102546 --- /dev/null +++ b/patch_v2/hello_app/ui/demo/list/list.c @@ -0,0 +1,181 @@ +/* ui/demo/list/list.c — 控件库 Demo 页内「列表区」CONTAINER 子视图(批次③ 视图深度化)。 + * + * 目标(SDK_VIEW_FRAMEWORK_DESIGN.md §B.4/§E③): + * 把 demo 页内的 LazyColumn 列表逻辑区块抽成一个 meow_view CONTAINER 子视图, + * 挂到 demo ACTIVITY view 的 children(meow_view_add_child),验证 + * ① 嵌套生命周期:on_enter/on_leave 顺序(父进入→子进入;子离开→父离开); + * ② 嵌套命中(子>父):点落列表区由本子视图消费,落列表区外回退父页; + * ③ on_draw 直绘:list 区块标题改由本子视图 on_draw 经注册表绘制(view→注册表→invalidate 链路)。 + * + * 职责边界(诚实): + * - 本子视图为**组织/结构节点 + 列表交互收口**:持有 list 控件引用 + 列表视图态 + * (focus/drag/scroll/sel),并对外暴露 list_view_hit/down/move/swipe 供 demo 页分发改派, + * 实现「子>父」命中。list **控件创建/释放**仍留在 demo 页内容重建流(demo_build_at/ + * demo_free_content),因为 widget 由 z 序注册表 auto 注册/注销、并随 scroll 重建——完整 + * 的「控件归容器拥有」需 SDK 侧支持(本批冻结 patch_v2/sdk/),故以绑定引用的方式折中。 + * - SDK 骨架(meow_ui_view.c)的 view_enter/view_leave 不递归 children(批次① 仅顶层页); + * 本子视图的 on_enter/on_leave 由 demo 页 on_enter/on_leave 显式驱动(list_view_enter/leave)。 + * - on_draw 是回调、view 不缓存像素(非保留,§5.8.7);绘制由 meow_ui_paint_full/invalidate + * 触发,仅当本子视图 state 含 MEOW_VIEW_STATE_ENTERED 时注册表才绘制(meow_draw_view_entered)。 + */ +#include "hello_internal.h" + +/* ---- 本子视图(CONTAINER,非页面:id 用越界值避免占用 g_view_by_id 顶层页槽位) ---- */ +static meow_view *g_list_view = NULL; + +/* ---- 列表视图态(跨重建保留;extern 供宿主测试对真实状态断言,见 hello_internal.h)---- + * g_dlc/r_list/g_demo_focus/g_drag_list 从 demo.c 迁入本文件(语义归列表区)。 + * g_demo_focus 亦被 demo.c 的页/列表滚动分流读取,经 extern 跨 TU 共享。 */ +meow_widget *g_dlc = NULL; +rect_t r_list = { 0, 0, 0, 0 }; +int g_demo_focus = 0; /* 1=LazyColumn 聚焦(swipe 滚列表而非页面) */ +int g_drag_list = 0; /* 手指按在 LazyColumn:拖拽滚列表 */ + +static rect_t r_list_title = { 0, 0, 0, 0 }; /* list 区块标题外接框(on_draw 用) */ +static int g_list_scroll = 0; /* 跨重建保留:列表滚动偏移 */ +static int g_list_sel = 0; /* 跨重建保留:选中行 */ +static int g_drag_list_last_y = 0; /* 列表拖拽上一帧 y */ + +/* ---- on_draw:list 区块标题直绘(注册表→invalidate 链路实测,批次③)---- + * 原 demo.c 用 d_title() 把标题注册成 CUSTOM 绘制物;本表标题改由本子视图 on_draw 绘制, + * 注册表在整帧/区域重画时经 draw_one(VIEW) 调 v->hooks.on_draw(需本子视图已进入)。 */ +static void list_view_draw(meow_view *v, const meow_theme *th, void *ctx) +{ + (void)ctx; + if (!g_dlc) return; /* 列表未建成(几何未绑)时不画 */ + meow_ui_text(meow_view_screen_x(v), meow_view_screen_y(v), + "LIST (LazyColumn, tap+swipe)", 20, th->primary); +} + +static void list_page_enter(meow_view *v, void *ctx) +{ + (void)v; (void)ctx; + meow_log(MEOW_LOG_INFO, "demo list view enter"); +} +static void list_page_leave(meow_view *v, void *ctx) +{ + (void)v; (void)ctx; + meow_log(MEOW_LOG_INFO, "demo list view leave"); +} +static void list_page_destroy(meow_view *v, void *ctx) +{ + (void)v; (void)ctx; + g_dlc = NULL; + r_list = RX(0, 0, 0, 0); + r_list_title = RX(0, 0, 0, 0); + g_list_view = NULL; /* meow_view_free 递归释放前清引用,防悬垂 */ +} + +/* 进入子视图:置 ENTERED + on_enter(幂等)。SDK view_enter 不递归,故由父页显式驱动。 */ +void list_view_enter(void) +{ + if (!g_list_view) return; + if (g_list_view->state & MEOW_VIEW_STATE_ENTERED) return; + g_list_view->state |= MEOW_VIEW_STATE_ENTERED; + if (g_list_view->hooks.on_enter) g_list_view->hooks.on_enter(g_list_view, g_list_view->ctx); +} +/* 离开子视图:清 ENTERED + on_leave(幂等)。 */ +void list_view_leave(void) +{ + if (!g_list_view) return; + if (!(g_list_view->state & MEOW_VIEW_STATE_ENTERED)) return; + g_list_view->state &= ~MEOW_VIEW_STATE_ENTERED; + if (g_list_view->hooks.on_leave) g_list_view->hooks.on_leave(g_list_view, g_list_view->ctx); +} + +/* 建 CONTAINER 子视图(demo_page_create 调,随即 meow_view_add_child 到 demo ACTIVITY view)。 */ +meow_view *list_view_create(void) +{ + static const meow_view_hooks h = { + .on_enter = list_page_enter, + .on_leave = list_page_leave, + .on_destroy = list_page_destroy, + .on_draw = list_view_draw, + }; + /* id 用非页面值:容器不占 g_view_by_id(那是 page_push/pop 顶层页查找表)。 */ + g_list_view = meow_view_create(0x1000, MEOW_VIEW_CONTAINER, &h, NULL); + return g_list_view; +} +meow_view *list_view_get(void) +{ + return g_list_view; +} + +/* 内容重建后绑定:list 控件 + 几何(list 区 + 标题条),并恢复/应用跨重建的 scroll/select。 + * demo_build_at 在创建 g_dlc 后调本函数,把标题条与列表区几何写进容器 view(on_draw/命中用)。 */ +void list_view_bind(meow_widget *w, rect_t list, rect_t title) +{ + g_dlc = w; + r_list = list; + r_list_title = title; + if (g_list_view) { + g_list_view->x = title.x; + g_list_view->y = title.y; + g_list_view->w = title.w; + g_list_view->h = title.h + list.h; /* 标题条 + 列表区 */ + } + if (g_dlc) { + meow_list_set_scroll(g_dlc, g_list_scroll); + meow_list_set_selected(g_dlc, g_list_sel); + } +} + +/* 内容释放后清引用(demo_free_content 调;list 控件已由 demo 释放,本处只摘引用)。 */ +void list_view_release(void) +{ + g_dlc = NULL; + r_list = RX(0, 0, 0, 0); + r_list_title = RX(0, 0, 0, 0); + if (g_list_view) g_list_view->x = g_list_view->y = g_list_view->w = g_list_view->h = 0; +} + +/* 点是否落列表区(嵌套命中断言/分发改派用)。 */ +int list_view_contains(int x, int y) +{ + return g_dlc && meow_widget_hit(g_dlc, x, y); +} + +/* Tap 分发给列表区(嵌套命中:demo_content_tap 先查本子视图,命中即消费——子>父)。 + * 命中行→置选中并局部刷;返回 1=已消费。 */ +int list_view_hit(int x, int y) +{ + if (!list_view_contains(x, y)) return 0; + g_demo_focus = 1; + int li = meow_list_tap_at(g_dlc, x, y); + if (li >= 0) { g_list_sel = li; meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); } + return 1; +} + +/* Touch Down 命中列表:置列表聚焦 + 拖拽锁;返回 1=已消费(demo_touch_down 改派)。 */ +int list_view_down(int x, int y) +{ + if (!list_view_contains(x, y)) return 0; + g_demo_focus = 1; + g_drag_list = 1; + g_drag_list_last_y = y; + return 1; +} + +/* Touch Move 拖动列表:跟随滚动;已有 drag 锁(由 down 设立);返回 1=在列表拖动。 */ +int list_view_move(int y) +{ + if (!g_drag_list) return 0; + int dy = y - g_drag_list_last_y; + g_drag_list_last_y = y; + if (dy) { + meow_list_scroll_by(g_dlc, -dy); + g_list_scroll = meow_list_scroll(g_dlc); + meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); + } + return 1; +} + +/* Swipe:列表聚焦时滚列表(返回 1=已消费;否则 demo 页滚页面)。del=方向加权位移。 */ +int list_view_swipe(int del) +{ + if (!(g_demo_focus && g_dlc)) return 0; + meow_list_scroll_by(g_dlc, del); + g_list_scroll = meow_list_scroll(g_dlc); + meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); + return 1; +} diff --git a/patch_v2/hello_app/ui/home.c b/patch_v2/hello_app/ui/home/home.c similarity index 98% rename from patch_v2/hello_app/ui/home.c rename to patch_v2/hello_app/ui/home/home.c index bc252c8..307c5fb 100644 --- a/patch_v2/hello_app/ui/home.c +++ b/patch_v2/hello_app/ui/home/home.c @@ -1,4 +1,4 @@ -/* ui/home.c — 主页(ACT_HOME)view + 控制器。 +/* ui/home/home.c — 主页(ACT_HOME)view + 控制器(批次③ 目录嵌套后)。 * * 负责 home 控件(TAP ME / 6 通知行 / CANCEL LAST / FULLSCREEN / WIDGETS DEMO)+ 手绘(非注册表 * 路径,batch① 仅 demo 迁注册表,home 保持命令式 draw+flush)+ 命中分发 + 业务监听(logic 推送)。 diff --git a/patch_v2/sdk/test_p1p2p3_repro.c b/patch_v2/sdk/test_p1p2p3_repro.c index 0811786..d779373 100644 --- a/patch_v2/sdk/test_p1p2p3_repro.c +++ b/patch_v2/sdk/test_p1p2p3_repro.c @@ -6,6 +6,8 @@ * * 批次② 变化:hello.c 已拆为 app.c + ui/{home,full,demo}.c + ui/common/chrome.c + * logic/{notify,state}.c;本文件不再 #include hello.c,改为 extern 驱动 demo 层并链接多文件。 + * 批次③ 变化:ui/home、ui/demo 子目录化(ui/home/home.c + ui/demo/demo.c),demo 列表区块抽成 + * CONTAINER 子视图 ui/demo/list/list.c;下表编译路径相应更新(断言未弱化)。 * * 覆盖: * P1 z-order 叠层:圆形进度条(实时重绘)与 FAB 浮层重叠时,局部重绘不再清掉/盖住 FAB。 @@ -24,8 +26,9 @@ * 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 meow_ui_draw.c \ * meow_ui_view.c stb_image.c \ - * ../hello_app/ui/home.c ../hello_app/ui/full.c ../hello_app/ui/demo.c \ - * ../hello_app/ui/common/chrome.c ../hello_app/logic/notify.c ../hello_app/logic/state.c \ + * ../hello_app/ui/home/home.c ../hello_app/ui/full.c ../hello_app/ui/demo/demo.c \ + * ../hello_app/ui/demo/list/list.c ../hello_app/ui/common/chrome.c \ + * ../hello_app/logic/notify.c ../hello_app/logic/state.c \ * -I. -I../hello_app -I../meow_launcherd -pthread -lm * 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕) *