feat(sdk): M6.39批 — LazyGrid/LazyColumn/LazyRow MD3容器化 + SDK全局App内底部上滑回桌面(系统手势优先)
- meow_ui_widget.c: W_LIST/meow_list/LazyColumn/LazyRow默认container=1(MD3圆角卡surfaceContainer+tonal选中+卡内按压+去分隔线) + 新增meow_list_set_container; 平坦回退set_container(0) - meow_lazygrid.c: lg_draw_cell容器化(卡内缩8,surfaceContainer圆角+tonal选中+按压) - meow_ui_input.c: 新增meow_ui_input_is_home_swipe(镜像np_home_gesture:屏底28px热区+上移65px+竖向主导,与左缘返回/列表中滑互斥) + MEOW_EV_HOME分发→meow_ui_nav_request_exit(系统保留手势**优先于App on_swipe**,任意App内生效→MSG_NAV EXIT→批①保活回桌面; 不调request_exit避免进程退出断送保活) - 声明: meow_ui_input.h / meow_ui_widgets.h 各追加 - 宿主测试: test_meow_ui_home_gesture 19-0 / test_meow_ui_lazygrid 32-0, 0warning
This commit is contained in:
1 parent
d0a5901ffb
commit
501867b362
7 files changed
+350
-32
No files matched your search
@@ -36,6 +36,13 @@ void meow_ui_request_exit(void); /* 请求退出(相当于返回/
|
|||||||
* x<=0 时清掉此前画的条(填回背景色)。不发 flush,由调用方 meow_ui_flush_region 上屏。 */
|
* x<=0 时清掉此前画的条(填回背景色)。不发 flush,由调用方 meow_ui_flush_region 上屏。 */
|
||||||
void meow_ui_swipe_hint(int x);
|
void meow_ui_swipe_hint(int x);
|
||||||
|
|
||||||
|
/* 批②(2026-09-04):底部热区上滑 → 回桌面(home)判定,镜像 launcher np_gesture.h
|
||||||
|
* np_home_gesture 同口径。down_x/down_y=抬手原点,dx/dy=抬手位移(释放-原点),
|
||||||
|
* fb_h=屏高(SDK 传 meow_ui_height())。命中=起点在底部热区(最后 HOME_EDGE_H≈28px)且
|
||||||
|
* **不在左缘**(down_x>=EDGE_W,与左缘返回互斥)+ 上移 ≥HOME_SWIPE(65px) + 竖向主导(adx<-dy)。
|
||||||
|
* 供宿主单测直调;触摸状态机(meow_ui_input.c touch_release)与 App 内判据共用,避免两端漂移。 */
|
||||||
|
int meow_ui_input_is_home_swipe(int down_x, int down_y, int dx, int dy, int fb_h);
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §6.3 通用长按(2026-08-31) */
|
/* §6.3 通用长按(2026-08-31) */
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
|
|||||||
@@ -266,6 +266,10 @@ int meow_list_selected(meow_widget *w);
|
|||||||
typedef void (*meow_list_tap_fn)(int idx, void *ctx);
|
typedef void (*meow_list_tap_fn)(int idx, void *ctx);
|
||||||
void meow_list_set_on_tap(meow_widget *w, meow_list_tap_fn cb, void *ctx); /* 命中行→回调 */
|
void meow_list_set_on_tap(meow_widget *w, meow_list_tap_fn cb, void *ctx); /* 命中行→回调 */
|
||||||
int meow_list_tap_at(meow_widget *w, int x, int y); /* 命中行:置选中+回调,返回 idx/-1 */
|
int meow_list_tap_at(meow_widget *w, int x, int y); /* 命中行:置选中+回调,返回 idx/-1 */
|
||||||
|
/* MD3 容器模式(W_LIST 共用,§5.5/§5.8.6):0=扁平满宽项+分隔线(回退);1=每项外套 surfaceContainer
|
||||||
|
* 圆角卡+项间空隙(去分隔线),选中=primaryContainer/按压=primary α26(卡内 tonal)。
|
||||||
|
* 覆盖 meow_list_create / meow_lazycolumn_create / meow_lazyrow_create。返回 0=成功;无效=负值。 */
|
||||||
|
int meow_list_set_container(meow_widget *w, int on);
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §5.5 设计模板 A② 结构化列表(W_LISTVIEW):行=图标+标题+副标题+右侧操作 + 选中
|
/* §5.5 设计模板 A② 结构化列表(W_LISTVIEW):行=图标+标题+副标题+右侧操作 + 选中
|
||||||
|
|||||||
@@ -268,35 +268,46 @@ int meow_lazygrid_hit(meow_lazygrid *g, int x, int y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 绘制(只画可见行;clip 钳到宫格视口)---- */
|
/* ---- 绘制(只画可见行;clip 钳到宫格视口)---- */
|
||||||
|
/* MD3 容器(默认 renderer P0):格=格内对称内缩 surfaceContainer 圆角卡(radius_card)+ 卡内 tonal
|
||||||
|
* 选中(primaryContainer)/ 按压(primary α26);画布=整格(触控目标),卡在其内对称内缩(同
|
||||||
|
* meow_listview 行>卡范式:卡片外仍命中整格,视觉卡留出呼吸空隙)。完全自绘(set_item_draw)
|
||||||
|
* 覆盖本 renderer,App 自理容器观感。 */
|
||||||
|
#define MEOW_LAZYGRID_CARD_MARGIN 8 /* 格内对称边距(卡内缩;与 cell gap 叠加出卡间空隙) */
|
||||||
static void lg_draw_cell(meow_lazygrid *g, const meow_theme *th, int index,
|
static void lg_draw_cell(meow_lazygrid *g, const meow_theme *th, int index,
|
||||||
int cell_x, int cell_y, meow_lazygrid_item *it)
|
int cell_x, int cell_y, meow_lazygrid_item *it)
|
||||||
{
|
{
|
||||||
int sel = (index == g->sel);
|
int sel = (index == g->sel);
|
||||||
int txtcol = sel ? th->onPrimaryContainer : th->onSurface;
|
int txtcol = sel ? th->onPrimaryContainer : th->onSurface;
|
||||||
int subcol = sel ? th->onPrimaryContainer : th->onSurfaceVariant;
|
int subcol = sel ? th->onPrimaryContainer : th->onSurfaceVariant;
|
||||||
uint32_t bg = sel ? th->primaryContainer : th->surfaceContainerLow;
|
int m = MEOW_LAZYGRID_CARD_MARGIN;
|
||||||
meow_gfx_fill_round(cell_x, cell_y, g->cell_w, g->cell_h, th->radius_card, bg);
|
int cw = g->cell_w - 2 * m, chh = g->cell_h - 2 * m; /* 卡尺寸(格内对称内缩) */
|
||||||
|
int cx = cell_x + m, cy = cell_y + m; /* 卡左上 */
|
||||||
|
int press = meow_input_touch_down() &&
|
||||||
|
meow_input_touch_x() >= cell_x && meow_input_touch_x() < cell_x + g->cell_w &&
|
||||||
|
meow_input_touch_y() >= cell_y && meow_input_touch_y() < cell_y + g->cell_h;
|
||||||
|
meow_gfx_fill_round(cx, cy, cw, chh, th->radius_card, th->surfaceContainer);
|
||||||
|
if (sel) meow_gfx_fill_round(cx, cy, cw, chh, th->radius_card, th->primaryContainer);
|
||||||
|
else if (press) meow_gfx_fill_round_alpha(cx, cy, cw, chh, th->radius_card, th->primary, 26);
|
||||||
|
|
||||||
int pad = 8;
|
int pad = 8;
|
||||||
int thh = meow_ui_text_height(th->font_body);
|
int thh = meow_ui_text_height(th->font_body);
|
||||||
int chh = g->cell_h, cw = g->cell_w;
|
/* 图标(可选):居中于卡顶 ~50%(卡中心=格中心,因对称内缩)。 */
|
||||||
/* 图标(可选):居中于格顶 ~50%。 */
|
|
||||||
if (it->icon) {
|
if (it->icon) {
|
||||||
int isz = cw * 6 / 10; if (isz > chh * 5 / 10) isz = chh * 5 / 10;
|
int isz = g->cell_w * 6 / 10; if (isz > g->cell_h * 5 / 10) isz = g->cell_h * 5 / 10;
|
||||||
if (isz < 16) isz = 16;
|
if (isz < 16) isz = 16;
|
||||||
int icx = cell_x + cw / 2, icy = cell_y + pad + isz / 2;
|
int icx = cx + cw / 2, icy = cy + pad + isz / 2;
|
||||||
meow_ui_img_scaled(icx - isz / 2, icy - isz / 2, isz, isz, (meow_img *)it->icon);
|
meow_ui_img_scaled(icx - isz / 2, icy - isz / 2, isz, isz, (meow_img *)it->icon);
|
||||||
}
|
}
|
||||||
/* 标题 + 副标题(主界面:名 + 状态)。底部对齐。 */
|
/* 标题 + 副标题(主界面:名 + 状态)。卡内底部对齐。 */
|
||||||
int has_sub = (it->subtitle && it->subtitle[0]);
|
int has_sub = (it->subtitle && it->subtitle[0]);
|
||||||
int ty = cell_y + chh - pad - thh - (has_sub ? (thh + 2) : 0);
|
int ty = cy + chh - pad - thh - (has_sub ? (thh + 2) : 0);
|
||||||
if (it->title) meow_ui_text_center(cell_x + cw / 2, ty, it->title, th->font_body, txtcol);
|
if (it->title) meow_ui_text_center(cx + cw / 2, ty, it->title, th->font_body, txtcol);
|
||||||
if (has_sub) meow_ui_text_center(cell_x + cw / 2, ty + thh + 2, it->subtitle, th->font_body, subcol);
|
if (has_sub) meow_ui_text_center(cx + cw / 2, ty + thh + 2, it->subtitle, th->font_body, subcol);
|
||||||
|
|
||||||
/* 选中描边(轮廓);禁用整体变淡。 */
|
/* 选中描边(轮廓);禁用卡内变淡(圆角 α,防圆角外叠出灰方块)。 */
|
||||||
if (sel) meow_ui_draw_rect_round(cell_x, cell_y, cw, chh, th->radius_card, th->primary);
|
if (sel) meow_ui_draw_rect_round(cx, cy, cw, chh, th->radius_card, th->primary);
|
||||||
if (!it->enabled)
|
if (!it->enabled)
|
||||||
meow_ui_fill_rect_alpha(cell_x, cell_y, cw, chh, th->onSurface, 90);
|
meow_gfx_fill_round_alpha(cx, cy, cw, chh, th->radius_card, th->onSurface, 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
void meow_lazygrid_draw(meow_lazygrid *g, const meow_theme *th)
|
void meow_lazygrid_draw(meow_lazygrid *g, const meow_theme *th)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "meow_ui_vol.h"
|
#include "meow_ui_vol.h"
|
||||||
#include "meow_ui_media.h"
|
#include "meow_ui_media.h"
|
||||||
#include "meow_ui_view.h" /* M7.0a 缺口#7:把 meow_view_dispatch_event 接入 meow_ui_run */
|
#include "meow_ui_view.h" /* M7.0a 缺口#7:把 meow_view_dispatch_event 接入 meow_ui_run */
|
||||||
|
#include "meow_ui_nav.h" /* 批②:底部上滑回桌面→meow_ui_nav_request_exit(MSG_NAV EXIT→批①保活) */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -57,6 +58,8 @@
|
|||||||
|
|
||||||
#define SWIPE_THRESH 65 /* px:抬起位移超过视为滑动(GESTURE_BACK: 90→65,用户实测 90 偏多,65 更顺手) */
|
#define SWIPE_THRESH 65 /* px:抬起位移超过视为滑动(GESTURE_BACK: 90→65,用户实测 90 偏多,65 更顺手) */
|
||||||
#define EDGE_W 24 /* 左滑返回的「左缘起点」宽度(t_dx < EDGE_W 才认返回手势) */
|
#define EDGE_W 24 /* 左滑返回的「左缘起点」宽度(t_dx < EDGE_W 才认返回手势) */
|
||||||
|
#define HOME_EDGE_H 28 /* 批②:底部起滑区高(自屏底向上;镜像 np_gesture.h NP_HOME_EDGE_H) */
|
||||||
|
#define HOME_SWIPE 65 /* 批②:底部上滑位移阈值(镜像 np_gesture.h NP_HOME_SWIPE;= SWIPE_THRESH) */
|
||||||
#define MEOW_LONG_PRESS_MS 500u /* §6.3 通用长按默认阈值(ms;meow_ui_set_long_press_ms 可配) */
|
#define MEOW_LONG_PRESS_MS 500u /* §6.3 通用长按默认阈值(ms;meow_ui_set_long_press_ms 可配) */
|
||||||
#define MEOW_LONG_PRESS_SLOP 12 /* §6.3 按下后「仍算按住」的最大位移(px);超此取消长按 */
|
#define MEOW_LONG_PRESS_SLOP 12 /* §6.3 按下后「仍算按住」的最大位移(px);超此取消长按 */
|
||||||
#define QUEUE_N 128
|
#define QUEUE_N 128
|
||||||
@@ -71,6 +74,10 @@ void meow_ui_gesture_end(void);
|
|||||||
* (路由 meow_ui_sys_notif_pull),不下发给 APP 的 on_swipe(顶部热区为系统保留手势)。
|
* (路由 meow_ui_sys_notif_pull),不下发给 APP 的 on_swipe(顶部热区为系统保留手势)。
|
||||||
* 与左缘返回(SWIPE_LEFT)/ meow_ui_swipe_hint 互不影响——后者仍全屏生效,详见下方触摸机。 */
|
* 与左缘返回(SWIPE_LEFT)/ meow_ui_swipe_hint 互不影响——后者仍全屏生效,详见下方触摸机。 */
|
||||||
#define MEOW_EV_NOTIF_PULL 5
|
#define MEOW_EV_NOTIF_PULL 5
|
||||||
|
/* 批②:底部热区上滑 → 回桌面(后台保活,走批①链路)。系统手势,a=MEOW_SWIPE_UP(供
|
||||||
|
* on_swipe 接管、view 树消费),b=位移(px)。定义在 input.c 内部(同 MEOW_EV_NOTIF_PULL
|
||||||
|
* 未入公共头),宿主单测按同值声明(见 test_meow_ui_home_gesture.c)。 */
|
||||||
|
#define MEOW_EV_HOME 9
|
||||||
|
|
||||||
/* 顶部下滑 → 通知中心判定:纵向 DOWN 手势的起点(origin_y)是否落在顶部热区内。
|
/* 顶部下滑 → 通知中心判定:纵向 DOWN 手势的起点(origin_y)是否落在顶部热区内。
|
||||||
* 热区由 meow_ui_statusbar_hotzone() 给出(非全屏=状态栏高、全屏=MEOW_SBAR_HOTZONE_FS、
|
* 热区由 meow_ui_statusbar_hotzone() 给出(非全屏=状态栏高、全屏=MEOW_SBAR_HOTZONE_FS、
|
||||||
@@ -80,6 +87,20 @@ int meow_ui_input_is_notif_pull(int origin_y, int hotzone)
|
|||||||
return origin_y >= 0 && origin_y < hotzone;
|
return origin_y >= 0 && origin_y < hotzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 批② 底部热区上滑 → 回桌面(home)判定:镜像 launcher np_gesture.h np_home_gesture 同口径
|
||||||
|
* (热区 28px / 上移 ≥65px / 竖向主导 / 避开左缘返回列),SDK 侧 fb_h=屏幕高(复用
|
||||||
|
* meow_ui_height())。供宿主单测直调(判据与触摸状态机 touch_release 共用)。本判定把
|
||||||
|
* 「底部热区起滑 + 上移超阈值且竖向主导」从普通上滑中剥离——中部上滑/滚动仍归 App
|
||||||
|
* (LazyColumn/LazyGrid 滚动不受影响),底部热区的横向滑仍走原有左缘返回/横向逻辑。 */
|
||||||
|
int meow_ui_input_is_home_swipe(int down_x, int down_y, int dx, int dy, int fb_h)
|
||||||
|
{
|
||||||
|
int adx = dx < 0 ? -dx : dx;
|
||||||
|
if (down_x >= EDGE_W && down_y >= fb_h - HOME_EDGE_H && down_y >= 0 &&
|
||||||
|
dy <= -HOME_SWIPE && adx < -dy)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int g_thread_started = 0;
|
static int g_thread_started = 0;
|
||||||
static pthread_t g_thread;
|
static pthread_t g_thread;
|
||||||
static volatile int g_thread_run = 1;
|
static volatile int g_thread_run = 1;
|
||||||
@@ -326,7 +347,16 @@ static void touch_release(void)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int dir = mdy > 0 ? MEOW_SWIPE_DOWN : MEOW_SWIPE_UP;
|
int dir = mdy > 0 ? MEOW_SWIPE_DOWN : MEOW_SWIPE_UP;
|
||||||
push_ev(MEOW_EV_SWIPE, dir, ady > adx ? ady : adx);
|
int dist = ady > adx ? ady : adx;
|
||||||
|
/* 批②:竖向主导且上移(dir==UP)时,判「底部热区上滑 → 回桌面」。仅当起点在底部
|
||||||
|
* 热区(最后 HOME_EDGE_H px)且**不在左缘**(down_x>=EDGE_W,与左缘返回互斥)且
|
||||||
|
* 上移 ≥HOME_SWIPE 且竖向主导(adx<-dy)才命中;否则照常 SWIPE_UP(中部上滑/滚动交
|
||||||
|
* 由 App)。命中改入队 MEOW_EV_HOME(区别于普通上滑,供 run 循环按兜底回桌面)。 */
|
||||||
|
if (dir == MEOW_SWIPE_UP &&
|
||||||
|
meow_ui_input_is_home_swipe(t_dx, t_dy, mdx, mdy, meow_ui_height()))
|
||||||
|
push_ev(MEOW_EV_HOME, MEOW_SWIPE_UP, dist);
|
||||||
|
else
|
||||||
|
push_ev(MEOW_EV_SWIPE, dir, dist);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push_ev(MEOW_EV_TAP, t_cx, t_cy);
|
push_ev(MEOW_EV_TAP, t_cx, t_cy);
|
||||||
@@ -735,6 +765,22 @@ void meow_ui_run(const meow_ui_events *ev)
|
|||||||
} else if (e.a == MEOW_SWIPE_LEFT && sb_active) {
|
} else if (e.a == MEOW_SWIPE_LEFT && sb_active) {
|
||||||
meow_ui_request_exit();
|
meow_ui_request_exit();
|
||||||
}
|
}
|
||||||
|
} else if (e.type == MEOW_EV_HOME) {
|
||||||
|
/* 系统级「底部热区上滑回桌面」(用户 2026-09-04 批②补全,任意 App 内生效):
|
||||||
|
* 屏底边缘热区+竖向主导上滑已由 meow_ui_input_is_home_swipe 过滤(与 App 中部
|
||||||
|
* 滚动、底部横向滑、左缘返回互斥),故作为**系统保留手势**优先于 App on_swipe /
|
||||||
|
* view 树——否则现有 App(ncm/hello/files/reader 均注册 on_swipe)会接管导致
|
||||||
|
* App 内上滑不回桌面。命中调 meow_ui_nav_request_exit()(MSG_NAV EXIT → launcher
|
||||||
|
* 批① meow_bg_add 保活,进程保留转后台、SDK present 自抑);**不**调
|
||||||
|
* meow_ui_request_exit()——那会断送保活(进程 exit(0))。launcher 据 app 声明
|
||||||
|
* (background_keepalive/background_audio+媒体活跃)决定无限期/宽限。 */
|
||||||
|
if (in_startup) continue; /* 启动窗口误触残留:丢弃 */
|
||||||
|
meow_ui_swipe_hint(-1);
|
||||||
|
meow_ui_gesture_end(); /* §6.4:抬手边沿,释放手势捕获 */
|
||||||
|
/* IME 打开时软键盘覆盖底部:键盘拥有底部区,把事件交给 IME 且**绝不**回桌面
|
||||||
|
* (防输入时误退)。 */
|
||||||
|
if (meow_ime_active()) { (void)meow_ime_handle_event(&e); continue; }
|
||||||
|
meow_ui_nav_request_exit();
|
||||||
} else if (e.type == MEOW_EV_NOTIF_PULL) {
|
} else if (e.type == MEOW_EV_NOTIF_PULL) {
|
||||||
if (in_startup) continue; /* 启动窗口顶区误触残留:丢弃,防进入即开通知中心 */
|
if (in_startup) continue; /* 启动窗口顶区误触残留:丢弃,防进入即开通知中心 */
|
||||||
/* 系统级「下拉展开通知中心」:起始于顶部热区的下滑为系统保留手势,不下发
|
/* 系统级「下拉展开通知中心」:起始于顶部热区的下滑为系统保留手势,不下发
|
||||||
|
|||||||
@@ -407,6 +407,10 @@ meow_widget *meow_list_create(int x, int y, int w, int h, int count,
|
|||||||
t->owner = meow_ui_activity_active();
|
t->owner = meow_ui_activity_active();
|
||||||
t->state = MEOW_WS_ENABLED;
|
t->state = MEOW_WS_ENABLED;
|
||||||
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
||||||
|
/* M6.37 P1:SDK 默认列表(meow_list_create / meow_lazycolumn_create / meow_lazyrow_create,皆 W_LIST)
|
||||||
|
* 走 MD3 容器模式——每项=surfaceContainer 圆角卡 + 项间空隙 + 去分隔线 + 卡内 tonal 选中/按压,
|
||||||
|
* 与 meow_listview 容器同范式(全局统一)。需扁平的宿主可显式 meow_list_set_container(w,0) 回退。 */
|
||||||
|
t->container = 1;
|
||||||
meow_draw_widget_register(t);
|
meow_draw_widget_register(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@@ -1014,6 +1018,17 @@ int meow_list_tap_at(meow_widget *w, int x, int y)
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MD3 容器模式(W_LIST 共用,§5.5/§5.8.6):0=扁平满宽项+分隔线(回退);1=每项外套 surfaceContainer
|
||||||
|
* 圆角卡+项间空隙(去分隔线),选中=primaryContainer/按压=primary α26(卡内 tonal)。
|
||||||
|
* 覆盖 meow_list_create / meow_lazycolumn_create / meow_lazyrow_create。返回 0=成功;无效=负值。 */
|
||||||
|
int meow_list_set_container(meow_widget *w, int on)
|
||||||
|
{
|
||||||
|
if (!w || w->type != W_LIST) return -1;
|
||||||
|
w->container = on ? 1 : 0;
|
||||||
|
meow_gfx_mark_dirty(w->x, w->y, w->w, w->h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §5.5 结构化列表(W_LISTVIEW):行=图标+标题+副标题+右侧操作+选中
|
/* §5.5 结构化列表(W_LISTVIEW):行=图标+标题+副标题+右侧操作+选中
|
||||||
* ------------------------------------------------------------
|
* ------------------------------------------------------------
|
||||||
@@ -1730,7 +1745,11 @@ void meow_widget_draw(meow_widget *w)
|
|||||||
}
|
}
|
||||||
case W_LIST: {
|
case W_LIST: {
|
||||||
/* §5.8.6 列表容器(LazyColumn/LazyRow):只画可见项(虚拟化)+ 滚动偏移。
|
/* §5.8.6 列表容器(LazyColumn/LazyRow):只画可见项(虚拟化)+ 滚动偏移。
|
||||||
* 纵向=行高 item_h(默认 44,兼容既有 meow_list_create);横向=LazyRow(列宽=item_h)。 */
|
* 纵向=行高 item_h(默认 44,兼容既有 meow_list_create);横向=LazyRow(列宽=item_h)。
|
||||||
|
* MD3 容器模式(w->container=1,默认):每项外套 surfaceContainer 圆角卡(12dp)+ 项间空隙
|
||||||
|
* (去分隔线),选中=primaryContainer/按压=primary α26(卡内 tonal),与 meow_listview 容器同范式;
|
||||||
|
* 卡在项内交叉轴内缩 MEOW_LISTV_CARD_MARGIN、滚动轴对称内缩 MEOW_LISTV_CARD_GAP(行中心=卡中心)。
|
||||||
|
* 非容器(meow_list_set_container(0) 回退):满幅扁平行 + primary 选中 + onSurfaceVariant 分隔线。 */
|
||||||
int pad = 16;
|
int pad = 16;
|
||||||
int item = list_item(w);
|
int item = list_item(w);
|
||||||
int vp = w->horizontal ? w->w : w->h;
|
int vp = w->horizontal ? w->w : w->h;
|
||||||
@@ -1747,36 +1766,70 @@ void meow_widget_draw(meow_widget *w)
|
|||||||
* 画到视口外 → 标脏并上屏 → 标题栏/底部残留脏区,P3)。 */
|
* 画到视口外 → 标脏并上屏 → 标题栏/底部残留脏区,P3)。 */
|
||||||
int vx0 = w->x, vy0 = w->y, vx1 = w->x + w->w, vy1 = w->y + w->h;
|
int vx0 = w->x, vy0 = w->y, vx1 = w->x + w->w, vy1 = w->y + w->h;
|
||||||
int thh = meow_ui_text_height(th->font_body);
|
int thh = meow_ui_text_height(th->font_body);
|
||||||
|
int cm = w->container ? MEOW_LISTV_CARD_MARGIN : 0; /* 卡交叉轴内缩(纵向=水平→横向=垂直) */
|
||||||
|
int cgap = w->container ? MEOW_LISTV_CARD_GAP : 0; /* 卡滚动轴对称内缩(去分隔线、留空隙) */
|
||||||
for (int i = first; i < last; i++) {
|
for (int i = first; i < last; i++) {
|
||||||
char label[64] = "";
|
char label[64] = "";
|
||||||
if (!w->src || !w->src(i, label, (int)sizeof label, w->ctx)) continue;
|
if (!w->src || !w->src(i, label, (int)sizeof label, w->ctx)) continue;
|
||||||
int pos = i * item - off; /* 相对容器起点的可视位置 */
|
int pos = i * item - off; /* 相对容器起点的可视位置 */
|
||||||
|
int sel = (i == w->sel);
|
||||||
if (w->horizontal) {
|
if (w->horizontal) {
|
||||||
int rx = w->x + pos;
|
int rx = w->x + pos;
|
||||||
if (rx >= vx1) break; /* 完全在右缘外 */
|
if (rx >= vx1) break; /* 完全在右缘外 */
|
||||||
if (rx + item <= vx0) continue; /* 完全在左缘外(滚出残余) */
|
if (rx + item <= vx0) continue; /* 完全在左缘外(滚出残余) */
|
||||||
int cl = rx > vx0 ? rx : vx0; /* 可见左界 */
|
int cl = rx > vx0 ? rx : vx0; /* 可见左界 */
|
||||||
int cr = (rx + item) < vx1 ? (rx + item) : vx1; /* 可见右界 */
|
int cr = (rx + item) < vx1 ? (rx + item) : vx1; /* 可见右界 */
|
||||||
if (i == w->sel) meow_ui_fill_rect(cl, w->y, cr - cl, w->h, th->primary);
|
int ctop = w->y + cm; /* 卡顶(交叉轴内缩) */
|
||||||
uint32_t col = (i == w->sel) ? 0xFFFFFF : th->onSurface;
|
int chh = w->h - 2 * cm; /* 卡高 */
|
||||||
|
int clft = rx + cgap / 2; /* 卡左(滚动轴对称内缩) */
|
||||||
|
int cwid = item - cgap; /* 卡宽 */
|
||||||
|
int press = meow_input_touch_down() &&
|
||||||
|
meow_input_touch_x() >= rx && meow_input_touch_x() < rx + item &&
|
||||||
|
meow_input_touch_y() >= w->y && meow_input_touch_y() < w->y + w->h;
|
||||||
|
if (w->container) {
|
||||||
|
meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||||
|
if (sel) meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||||
|
else if (press) meow_gfx_fill_round_alpha(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||||
|
} else {
|
||||||
|
if (sel) meow_ui_fill_rect(cl, w->y, cr - cl, w->h, th->primary);
|
||||||
|
}
|
||||||
|
uint32_t col = sel ? (w->container ? th->onPrimaryContainer : 0xFFFFFF) : th->onSurface;
|
||||||
int ty = w->y + (w->h - thh) / 2;
|
int ty = w->y + (w->h - thh) / 2;
|
||||||
if (rx >= vx0 && rx + item <= vx1) /* 仅整项可见才画文本(防泄漏) */
|
if (rx >= vx0 && rx + item <= vx1) /* 仅整项可见才画文本(防泄漏) */
|
||||||
meow_ui_text_center(rx + item / 2, ty, label, th->font_body, col);
|
meow_ui_text_center(rx + item / 2, ty, label, th->font_body, col);
|
||||||
int sxp = rx + item - 1; /* 分隔线:仅当落在可见区 */
|
if (!w->container) { /* 非容器才画分隔线(容器模式去冗余) */
|
||||||
if (sxp >= cl && sxp < cr) meow_ui_fill_rect(sxp, w->y, 1, w->h, th->onSurfaceVariant);
|
int sxp = rx + item - 1; /* 分隔线:仅当落在可见区 */
|
||||||
|
if (sxp >= cl && sxp < cr) meow_ui_fill_rect(sxp, w->y, 1, w->h, th->onSurfaceVariant);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int ry = w->y + pos;
|
int ry = w->y + pos;
|
||||||
if (ry >= vy1) break; /* 完全在底缘外 */
|
if (ry >= vy1) break; /* 完全在底缘外 */
|
||||||
if (ry + item <= vy0) continue; /* 完全在顶缘外(滚出残余) */
|
if (ry + item <= vy0) continue; /* 完全在顶缘外(滚出残余) */
|
||||||
int cl = ry > vy0 ? ry : vy0; /* 可见顶界 */
|
int cl = ry > vy0 ? ry : vy0; /* 可见顶界 */
|
||||||
int cr = (ry + item) < vy1 ? (ry + item) : vy1; /* 可见底界 */
|
int cr = (ry + item) < vy1 ? (ry + item) : vy1; /* 可见底界 */
|
||||||
if (i == w->sel) meow_ui_fill_rect(w->x, cl, w->w, cr - cl, th->primary);
|
int clft = w->x + cm; /* 卡左(交叉轴内缩) */
|
||||||
uint32_t col = (i == w->sel) ? 0xFFFFFF : th->onSurface;
|
int cwid = w->w - 2 * cm; /* 卡宽 */
|
||||||
|
int ctop = ry + cgap / 2; /* 卡顶(滚动轴对称内缩) */
|
||||||
|
int chh = item - cgap; /* 卡高 */
|
||||||
|
int press = meow_input_touch_down() &&
|
||||||
|
meow_input_touch_x() >= w->x && meow_input_touch_x() < w->x + w->w &&
|
||||||
|
meow_input_touch_y() >= ry && meow_input_touch_y() < ry + item;
|
||||||
|
if (w->container) {
|
||||||
|
meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->surfaceContainer);
|
||||||
|
if (sel) meow_gfx_fill_round(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primaryContainer);
|
||||||
|
else if (press) meow_gfx_fill_round_alpha(clft, ctop, cwid, chh, MEOW_LISTV_CARD_RADIUS, th->primary, 26);
|
||||||
|
} else {
|
||||||
|
if (sel) meow_ui_fill_rect(w->x, cl, w->w, cr - cl, th->primary);
|
||||||
|
}
|
||||||
|
uint32_t col = sel ? (w->container ? th->onPrimaryContainer : 0xFFFFFF) : th->onSurface;
|
||||||
|
int txx = (w->container ? clft : w->x) + pad; /* 卡内文本左缘 */
|
||||||
int ty = ry + (item - thh) / 2;
|
int ty = ry + (item - thh) / 2;
|
||||||
if (ty >= vy0 && ty + thh <= vy1) /* 文本不越界才画(防标题/底部泄漏) */
|
if (ty >= vy0 && ty + thh <= vy1) /* 文本不越界才画(防标题/底部泄漏) */
|
||||||
meow_ui_text(w->x + pad, ty, label, th->font_body, col);
|
meow_ui_text(txx, ty, label, th->font_body, col);
|
||||||
int sy = ry + item - 1; /* 分隔线:仅当落在可见区 */
|
if (!w->container) { /* 非容器才画分隔线(容器模式去冗余) */
|
||||||
if (sy >= cl && sy < cr) meow_ui_fill_rect(w->x, sy, w->w, 1, th->onSurfaceVariant);
|
int sy = ry + item - 1; /* 分隔线:仅当落在可见区 */
|
||||||
|
if (sy >= cl && sy < cr) meow_ui_fill_rect(w->x, sy, w->w, 1, th->onSurfaceVariant);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
if (disabled) meow_ui_fill_rect_alpha(w->x, w->y, w->w, w->h, th->onSurface, 90);
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/* test_meow_ui_home_gesture.c — 批② SDK 全局「App 内底部热区上滑回桌面」宿主验证。
|
||||||
|
*
|
||||||
|
* 覆盖(并同 meow_ui_input_is_home_swipe 判据、touch_release 分类、meow_ui_run 分发三层):
|
||||||
|
* T1 判定矩阵(meow_ui_input_is_home_swipe,镜像 launcher np_gesture.h np_home_gesture):
|
||||||
|
* 底部热区上滑=1;底部左缘上滑=0(左缘返回互斥);中部上滑=0(App 滚动);底部横向=0;
|
||||||
|
* 底部下滑=0;上移不足=0;横向主导=0;屏底边界(down_y=fb_h-HOME_EDGE_H)之外=0。
|
||||||
|
* T2 触摸状态机分类(真实 touch_release → 队列 pop 断言):
|
||||||
|
* 底部热区上滑→MEOW_EV_HOME(a=MEOW_SWIPE_UP);中部上滑→MEOW_EV_SWIPE(UP)(不被剥回桌面);
|
||||||
|
* 底部左缘横滑→MEOW_EV_SWIPE(LEFT)(原左缘返回,不被剥)。
|
||||||
|
* T3 分发(meow_ui_run 主循环,run-loop 复用 test_meow_ui_view_event 的 driver 线程范式):
|
||||||
|
* 3a 未注册 on_swipe:注入 MEOW_EV_HOME → meow_ui_nav_request_exit 被触发(一次)——回桌面;
|
||||||
|
* 3b 未注册 on_swipe:注入 MEOW_EV_SWIPE(UP)(中部上滑)→ nav_request_exit 不触发(App 滚动);
|
||||||
|
* 3c 注册 on_swipe:注入 MEOW_EV_HOME → nav_request_exit 触发(系统级手势优先于 App on_swipe),
|
||||||
|
* on_swipe 不被调用——屏底热区上滑是系统保留手势,任意 App 内生效(用户 2026-09-04 批②)。
|
||||||
|
*
|
||||||
|
* 编译(宿主 gcc,链真实 SDK 源全集 + 打桩 font/global;**不链 meow_ui_nav.c**——本测以测试内
|
||||||
|
* meow_ui_nav_request_exit 桩计数验证触发):
|
||||||
|
* gcc -Wall -Wextra -o test_meow_ui_home_gesture test_meow_ui_home_gesture.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_home_gesture
|
||||||
|
*/
|
||||||
|
#include "meow_ui.h"
|
||||||
|
#include "meow_ui_internal.h" /* meow_input_touch_set/move/release + meow_input_pop + MEOW_EV_* */
|
||||||
|
#include "meow_ui_nav.h" /* meow_ui_nav_request_exit 原型(本测以桩计数验证) */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* MEOW_EV_HOME 是 meow_ui_input.c 内部常量(未入公共头,同 MEOW_EV_NOTIF_PULL 惯例),按同值声明。 */
|
||||||
|
#ifndef MEOW_EV_HOME
|
||||||
|
#define MEOW_EV_HOME 9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int g_pass = 0, g_fail = 0;
|
||||||
|
#define CHECK(cond, ...) do { \
|
||||||
|
if (cond) { g_pass++; } \
|
||||||
|
else { g_fail++; printf("FAIL %s:%d ", __FILE__, __LINE__); printf(__VA_ARGS__); printf("\n"); } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* fb 高度(宿主 480x720) */
|
||||||
|
#define FBW 480
|
||||||
|
#define FBH 720
|
||||||
|
/* 判据常量镜像(np_gesture.h NP_HOME_EDGE_H=28 / NP_HOME_SWIPE=65 / NP_EDGE_W=24)。 */
|
||||||
|
#define H_EDGE 28
|
||||||
|
#define H_SWIPE 65
|
||||||
|
#define EDGE_W 24
|
||||||
|
|
||||||
|
/* ---- nav_request_exit 桩(不链 meow_ui_nav.c;计数验证 SDK 触发) ---- */
|
||||||
|
static int g_nav_exit_calls = 0;
|
||||||
|
void meow_ui_nav_request_exit(void) { g_nav_exit_calls++; }
|
||||||
|
|
||||||
|
/* ---- on_swipe 桩(App 接管验证) ---- */
|
||||||
|
static int g_swipe_calls = 0;
|
||||||
|
static int g_swipe_dir = -1;
|
||||||
|
static int g_swipe_dx = 0;
|
||||||
|
static void app_on_swipe(int dir, int dx, int dy) { (void)dy; g_swipe_calls++; g_swipe_dir = dir; g_swipe_dx = dx; }
|
||||||
|
|
||||||
|
/* 从队列 pop 一个事件并回填 (type,a,b);无事件返回 0。 */
|
||||||
|
static int pop_ev(int *type, int *a, int *b)
|
||||||
|
{
|
||||||
|
meow_input_ev e;
|
||||||
|
if (!meow_input_pop(&e)) return 0;
|
||||||
|
*type = e.type; *a = e.a; *b = e.b;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============ T1 判定矩阵(meow_ui_input_is_home_swipe) ============ */
|
||||||
|
static void test_predicate(void)
|
||||||
|
{
|
||||||
|
printf("T1 meow_ui_input_is_home_swipe matrix\n");
|
||||||
|
int bz = FBH - H_EDGE; /* 底部热区上边界 y = 720-28 = 692 */
|
||||||
|
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, 0, -120, FBH) == 1, "T1 bottom-hotzone up -> 1");
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(100, FBH - 1, 20, -80, FBH) == 1, "T1 screen-bottom up (x>EDGE_W) -> 1");
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, 0, -H_SWIPE, FBH) == 1, "T1 exactly threshold up -> 1");
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, -30, -70, FBH) == 1, "T1 up w/ small left dx (adx<dy) -> 1");
|
||||||
|
|
||||||
|
/* 左缘互斥(down_x<EDGE_W) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(10, bz + 10, 0, -120, FBH) == 0, "T1 left-edge origin -> 0 (edge-back reserved)");
|
||||||
|
/* 中部上滑(App 滚动) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, 300, 0, -120, FBH) == 0, "T1 mid-screen up -> 0 (App scroll)");
|
||||||
|
/* 底部横向(左缘返回/横向逻辑保留) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, 120, 0, FBH) == 0, "T1 bottom horizontal -> 0");
|
||||||
|
/* 底部下滑 */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, 0, 120, FBH) == 0, "T1 bottom down -> 0");
|
||||||
|
/* 上移不足(<H_SWIPE) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, 0, -(H_SWIPE - 1), FBH) == 0, "T1 up below threshold -> 0");
|
||||||
|
/* 竖向未主导(横向位移≥上移量,adx>=dy) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz + 10, -120, -80, FBH) == 0, "T1 up w/ big dx (not vertical-dominant) -> 0");
|
||||||
|
/* 热区边界之外(down_y < bz) */
|
||||||
|
CHECK(meow_ui_input_is_home_swipe(240, bz - 1, 0, -120, FBH) == 0, "T1 just above hotzone -> 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============ T2 触摸状态机分类(touch_release → 队列) ============ */
|
||||||
|
static void test_touch_classify(void)
|
||||||
|
{
|
||||||
|
printf("T2 touch_release classification\n");
|
||||||
|
meow_input_drain();
|
||||||
|
|
||||||
|
/* 底部热区上滑 → MEOW_EV_HOME */
|
||||||
|
meow_input_touch_set(1, 240, FBH - 5, 0); /* 起点 y=715 ∈ [692,720) */
|
||||||
|
meow_input_touch_move(240, FBH - 5 - 130); /* 上移 130 */
|
||||||
|
meow_input_touch_release();
|
||||||
|
{
|
||||||
|
int t, a, b;
|
||||||
|
CHECK(pop_ev(&t, &a, &b) == 1 && t == MEOW_EV_HOME && a == MEOW_SWIPE_UP,
|
||||||
|
"T2 bottom-hotzone up -> MEOW_EV_HOME(UP) got type=%d a=%d", t, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 中部上滑 → 普通 MEOW_EV_SWIPE(UP)(不被剥回桌面) */
|
||||||
|
meow_input_touch_set(1, 240, 300, 0);
|
||||||
|
meow_input_touch_move(240, 300 - 130);
|
||||||
|
meow_input_touch_release();
|
||||||
|
{
|
||||||
|
int t, a, b;
|
||||||
|
CHECK(pop_ev(&t, &a, &b) == 1 && t == MEOW_EV_SWIPE && a == MEOW_SWIPE_UP,
|
||||||
|
"T2 mid up -> SWIPE(UP) got type=%d a=%d", t, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部左缘横滑 → 原有左缘返回(不被剥) */
|
||||||
|
meow_input_touch_set(1, 5, FBH - 5, 0);
|
||||||
|
meow_input_touch_move(5 + 100, FBH - 5);
|
||||||
|
meow_input_touch_release();
|
||||||
|
{
|
||||||
|
int t, a, b;
|
||||||
|
CHECK(pop_ev(&t, &a, &b) == 1 && t == MEOW_EV_SWIPE && a == MEOW_SWIPE_LEFT,
|
||||||
|
"T2 bottom-left horizontal -> SWIPE(LEFT) got type=%d a=%d", t, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============ T3 分发(meow_ui_run 主循环) ============ */
|
||||||
|
static int g_inj_type, g_inj_a, g_inj_b;
|
||||||
|
static void *driver(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
usleep(700000); /* 等 startup cooldown(500ms) 过后再注入 */
|
||||||
|
meow_input_inject(g_inj_type, g_inj_a, g_inj_b);
|
||||||
|
usleep(80000);
|
||||||
|
meow_ui_request_exit();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_scenario(int inj_type, int inj_a, int inj_b, int register_swipe)
|
||||||
|
{
|
||||||
|
g_inj_type = inj_type; g_inj_a = inj_a; g_inj_b = inj_b;
|
||||||
|
g_nav_exit_calls = 0;
|
||||||
|
g_swipe_calls = 0; g_swipe_dir = -1; g_swipe_dx = 0;
|
||||||
|
meow_input_drain(); /* 防上一次残留事件影响本次分发 */
|
||||||
|
|
||||||
|
meow_ui_events ev; memset(&ev, 0, sizeof ev);
|
||||||
|
if (register_swipe) ev.on_swipe = app_on_swipe;
|
||||||
|
|
||||||
|
pthread_t thd; pthread_create(&thd, NULL, driver, NULL);
|
||||||
|
meow_ui_run(&ev);
|
||||||
|
pthread_join(thd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dispatch(void)
|
||||||
|
{
|
||||||
|
printf("T3 meow_ui_run dispatch (home = nav_request_exit fallback)\n");
|
||||||
|
|
||||||
|
/* 3a 未注册 on_swipe:底部热区上滑 → nav_request_exit 触发一次(回桌面) */
|
||||||
|
run_scenario(MEOW_EV_HOME, MEOW_SWIPE_UP, 120, 0);
|
||||||
|
CHECK(g_nav_exit_calls == 1, "T3a no-on_swipe MEOW_EV_HOME -> nav_request_exit fired (got %d)", g_nav_exit_calls);
|
||||||
|
CHECK(g_swipe_calls == 0, "T3a no-on_swipe -> on_swipe NOT called");
|
||||||
|
|
||||||
|
/* 3b 未注册 on_swipe:中部上滑(普通 MEOW_EV_SWIPE UP)→ nav_request_exit 不触发(App 滚动) */
|
||||||
|
run_scenario(MEOW_EV_SWIPE, MEOW_SWIPE_UP, 120, 0);
|
||||||
|
CHECK(g_nav_exit_calls == 0, "T3b mid-swipe-up -> nav_request_exit NOT fired (App scroll), got %d", g_nav_exit_calls);
|
||||||
|
|
||||||
|
/* 3c 注册 on_swipe:底部热区上滑 → 系统优先,nav_request_exit 触发(回桌面),on_swipe 不被调用 */
|
||||||
|
run_scenario(MEOW_EV_HOME, MEOW_SWIPE_UP, 120, 1);
|
||||||
|
CHECK(g_nav_exit_calls == 1, "T3c on_swipe registered -> nav_request_exit STILL fired (system gesture wins), got %d", g_nav_exit_calls);
|
||||||
|
CHECK(g_swipe_calls == 0, "T3c system-priority home -> on_swipe NOT called");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
meow_ui_opts o = { FBW, FBH };
|
||||||
|
if (meow_ui_init(&o) != 0) { printf("init failed\n"); return 1; }
|
||||||
|
|
||||||
|
test_predicate();
|
||||||
|
test_touch_classify();
|
||||||
|
test_dispatch();
|
||||||
|
|
||||||
|
meow_ui_shutdown();
|
||||||
|
printf("home_gesture: %d pass / %d fail\n", g_pass, g_fail);
|
||||||
|
return g_fail ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -109,8 +109,8 @@ int main(void)
|
|||||||
meow_ui_opts o = { 480, 720 };
|
meow_ui_opts o = { 480, 720 };
|
||||||
if (meow_ui_init(&o) != 0) { printf("init failed\n"); return 1; }
|
if (meow_ui_init(&o) != 0) { printf("init failed\n"); return 1; }
|
||||||
const meow_theme *th = meow_theme_get();
|
const meow_theme *th = meow_theme_get();
|
||||||
int scl_r, scl_g, scl_b, on_r, on_g, on_b, pc_r, pc_g, pc_b, osv_r, osv_g, osv_b, opc_r, opc_g, opc_b;
|
int sc_r, sc_g, sc_b, on_r, on_g, on_b, pc_r, pc_g, pc_b, osv_r, osv_g, osv_b, opc_r, opc_g, opc_b;
|
||||||
UNPK(th->surfaceContainerLow, scl_r, scl_g, scl_b);
|
UNPK(th->surfaceContainer, sc_r, sc_g, sc_b);
|
||||||
UNPK(th->onSurface, on_r, on_g, on_b);
|
UNPK(th->onSurface, on_r, on_g, on_b);
|
||||||
UNPK(th->primaryContainer, pc_r, pc_g, pc_b);
|
UNPK(th->primaryContainer, pc_r, pc_g, pc_b);
|
||||||
UNPK(th->onSurfaceVariant, osv_r, osv_g, osv_b);
|
UNPK(th->onSurfaceVariant, osv_r, osv_g, osv_b);
|
||||||
@@ -196,17 +196,18 @@ int main(void)
|
|||||||
meow_lazygrid_draw(g, th);
|
meow_lazygrid_draw(g, th);
|
||||||
/* 选中 cell0 → primaryContainer 底([GX,GY,100,80]) */
|
/* 选中 cell0 → primaryContainer 底([GX,GY,100,80]) */
|
||||||
CHECK(region_has(GX + 4, GY + 4, 90, 60, pc_r, pc_g, pc_b) > 40, "selected cell primaryContainer bg");
|
CHECK(region_has(GX + 4, GY + 4, 90, 60, pc_r, pc_g, pc_b) > 40, "selected cell primaryContainer bg");
|
||||||
/* 未选中 cell1 → surfaceContainerLow 底 */
|
/* 未选中 cell1 → surfaceContainer 底(MD3 容器:格内对称内缩 m=8 的圆角卡) */
|
||||||
int x1 = GX + 1 * (CW + GAP);
|
int x1 = GX + 1 * (CW + GAP);
|
||||||
CHECK(region_has(x1 + 4, GY + 4, 90, 60, scl_r, scl_g, scl_b) > 40, "cell1 surfaceContainerLow bg");
|
CHECK(region_has(x1 + 4, GY + 4, 90, 60, sc_r, sc_g, sc_b) > 40, "cell1 surfaceContainer bg");
|
||||||
/* 标题画在 cell0 底部(选中 → onPrimaryContainer;副标题在下方 onPrimaryContainer 同色带) */
|
/* 标题画在 cell0 卡内底部(选中 → onPrimaryContainer;副标题在下方 onPrimaryContainer 同色带)。
|
||||||
|
* 镜像 lg_draw_cell 的 ty:cy=GY+m、chh=CH-2m、pad=8 → ty = GY+CH-m-pad-thh-(thh+2)。 */
|
||||||
int thh = meow_ui_text_height(th->font_body);
|
int thh = meow_ui_text_height(th->font_body);
|
||||||
int title_y = GY + CH - 8 - thh - (thh + 2); /* = lg_draw_cell 的 ty */
|
int title_y = GY + CH - 8 - 8 - thh - (thh + 2);
|
||||||
int c0cx = GX + CW / 2;
|
int c0cx = GX + CW / 2;
|
||||||
CHECK(region_has(c0cx - 30, title_y, 60, thh, opc_r, opc_g, opc_b) > 2, "cell0 title drawn (onPrimaryContainer)");
|
CHECK(region_has(c0cx - 30, title_y, 60, thh, opc_r, opc_g, opc_b) > 2, "cell0 title drawn (onPrimaryContainer)");
|
||||||
/* 禁用 cell2 变淡:左上角(图标/文本区之外)不再是纯 surfaceContainerLow(被 onSurface α 叠暗) */
|
/* 禁用 cell2 变淡:卡内左上角(图标/文本区之外)不再是纯 surfaceContainer(被 onSurface α 叠暗) */
|
||||||
int x2 = GX + 2 * (CW + GAP);
|
int x2 = GX + 2 * (CW + GAP);
|
||||||
CHECK(!px_near(x2 + 4, GY + 4, scl_r, scl_g, scl_b), "disabled cell overlaid (bg dimmed)");
|
CHECK(!px_near(x2 + 8 + 4, GY + 8 + 4, sc_r, sc_g, sc_b), "disabled cell overlaid (bg dimmed)");
|
||||||
meow_lazygrid_free(g);
|
meow_lazygrid_free(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user