/* np_gesture.h — Now Playing 双页手势方向感知(header-only 纯逻辑,宿主可单测)。 * * 定案(用户,批4):Now Playing 同一容器两页——播放页 + 歌词页,手势按当前页方向感知: * - 播放页:右→左滑 → 进歌词页;任意右滑 → 回桌面(用户拍板保留任意右滑)。 * - 歌词页:左→右滑 → 回播放页(不是回桌面);左缘右滑不接桌面(避免误退)。 * 本头为 now_playing.c 与宿主单测(test_now_playing_widgets.c)共用的唯一手势决策,避免两端漂移。 * * 依赖:仅 + meow_notif_panel.h(mnp_top_swipe_down,纯函数)。左缘返回逻辑自 * (re)实现(镜像 meow_touch.c meow_edge_back 同口径,宿主编译无需链 meow_touch.c)。 */ #ifndef NP_GESTURE_H #define NP_GESTURE_H #include #include "meow_notif_panel.h" /* mnp_top_swipe_down(顶部下滑→通知中心) */ /* ---- 页面 ---- */ #define NP_PAGE_PLAY 0 #define NP_PAGE_LYRIC 1 /* ---- 手势动作 ---- */ typedef enum { NP_GEST_NONE = 0, /* 无(横向反向滑/纵向主导不匹配;调用方忽略,不误切页) */ NP_GEST_TOP, /* 顶部热区下滑 → 打开通知中心 */ NP_GEST_NEXT, /* 播放页 右→左滑 → 进入歌词页 */ NP_GEST_PREV, /* 歌词页 左→右滑 → 回到播放页 */ NP_GEST_EXIT, /* 播放页 任意右滑 → 返回桌面 */ NP_GEST_HOME, /* 批②:底部上滑 → 返回桌面(后台保留) */ NP_GEST_TAP, /* 近点按(按当前页分派:播放页=按钮/进度看点) */ } np_gest_t; /* ---- 常量(对齐 launcher 同口径;#ifndef 防与 meow_touch.h 等重复定义冲突)---- */ #ifndef NP_SWIPE_THRESH #define NP_SWIPE_THRESH 65 /* 顶部下滑触发位移阈值(对齐 launcher MENU_SWIPE_THRESH) */ #endif #ifndef NP_PAGE_SWIPE #define NP_PAGE_SWIPE 40 /* 横向切页最小位移(对齐 M6.26 np_anyright 的 dx>=40) */ #endif #ifndef NP_TAP_MAX #define NP_TAP_MAX 60 /* 点按位移上限(对齐现有 adx<60 && ady<60) */ #endif #ifndef NP_TOP_HOTZONE #define NP_TOP_HOTZONE 28 /* 顶部热区高(= launcher SB_BAR_H;通知中心/播放页同) */ #endif #ifndef NP_EDGE_W #define NP_EDGE_W 24 /* 左缘起点宽度(镜像 meow_touch.h MEOW_EDGE_W) */ #endif #ifndef NP_EDGE_SWIPE #define NP_EDGE_SWIPE 65 /* 左缘右滑位移阈值(镜像 meow_touch.h MEOW_EDGE_SWIPE) */ #endif #ifndef NP_HOME_EDGE_H #define NP_HOME_EDGE_H 28 /* 底部起滑区高(自屏底向上;镜像顶部热区 NP_TOP_HOTZONE 同为 28) */ #endif #ifndef NP_HOME_SWIPE #define NP_HOME_SWIPE 65 /* 底部上滑位移阈值(镜像 NP_SWIPE_THRESH / meow_edge_back 同口径) */ #endif /* 左缘返回(镜像 meow_touch.c meow_edge_back:down_x∈[0,NP_EDGE_W) 且 dx>=NP_EDGE_SWIPE * 且横向主导)。为宿主测试免链 meow_touch.c,此处 static inline 复刻同口径。 */ static inline int np_edge_back(int down_x, int dx, int dy) { int ady = dy < 0 ? -dy : dy; if (down_x >= 0 && down_x < NP_EDGE_W && dx >= NP_EDGE_SWIPE && ady < dx) return 1; return 0; } /* 批② 底部上滑返回桌面(home,与左缘返回 np_edge_back 对称):原点在底部起滑区 * (down_y∈[fb_h-NP_HOME_EDGE_H, fb_h))且**不在左缘**(down_x>=NP_EDGE_W,与 np_edge_back 按 * 原点分界互斥——左缘 24px 列留给左缘返回)+ 向上位移≥NP_HOME_SWIPE 且竖向主导(adx<-dy)。 * fb_h=屏高(调用方喂 fb_yres,宿主单测亦可喂固定值)。其余(顶部/中部起滑、横向主导、 * 向下滑、未达阈值)一律 0,不与顶部下滑/横向切页/点按冲突。 */ static inline int np_home_gesture(int down_x, int down_y, int dx, int dy, int fb_h) { int adx = dx < 0 ? -dx : dx; if (down_x >= NP_EDGE_W && down_y >= fb_h - NP_HOME_EDGE_H && down_y >= 0 && dy <= -NP_HOME_SWIPE && adx < -dy) return 1; return 0; } /* 按当前页把手势几何 → 动作。down_x/down_y=抬手原点;dx/dy=抬手位移(释放-原点,即 tlx-tdx)。 * 优先级:顶部下滑 > 横向主导切页/返回 > 点按。横向反向或无主导 → NONE(调用方忽略,不误切)。 */ static inline np_gest_t np_gesture_decide(int page, int down_x, int down_y, int dx, int dy) { int adx = dx < 0 ? -dx : dx, ady = dy < 0 ? -dy : dy; /* 顶部热区下滑 → 通知中心(与主界面同语义;mnp_top_swipe_down 内部排除左缘起点) */ if (mnp_top_swipe_down(down_x, down_y, dx, dy, NP_TOP_HOTZONE, NP_SWIPE_THRESH)) return NP_GEST_TOP; /* 横向主导(adx>=NP_PAGE_SWIPE 且横向位移>竖向)→ 按当前页分流切页/返回 */ if (adx >= NP_PAGE_SWIPE && adx > ady) { if (page == NP_PAGE_PLAY) { if (dx >= NP_PAGE_SWIPE) return NP_GEST_EXIT; /* 任意右滑 → 回桌面(含左缘/非左缘;用户拍板保留任意右滑) */ if (dx <= -NP_PAGE_SWIPE) return NP_GEST_NEXT; /* 右→左滑 → 进歌词页 */ return NP_GEST_NONE; /* 其余忽略 */ } else { /* NP_PAGE_LYRIC */ if (dx >= NP_PAGE_SWIPE) return NP_GEST_PREV; /* 左→右滑 → 回播放页(含左缘,不接桌面) */ return NP_GEST_NONE; /* 右→左滑=歌词页是末页,忽略 */ } } /* 非横向主导:近点按 */ if (adx < NP_TAP_MAX && ady < NP_TAP_MAX) return NP_GEST_TAP; return NP_GEST_NONE; } #endif /* NP_GESTURE_H */