sdk: sb_icons 扩充动作图标 + TopAppBar 位图图标支持

TopAppBar 动作项此前用字体码点(⚙↻⌕)绘制,4k 字库无这些码点→豆腐。改走位图:
- sb_icons.h 追加 15 个 Material Symbols Rounded 动作位图(settings/refresh/search/
  play_arrow/pause/skip_next/skip_previous/arrow_back/close/add/check/lyrics/
  queue_music/download/heart),FILL=1 实心与状态栏一致;sb_icons[] 只追加(0-14 不变),
  动作索引 15-29。
- 生成脚本 tools/gen_action_icons.py(cairosvg svg→32x32 单通道 alpha,SVG 缓存
  icons_src/ 可复现、断网可跑)。
- meow_ui_gfx.c 抽取图标 blit 像素核心 icon_blit_px,新增 meow_gfx_blit_icon_ink
  (控件路径不标顶栏脏区);meow_gfx_blit_icon 状态栏路径行为不变。
- meow_ui_widget.c W_TOPAPPBAR 项支持位图模式:新 API meow_topappbar_set_item_icon
  (w, idx, icon_idx),绘制取主题 onSurface/按压向栏底色淡 12%,文本项行为不变;
  hit 用统一项宽。
- 公共头 widgets.h 加 MEOW_ICON_*(15-29) 枚举与 set_item_icon 声明;internal.h 声明
  meow_gfx_blit_icon_ink。
- 宿主测试(test_meow_ui_widgets)加 topbar 位图图标绘制/命中/按压变淡 + 状态栏 blit
  回归断言;test_umbrella 加 MEOW_ICON_* 编译期锁;MEOW_APP_SDK.md 补说明+索引表。
- 验证:宿主测试 ALL PASS(14项);交叉 zig 构建 0 warning;meow_ui.a 新 md5
  1d69cdae55ab5dde3a98f5e2124f3656。
This commit is contained in:
AskaEth committed 2026-09-02 03:24:46 +08:00
1 parent 41427fdcb3
commit 3611cbbbde
24 files changed
+1006 -22

No files matched your search

+69
View File
@@ -201,6 +201,75 @@ int main(void)
assert(meow_topappbar_hit(tab_, 440, 28) == 1); /* 右缘动作 "Edit"(最右) */
printf("PASS topappbar: create/back/action/hit\n");
/* ---------- TopAppBar 位图动作图标(sb_icons[],Material Symbols)----------
* 文本项默认;set_item_icon 把动作项改为位图 → 绘制用 meow_gfx_blit_icon_ink(32px 槽
* 居中 + ink 垂直对齐栏中点),颜色取主题 onSurface(按压向栏底色淡 12%)。断言用
* back_buf 真实像素:画完读亮度,非空 ink + 按压变淡 + 图标项命中。 */
{
/* 用独立 topbar(y=300,避让其它控件);meow_widget_draw 自填 surfaceContainerHigh 底 */
meow_widget *ti = W(meow_topappbar_create(0, 300, 480, 56, ""));
int ai = meow_topappbar_add_action(ti, ""); /* 文本占位 → 转图标 */
assert(ai == 0);
assert(meow_topappbar_set_item_icon(ti, ai, MEOW_ICON_SETTINGS) == 0);
assert(meow_topappbar_set_item_icon(ti, 99, MEOW_ICON_SETTINGS) == -1); /* 越界 */
assert(meow_topappbar_set_item_icon(ti, ai, -1) == -1); /* 非法图标 */
assert(meow_topappbar_set_item_icon(NULL, ai, MEOW_ICON_SETTINGS) == -1);
meow_widget_draw(ti);
/* 右起动作格(SDK 位图动作项宽 48)命中:几何中心 → 项 0(最右图标) */
assert(meow_topappbar_hit(ti, 444, 328) == ai);
/* 图标 ink 采样:与栏底色有「绝对对比度」的像素即 ink(日/夜主题都适用——
* 日 = 深 onSurface 画浅底、夜 = 浅 onSurface 画深底,对比度都大)。 */
int x0 = 480 - 48, y0 = 300 + 10, x1 = 480, y1 = 300 + 46;
int bg_b, bg_g, bg_bgv;
rd_px(480 - 3, 302, &bg_b, &bg_g, &bg_bgv); /* 栏右上角 ≈ 背景 */
int bg_lum = (bg_b + bg_g + bg_bgv) / 3;
int sum_ink = 0, cnt_ink = 0;
for (int xx = x0; xx < x1; xx++) {
for (int yy = y0; yy < y1; yy++) {
int rr, gg, bb;
rd_px(xx, yy, &rr, &gg, &bb);
int lum = (rr + gg + bb) / 3;
int d = lum - bg_lum; if (d < 0) d = -d;
if (d > 20) { sum_ink += d; cnt_ink++; }
}
}
assert(cnt_ink > 4); /* 位图 ink 非空(为抗锯齿留余量) */
int before = sum_ink;
/* 按压态 → 图标向栏底色淡 12% → 对比度整体下降 */
meow_widget_set_state(ti, MEOW_WS_PRESSED, 1);
meow_widget_draw(ti);
sum_ink = 0;
for (int xx = x0; xx < x1; xx++) {
for (int yy = y0; yy < y1; yy++) {
int rr, gg, bb;
rd_px(xx, yy, &rr, &gg, &bb);
int lum = (rr + gg + bb) / 3;
int d = lum - bg_lum; if (d < 0) d = -d;
if (d > 20) sum_ink += d;
}
}
assert(sum_ink < before); /* 按压变淡 */
meow_widget_set_state(ti, MEOW_WS_PRESSED, 0);
printf("PASS topappbar: bitmap action icon draw/hit/pressed-fade (ink=%d->%d)\n",
before, sum_ink);
}
/* ---------- 状态栏图标 blit 路径回归(meow_gfx_blit_icon 同源核心)----------
* 证明 refactor 后状态栏路径(blit + 顶栏脏区)仍写非空像素;复用 SB_ICON_WIFI(0)。 */
{
meow_ui_fill_rect(0, 0, 480, 28, 0x000000); /* 清顶栏区为黑底 */
int bgr, bgg, bgb, bright = 0;
meow_gfx_blit_icon(0, 0, 0, 16, 0xFFFFFF, 14); /* idx0=WIFI 槽左缘 0 */
for (int xx = 0; xx < 32; xx++) {
for (int yy = 4; yy < 24; yy++) {
rd_px(xx, yy, &bgr, &bgg, &bgb);
if ((bgr + bgg + bgb) / 3 > 40) bright++;
}
}
assert(bright > 4); /* 状态栏 WiFi 位图 ink 非空(黑底 + 白前景 → 亮像素) */
printf("PASS statusbar: meow_gfx_blit_icon(0) draws non-empty ink (brt=%d)\n", bright);
}
/* ---------- NavigationBar ---------- */
meow_widget *nav = W(meow_navigationbar_create(0, 680, 480, 40));
int n0 = meow_navigationbar_add_item(nav, "Home");