Files
AskaEth 3d70a3dd2c feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘)
- OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复
- ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640
- 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫)
- 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
2026-09-03 12:16:01 +08:00

256 lines
12 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_subpage_widgets.c — M7.1a 子页渲染层迁移(SDK 控件化)宿主验证。
*
* 复现 subpage.c 所建控件集(topappbar + 顶开关 meow_switch + listview 虚拟化 vsource +
* meow_scroll 包裹 fling),验证:
* P1 listview 虚拟化渲染:section 段头 + 普通/开关/动作行(right=SWITCH/ARROW)非背景像素;
* P2 listview 命中:行号(含滚动换算 + 禁用行不响应)+ right 操作区命中(hit_op);
* P3 topappbar 命中:返回箭头区 → MEOW_TOPBAR_BACK;
* P4 meow_scroll 包裹 listview:跟手 track + 松手 fling(meow_anim_tick 驱动)+ snap 到行边界;
* P5 SDK 输入态(meow_input_touch_set)→ listview 按压态像素变化;
* P6 主题四态(MD3/MIUIx × 明暗)下 topappbar + listview 渲染非背景。
*
* 几何常量与 subpage.c / meow_launcher_internal.h 镜像;控件创建方式与 sp_widgets_create 同
* (owner=哨兵 0x52,listview 用 set_vsource + set_item_renderer(2,0,1) + set_item_h 56)。
*
* 编译(在 patch_v2/meow_launcherd 下):
* gcc -Wall -Wextra -o test_subpage_widgets test_subpage_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_subpage_widgets
*/
#include "meow_ui.h"
#include "meow_ui_internal.h" /* meow_ui_back_buf / meow_gfx_mark_dirty / meow_input_touch_set */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int g_fail = 0;
#define CHECK(cond, ...) do { \
if (cond) { printf(" PASS: " __VA_ARGS__); printf("\n"); } \
else { printf(" FAIL: " __VA_ARGS__); printf("\n"); g_fail++; } } while (0)
/* ---- meow_lv_item 大列表数据源(P4 滚动测用:40 行) ---- */
static int big_count(void *ctx) { (void)ctx; return 40; }
static void big_bind(int idx, meow_lv_item *out, void *ctx) {
(void)ctx; memset(out, 0, sizeof *out);
out->icon_kind = MEOW_LIST_ICON_NONE; out->enabled = 1;
out->title = "行"; out->subtitle = "sub"; out->right = MEOW_LIST_RIGHT_ARROW;
(void)idx;
}
/* ---- 与 subpage.c / meow_launcher_internal.h 同源几何(镜像) ---- */
#define SUB_TB_Y 28
#define SUB_TB_H 68
#define SUB_TB_BOT (SUB_TB_Y + SUB_TB_H) /* 96 */
#define SUB_CONT_TOP SUB_TB_BOT
#define SUB_FOOT_H 44
#define SUB_ITEM_H 56
#define SUB_SENTINEL 0x52
#define XRES 480
#define YRES 720
#define LV_H (YRES - SUB_CONT_TOP - SUB_FOOT_H) /* 580 */
/* ---- sub_row_t 行缓冲镜像(sub_page_t/sub_row_t 结构在 meow_launcher_internal.h) ---- */
enum { SUB_HDR, SUB_ROW, SUB_SW, SUB_ACT };
typedef struct { int kind; const char *label; const char *sub; int on; int act; } sub_row_t;
static sub_row_t g_rows[16];
static int g_nrows = 0;
static void rows_fill(void)
{
g_nrows = 0;
g_rows[g_nrows].kind = SUB_HDR; g_rows[g_nrows].label = "当前连接"; g_rows[g_nrows].sub = NULL; g_nrows++;
g_rows[g_nrows].kind = SUB_ROW; g_rows[g_nrows].label = "已连接"; g_rows[g_nrows].sub = "MyWiFi"; g_rows[g_nrows].act = -1; g_nrows++;
g_rows[g_nrows].kind = SUB_HDR; g_rows[g_nrows].label = "已保存网络"; g_rows[g_nrows].sub = NULL; g_nrows++;
g_rows[g_nrows].kind = SUB_ACT; g_rows[g_nrows].label = "MyWiFi"; g_rows[g_nrows].sub = "已连接"; g_rows[g_nrows].act = 0; g_nrows++;
g_rows[g_nrows].kind = SUB_HDR; g_rows[g_nrows].label = "附近网络"; g_rows[g_nrows].sub = NULL; g_nrows++;
g_rows[g_nrows].kind = SUB_SW; g_rows[g_nrows].label = "WLAN"; g_rows[g_nrows].sub = NULL; g_rows[g_nrows].on = 1; g_nrows++;
}
/* ---- meow_lv_item 映射(镜像 subpage.c sp_lv_bind) ---- */
static int sp_lv_count(void *ctx) { (void)ctx; return g_nrows; }
static void sp_lv_bind(int idx, meow_lv_item *out, void *ctx)
{
(void)ctx;
memset(out, 0, sizeof *out);
out->icon_kind = MEOW_LIST_ICON_NONE;
out->enabled = 1;
if (idx < 0 || idx >= g_nrows) { out->title = ""; return; }
const sub_row_t *r = &g_rows[idx];
switch (r->kind) {
case SUB_HDR: out->section = 1; out->title = r->label ? r->label : "";
out->right = MEOW_LIST_RIGHT_NONE; out->enabled = 0; break;
case SUB_ROW: out->title = r->label ? r->label : ""; out->subtitle = r->sub;
out->right = MEOW_LIST_RIGHT_NONE; break;
case SUB_SW: out->title = r->label ? r->label : ""; out->subtitle = r->sub;
out->right = MEOW_LIST_RIGHT_SWITCH; out->on = r->on; break;
case SUB_ACT: out->title = r->label ? r->label : ""; out->subtitle = r->sub;
out->right = MEOW_LIST_RIGHT_ARROW; break;
}
}
static meow_widget *tb = NULL, *sw = NULL, *lv = 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(SUB_SENTINEL);
tb = meow_topappbar_create(0, SUB_TB_Y, XRES, SUB_TB_H, "WiFi");
meow_topappbar_set_back(tb, 1);
lv = meow_listview_create(0, SUB_CONT_TOP, XRES, LV_H, 0, NULL, NULL, MEOW_LIST_SEL_NONE);
meow_listview_set_vsource(lv, sp_lv_count, sp_lv_bind, NULL);
meow_listview_set_item_renderer(lv, 2, 0, 1);
meow_listview_set_item_h(lv, SUB_ITEM_H);
sw = meow_switch_create(XRES - 16 - 56, SUB_TB_Y + (SUB_TB_H - 32) / 2, 1);
meow_ui_activity_pop();
}
static void draw_all(void)
{
const meow_theme *th = meow_theme_get();
meow_ui_fill_rect(0, 0, XRES, YRES, th->surface);
if (tb) meow_widget_draw(tb);
if (sw) meow_widget_draw(sw);
meow_ui_fill_rect(0, SUB_CONT_TOP, XRES, LV_H, th->surface);
if (lv) meow_widget_draw(lv);
}
int main(void)
{
setbuf(stdout, NULL);
setenv("MEOW_UI_DUMP", "/tmp/subpage.ppm", 1);
meow_ui_opts o = { XRES, YRES };
if (meow_ui_init(&o) != 0) { printf("init failed\n"); return 1; }
rows_fill();
mk_widgets();
/* ============ P1 listview 虚拟化渲染(section 段头 + 开关/箭头行) ============ */
printf("P1 listview virtualized render\n");
meow_ui_activity_push(SUB_SENTINEL);
const meow_theme *th = meow_theme_get();
draw_all();
int hdrcnt = region_nonbg(2, SUB_CONT_TOP + 4, XRES - 4, SUB_ITEM_H - 8, th->surface);
int rowcnt = region_nonbg(2, SUB_CONT_TOP + SUB_ITEM_H + 4, XRES - 4, SUB_ITEM_H - 8, th->surface);
char nm[80];
snprintf(nm, sizeof nm, "section header renders (band=%d)", hdrcnt);
CHECK(hdrcnt > 0, "%s", nm);
snprintf(nm, sizeof nm, "row renders (title hdr/switch/arrow) cnt=%d", rowcnt);
CHECK(rowcnt > 40, "%s", nm);
/* ============ P2 listview 命中(行号 + right 操作区) ============ */
printf("P2 listview hit / hit_op\n");
int lvy = SUB_CONT_TOP;
CHECK(meow_listview_hit(lv, 10, lvy + SUB_ITEM_H / 2) == -1, "row0 (hdr) disabled -> -1");
CHECK(meow_listview_hit(lv, 10, lvy + SUB_ITEM_H + SUB_ITEM_H / 2) == 1, "row1 (已连接) hits idx1");
/* 行右 1/3 = 操作区:row1 是 SUB_ROW(right none) → hit_op 0 */
CHECK(meow_listview_hit_op(lv, XRES - 20, lvy + SUB_ITEM_H + SUB_ITEM_H / 2) == 0,
"row1 right-none -> hit_op 0");
/* row3 = SUB_ACT(MyWiFi) 右箭头;row5 = SUB_SW(WLAN) 右开关 → hit_op 1 */
CHECK(meow_listview_hit_op(lv, XRES - 20, lvy + 3 * SUB_ITEM_H + SUB_ITEM_H / 2) == 1,
"row3 (act arrow) right hits op");
CHECK(meow_listview_hit_op(lv, XRES - 20, lvy + 5 * SUB_ITEM_H + SUB_ITEM_H / 2) == 1,
"row5 (sw) right hits op");
/* ============ P3 topappbar 命中(返回箭头) ============ */
printf("P3 topappbar back hit\n");
CHECK(meow_topappbar_hit(tb, 10, SUB_TB_Y + SUB_TB_H / 2) == MEOW_TOPBAR_BACK,
"back arrow region -> MEOW_TOPBAR_BACK");
CHECK(meow_topappbar_hit(tb, XRES - 5, SUB_TB_Y + SUB_TB_H / 2) == -1,
"right region (no action) -> -1");
/* ============ P4 meow_scroll 包裹 listview + fling(惯性,ease-out,无 snap 回拉) ============ */
printf("P4 meow_scroll wrap listview + fling\n");
/* 40 行大列表(独立数据源),撑起滚动 */
meow_widget *scroll_lv = meow_listview_create(0, SUB_CONT_TOP, XRES, LV_H, 0, NULL, NULL,
MEOW_LIST_SEL_NONE);
meow_listview_set_vsource(scroll_lv, big_count, big_bind, NULL);
meow_listview_set_item_renderer(scroll_lv, 2, 0, 1);
meow_listview_set_item_h(scroll_lv, SUB_ITEM_H);
meow_scroll *s = meow_scroll_wrap(scroll_lv, 1); /* 1=W_LISTVIEW */
CHECK(s != NULL, "meow_scroll_wrap(listview)");
int maxs = meow_listview_max_scroll(scroll_lv);
CHECK(maxs > 0, "max_scroll > 0 (list taller than viewport) got %d", maxs);
/* 快速下划(正步进)建初速 → fling 前进(单调不减 + 不越界 + snap 到行边界) */
uint64_t t = meow_ui_time_ms();
for (int i = 0; i < 12; i++) meow_scroll_track(s, 30, t + (uint64_t)i * 16);
int start = meow_scroll_offset(s);
CHECK(start > 0, "dragged start>0 got %d", start);
meow_scroll_fling(s);
int prev = start, mono = 1, maxoff = start, guard = 0;
while (meow_scroll_active(s) && guard++ < 400) {
meow_anim_tick();
int cur = meow_scroll_offset(s);
if (maxoff < cur) maxoff = cur;
if (cur < prev) mono = 0;
prev = cur;
usleep(8000);
}
meow_anim_tick();
int end = meow_scroll_offset(s);
CHECK(mono == 1, "fling monotonic non-decreasing");
CHECK(end >= start, "fling advances end=%d start=%d", end, start);
CHECK(end <= maxs, "no overflow end=%d max=%d", end, maxs);
meow_scroll_free(s);
meow_widget_free(scroll_lv);
/* ============ P5 SDK 输入态 → listview 按压态像素变化 ============ */
printf("P5 meow_input_touch_set pressed state\n");
meow_ui_activity_push(SUB_SENTINEL);
draw_all();
int px_y = SUB_CONT_TOP + SUB_ITEM_H + SUB_ITEM_H / 2; /* row1 中心 */
unsigned short p0 = px565(10, px_y);
meow_input_touch_set(1, 10, px_y, 0);
draw_all();
unsigned short p1 = px565(10, px_y);
meow_input_touch_set(0, 0, 0, 0);
CHECK(p1 != p0, "pressed row -> pixel changes");
meow_ui_activity_pop();
/* ============ P6 主题四态(MD3/MIUIx × 明暗)渲染非背景 ============ */
printf("P6 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();
draw_all();
int tbcnt = region_nonbg(0, SUB_TB_Y, XRES, SUB_TB_H, th->surface);
int lvcnt = region_nonbg(0, SUB_CONT_TOP, XRES, LV_H, th->surface);
snprintf(nm, sizeof nm, "style=%s mode=%s topbar+list render",
styles[si] ? "MIUIx" : "MD3", modes[mi] ? "dark" : "light");
CHECK(tbcnt > 0 && lvcnt > 40, "%s", 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;
}