31 KiB
MeowOS 应用开发框架 SDK(meow_ui)设计
状态:设计稿(2026-08-29)。路线 B:框架承载——MeowAPPs 不再裸
mmap("/dev/fb0")自绘、自读输入,而是链接统一静态库meow_ui.a,用 API 开发业务;渲染/控件/图片/输入/导航由框架收口。 目标:应用只写业务,不重复造轮子;观感、交互、生命周期统一;避免每个应用踩一遍 fb 双缓冲 / ioctl 号 / 返回键 / 息屏交互这些坑。
1. 问题与定案
现状(APPS.md §3.3):应用必须"独占屏幕自绘"——自行 open("/dev/fb0")+mmap 绘制;自行 open("/dev/input/event*") 读输入;自行管返回。全部 480×720、RGB565、双缓冲 yoffset、ioctl 号 0x4600/0x4602,每个应用都要重写一遍,观感必然乱。
定案:路线 B(框架承载)。理由:
- 现状只有 1 个示范应用能凑合;要开放多应用/第三方,裸自绘 = 爆炸。
- 渲染基建已就绪(
back_buf+meow_present无闪烁、meow_font字库、blend565混叠、脏区追踪),把它开放成 app 可链接的 API,是低成本高收益。
分层决策(分两步落地,不一次做完):
- B1 渲染/控件/图片 SDK(本文档主体,优先):应用链接
meow_ui.a。依赖现成meow_font.a+ 内建stb_image(单头文件、静态编入、解 PNG/JPEG/BMP)。不依赖阶段 D,可独立先行。 - B2 输入/生命周期/导航(衔接阶段 D):把应用从"自读 event / 自管返回"解放,走 IPC + M3 导航栈。本文档 §5 给衔接设计,B2 实现归阶段 D。
2. 架构分层
┌─────────────────────────────────────────────┐
│ MeowAPP(业务逻辑,只调 meow_ui API) │
├─────────────────────────────────────────────┤
│ meow_ui 静态库(meow_ui.a) │
│ ├─ 绘制层 meow_draw_* │
│ ├─ 控件层 meow_widget_*(按钮/列表/滑条…)│
│ ├─ 图片层 meow_img_*(stb_image 解码) │
│ ├─ 输入层 meow_input_*(语义事件) │ ← B1:只收事件;B2:接 M3 导航
│ └─ 主题/配置 meow_theme_*(颜色/间距/字体) │
├─────────────────────────────────────────────┤
│ 渲染后端 meow_ui_gfx(复用 launcher 机制) │
│ back_buf(RGB565) + meow_present(dirty) │
│ + meow_font(位图字库) + blend565 │
└─────────────────────────────────────────────┘
关键约定:
- 应用只调 API,绝不
open fb、mmap、ioctl、open event。屏幕/输入由 meow_ui 在应用meow_app_start()时建立、退出时释放。 - 渲染统一走
back_buf+meow_present:应用画到离屏,只在meow_ui_flush()时单次原子 blit 到 fb0(无撕裂无频闪,复用 M2.16 地基)。 - 颜色统一 24-bit RGB(
0xRRGGBB),meow_ui 内部做rgb565()转换;字体绘制用meow_font,字号约定 28(标题/状态栏)/20(正文/按钮)。
3. 绘制层 API(B1)
所有绘制先画进离屏 back_buf;调用 meow_ui_flush() 才上屏。坐标 0,0 = 左上。
/* 初始化/销毁(应用 main 里 meow_app_start 的懒加载) */
int meow_ui_init(const meow_ui_opts *opts); /* 开 fb、读几何、载字库、建 back_buf */
void meow_ui_shutdown(void);
/* 帧缓冲几何(应用需自适应时读取) */
int meow_ui_width(void); /* 480 */
int meow_ui_height(void); /* 720 */
/* 基本绘制(全部画进 back_buf) */
void meow_ui_clear(uint32_t color); /* 整屏清(填背景色) */
void meow_ui_put_px(int x, int y, uint32_t color);
void meow_ui_fill_rect(int x, int y, int w, int h, uint32_t color);
void meow_ui_draw_rect(int x, int y, int w, int h, uint32_t color); /* 空心框 */
void meow_ui_draw_rect_round(int x, int y, int w, int h, int r, uint32_t color); /* 圆角框 */
/* 文本 */
void meow_ui_text(int x, int y, const char *utf8, int size, uint32_t color); /* size=20/28 */
void meow_ui_text_right(int right_x, int y, const char *utf8, int size, uint32_t color);
void meow_ui_text_center(int cx, int y, const char *utf8, int size, uint32_t color);
int meow_ui_text_width(const char *utf8, int size);
int meow_ui_text_height(int size); /* = meow_font_line_height */
/* 上屏:vsync + 原子 blit 脏区(内建脏区追踪,应用无需关心) */
void meow_ui_flush(void);
void meow_ui_flush_region(int x, int y, int w, int h); /* 只刷新指定区 */
/* 半透明(已有 blend565:前景按 alpha 与背景混叠) */
void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alpha); /* 0-255 */
说明:
meow_ui_text_*底层即meow_font_drawtext+meow_font_width_text;meow_ui_fill_rect_alpha复用blend565。模糊/毛玻璃不在 B1 承诺(硬件无 GPU、CPU 软渲;仅在静态小区域可考虑,见 §7)。
3.1 全局状态栏(系统级组件,A+C 方案并入)
定位:状态栏是系统级全局组件,由 SDK 统一绘制——所有界面(launcher 菜单 + MeowAPP 画面)默认都显示,仅由 SDK 运行时 meow_ui_set_fullscreen(1) 控制隐藏(fullscreen 字段未在 app.json 解析,已定未做,见 §3.1 注 [源:审计 2026-08-30])。数据由 SDK 内置状态读取器抓系统快照(与 launcher 同源单点一致),非各画各的。
/* 状态栏显隐(默认显示;APP 声明全屏则隐藏——沉浸) */
void meow_ui_set_statusbar(int visible); /* 1=显示(默认) 0=隐藏(全屏) */
int meow_ui_statusbar_visible(void);
/* 全屏:由 SDK 运行时 meow_ui_set_fullscreen(1) 控制(app.json `fullscreen` 未解析,已定未做;外观=隐藏状态栏+隐藏返回键)。[源:审计 2026-08-30] */
void meow_ui_set_fullscreen(int on);
/* 状态栏高度(px,供 APP 布局上移内容,避免被盖——status bar inset) */
int meow_ui_statusbar_height(void);
绘制规则:
meow_ui_flush()上屏前,SDK 自动在顶部画状态栏(28px,meow_ui_statusbar_height()即此值;用户定 40→28,栏内字号 20),内容:时钟 / 电量 / WiFi / 蓝牙 / 音量(与 launcher 一致)。- 状态栏数据由 SDK 内置读取器周期刷新(~1s 轻刷,读
/sys/class/power_supply/*、WiFi 状态、时钟、音量寄存器——与 launcher 同一批 source)。 - z 顺序:状态栏是最顶层。APP 内容需
meow_ui_statusbar_height()下移(inset),否则被状态栏盖住(有状态栏 OS 的通用做法)。 - 全屏:运行时
meow_ui_set_fullscreen(1)控制 → 隐藏状态栏 + 隐藏返回键(沉浸);退出恢复。注:app.jsonfullscreen字段未在解析器读取(已定未做 [源:审计 2026-08-30]),故不能经 app.json 声明全屏。
与 launcher 统一(A+C):launcher 迁移到 SDK 后,其状态栏(现私有 draw_statusbar())改走 SDK 这一套,全局统一、单点一致。
注意(诚实):这是 SDK 的较大增强——需引入系统状态读取器 + 顶部留白(inset)协调 + 与 APP 内容 z 顺序。非全屏 APP 必须给顶部 inset,否则内容被盖。API 名实现时以 meow_ui.h 为准。
4. 图片层 API(B1)
内建 stb_image(单头文件,静态编入 meow_ui.a),解 PNG/JPEG/BMP,统一转 RGBA。这是对"图片渲染"的直接答案(背景/封面/图标)。
/* 加载图片(从 RAM 缓冲或 TF 卡文件)。返回句柄,失败 NULL。
* mem: 应用可先读文件到 RAM 再喂给解码器;meow_ui 不解读自身以外的 IO。 */
meow_img *meow_img_load_file(const char *path); /* 内部读文件 + stb 解码 */
meow_img *meow_img_load_mem(const void *buf, int len);
void meow_img_free(meow_img *img);
/* 查询 */
int meow_img_w(meow_img *img);
int meow_img_h(meow_img *img);
/* 绘制:整图 / 缩放 / 带 alpha */
void meow_ui_img(int x, int y, meow_img *img); /* 原始尺寸 */
void meow_ui_img_scaled(int x, int y, int w, int h, meow_img *img); /* 最近邻缩放 */
void meow_ui_img_alpha(int x, int y, int w, int h, meow_img *img, int alpha);
/* 最常用:封面/图标九宫格或圆形裁剪(封面/专辑图等) */
void meow_ui_img_cover(int x, int y, int size, meow_img *img); /* 居中正方形裁剪成 size×size */
裁剪/缩放:软渲用最近邻(快),不做高质量插值(省 CPU)。封面用
meow_ui_img_cover居中裁方 + 缩放到目标尺寸即可。
5. 控件层 API(B1)
内置常用控件,观感统一(MD3 优先 / MIUIx 备选,见 §6 主题)。控件状态由 meow_ui 维护,绘制走 back_buf。
typedef struct meow_widget meow_widget;
/* 创建/销毁;控件 layout 由应用每次 flush 前调用 meow_widget_draw 绘制 */
meow_widget *meow_btn_create(int x, int y, int w, int h, const char *label);
meow_widget *meow_slider_create(int x, int y, int w, int min, int max, int val);
meow_widget *meow_switch_create(int x, int y, int on);
meow_widget *meow_list_create(/* 数据源回调 */);
void meow_widget_free(meow_widget *w);
/* 绘制 */
void meow_widget_draw(meow_widget *w);
/* 状态/取值 */
void meow_slider_set(meow_widget *s, int val);
int meow_slider_get(meow_widget *s);
void meow_switch_set(meow_widget *s, int on);
控件命中(触摸点是否落在控件内)由输入层语义事件驱动,应用在
meow_ui_on_tap(x,y)回调里做分发——见下节。 B1 先做最小控件集(按钮/滑条/开关/列表四件套),其余(下拉、进度圈、通知卡片)随阶段 B 通知中心 / 网易云需要用再加。
5.1 输入法(IME)—— 内置触屏软键盘
背景:R3 Pro II 无独立键盘设备(仅触摸 goodix-ts + 物理按键 md-gpio-keys / jz adc keyboard),无 USB/蓝牙 HID 键盘栈。任何需要文本输入的应用(输入框/搜索/设置项)都依赖 IME,且必须由 SDK 内置——应用绝不能自己实现键盘,否则观感/行为不一、重复造轮子。
形态:系统级单例软键盘,作为控件层的一个特例(meow_ime),应用调 meow_ui_text_input() 弹出,键盘覆盖在应用之上,由 SDK 绘制与分发(复用 back_buf + meow_present 无闪烁地基,不干扰业务渲染)。
B1 范围:英文 QWERTY 键盘(数字+字母+符号),覆盖字符输入、退格 Backspace、空格、回车/完成。 不在 B1:中文拼音/词库选字——复杂度高、依赖词库,留到后期独立 IME(网易云/中文搜索需要时再上)。B1 的 IME 只保证"能输入 ASCII 文本"。
/* 弹出软键盘,输入到应用提供的缓冲。返回 1=确认(fn=enter),0=取消(fn=esc/背景点)。
* 回调驱动:输入变化由 SDK 内部循环处理,应用只需在 done 时读 out。 */
typedef enum { MEOW_IME_ASCII, MEOW_IME_NUM } meow_ime_mode; /* 全键盘/数字键盘 */
typedef struct {
meow_ime_mode mode;
char buf[256]; /* 应用提供的输入缓冲(初始值可预填,如 Wi-Fi 密码) */
int maxlen;
/* 回调:每次字符变化回调一次(用于实时预览/校验) */
void (*on_change)(const char *text, void *ctx);
void *ctx;
} meow_ime_ctx;
/* 阻塞:弹出键盘直到确认/取消。返回 1=确认(buf 已回填),0=取消。 */
int meow_ui_text_input(meow_ime_ctx *ctx);
/* 非阻塞变体:返回后应用在 on_tick 里轮询 meow_ime_active()/meow_ime_text() */
void meow_ui_text_input_async(meow_ime_ctx *ctx);
int meow_ime_active(void);
const char *meow_ime_text(void);
布局(480×720 竖屏):键盘占底部约 40% 高(~290px),上方为输入预览行 + 候选区。键位 40×40(够 touch target),触屏点按输入。 物理键辅助(兼容未来硬件键/可访问性):方向键移动光标、播放/确认键=选择、音量=翻页。B1 以触摸为主,物理键作为可选加分项(SDK 内实现)。
[B1 后续 / 不阻塞]:中文拼音 IME、词库、候选词联想、剪贴板、长按重复——作为独立里程碑,等首个中文输入场景(网易云搜索)出现再做。
6. 输入层 / 生命周期(B1 部分 + B2 衔接)
B1(本阶段):应用不再自读 /dev/input/event*,meow_ui 建立输入线程,把按键/触摸翻译成语义事件回调:
/* 应用注册事件回调(meow_app_start 时传入) */
typedef struct {
void (*on_key)(int keycode, int is_down); /* KEY_VOLUP/VOLDOWN/PLAYPAUSE/POWER…(SDK 已消化系统语义) */
void (*on_tap)(int x, int y); /* 触摸抬起落点 */
void (*on_swipe)(int dir, int dx, int dy); /* 左缘返回手势=LEFT;中部滑动=RIGHT/UP/DOWN */
void (*on_tick)(void); /* 空闲周期回调(动画/时钟用,见 §7) */
void (*on_swipe_progress)(int x_start, int dx);/* 左缘返回手势过程实时回调;x_start=按下X, dx=当前X-按下X */
} meow_ui_events;
void meow_ui_run(const meow_ui_events *ev); /* 阻塞:事件循环,直到 meow_app 请求退出 */
void meow_ui_request_exit(void); /* 应用调它请求退出(相当于触返回/按退出键) */
/* 左缘返回手势的顶部视觉条(SDK 已自动绘制,应用一般无需自画)。
* 画屏幕顶部 5px、从 x=0 到 x 的横条(主题 accent 色);x<=0 清条。应用可在
* on_swipe_progress 里用它自画(长度=当前 X=x_start+dx),或留空全靠 SDK。 */
void meow_ui_swipe_hint(int x);
- 返回语义:B1 下按"返回"(左缘返回手势/虚拟返回键)→ 由应用决定:
on_swipe(LEFT)是返回手势,应用自行meow_ui_request_exit()回应用列表;若想在页内返回,可在on_swipe(LEFT)里处理并return不退出。 - 左缘返回手势(抬手触发):手指从屏幕左缘(≤24px)向内划 ≥90px,抬手(release 边沿)后才触发
on_swipe(LEFT);过程以on_swipe_progress实时上报并自动画顶部进度条(meow_ui_swipe_hint,长度=当前 X)。中部左/右滑不触发返回(中部右滑→on_swipe(RIGHT)内容导航;中部左滑→落 TAP)。与设计稿 §2.2 的偏差:§2.2 写「左縁 + 向左 mdx<-90」物理不可达(左縁起点再向左最多走 ~24px),故取「左縁向内(右)划 ≥90px」实现,事件仍报MEOW_SWIPE_LEFT(保持「左滑=返回」契约),方向与 watchdog immersive 兜底一致。 - 沉浸模式:应用声明(app.json
immersive=1)→ launcher 写/tmp/meowapp_state=1→ watchdog 隐藏虚拟返回键,返回手势归 SDK。这是 B1 可做、B2 转正的一部分。
B2(衔接阶段 D):把 on_key/on_swipe 换成走 IPC 的语义导航(MSG_NAV 上报 + 启动链路),应用不再自己决定"返回回哪层",而是上报当前 Activity,由框架导航栈统一回退。届时:
meow_ui_run改为从 IPC 收启动链路(MEOW_CHAIN/MEOW_ACTIVITY环境变量)初始化导航栈;- 返回 = 栈回退,到根才
meow_ui_request_exit()。本文档 §5 的控件与 §3/§4 绘制在 B2 不变,只换输入/导航后端。
7. 动画/时间(B1 最小可用)
当前无动画框架。B1 提供帧驱动回调 + 内置时间,应用据此做低成本的帧序列/淡入淡出:
/* on_tick(ev) 里用 meow_ui_time_ms() 做时间轴动画 */
uint64_t meow_ui_time_ms(void); /* 单调毫秒时间戳 */
/* 动画 = 应用在 on_tick 里根据时间更新状态 → 调绘制 → meow_ui_flush_region 只刷变化区 */
约束:
- 只做状态时间轴动画(如滑条拖动回馈、列表项滑动、淡入淡出用
fill_rect_alpha叠加),不做实时 tween 每帧重算几何(CPU 软渲扛不住)。 - 动图/视频:B1 不提供(无解码器/无 GPU)。若确需"动画封面",用预渲染位图帧序列(应用持有若干帧,
on_tick按时间切帧 +flush_region),这是唯一低成本的动图方案。 - 毛玻璃/模糊背景:支持廉价版(HibyOS 同款降采样模糊,见 §11)——用
meow_ui_img_scaled缩 1/8 铺底 +fill_rect_alpha遮罩;仅在切歌/换封面时算一次,非每帧。真高斯卷积/全屏动态模糊不做。
8. 主题/配置(B1)
观感统一的核心,也是回应"控件样式效果"。内置日间 / 夜间两套主题,跟随 MeowOS 系统设置的主题模式自动切换。
typedef enum { MEOW_THEME_LIGHT, MEOW_THEME_DARK, MEOW_THEME_AUTO } meow_theme_mode;
typedef struct {
uint32_t bg; /* 背景色 */
uint32_t fg; /* 前景/正文 */
uint32_t accent; /* 强调色(按钮/选中) */
uint32_t dim; /* 次要文字 */
int font_title; /* 28 */
int font_body; /* 20 */
/* MD3 优先 / MIUIx 备选 */
} meow_theme;
/* 当前生效主题(应用只读)。AUTO 时按系统主题设置(display.theme_mode)解析,
* 日间取 light 表、夜间取 dark 表;由框架在主题模式变化时刷新。 */
const meow_theme *meow_theme_get(void);
/* 设置主题模式(AUTO 时联动系统设置键 display.theme_mode)。 */
void meow_theme_set_mode(meow_theme_mode m);
meow_theme_mode meow_theme_get_mode(void);
/* 主题变化通知:应用注册后,AUTO 切换日/夜时收到回调(据此重绘)。 */
typedef void (*meow_theme_listener)(meow_theme_mode m);
void meow_theme_add_listener(meow_theme_listener cb);
void meow_theme_remove_listener(meow_theme_listener cb);
双主题 + 跟随系统设置:
- 日间/夜间:SDK 内置两套标准色板(
meow_theme_light/meow_theme_dark),日间高亮(浅底深字)、夜间低亮度(深底浅字,护眼省电)。框架所有控件/绘制默认读当前生效主题,应用meow_theme_get()只读、不自配色。 - 跟随系统设置:主题模式
display.theme_mode(light/dark/auto)是meow_settings的一个设置键。auto时按系统时间(如 6:00-18:00 日间,其余夜间)或系统亮度/环境判定切换(B1 先用固定时段,后续可接入环境光,见遗留)。框架监听该键,变时对注册的 listener 广播,实体 UI / Web / 应用统一重绘。 - 主题切换即时生效:
meow_theme_set_mode非"只改设置",会立即广播 listener 并让当前绘制的控件用新主题重绘(应用在on_tick里据 listener 触发meow_ui_flush_region)。
主题随
meow_settings的display.theme_mode键分发;框架统一,应用不必自配色——这正是"实体 UI / Web 面板 / 应用全程一致观感"的保证。
9. 目录/构建约定
patch_v2/apps_assets/apps/<pkg>/app.json # 应用描述(新增 SDK/immersive 字段,见下)
patch_v2/hello_app/hello.c # 应用源码(改造为调 meow_ui 的示例)
patch_v2/sdk/ # SDK 源码
├── meow_ui.h # 对外 API(本文档 §3-§8)
├── meow_ui_gfx.c # 渲染后端(back_buf+present+font)
├── meow_ui_widget.c # 控件
├── meow_ui_img.c # stb_image 解码
├── meow_ui_input.c # 输入线程+语义事件
├── meow_ui_theme.c
├── stb_image.h / stb_image.c # 单头文件(vendor)
patch_v2/meow_launcherd/meow_font.a # 复用(静态链接)
构建出 patch_v2/sdk/meow_ui.a;应用编译链(zig-mipsel-cc)额外链 meow_ui.a meow_font.a libz.a -lpthread。
构建耦合(已知设计,非缺陷):
build_sdk.sh用-I../meow_launcherd引meow_ipc.h(meow_notify_ipc.c复用共享协议头,同一份、杜绝两端漂移),故 SDK 编译期依赖 launcher 头、非独立库;运行时无碍 —— App 只链meow_ui.a(含 meow_font.o),不链入 launcher 符号,故 app 侧无 launcher 依赖。
app.json 扩展字段(向后兼容,缺省即旧行为):
{
"name": "Hello App",
"exec": "/usr/data/mnt/sd_0/MeowAPPs/os.meow.hello/hello",
"package": "os.meow.hello", // 反域名权威 app_id;目录名=package,launcher 取之为 app_id
"version": "0.1",
"framework": 1, // 1=走 meow_ui(框架承载);缺省/0=裸自绘(旧)
"immersive": 0, // 1=沉浸模式(隐藏虚拟返回键,左缘滑动返回)
"icon": "apps/os.meow.hello/icon.png" // 可选:列表图标(供图片层)
}
上例 <pkg>=os.meow.hello(= apps/<pkg>/ 目录名 = package 字段值);exec 即 <挂载点>/MeowAPPs/<pkg>/<binary>。
app 字体来源(M2.x 已落地):app 若自带字库(
load_handle,见 §5.7.3,未实现)则用它;否则 SDKmeow_ui_gfx.c load_font()优先读 launcher 注入的环境变量MEOW_FONT_PNG/MEOW_FONT_IDX(=系统font.file当前生效字体,绝对路径)/MEOW_FONT_APP(family),无 env 则回退卡默认MeowOS/fonts/default/regular/font.png(M2.6 字重结构)→ 固件。因此app 未自带字库时跟随系统font.file,不再硬编码MeowAPPs/fonts。app 多字体(M2.5x,
display.multi_font):launcher 注入MEOW_MULTI_FONT=0/1与 6 类MEOW_FONT_CLS_<类>_PNG/IDX(命中则覆盖全局;类值为空=跟随全局不注入)。SDKmeow_ui_gfx的meow_gfx_load_multifont()读 env → 调meow_font_config_multifont()(同 png 去重、≤4 套上限、缺类回退全局)构建逐字符分类路由:meow_font_drawtext/width_text/line_height按meow_font_class_of(cp)(MEOW_FCLS_CJK/_CJK_SYM/_NUM/_LATIN/_LATIN_SYM/_OTHER)用对应字库取字形与度量;meow_font_has_glyph(cp)可预判缺字。display.multi_font=0/无 env → 单字体(现状,零额外开销)。底层接口见 meow_font.h:meow_font_load_slot/meow_font_unload_slot/meow_font_enable_multifont/meow_font_set_class_slot/meow_font_config_multifont;MEOW_MAX_SLOTS=5。app 字体档位(M2.5x,
app.json "fonts"声明 +font.load_full):launcher 按app.json "fonts":"common|gbk|full"与系统「加载大字库」开关(font.load_full,默认 0;开=强制 ≥gbk 档)算出生效档,注入MEOW_FONT_TIER=<0|1|2>(0=common≈4k 常用 1=gbk≈20k+ 大 2=full 全/可选),并把MEOW_FONT_PNG/IDX指向该档字库绝对路径——meow_font_effective_paths_tiered()在卡内MeowOS/fonts/<family>/<weight>/按font.json的charset(common|gbk|full)选库(gbk 请求接受 gbk/full;full 请求优先 full 再降级 gbk;M2.6 优先同 family(其次同 weight);无匹配回退全局font.file)。SDKmeow_ui_gfx.c load_font()载入后,应用可经meow_font_tier()查询当前档、meow_font_set_tier()切档(触发meow_font_reload_tier()真重载:大字库切换先 unload 旧再 load 新,释放旧 atlas,防 GBK/Full 大库双驻留)。判缺字:meow_font_has_glyph(cp)预判当前字库是否含该码位(common 小库下缺字→app 回退/提示,避免静默豆腐)。底层接口见 meow_font.hmeow_font_reload_tier;font/gen/gen_font.py --charset common|gbk|full [--weight <name>]按档生成font.png/font.idx/font.json(font.json写weight+charset+glyph_count)。
10. 与阶段关系 / 落地顺序
- B1(本文档,先行):
meow_ui.h+ gfx/widget/img/input/theme 最小实现 +meow_ui.a;改造 hello.c 为 SDK 版作为示例;出包r3proii_m2_20.upt或独立应用包验证。不依赖阶段 D。 - B2(衔接阶段 D):输入/导航后端换成 IPC + M3 导航栈,应用框架字段
framework=1的应用自动升级为"导航栈承载",裸应用保持兼容。 - 依赖:
meow_present/back_buf/dirty(M2.16 地基,✅)、meow_font(✅)、blend565(✅)——B1 全部基于现有能力,无需新的硬件依赖;仅新增 stb_image(单头文件)与输入线程。
11. 硬件约束(务必让应用作者知道)
| 能力 | 可行性 | 说明 |
|---|---|---|
| 图片(PNG/JPEG/BMP 静态图) | ✅ 支持 | stb_image 解码 + 最近邻缩放;封面居中裁方 |
| 半透明叠加 | ✅ 支持 | fill_rect_alpha(blend565),面板/遮罩可用 |
| 圆角/描边 | ✅ 支持 | 圆角框 + 字体描边 |
| 毛玻璃/模糊背景 | ✅ 支持(廉价版) | HibyOS 同款「降采样模糊」:封面缩到 1/8 再放大铺底(天然低通滤波抹掉高频),叠一层 fill_rect_alpha 半透明遮罩,清晰小封面叠其上。背景只在切歌/换封面时算一次,非每帧;不是真高斯卷积、不需 GPU。用 meow_ui_img_blur_bg() 生成背景 cache。已实测依据:设备 playing_plane/ 无模糊背景图 + 无 GPU/无 SIMD/14MB 内存 → 运行时模糊只能走降采样近似,成本微秒级 |
| 控件动画(时间轴/帧序列) | ⚠️ 有限 | 只做状态式动画;实时 tween 不做;动图=预渲染帧序列 |
| 动图(GIF/WebP 动画) | ⚠️ 弱支持 | 用预渲染位图帧序列模拟;不承诺实时 GIF 解码 |
| 视频 | ❌ 不做 | 无解码器/无 GPU/内存 14MB 会 OOM;如需"视频"用预渲染帧序列 |
| 刷新率 | 上限 60(默认)/30/15 | 应用动画别贪高帧率,软渲耗 CPU |
12. 遗留 / 待实现
meow_ui渲染后端需从 launcher 里抽公共绘制实现(back_buf/meow_dirty_*/meow_present/meow_font_bind目前是 launcher 静态函数——需提取为可链接的meow_ui_gfx或改为共享 obj,注意 launcher 与 app 是不同进程,不能共享同一 back_buf;meow_ui.a是独立库,内部自建 fb 上下文,不复用 launcher 的全局g_dirty)。- 输入线程优先级:vs 主循环 10ms 热键轮询的竞态,需在 B1 实现时定义清楚(应用进程内独立事件循环,不与 launcher 抢)。
- 网易云跑通后迭代控件集(播放页/列表/歌词),非一次性补齐。
meow_ui_img_blur_bg(降采样模糊背景,HibyOS 同款)API 待加:已在 §11 确认可行性(缩 1/8 放大铺底 + α 遮罩,切歌算一次);函数签名与实现留到 B1 之后(或并入网易云播放页时)。当前 SDK B1 的图片层先用meow_ui_img_scaled+fill_rect_alpha手动组合即可达到同等观感。- 视频已定不做:无解码器/无 GPU/内存 14MB 会 OOM;"视频"一律用预渲染帧序列模拟。若确需播放具体小视频,宿主机离线转帧序列 PNG → 打包到 TF 卡 → SDK 按帧播放(规避设备一切解码负担)。
B1 落地状态(2026-08-29)
- B1.0 渲染后端 ✅
meow_ui_gfx.c:自建 fb 上下文(自 mmap/dev/fb0、自建back_buf、独立脏区集 + vsync+原子 blit);无 fb 时(宿主/qemu)离屏 480×720,MEOW_UI_DUMP=<path>可把 back_buf 导出 PPM 截图。 - B1.1 绘制层 ✅ §3 全量:
meow_ui_clear/put_px/fill_rect/draw_rect/draw_rect_round/fill_rect_alpha/blend565+text/text_right/text_center/text_width/text_height。字库(真机)优先,回退内建 5×7 点阵。 - B1.2 图片层 ✅
meow_ui_img.c+ 内建stb_image(PNG/JPEG/BMP→RGBA):meow_img_load_file/mem/free/w/h、meow_ui_img/scaled/alpha/cover(最近邻 + 居中裁方)。宿主已用 test.png 验证预览/裁剪/缩放。 - B1.3 控件层 ✅
meow_ui_widget.c:meow_btn/slider/switch/list最小集(绘制 + 命中 + 取值)。 - B1.4 输入层 ✅
meow_ui_input.c:输入线程读event*(触摸 goodix-ts / md-gpio-keys / ADC 键),翻译成on_key/on_tap/on_swipe/on_tick语义事件;meow_ui_run/request_exit。手势专项(GESTURE_BACK):左缘返回手势=抬手触发 +MEOW_EV_SWIPE_PROGRESS进度上报 +on_swipe_progress回调;SDK 自动画顶部进度条meow_ui_swipe_hint。 - 配套:Launcher 统一触摸接口
meow_touch(M2.25,launcher 内部,应用不依赖)✅patch_v2/meow_launcherd/meow_touch.{h,c}:Launcher 自身 UI(应用列表 / 电源菜单 / 确认框)的低性能触摸解析收敛为一份,goodix 时序免疫(BTN_TOUCH=1不锁原点,等按下后首个有效ABS才锁;抬手位移 ≥65px 判滑动不命中)。应用侧不用它——应用触摸由本 SDK 输入层(meow_ui_input.c)翻译成on_tap/on_swipe回调,两者互不干扰;与 SDK 触摸保持一致的 goodix 时序免疫语义(详见meow_touch.h注释)。 - B1.5 主题 ✅
meow_ui_theme.c:日间/夜间两套色板 +get/set_mode/get_mode/add/remove_listener;跟随display.theme_mode(/usr/data/meow/settings.conf)。AUTO 按本地 6:00-18:00 日间。 - B1.6 IME ✅
meow_ui_ime.c:英文 QWERTY / 数字软键盘(ASCII),meow_ui_text_input(阻塞)+meow_ui_text_input_async/meow_ime_active/meow_ime_text;覆盖底部约 300px,背景点=取消、OK=确认。 - 构建 ✅
patch_v2/sdk/meow_ui.a(含 meow_font.o 内联,应用只需链meow_ui.a libz.a -lpthread);build_sdk.sh一键重编。宿主 +qemu-mipsel均跑通;示例hello改造为 SDK 版(见 §9 目录与patch_v2/hello_app/build_hello.sh)。 - 验证:
meow_ui.amipsel 静态编译链接 ✅(宿主 demo + qemu 均导出可见画面到device_test/);真机 /dev/fb0 几何与输入触屏未实测(设备本次不可达,逻辑参照 launcher 既有实现)。
实现期 API 微调(相对本文档):
- [D1]
meow_ui_opts补充width/height(0=自动读 fb;离屏缺省 480×720)。 - [D2]
meow_list_create数据源回调定案为int (*)(int idx, char *label, int len, void *ctx)。 - [D3] 新增内部
meow_gfx_fill_round/blit_rgba/mark_dirty(控件/图片用,非公共 API)。 - [D4] 新增
meow_theme_defaults(mode)(脱机取内置色板)。 - [D5] 新增
on_swipe_progress回调 +meow_ui_swipe_hint(x)(左缘返回手势视觉条)+ 内部MEOW_EV_SWIPE_PROGRESS/meow_input_inject(宿主验证用)。 meow_ui.h为对外权威签名;本文件 §3-§8 作为设计蓝本。
文档基于 2026-08-29 现有渲染基建(M2.16 无闪烁地基 + meow_font + blend565)编写;API 名会随 B1 实现微调,实现时以 meow_ui.h 为准。