Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_now_playing_widgets.c
T
AskaEth d8241cd2d6 launcher(M7.0b): 电源菜单/Now Playing 控件化 + SDK 主题薄壳 + i18n 抽取(试点迁移)
M7 整体 MD3 重写试点(M7.0 定两隔离页,只动 patch_v2/meow_launcherd/):
- 电源菜单 power_menu.c:圆角卡→meow_card;6 圆钮→meow_iconbtn(回HiBy=ARROW_BACK、
  取消=CLOSE;sb_icons 表在位图)+ meow_widget_custom_create(关机/重启/升级/锁定=pm_icons
  专有,圆形命中自定义);命中/选中/按压态全走 SDK(meow_widget_hit/set_state/draw),
  触摸按下置 PRESSED、抬起清(pm_blend 按主题混合状态层);py 手动驱动控件(哨兵 activity
  0x50 push/pop,owner 闸门使命中生效)。
- Now Playing now_playing.c:进度条→meow_progress;播放控制三钮→meow_iconbtn(SKIP_PREV /
  PLAY_ARROW|PAUSE同位双钮按状态只画其一/ SKIP_NEXT);命中走 meow_widget_hit;封面
  (meow_img contain) 与歌名/艺术家 (meow_font) 保留;哨兵 activity 0x51 push/pop。
- 主题薄壳 font_theme.c:s_ui_theme() 改读 SDK meow_theme_export()(单一权威,9 字段映射
  §8.1.5),退役 launcher 自持 4 套静态色板(#if 0 回退位)。
- i18n 抽取:两页硬编码中文案改 meow_str(新增 meow_str_zh 辅助:SDK 内嵌表无 launcher 域串
  时回退中文默认,TF 覆盖表/后续并入 SDK 内嵌后自动换语)。
- 会话骨架不动:物理键语义(单击息屏/3s 菜单/8s 强关/左缘返回/横划 NP)与两页进入退出/事件流
  未改,只替换「怎么画/怎么命中」;旧绘制函数 #if 0 留回退位。
- 验证:新增 test_power_menu_widgets / test_now_playing_widgets 宿主测试(圆形命中/owner+enabled
  闸门/选中按压态像素/主题四态 MD3+MIUIx×明暗 渲染 + meow_theme_export 九字段)全 PASS;
  launcher 全量宿主回归(lock_screen/overlay_gate/utf8_name/media/depends/ams_start/bgplay/
  settings_brightness/netmgr_ipc/vol_ramp_jack/notif_panel/notif_tf/lock_render + SDK theme_export/
  iconbtn)全 PASS;交叉 -Wall -Wextra 0 warning。新 meow_launcherd md5 94a33b7b。
2026-09-02 17:25:21 +08:00

176 lines
8.4 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 -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 <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();
}
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);
}
}
meow_ui_activity_pop();
meow_ui_shutdown();
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
return g_fail;
}