172 lines
8.2 KiB
C
172 lines
8.2 KiB
C
/* test_meow_md3.c — 宿主验证 MD3(Material You)对齐修复(agent-434 P0/P1/P3):
|
||
* P0 listview 容器模式(默认 renderer:行=surfaceContainer 圆角卡 + 行间空隙 + 去分隔线);
|
||
* P1 按钮胶囊化(圆角=h/2);
|
||
* P3 Switch off-track/off-thumb、NavigationBar active pill 64×32、Checkbox/Radio 视觉尺寸。
|
||
* 断言全部「画完读 back_buf 像素」(region_has/px_near),不依赖 /dev/fb0/字库(meow_font 打桩)。
|
||
*
|
||
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global):
|
||
* gcc -Wall -Wextra -o test_meow_md3 test_meow_md3.c test_host_stub.c \
|
||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
||
* 运行:./test_meow_md3
|
||
*/
|
||
#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 void rd_px(int x, int y, int *r, int *g, int *b)
|
||
{
|
||
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) { *r = *g = *b = 0; return; }
|
||
if (bpp == 16) {
|
||
uint16_t px = *(uint16_t *)(bb + (size_t)y * line + (size_t)x * 2);
|
||
*r = (((px >> 11) & 0x1F) << 3) | ((px >> 11) & 0x1F) >> 2;
|
||
*g = (((px >> 5) & 0x3F) << 2) | ((px >> 5) & 0x3F) >> 4;
|
||
*b = ((px & 0x1F) << 3) | ((px & 0x1F) >> 2);
|
||
} else {
|
||
uint32_t px = *(uint32_t *)(bb + (size_t)y * line + (size_t)x * 4);
|
||
*r = (px >> 16) & 0xFF; *g = (px >> 8) & 0xFF; *b = px & 0xFF;
|
||
}
|
||
}
|
||
static int near2(int a, int b) { int d = a - b; if (d < 0) d = -d; return d <= 12; }
|
||
static int px_near(int x, int y, int r, int g, int b)
|
||
{
|
||
int rr, gg, bb; rd_px(x, y, &rr, &gg, &bb);
|
||
return near2(rr, r) && near2(gg, g) && near2(bb, b);
|
||
}
|
||
#define UNPK(c, rr, gg, bb) do { (rr) = ((c) >> 16) & 0xFF; (gg) = ((c) >> 8) & 0xFF; (bb) = (c) & 0xFF; } while (0)
|
||
|
||
/* Listview src2 数据源:2 行普通富 item(无图标、无右尾件,label-only)。 */
|
||
typedef struct { const char *title; const char *sub; int right; int enabled; } trow_t;
|
||
static trow_t g_rows[2] = {
|
||
{ "Row 0", NULL, MEOW_LIST_RIGHT_NONE, 1 },
|
||
{ "Row 1", NULL, MEOW_LIST_RIGHT_NONE, 1 },
|
||
};
|
||
static int trow_src(int idx, meow_list_item *out, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
if (idx < 0 || idx >= 2) return 0;
|
||
out->icon_kind = MEOW_LIST_ICON_NONE;
|
||
out->title = g_rows[idx].title;
|
||
out->subtitle = g_rows[idx].sub;
|
||
out->right = g_rows[idx].right;
|
||
out->on = 0;
|
||
out->enabled = g_rows[idx].enabled;
|
||
return 1;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
setenv("MEOW_UI_DUMP", "/tmp/md3.ppm", 1);
|
||
meow_ui_opts o = { 480, 720 };
|
||
assert(meow_ui_init(&o) == 0);
|
||
assert(meow_ui_width() == 480 && meow_ui_height() == 720);
|
||
const meow_theme *th = meow_theme_get();
|
||
int sf_r, sf_g, sf_b, sc_r, sc_g, sc_b, p_r, p_g, p_b;
|
||
int pc_r, pc_g, pc_b, ov_r, ov_g, ov_b, sch_r, sch_g, sch_b, scs_r, scs_g, scs_b;
|
||
UNPK(th->surface, sf_r, sf_g, sf_b);
|
||
UNPK(th->surfaceContainer, sc_r, sc_g, sc_b);
|
||
UNPK(th->primary, p_r, p_g, p_b);
|
||
UNPK(th->primaryContainer, pc_r, pc_g, pc_b);
|
||
UNPK(th->outline, ov_r, ov_g, ov_b);
|
||
UNPK(th->surfaceContainerHighest, sch_r, sch_g, sch_b);
|
||
UNPK(th->secondaryContainer, scs_r, scs_g, scs_b);
|
||
|
||
/* ---- P0 listview 容器模式:行=surfaceContainer 圆角卡 + 空隙,去分隔线 ---- */
|
||
meow_widget *lv = meow_listview_create(20, 240, 320, 112, 2, trow_src, NULL, MEOW_LIST_SEL_SINGLE);
|
||
assert(lv);
|
||
assert(meow_listview_set_item_h(lv, 56) == 56);
|
||
assert(meow_listview_set_container(lv, 1) == 0);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(lv);
|
||
/* 行 0 卡(x=28,y=244,w=304,h=48):中心=surfaceContainer;行 1 同。 */
|
||
assert(px_near(180, 268, sc_r, sc_g, sc_b));
|
||
assert(px_near(180, 324, sc_r, sc_g, sc_b));
|
||
/* 卡间空隙(y=292..300):surface(行间分隔用空隙)。 */
|
||
assert(px_near(180, 296, sf_r, sf_g, sf_b));
|
||
/* 去分隔线:行边界不再画 outlineVariant(改空隙代替)。 */
|
||
assert(!px_near(180, 292, ov_r, ov_g, ov_b));
|
||
/* 选中行 0 → primaryContainer(tonal,非满幅实心)。 */
|
||
meow_listview_set_sel(lv, 0);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(lv);
|
||
assert(px_near(180, 268, pc_r, pc_g, pc_b));
|
||
assert(px_near(180, 324, sc_r, sc_g, sc_b)); /* 行 1 未选仍卡 */
|
||
printf("PASS listview container: rounded card + gap + no-divider + tonal select\n");
|
||
|
||
/* ---- P1 按钮胶囊化:圆角=h/2(56/2=28)---- */
|
||
meow_widget *btn = meow_btn_create_variant(10, 10, 200, 56, "FILLED", MEOW_BTN_FILLED);
|
||
assert(btn);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(btn);
|
||
assert(px_near(110, 22, p_r, p_g, p_b)); /* 上部(避开文字)=primary */
|
||
/* 顶缘中心在圆角胶囊内(仍 primary);角落(圆角外)回 surface。 */
|
||
assert(px_near(110, 13, p_r, p_g, p_b));
|
||
assert(px_near(12, 12, sf_r, sf_g, sf_b)); /* 角落被圆角切掉 */
|
||
/* 同高矮按钮(h=40 → 圆角 20):上部仍 primary,角落 surface。 */
|
||
meow_widget *btn2 = meow_btn_create_variant(10, 120, 120, 40, "B", MEOW_BTN_FILLED);
|
||
assert(btn2);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(btn2);
|
||
assert(px_near(70, 125, p_r, p_g, p_b));
|
||
assert(px_near(12, 122, sf_r, sf_g, sf_b));
|
||
printf("PASS button: capsule radius = h/2\n");
|
||
|
||
/* ---- P3 Switch off-track/off-thumb ---- */
|
||
meow_widget *sw = meow_switch_create(20, 300, 0); /* off */
|
||
assert(sw);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(sw);
|
||
assert(px_near(60, 316, sch_r, sch_g, sch_b)); /* off-track=surfaceContainerHighest */
|
||
assert(px_near(36, 316, sf_r, sf_g, sf_b)); /* off-thumb=surface(表面色,非恒白) */
|
||
meow_switch_set(sw, 1);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(sw);
|
||
assert(px_near(28, 316, p_r, p_g, p_b)); /* on-track=primary(thumb 左侧) */
|
||
printf("PASS switch: off-track surfaceContainerHighest / off-thumb surface\n");
|
||
|
||
/* ---- P3 NavigationBar active pill 64×32 ---- */
|
||
meow_widget *nb = meow_navigationbar_create(0, 600, 480, 80);
|
||
assert(nb);
|
||
meow_navigationbar_add_item(nb, "A");
|
||
meow_navigationbar_add_item(nb, "B");
|
||
meow_navigationbar_add_item(nb, "C");
|
||
meow_navigationbar_add_item(nb, "D");
|
||
meow_navigationbar_set_selected(nb, 0);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(nb);
|
||
/* item0 pill 中心 (ix+60, y+40)=(60,640) — 64×32 居中于栏;pill 内=secondaryContainer。 */
|
||
assert(px_near(60, 640, scs_r, scs_g, scs_b));
|
||
/* pill 外(栏上部)= surfaceContainer(navbar 容器底)。 */
|
||
assert(px_near(60, 610, sc_r, sc_g, sc_b));
|
||
printf("PASS navbar: active pill 64x32 (was 48x22)\n");
|
||
|
||
/* ---- P3 Checkbox 视觉 24dp(原 34 偏大):勾选框视觉居中,角落回 surface ---- */
|
||
meow_widget *ck = meow_checkbox_create(150, 60);
|
||
assert(ck);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(ck);
|
||
/* 未选:24dp 描边框(左缘=150+5=155);框边=outline;内部=surface(空心)。 */
|
||
assert(px_near(155, 77, ov_r, ov_g, ov_b)); /* 框左缘 stroke */
|
||
assert(px_near(167, 77, sf_r, sf_g, sf_b)); /* 内部空心 */
|
||
meow_widget_set_selected(ck, 1);
|
||
meow_ui_clear(th->surface);
|
||
meow_widget_draw(ck);
|
||
/* 选中:24dp 实心 primary 居中(左缘 155..179 顶 65..89);控件矩形角落(视觉 24 外)不填。 */
|
||
assert(px_near(150, 60, sf_r, sf_g, sf_b)); /* 视觉 24 外 → surface */
|
||
assert(px_near(167, 77, p_r, p_g, p_b)); /* 视觉中心=primary */
|
||
printf("PASS checkbox: 24dp visual (was 34)\n");
|
||
|
||
meow_widget_free(lv); meow_widget_free(btn); meow_widget_free(btn2);
|
||
meow_widget_free(sw); meow_widget_free(nb); meow_widget_free(ck);
|
||
printf("ALL MD3 PASS\n");
|
||
return 0;
|
||
}
|