- 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 推卡自刷验收全绿
256 lines
12 KiB
C
256 lines
12 KiB
C
/* 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;
|
||
}
|