refactor(hello): 视图框架批次③ — 目录嵌套(ui/home/home.c, ui/demo/demo.c+ui/demo/list/list.c) + 视图深度化(demo列表区抽 CONTAINER 子视图, 子>父命中) + on_draw 链路实测通过(list标题改由子视图 on_draw 经注册表绘制) + g_ds.prog 上收 logic/state.c (agent-181)

hello c06b3b4f→07b1ee37; mipsel -Wall -Wextra 0 warning; 宿主 P1c/P2/P3 + widgets 全 PASS
SDK 后续项(本批 App 层显式驱动适配, 未动 SDK): view enter/leave 不递归 children + on_event 路由未接线 — 待 SDK 侧补
This commit is contained in:
MeowOS committed 2026-08-31 04:00:15 +08:00
1 parent d1a3cce7f1
commit 040e799c5f
9 files changed
+281 -63

No files matched your search

+181
View File
@@ -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;
}