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

+32 -13
View File
@@ -254,22 +254,21 @@ int meow_ui_back_buf_bpp(void) { return g_bpp; }
* 从而 launcher 与 app 统一渲染栈(同一离屏 + 同一 present)。 */
unsigned char *meow_ui_back_buf(void) { return g_back_buf; }
/* ================= 状态栏 MD3 图标 blit(写进本 SDK back_buf) =================
* 复用 launcher sb_icons.h(Material Symbols rounded,32x32 单通道 alpha)作为状态栏
* 右侧图标簇(「同一个状态栏」图标式,见 meow_ui_sys_statusbar_render)。
* idx = sb_icons[] 索引(SB_I_*,见 meow_ui_internal.h)
/* ================= MD3 图标 blit(写进本 SDK back_buf) =================
* 复用 sb_icons.h(Material Symbols rounded,32x32 单通道 alpha)——状态栏右侧图标簇
* (meow_ui_sys_statusbar_render)与 TopAppBar 位图动作图标(W_TOPAPPBAR)共用同源位图。
* idx = sb_icons[] 索引(状态栏 SB_I_*、动作 MEOW_ICON_*,见 meow_ui_internal.h)
* x = 图标槽左缘(槽宽 SB_ICON_SIZE=32)
* y = 图标槽顶(仅作参考;实际按 ink 垂直中心对齐 cy)
* ink_h = 目标 ink 高(>0 等比缩放;0 = 保持位图自然 ink 尺寸——WiFi 强弱档用)
* fg = 24-bit RGB 前景(主题 on_surface / on_surface_variant,日/夜由主题表提供)
* cy = ink 垂直中心线(= 状态栏文字中心,28px 栏约 14)
* cy = ink 垂直中心线(状态栏=28px 栏约 14;TopAppBar=栏中点)
* 先求位图 ink 边界(阈值 32,忽略近透明抗锯齿),按 ink 在槽内水平居中、垂直中心对齐 cy;
* 像素按 alpha 软边混合进 back_buf(自 g_fb/g_line/g_xres/g_yres,与 launcher sb_blit_icon 同源算法)。 */
void meow_gfx_blit_icon(int idx, int x, int y, int ink_h, uint32_t fg, int cy)
/* 像素核心:只采样混合进 back_buf,不标脏区。供状态栏路径(blit 后另标顶栏脏区)与
* 控件路径(meow_gfx_blit_icon_ink,控件 invalidation 独立管理脏区)共用,避免状态栏的
* 顶栏脏区假设污染控件绘制(topbar 不在屏幕最顶行时标错区域)。 */
static void icon_blit_px(int idx, int x, int ink_h, uint32_t fg, int cy)
{
(void)y;
if (!g_init_ok || !g_fb) return;
if (idx < 0 || idx >= (int)(sizeof sb_icons / sizeof sb_icons[0])) return;
const unsigned char *src = sb_icons[idx].data;
uint16_t col = rgb565(fg);
/* 1) ink 边界(含空图兜底) */
@@ -277,8 +276,10 @@ void meow_gfx_blit_icon(int idx, int x, int y, int ink_h, uint32_t fg, int cy)
for (int i = 0; i < SB_ICON_SIZE * SB_ICON_SIZE; i++) {
if (src[i] >= 32) {
int xx = i % SB_ICON_SIZE, yy = i / SB_ICON_SIZE;
if (xx < minx) minx = xx; if (xx > maxx) maxx = xx;
if (yy < miny) miny = yy; if (yy > maxy) maxy = yy;
if (xx < minx) minx = xx;
if (xx > maxx) maxx = xx;
if (yy < miny) miny = yy;
if (yy > maxy) maxy = yy;
}
}
if (maxx < minx || maxy < miny) { minx = miny = 0; maxx = maxy = SB_ICON_SIZE - 1; }
@@ -311,10 +312,28 @@ void meow_gfx_blit_icon(int idx, int x, int y, int ink_h, uint32_t fg, int cy)
row[tx] = (uint16_t)((r << 11) | (g << 5) | b);
}
}
/* 整条顶栏作为脏区标出(图标在顶条内,present 只重画顶条即可) */
}
/* 状态栏路径:blit 像素 + 把整条顶栏标脏(present 只重画顶条即可)。 */
void meow_gfx_blit_icon(int idx, int x, int y, int ink_h, uint32_t fg, int cy)
{
(void)y;
if (!g_init_ok || !g_fb) return;
if (idx < 0 || idx >= (int)(sizeof sb_icons / sizeof sb_icons[0])) return;
icon_blit_px(idx, x, ink_h, fg, cy);
dirty_add(x, 0, SB_ICON_SIZE, MUI_SBAR_H);
}
/* 控件路径(TopAppBar 动作图标):只写像素,不标「顶栏」脏区——控件矩形由
* meow_widget_draw 的 clip + invalidation(setter 标脏)独立管理,避免把状态栏的
* 顶栏脏区假设带进控件绘制(topbar 不位于屏幕最顶行时标错区域、触发误重画)。 */
void meow_gfx_blit_icon_ink(int idx, int x, int ink_h, uint32_t fg, int cy)
{
if (!g_init_ok || !g_fb) return;
if (idx < 0 || idx >= (int)(sizeof sb_icons / sizeof sb_icons[0])) return;
icon_blit_px(idx, x, ink_h, fg, cy);
}
/* ================= 像素写入 ================= */
static void px_write_rgb565(int x, int y, uint16_t c16)
{