Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_now_playing_widgets.c
T

253 lines
13 KiB
C
Raw 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_now_playing_widgets.c — M7.0b Now Playing 控件化宿主验证。
*
* 复现 run_now_playing() 所建控件集(np_widgets_create:meow_progress 进度条 + meow_iconbtn
* 三钮,play/pause 同位双钮按状态只画其一),验证:
* N1 进度条:value clamp 0-100 + track/fill 渲染(填充分界像素不同);
* N2 三钮圆形命中:圆心命中、角部不命中;
* N3 play/pause 同位切换:两钮图标位图不同 → 中心像素不同(画 PAUSE vs PLAY_ARROW);
* N4 主题四态(MD3/MIUIx × 明暗)下进度条+三钮渲染非背景像素。
*
* 几何常量与 now_playing.c 同源(镜像);控件创建方式与 np_widgets_create 同。
* 编译(在 patch_v2/meow_launcherd 下):
* gcc -Wall -Wextra -o test_now_playing_widgets test_now_playing_widgets.c \
* ../sdk/test_host_stub.c ../sdk/meow_ui_gfx.c ../sdk/meow_ui_sys.c \
* ../sdk/meow_ui_theme.c ../sdk/meow_ui_vol.c ../sdk/meow_ui_log.c \
* ../sdk/meow_ui_widget.c ../sdk/meow_ui_input.c ../sdk/meow_ui_activity.c \
* ../sdk/meow_ui_dialog.c ../sdk/meow_ui_ime.c ../sdk/meow_ui_str.c ../sdk/meow_pinyin.c \
* ../sdk/meow_ui_draw.c ../sdk/meow_ui_view.c ../sdk/meow_ui_box.c ../sdk/meow_ui_anim.c \
* ../sdk/meow_ui_scroll.c ../sdk/meow_ui_img.c ../sdk/meow_ui_media.c \
* ../sdk/meow_notify_ipc.c ../sdk/stb_image.c \
* ../sdk/meow_lyric.c ../sdk/meow_lyric_view.c \
* -I../sdk -I. -DMEOW_UI_HOST_TEST -pthread -lm
* 运行:./test_now_playing_widgets
*/
#include "meow_ui.h"
#include "meow_ui_internal.h" /* meow_ui_back_buf/pitch/bpp */
#include "np_gesture.h" /* 批4:双页方向感知手势决策(纯逻辑,宿主可单测) */
#include "meow_lyric_view.h" /* 批2:歌词页控件(批4接入,数据批3 meow_media_lyric_*) */
#include <stdio.h>
#include <stdlib.h>
#include <string.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)
/* ---- 与 now_playing.c 同源几何(镜像) ---- */
#define NP_PROG_X 40
#define NP_PROG_W (480 - 80) /* 400 */
#define NP_PROG_Y 518
#define NP_TIME_Y 492
#define NP_BTN_Y 568
#define NP_PLAY_CX 240
#define NP_PREV_CX (NP_PLAY_CX - 78) /* 162 */
#define NP_NEXT_CX (NP_PLAY_CX + 78) /* 318 */
#define NP_PLAY_R 30
#define NP_PREV_R 22
#define NP_SENTINEL 0x51
static meow_widget *prog = NULL, *prev = NULL, *play = NULL, *pause = NULL, *next = NULL;
static void rd_px(int x, int y, unsigned short *p)
{
unsigned char *bb = meow_ui_back_buf();
int line = meow_ui_back_buf_pitch(), bpp = meow_ui_back_buf_bpp();
if (!bb || x < 0 || y < 0) { *p = 0; return; }
if (bpp == 16) *p = *(unsigned short *)(bb + (size_t)y * line + (size_t)x * 2);
else *p = (unsigned short)(*(unsigned int *)(bb + (size_t)y * line + (size_t)x * 4) >> 16);
}
static unsigned short px565(int x, int y) { unsigned short p; rd_px(x, y, &p); return p; }
static int region_nonbg(int x, int y, int w, int h, uint32_t bg)
{
unsigned short bg565 = ((bg >> 8) & 0xF800) | ((bg >> 5) & 0x07E0) | ((bg >> 3) & 0x001F);
int cnt = 0;
for (int dy = 0; dy < h; dy++)
for (int dx = 0; dx < w; dx++)
if (px565(x + dx, y + dy) != bg565) cnt++;
return cnt;
}
static void mk_widgets(void)
{
meow_ui_activity_push(NP_SENTINEL);
prog = meow_progress_create(NP_PROG_X, NP_PROG_Y, NP_PROG_W, 6, 0);
prev = meow_iconbtn_create(NP_PREV_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R,
NP_PREV_R * 2, MEOW_ICON_SKIP_PREV);
play = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
NP_PLAY_R * 2, MEOW_ICON_PLAY_ARROW);
pause = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
NP_PLAY_R * 2, MEOW_ICON_PAUSE);
next = meow_iconbtn_create(NP_NEXT_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R,
NP_PREV_R * 2, MEOW_ICON_SKIP_NEXT);
/* 主播放钮强调:primary/onPrimary(镜像 np_widgets_create) */
const meow_theme *th = meow_theme_get();
meow_widget_opts op; memset(&op, 0, sizeof op);
op.bg = th->primary; op.fg = th->onPrimary;
meow_widget_set_opts(play, &op);
meow_widget_set_opts(pause, &op);
meow_ui_activity_pop();
}
/* 歌词视图宽度测量(宿主:字节数近似,够用不裂屏;launcher 侧为 ui_width)。 */
static int lv_test_width(const char *u, int size, void *ctx)
{
(void)size; (void)ctx;
return (int)strlen(u);
}
int main(void)
{
setbuf(stdout, NULL);
setenv("MEOW_UI_DUMP", "/tmp/nowplaying.ppm", 1);
meow_ui_opts o = { 480, 720 };
assert(meow_ui_init(&o) == 0);
meow_ui_activity_push(NP_SENTINEL);
mk_widgets();
const meow_theme *th = meow_theme_get();
meow_ui_set_style(MEOW_STYLE_MD3);
meow_theme_set_mode(MEOW_THEME_DARK);
th = meow_theme_get();
/* ============ N1 进度条 clamp + track/fill 渲染 ============ */
printf("N1 progress value + track/fill\n");
meow_widget_set_opts(prog, &(meow_widget_opts){ .bg = 0 });
meow_ui_clear(0);
meow_progress_set(prog, 150); /* clamp → 100 */
meow_widget_draw(prog);
unsigned short fill_end = px565(NP_PROG_X + NP_PROG_W - 2, NP_PROG_Y + 3);
unsigned short track_mid = px565(NP_PROG_X + NP_PROG_W / 2, NP_PROG_Y + 3);
CHECK(fill_end != 0 && track_mid != 0, "value 150 clamp 100 -> full fill renders");
meow_progress_set(prog, 50);
meow_widget_draw(prog);
/* 50% 填充区 [40,240) 内像素应为主色;240 之后的轨道区应为轨道色(surfaceVariant) */
unsigned short infill = px565(NP_PROG_X + NP_PROG_W / 4, NP_PROG_Y + 3); /* x=140,填充区 */
unsigned short empty = px565(NP_PROG_X + NP_PROG_W - 4, NP_PROG_Y + 3); /* x=436,轨道区 */
CHECK(infill != empty, "value 50 -> fill region differs from empty tail");
/* ============ N2 三钮圆形命中 ============ */
printf("N2 circular hit\n");
CHECK(meow_widget_hit(prev, NP_PREV_CX, NP_BTN_Y), "prev center hits");
CHECK(!meow_widget_hit(prev, NP_PREV_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R), "prev corner MISSES");
CHECK(meow_widget_hit(play, NP_PLAY_CX, NP_BTN_Y), "play center hits");
CHECK(meow_widget_hit(pause, NP_PLAY_CX, NP_BTN_Y), "pause(overlay) center hits");
CHECK(!meow_widget_hit(play, NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R), "play corner MISSES");
CHECK(meow_widget_hit(next, NP_NEXT_CX, NP_BTN_Y), "next center hits");
/* ============ N3 play/pause 同位切换(两钮位图不同 → 像素不同) ============ */
printf("N3 play/pause overlay icon switch\n");
meow_ui_clear(0);
meow_widget_draw(play); meow_ui_clear(0); /* 只画 play */
meow_widget_draw(play);
unsigned short p_play = px565(NP_PLAY_CX, NP_BTN_Y); /* 中心=图标墨色 */
meow_ui_clear(0);
meow_widget_draw(pause);
unsigned short p_pause = px565(NP_PLAY_CX, NP_BTN_Y);
CHECK(p_play != p_pause, "play vs pause icon differs at centre (overlay switch works)");
/* 圆心区域非页面底色(画出来了) */
meow_ui_clear(0); meow_widget_draw(pause);
CHECK(region_nonbg(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
NP_PLAY_R * 2, NP_PLAY_R * 2, th->surface) > 0,
"pause button renders non-bg in circle");
/* ============ N4 主题四态:进度条+三钮渲染非背景 ============ */
printf("N4 theme 4-state render\n");
const int styles[2] = { MEOW_STYLE_MD3, MEOW_STYLE_MIUIX };
const int modes[2] = { MEOW_THEME_LIGHT, MEOW_THEME_DARK };
for (int si = 0; si < 2; si++) {
for (int mi = 0; mi < 2; mi++) {
meow_ui_set_style(styles[si]);
meow_theme_set_mode((meow_theme_mode)modes[mi]);
th = meow_theme_get();
meow_theme ex; meow_theme_export(&ex);
CHECK(ex.primary == th->primary && ex.surface == th->surface &&
ex.surfaceVariant == th->surfaceVariant, "export == get (spot roles)");
meow_ui_clear(0);
meow_progress_set(prog, 40); meow_widget_draw(prog);
meow_widget_draw(prev);
meow_widget_draw(pause);
meow_widget_draw(next);
char nm[80];
int progpx = region_nonbg(NP_PROG_X, NP_PROG_Y, NP_PROG_W, 6, th->surface);
int btnpx = region_nonbg(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
NP_PLAY_R * 2, NP_PLAY_R * 2, th->surface);
snprintf(nm, sizeof nm, "style=%s mode=%s prog+btn render",
styles[si] ? "MIUIx" : "MD3", modes[mi] ? "dark" : "light");
CHECK(progpx > 0 && btnpx > 0, nm);
}
}
/* ============ G5 双页手势方向感知(np_gesture.h,纯逻辑) ============ */
printf("G5 dual-page direction-aware gestures\n");
/* 播放页:右→左滑 → 进歌词页 */
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 100, -50, 5) == NP_GEST_NEXT,
"play: left-swipe -> lyric");
/* 播放页:左缘右滑 → 回桌面(保留 M6.26) */
CHECK(np_gesture_decide(NP_PAGE_PLAY, 8, 100, 80, 5) == NP_GEST_EXIT,
"play: edge right-swipe -> exit");
/* 播放页:非左缘右滑 → 播放页无上一页,忽略(不误切/不误退) */
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 100, 80, 5) == NP_GEST_NONE,
"play: non-edge right-swipe -> none");
/* 歌词页:左→右滑 → 回播放页(不是回桌面) */
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 200, 100, 60, 5) == NP_GEST_PREV,
"lyric: right-swipe -> play");
/* 歌词页:左缘右滑 → 回播放页(不接桌面,避免误退) */
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 8, 100, 80, 5) == NP_GEST_PREV,
"lyric: edge right-swipe -> play (not exit)");
/* 歌词页:右→左滑 → 歌词页是末页,忽略 */
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 200, 100, -60, 5) == NP_GEST_NONE,
"lyric: left-swipe -> none");
/* 顶部热区下滑 → 通知中心(两个页面同语义) */
CHECK(np_gesture_decide(NP_PAGE_PLAY, 100, 10, 0, 70) == NP_GEST_TOP,
"top swipe-down -> notif");
/* 近点按 → TAP;纵向主导 → NONE(不误切) */
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 300, 5, 5) == NP_GEST_TAP,
"near tap -> TAP");
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 300, 5, 80) == NP_GEST_NONE,
"vertical dominant -> NONE");
/* ============ G6 歌词页:空态 + 渲染(批2 控件 + 批3 数据语义) ============ */
printf("G6 lyric view: empty + render\n");
meow_ui_activity_push(NP_SENTINEL);
meow_lyric_view *lv = meow_lyric_view_create(0, 28, 480, 720 - 28, lv_test_width, NULL);
meow_lyric_view_set_empty(lv, "暂无歌词");
meow_ui_activity_pop();
CHECK(lv != NULL, "lyric_view created");
if (lv) {
/* 无歌词空态:无解析 → 0 行、visible=0(视图内建空态文案) */
meow_lyric_clear();
CHECK(meow_lyric_count() == 0, "clear -> 0 lines");
CHECK(meow_lyric_view_visible(lv, 0, NULL, 0) == 0, "empty -> 0 visible entries");
/* 有词:解析两行 → count/line_at/visible/当前行色 */
int np = meow_lyric_parse("[00:01.00]第一行歌词\n[00:05.00]第二行歌词", "");
CHECK(np == 2, "parse -> 2 lines");
CHECK(meow_lyric_count() == 2, "count == 2");
CHECK(meow_lyric_line_at(0) == 0, "line_at(0) -> first");
CHECK(meow_lyric_line_at(3000) == 0, "line_at(3000) -> first");
CHECK(meow_lyric_line_at(6000) == 1, "line_at(6000) -> second");
CHECK(strcmp(meow_lyric_line_text(0), "第一行歌词") == 0, "text(0) == 第一行歌词");
meow_lyric_view_vis vb[9];
int vn = meow_lyric_view_visible(lv, 3000, vb, 9);
CHECK(vn > 0, "visible(3000) > 0");
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->onSurface,
"cur_color == theme onSurface");
/* 批5 取色预留:set_colors 可接入(覆盖活动行为主题 accent 后再还原默认) */
meow_lyric_view_colors c; memset(&c, 0, sizeof c);
c.cur = meow_theme_get()->accent;
meow_lyric_view_set_colors(lv, &c);
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->accent,
"set_colors cur override works");
meow_lyric_view_set_colors(lv, NULL); /* 回主题默认 */
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->onSurface,
"set_colors NULL -> theme default");
meow_lyric_view_free(lv);
}
meow_ui_activity_pop();
meow_ui_shutdown();
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
return g_fail;
}