Files
MeowOS 4f66da66ad Add 'examples/hello/' from commit 'e88e5a6ff3b0f55671cb64c0a506e552360010e9'
git-subtree-dir: examples/hello
git-subtree-mainline: f44e3bc6d0
git-subtree-split: e88e5a6ff3
2026-09-01 21:08:44 +08:00

167 lines
7.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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;
}