/* 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**(批次①→③ 后接线): * 本子视图随 demo 页 on_enter/on_leave 自动进入/离开,无需 App 层显式驱动(list_view_enter/leave * 已退役);父 on_enter 重绘时子视图经 meow_draw_view_entered(含祖先已进入)可见。 * - 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 递归释放前清引用,防悬垂 */ } /* 建 CONTAINER 子视图(demo_page_create 调,随即 meow_view_add_child 到 demo ACTIVITY view)。 * 进入/离开经 SDK view_enter/view_leave 递归驱动(随 demo 页),本文件不再显式接管。 */ 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; }