Files
MeowOS-SDK/sdk/test_meow_ui_view_event.c
AskaEth c0396e40ce sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓
sdk/:
- 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头
  (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退;
   全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势;
   LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定;
   DSD 音频格式等)
- 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c
- 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动;
  build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径;
  meow_ui_internal.h 去除 FreeType 内部声明
- meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议)
- 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font
  自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs

examples/hello/:
- 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含)

docs / README / .gitignore:
- docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API)
- README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」
- .gitignore 补新增宿主测试二进制

验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
2026-09-04 18:05:36 +08:00

153 lines
8.0 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.
/* test_meow_ui_view_event.c — M7.0a 缺口#7 宿主验证:meow_view 事件接线 + 递归 enter/leave。
*
* A 部(无 run 循环,直调 meow_view_*):递归 enter/leave 顺序 + 运行期动态挂子视图立即进入
* (view.c meow_view_add_child 修正)+ 子>父 on_event 路由。
* B 部(经 meow_ui_run 主循环):把语义事件注入队列 → run 循环先经 meow_view_dispatch_event
* 路由,命中的事件不再落 App on_* 回调(on_tap/on_key/on_swipe/long_press 零触发),未命中
* 的事件照常回落 App 回调——验证「接线于 meow_ui_run、于 §6.4 分流之上」。
*
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global):
* gcc -Wall -Wextra -o test_meow_ui_view_event test_meow_ui_view_event.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_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
* 运行:./test_meow_ui_view_event
*/
#include "meow_ui.h"
#include "meow_ui_internal.h" /* MEOW_EV_* */
#include "meow_ui_view.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
static int g_fail = 0;
#define CHECK(cond, name) do { \
if (cond) printf(" PASS %s\n", name); \
else { printf(" FAIL %s\n", name); g_fail++; } } while (0)
/* ---------- A 部:递归 enter/leave 顺序 + 运行期动态挂子 ---------- */
static int g_trace[16]; static int g_trace_n = 0;
static void vtrace_enter(meow_view *v, void *ctx) { (void)ctx; g_trace[g_trace_n++] = v->id; }
static void vtrace_leave(meow_view *v, void *ctx) { (void)ctx; g_trace[g_trace_n++] = -v->id; }
static int g_child3_hits = 0;
static int vev_child3(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)ctx; if (ev == MEOW_EV_TAP && a == 33 && b == 33) { g_child3_hits++; return 1; } return 0; }
/* ---------- B 部:run 循环接线 ---------- */
static int g_tap_calls = 0, g_key_calls = 0, g_swipe_calls = 0, g_lp_calls = 0;
static void app_on_tap(int x, int y) { (void)x;(void)y; g_tap_calls++; }
static void app_on_key(int k, int d) { (void)k;(void)d; g_key_calls++; }
static void app_on_swipe(int dir, int dx, int dy) { (void)dir;(void)dx;(void)dy; g_swipe_calls++; }
static void app_lp(int x, int y) { (void)x;(void)y; g_lp_calls++; }
/* 父 view:消费 TAP@(10,10) 与 LONG_PRESS(任何)。 */
static int vev_parent(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)ctx;
if (ev == MEOW_EV_TAP && a == 10 && b == 10) return 1;
if (ev == MEOW_EV_LONG_PRESS) return 1;
return 0; }
/* 子 view:消费 KEY(任何)与 SWIPE_LEFT。 */
static int vev_child(meow_view *v, int ev, int a, int b, void *ctx)
{ (void)v;(void)b;(void)ctx;
if (ev == MEOW_EV_KEY) return 1;
if (ev == MEOW_EV_SWIPE && a == MEOW_SWIPE_LEFT) return 1;
return 0; }
static void *driver(void *arg)
{
(void)arg;
usleep(700000); /* 等 startup cooldown(500ms) 过后再发 */
meow_input_inject(MEOW_EV_KEY, MEOW_KEY_VOLUMEUP, 1); /* child 消费 → app_on_key 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_TAP, 10, 10); /* parent 消费 → app_on_tap 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_TAP, 50, 50); /* 无 view 命中 → 回落 app_on_tap */
usleep(80000);
meow_input_inject(MEOW_EV_SWIPE, MEOW_SWIPE_LEFT, 80); /* child 消费 → app_on_swipe 不触发 */
usleep(80000);
meow_input_inject(MEOW_EV_SWIPE, MEOW_SWIPE_RIGHT, 80); /* 无 view 命中 → 回落 app_on_swipe */
usleep(80000);
meow_input_inject(MEOW_EV_LONG_PRESS, 10, 10); /* parent 消费 → long_press 不触发 */
usleep(80000);
meow_ui_request_exit();
return NULL;
}
int main(void)
{
setenv("MEOW_UI_DUMP", "/tmp/view_event.ppm", 1);
meow_ui_opts o = { 480, 720 };
assert(meow_ui_init(&o) == 0);
/* ================= A 部:递归 enter/leave + 动态挂子 ================= */
printf("A: recursive enter/leave + runtime child add\n");
{
static const meow_view_hooks ph = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_parent };
static const meow_view_hooks ch = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_child };
static const meow_view_hooks c3 = { .on_enter = vtrace_enter, .on_leave = vtrace_leave,
.on_event = vev_child3 };
meow_view *pv = meow_view_create(1, MEOW_VIEW_ACTIVITY, &ph, NULL);
meow_view *cv = meow_view_create(2, MEOW_VIEW_CONTAINER, &ch, NULL);
assert(meow_view_add_child(pv, cv) == 0);
g_trace_n = 0;
meow_view_page_push(1); /* pv.enter → cv.enter */
CHECK(g_trace_n == 2 && g_trace[0] == 1 && g_trace[1] == 2, "push: parent.enter -> child.enter");
/* 运行期动态挂第三个子视图(父已 ENTERED)→ 立即进入(view.c 修正) */
meow_view *c3v = meow_view_create(3, MEOW_VIEW_CONTAINER, &c3, NULL);
g_trace_n = 0;
assert(meow_view_add_child(pv, c3v) == 0);
CHECK(g_trace_n == 1 && g_trace[0] == 3, "runtime add-child-while-entered -> child.enter fires");
/* 新挂子 view 参与事件路由:命中 (33,33) 被子 3 消费 */
g_child3_hits = 0;
CHECK(meow_view_dispatch_event(MEOW_EV_TAP, 33, 33) == 1 && g_child3_hits == 1,
"runtime-added child participates in dispatch");
/* 离开:子视图(挂载序 2 → 3)先后离开 → 父(递归离开,子->父) */
g_trace_n = 0;
meow_view_page_pop();
CHECK(g_trace_n == 3 && g_trace[0] == -2 && g_trace[1] == -3 && g_trace[2] == -1,
"pop: child2.leave -> child3.leave -> parent.leave");
meow_view_free(pv); /* 递归释放 2/3 */
printf(" PASS A: recursive order + dynamic child\n");
}
/* ================= B 部:meow_ui_run 接线(§6.4 之上) ================= */
printf("B: meow_view_dispatch_event wired into meow_ui_run\n");
{
static const meow_view_hooks ph = { .on_event = vev_parent };
static const meow_view_hooks ch = { .on_event = vev_child };
meow_view *pv = meow_view_create(20, MEOW_VIEW_ACTIVITY, &ph, NULL);
meow_view *cv = meow_view_create(21, MEOW_VIEW_CONTAINER, &ch, NULL);
assert(meow_view_add_child(pv, cv) == 0);
meow_view_page_push(20); /* 进入父+子(g_top_view=20) */
g_tap_calls = g_key_calls = g_swipe_calls = g_lp_calls = 0;
meow_ui_set_long_press_cb(app_lp);
meow_ui_events ev; memset(&ev, 0, sizeof ev);
ev.on_tap = app_on_tap; ev.on_key = app_on_key; ev.on_swipe = app_on_swipe;
pthread_t thd; pthread_create(&thd, NULL, driver, NULL);
meow_ui_run(&ev); /* 阻塞直到 driver 里 request_exit */
pthread_join(thd, NULL);
CHECK(g_key_calls == 0, "KEY consumed by child -> app_on_key NOT called");
CHECK(g_tap_calls == 1, "TAP(10,10) consumed by parent; TAP(50,50) fell through -> exactly 1 on_tap");
CHECK(g_swipe_calls == 1, "SWIPE_LEFT consumed by child; SWIPE_RIGHT fell through -> exactly 1 on_swipe");
CHECK(g_lp_calls == 0, "LONG_PRESS consumed by parent -> long_press cb NOT called");
printf(" PASS B: run loop routes through views, fallback preserved\n");
meow_view_page_pop();
meow_view_free(pv);
}
meow_ui_shutdown();
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
return g_fail;
}