/* * meow_ui.h — MeowOS 应用框架 SDK 公共 API(B1)。 * * 蓝本:MEOW_APP_SDK.md §3-§8。应用只调本头声明的 API;绝不 open/mmap/ioctl * /dev/fb0、绝不 open /dev/input/event* —— 屏幕与输入由 meow_ui 接管。 * * 约定: * - 坐标 0,0 = 左上;所有颜色为 24-bit RGB(0xRRGGBB),内部转 RGB565。 * - 所有绘制先进离屏 back_buf,调用 meow_ui_flush()/flush_region() 才上屏。 * - 文本字号:28(标题/状态栏)、20(正文/按钮)。 * * 与设计文档的偏差(实现期定案,见 MEOW_APP_SDK.md §12 更新): * [D1] meow_ui_opts 由实现补充(宽/高覆写,0=自动读 /dev/fb0);文档只引用未定义。 * [D2] meow_list_create 的数据源回调签名由实现定案(文档留占位注释)。 * [D3] meow_img_blend 内部实现补充(见 meow_ui_internal.h),非公共 API 增量。 * [D4] 增加 meow_theme_defaults()/meow_theme_current() 便于脱机(无 settings 文件)使用。 */ #ifndef MEOW_UI_H #define MEOW_UI_H #include #include #ifdef __cplusplus extern "C" { #endif /* ============================================================ */ /* 物理键 keycode(内核 input.h 常用值;KEEP 与 launcher/settings 一致) */ /* ============================================================ */ #define MEOW_KEY_POWER 116 #define MEOW_KEY_VOLUMEDOWN 114 #define MEOW_KEY_VOLUMEUP 115 #define MEOW_KEY_PLAYPAUSE 164 #define MEOW_KEY_PREVIOUS 165 /* KEY_PREVIOUSSONG=165(上一曲;19 是另一码,勿混用) */ #define MEOW_KEY_NEXT 163 /* KEY_NEXTSONG */ /* 滑动方向(on_swipe 的 dir 参数) */ #define MEOW_SWIPE_LEFT 0 #define MEOW_SWIPE_RIGHT 1 #define MEOW_SWIPE_UP 2 #define MEOW_SWIPE_DOWN 3 /* ============================================================ */ /* §3 绘制层 */ /* ============================================================ */ /* init 选项。width/height 为 0 表示自动读取 /dev/fb0 几何; * 无 fb(宿主/qemu 离屏)时用 480×720 缺省([D1])。 */ typedef struct meow_ui_opts { int width; int height; } meow_ui_opts; int meow_ui_init(const meow_ui_opts *opts); /* 开 fb、读几何、载字库、建 back_buf;0=成功 */ void meow_ui_shutdown(void); int meow_ui_width(void); /* 480 */ int meow_ui_height(void); /* 720 */ 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); /* 圆角框 */ /* 文本(size=20/28) */ void meow_ui_text(int x, int y, const char *utf8, int size, uint32_t color); 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 */ /* ============================================================ */ /* §4 图片层 */ /* ============================================================ */ typedef struct meow_img meow_img; /* 句柄,由 meow_img_* 管理,不透明 */ 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); 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 */ /* ============================================================ */ /* §5 控件层 */ /* ============================================================ */ typedef struct meow_widget meow_widget; 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); /* 列表数据源回调:idx 有效时填 label 并返回 1;越界返回 0([D2] 定案签名) */ typedef int (*meow_list_source)(int idx, char *label, int len, void *ctx); meow_widget *meow_list_create(int x, int y, int w, int h, int count, meow_list_source src, void *ctx); void meow_widget_free(meow_widget *w); void meow_widget_draw(meow_widget *w); /* 每次 flush 前调用 */ int meow_widget_hit(meow_widget *w, int x, int y); /* 点是否落在控件内 */ void meow_slider_set(meow_widget *s, int val); int meow_slider_get(meow_widget *s); void meow_switch_set(meow_widget *w, int on); int meow_switch_get(meow_widget *s); int meow_btn_pressed(meow_widget *w); /* 应用在 on_tap 命中后标记按下 */ /* ============================================================ */ /* §5.1 输入法(IME)—— 内置触屏软键盘(仅英文 QWERTY / 数字,ASCII) */ /* ============================================================ */ typedef enum { MEOW_IME_ASCII, MEOW_IME_NUM } meow_ime_mode; typedef struct meow_ime_ctx { meow_ime_mode mode; char buf[256]; /* 输入缓冲(初始值可预填) */ int maxlen; /* 最大字符数(含 NUL 预算) */ 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); /* 非阻塞:返回后 app 在 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); /* ============================================================ */ /* §6 输入层 / 生命周期(B1) */ /* ============================================================ */ typedef struct meow_ui_events { void (*on_key)(int keycode, int is_down); /* M2.24:物理键为系统语义,SDK 不下发;回调保留(应用不映射键为确认/exit) */ void (*on_tap)(int x, int y); /* 触摸抬起落点 */ void (*on_swipe)(int dir, int dx, int dy); /* 左滑=返回(左缘起点+抬手触发) */ void (*on_tick)(void); /* 空闲周期回调(动画/时钟) */ 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_ui_request_exit */ void meow_ui_request_exit(void); /* 请求退出(相当于返回/退出键) */ /* 顶部左滑进度条(视觉反馈):画一条 5px 高、从 x=0 到 x 的横条(主题 accent 色)。 * x<=0 时清掉此前画的条(填回背景色)。不发 flush,由调用方 meow_ui_flush_region 上屏。 */ void meow_ui_swipe_hint(int x); /* ============================================================ */ /* §6.1 控件生命周期与归属(Activity 栈 + 三层控件模型) [源:2026-08-30] */ /* ============================================================ */ /* 根治「跨页面控件残留」:控件命中/绘制必须严格绑定其所属页面,否则会出现 * "按钮已不可见但仍被触摸命中"(如全屏页触摸到主页按钮位置闪现 accent 底)。 * * 三层职责(从 App 到系统,风险从低到高): * ① 页面控件:归属唯一 owner Activity;命中/实时按压只在「当前 active Activity * 的控件集」里生效。对象不销毁(同 Activity 内复用),弹栈回来自动恢复 → * 回页面零重建。 * ② App 跨 Activity 控件(SDK 托管):钉在 App 的 Activity 栈之上、跨 Activity 常驻, * 逻辑/渲染由 SDK 调度。本轮为「可用骨架」(见上 API 注释),待 B2 细化。 * ③ 系统级控件(状态栏/通知中心/返回滑条/电源菜单):仅框架内部,无公共 API(不开放)。 * * 触摸命中分流顺序:③ 系统全局 → ② App 全局 → ① 当前 active Activity 页面控件; * 某层命中即消费,否则落到下一层。 */ /* ① Activity 栈。控件创建时绑定「当前 active Activity」为 owner;弹栈回来自动恢复。 * 栈空时 active() 返回 0(根/default Activity),故未显式管理栈的 App 默认所有控件 * 归属根 Activity 0。push 新 Activity(进子页/全屏)、pop 回上级(回根)。 */ void meow_ui_activity_push(int id); void meow_ui_activity_pop(void); int meow_ui_activity_active(void); /* 当前 active activity id(栈空=0) */ /* ② App 跨 Activity 控件(SDK 托管,骨架)。SDK 维护全局控件列表: * - 渲染:每帧(有脏区需上屏时,meow_ui_gfx present())在 active activity 内容之上、 * 全局状态栏之下调用 render_cb(跨 Activity 常驻); * - 触摸:TAP 先给 global hit_cb(返回 1=消费),否则落到 active activity 页面控件。 * 逻辑/渲染由 SDK 调度,App 只需声明。注:骨架,待 B2 细化。 */ typedef void (*meow_global_render_fn)(void *ctx); /* 每次渲染帧回调(SDK 调用) */ typedef int (*meow_global_hit_fn)(void *ctx, int x, int y); /* 命中返回1=消费 */ void meow_ui_global_add(int id, meow_global_render_fn r, meow_global_hit_fn h, void *ctx); void meow_ui_global_remove(int id); /* ③ 系统级控件:状态栏/通知中心/左缘返回滑条/电源菜单等全局叠加层——仅 SDK 内部接口, * 不向用户 App 开放任何公共悬浮/叠加层 API。既有状态栏/返回滑条逻辑(§3.1)不动。 */ /* ============================================================ */ /* §3.1 全局状态栏 / 全屏(A-0,SDK 系统级组件) */ /* ============================================================ */ /* 状态栏是 SDK 内置全局组件:所有界面默认显示(时钟/电量/WiFi/蓝牙/音量,slim ~40px), * 数据由 SDK 内置 meow_ui_sys 读取器 1s 轻刷(与 launcher 同源单点一致)。 * z 顺序最顶:meow_ui_flush() 上屏前自动把状态栏画进 back_buf 顶部行,覆盖非全屏内容; * 非全屏 APP 需用 meow_ui_statusbar_height() 把内容下移(inset),否则被状态栏盖住。 */ /* 状态栏显隐(默认显示;APP 声明全屏则隐藏——沉浸)。 */ void meow_ui_set_statusbar(int visible); /* 1=显示(默认) 0=隐藏(全屏) */ int meow_ui_statusbar_visible(void); /* 全屏声明:等价 app.json fullscreen:1(外观上隐藏状态栏 + 左缘返回手势/进度条——沉浸)。 */ void meow_ui_set_fullscreen(int on); /* 状态栏高度(px,供 APP 布局上移内容,避免被盖——status bar inset); * 全屏/隐藏时返回 0。 */ int meow_ui_statusbar_height(void); /* ---- 状态栏「上收出屏只留提示线」(collapsed,草案/待定案——本批仅加声明)---- * 供全屏调用:把状态栏内容上移出屏顶、只留一条「提示线」高度(可下拉还原)。 * 与 meow_ui_set_fullscreen(1) 的关系:fullscreen 隐藏整条状态栏(沉浸,inset=0); * collapsed 仍视状态栏为「激活」,左缘返回手势(SWIPE_LEFT)与顶部伸缩提示线 * (meow_ui_swipe_hint)依旧生效,只是其内容上收、仅留提示线——用于「不完全沉浸」, * 保留一处可下拉拉出状态栏的入口。顶部下滑热区 meow_ui_statusbar_hotzone() 在全屏时缩小。 * 实现位置:meow_ui_gfx.c(基座让 on 生效:true→只画提示线/内容上移);逐帧过渡动画 * (上收/恢复插值)为待定案,后续代理可经 meow_ui_statusbar_animate(ms) 补齐。 */ void meow_ui_statusbar_set_collapsed(int on); /* on=1 上收(内容上移出屏、只留提示线);on=0 恢复 */ int meow_ui_statusbar_collapsed(void); /* 当前是否处于「上收」目标(1=是) */ void meow_ui_statusbar_animate(int ms); /* TBD:上收/恢复过渡时长(ms);占位,后续代理实现插值 */ /* 顶部下滑热区(下拉展开状态栏/通知)高度(px)。 * 非全屏=整条状态栏可视高度;全屏时缩小到 MEOW_SBAR_HOTZONE_FS(保留一处下拉入口)。 * 返回「可用于起始下拉」的热区高度;由输入层/后续代理据此判定下拉起点。 */ int meow_ui_statusbar_hotzone(void); #define MEOW_SBAR_HOTZONE_FS 4 /* 全屏时缩小后的顶部热区高度(px,草案值) */ /* ============================================================ */ /* §7 动画/时间(B1 最小可用) */ /* ============================================================ */ uint64_t meow_ui_time_ms(void); /* 单调毫秒时间戳 */ /* ============================================================ */ /* §7.1 显示刷新率调度(A-1/A-2:从 launcher M2.16 迁入,归口 SDK,PERF_SCHEDULER 显示子域) */ /* ============================================================ */ /* 设目标档位 60/30/15(launcher 与 app 统一走 SDK 的 present 帧率门控一致)。 * 同时把当前有效档对齐到目标(与 launcher settings_load 语义一致)。 */ void meow_ui_set_refresh_rate(int r); /* 1=恒 max 不降档(性能优先);0=允许 governor 在 [15,30,60] 自适应降/升档。 */ void meow_ui_set_refresh_always_max(int on); /* 当前有效帧率(governor 可能已降档;诊断用)。 */ int meow_ui_effective_rate(void); /* 已呈现帧计数(验证 present 频率用)。 */ unsigned long long meow_ui_frames_presented(void); /* ============================================================ */ /* §8 主题/配置 */ /* ============================================================ */ typedef enum { MEOW_THEME_LIGHT, MEOW_THEME_DARK, MEOW_THEME_AUTO } meow_theme_mode; typedef struct meow_theme { uint32_t bg; /* 背景色 */ uint32_t fg; /* 前景/正文 */ uint32_t accent; /* 强调色(按钮/选中) */ uint32_t dim; /* 次要文字 */ int font_title; /* 28 */ int font_body; /* 20 */ } meow_theme; const meow_theme *meow_theme_get(void); void meow_theme_set_mode(meow_theme_mode m); meow_theme_mode meow_theme_get_mode(void); 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); /* [D4] 脱机访问两套内置色板(无 settings 文件也可靠):返回当前解析生效的色板副本。 */ meow_theme meow_theme_defaults(meow_theme_mode m); /* ---- §8.1 顶级主题风格族(minimal,2026-08-30)---- * 主题 = 顶级主题风格族(ui.style:MD3/MIUIx)× 明暗(display.theme)。本批只落「状态栏图标集 * 随 ui.style 换集」的最小闭环:meow_ui_set_style 记录 style(同值忽略)+ 触发 theme_reload/ * 广播(让状态栏/控件下一帧用新 style 重绘)。style 还决定状态栏右侧图标集(§3.1 同一个状态栏)。 * 完整 style×mode 配色/控件形态矩阵(§8.1.3)为后续里程碑。 */ #define MEOW_STYLE_MD3 0 /* Material You(默认) */ #define MEOW_STYLE_MIUIX 1 /* MIUI 风格族(基础占位) */ void meow_ui_set_style(int style); /* 设顶级主题风格族;越界 clamp 到合法值;同值忽略 */ int meow_ui_style(void); /* 当前 style(默认 MEOW_STYLE_MD3) */ /* ============================================================ */ /* §9 应用日志(统一日志 API,M2.51 最小可用版) */ /* ============================================================ */ /* app 只需一行 meow_log();SDK 管「写哪/怎么写/过滤/降级/上限」: * - 路径:/apps//logs/<启动时间>_.log * (目录不存在 mkdir -p,按 app 分目录),每次启动=新文件,同一次启动内 O_APPEND 追加; * - 级别过滤:lvl < meow_log_get_level() 丢弃;默认 MEOW_LOG_INFO; * - 格式: [] message\n; * - 上限:单文件 ≥2MB 自动开新文件追加 _;每 App 总量 ≥50MB 按期删最旧,防撑爆卡; * - 无卡/写失败降级 stderr,不阻塞 app 不崩;线程安全。 * 注意:MEOW_LOG_APP 由 launcher 注入;未注入时默认 app_id="app"。 */ typedef enum { MEOW_LOG_DEBUG=0, MEOW_LOG_INFO, MEOW_LOG_WARN, MEOW_LOG_ERROR } meow_log_level; void meow_log(meow_log_level lvl, const char *fmt, ...); /* app 一行调用,写到按 app 分离日志 */ void meow_log_set_level(meow_log_level lvl); /* 可选:app 设本 app 级别;默认 MEOW_LOG_INFO */ meow_log_level meow_log_get_level(void); /* ============================================================ */ /* §9.1 应用通知(meow_notify_*,M2.53 最小可用版) */ /* ============================================================ */ /* app 只需声明类型 + meow_notify_send() 即可发通知,SDK 管配额/活动表/降级: * - 类型注册:app 声明支持的类型(最多 MEOW_NOTIFY_MAX_TYPES 4 种); * meow_notify_send 也会自动注册未声明类型(受同样 4 种上限约束); * - 配额(NOTIFICATION_SYSTEM.md §7,2026-08-29 用户拍板):每 App 最多 4 种类型; * 每类型活动(未过期)通知上限 4,满则丢最旧(替换);媒体类型单例(每 app 仅 * 保留最近 1 条,重发替换——可多媒体 App); * - 超时语义 [实现定案,沿用 NOTIFICATION_SYSTEM.md §2]:timeout_ms>0 = 过期毫秒数; * 0 = 不自动过期(直到 meow_notify_cancel);-1 = 常驻(ONGOING),同样不自动过期; * - 落点:本阶段 SDK 内部维护活动通知表 + 用 meow_log() 打日志作为落点;真实投递到 * 通知中心 UI / D-Bus(org.freedesktop.Notifications)是后续任务——本结构已对齐 * freedesktop 字段(summary/body/…)为此预留,但不写死后端; * - 线程安全;不依赖 /dev/fb0、不依赖板子,可宿主编译。 */ #define MEOW_NOTIFY_MAX_TYPES 4 /* 每 App 最多 4 种通知类型 */ #define MEOW_NOTIFY_MAX_PER_TYPE 4 /* 每类型活动(未过期)通知上限 */ #define MEOW_NOTIFY_MAX_MEDIA 1 /* 媒体通知每 App 仅 1 条(单例) */ #define MEOW_NOTIFY_TIMEOUT_ONGOING (-1) /* 常驻(ONGOING),不自动过期 */ #define MEOW_NOTIFY_TIMEOUT_NEVER 0 /* 不自动过期,直到取消 */ /* 通知分类(freedesktop.org Desktop Notifications 的 category 最小子集 [实现定案]) */ typedef enum { MEOW_NOTIFY_CAT_GENERAL = 0, /* 通用(默认) */ MEOW_NOTIFY_CAT_MESSAGE = 1, /* 即时消息/聊天 */ MEOW_NOTIFY_CAT_EMAIL = 2, /* 邮件 */ MEOW_NOTIFY_CAT_EVENT = 3, /* 事件/日历提醒 */ MEOW_NOTIFY_CAT_PROGRESS = 4, /* 进度/下载 */ MEOW_NOTIFY_CAT_MEDIA = 5, /* 媒体播放(MPRIS;每 app 单例) */ MEOW_NOTIFY_CAT_COUNT = 6, /* 边界哨兵(非合法类型) */ } meow_notify_category; /* 紧急度(UI 视觉分级 + 提示音/震动强弱) */ typedef enum { MEOW_NOTIFY_URG_LOW = 0, /* 低:仅进通知中心,不打扰 */ MEOW_NOTIFY_URG_NORMAL = 1, /* 普通 */ MEOW_NOTIFY_URG_HIGH = 2, /* 高:顶部横幅 + 提示音 */ MEOW_NOTIFY_URG_CRITICAL = 3, /* 紧急:需立刻注意 */ MEOW_NOTIFY_URG_COUNT = 4, /* 边界哨兵(非合法值) */ } meow_notify_urgency; /* 发送负载(对齐 freedesktop Notify() 字段;SDK 内部复制副本,不持 app 外部指针, * app 只需保证 icon/title/body/target_activity 指针在调用返回前有效)。 */ typedef struct meow_notify { meow_notify_category cat; /* 类型(未声明则按 4 种上限自动注册) */ meow_notify_urgency urgency; /* 紧急度(缺省 MEOW_NOTIFY_URG_NORMAL;越界钳位) */ const char *title; /* summary:标题,单行(必填,NULL 则发送失败) */ const char *body; /* body:正文,可多行(可 NULL) */ const char *icon; /* app_icon:图标 icon name 或 path;NULL/空 = 用该 app 默认图标(launcher 按 app_id 回退) */ int timeout_ms; /* 见上超时语义;推荐 MEOW_NOTIFY_TIMEOUT_* */ const char *target_activity; /* 通知中心点击跳转的 Activity 名(可 NULL;M3 导航预留) */ int progress; /* 进度 0-100;-1=不显示进度条(缺省 -1) */ } meow_notify; /* 类型注册:app 声明支持的类型。0=成功;-1=已声明/已达 4 种上限/非法。 */ int meow_notify_register_type(meow_notify_category cat); /* 发送一条通知。返回通知 id(用于 meow_notify_cancel);失败返回 0。 * 同类型满 4 条时丢弃最旧(替换);媒体类型单例(重发替换同 app 上一条媒体通知)。 */ uint32_t meow_notify_send(const meow_notify *n); /* 取消一条通知。1=成功;0=未找到(id 无效/已过期/已取消)。 */ int meow_notify_cancel(uint32_t id); /* 实时更新一条活动通知的进度(0-100,-1=清除进度条)。local_id=meow_notify_send 的返回值。 * 语义(用户定案):仅改 SDK 内部活动槽 + 经 IPC 通知 launcher 改**内存活跃槽**;不落盘—— * TF 快照只在「创建时 / 结束(100% 或 dismiss)」触发。返回 1=找到并更新;0=未找到/非法。 */ int meow_notify_update_progress(uint32_t local_id, int progress); /* 查询当前活动(未过期、未取消)通知数/是否还有。 */ int meow_notify_active_count(void); int meow_notify_count_in_type(meow_notify_category cat); int meow_notify_has_active(void); /* 1=尚有活动通知,0=无 */ /* 紧急度/分类 → 字符串("low"/"normal"/"high"/"critical"、"general"/"message"/…)。 */ const char *meow_notify_urgency_str(meow_notify_urgency u); const char *meow_notify_category_str(meow_notify_category cat); /* ============================================================ */ /* §5.7 应用可读 TF 卡字体列表(M2.58:字体索引 / 查列表 / 丢失降级默认) */ /* ============================================================ */ /* 系统字体管理器的面向应用接口(规格 §5.7.1/§5.7.2): * - 权威列表 = launcher 扫描 MeowOS/fonts/// 后落盘的持久文件 * MeowOS/config/fonts/index(CSV:family,weight,path,label,tier,glyph_count)。 * app 只经本接口读该列表(不直接拼路径、不依赖 launcher 内存数组)。 * - 渲染仍走 env MEOW_FONT_PNG/MEOW_FONT_IDX(launcher 注入的「当前生效字体」, * 选中字体那一套);本节的 get_available_count/enumerate 只负责「列有哪些库」, * select_by_id 负责「app 会话内固定用哪套」。两路明确。 * - 无卡 / 无 index → 仅 1 项板载默认(family=default)。 */ #ifndef MEOW_FONT_INFO_DEFINED #define MEOW_FONT_INFO_DEFINED typedef struct meow_font_info { char family[64]; /* family slug = MeowOS/fonts// 一级目录名 */ char name[64]; /* 显示名(index 无单列 → 回退 family) */ char weight[32]; /* weight slug(regular|bold|…,缺省 regular) */ char tier[8]; /* 档位 common|gbk|full(info 用) */ int glyph_count; /* font.json glyph_count(info 用) */ char label[128]; /* index 显示名(含字重 + 尺寸标记) */ int size_list[16]; /* 原生字号表(index 无 → 空) */ int size_count; /* 有效字号数 */ int bit_depth; /* 4|8(index 无 → 0) */ char path_png[320]; /* 卡根相对 MeowOS/fonts///font.png */ } meow_font_info; #endif /* 可用字库数(含默认;无卡 → 1)。 */ int meow_font_get_available_count(void); /* 按序号取:idx=0=默认行(family=default);越界返回 0。 */ int meow_font_enumerate(int idx, meow_font_info *out); /* 选该套为 app 会话默认字体:id=0 跟随系统默认(font.file,经 env);id>0 固定用该套。 * 该套字库缺失 → 降级默认(不丢请求)+ WARN(meow_log→app 日志)。成功 0,越界负值。 */ int meow_font_select_by_id(int id); /* ============================================================ */ /* §10 字体分层 / 大字库(M2.5x:基座声明 + font 域已实现按档装载) */ /* ============================================================ */ /* 字体「档位」概念:launcher 按 app.json 声明的字库档("fonts":<档>)向 app 注入 * MEOW_FONT_TIER=<0|1|2>;SDK(meow_ui_gfx / meow_font 大字库加载)据档选库: * MEOW_FONT_TIER_COMMON=0 默认 4K 常用字库; * MEOW_FONT_TIER_GBK =1 大字库 GBK; * MEOW_FONT_TIER_FULL =2 Full(全字符集)。 * 大字库生成由 font/gen/gen_font.py --charset 按档产出;按档装载由 meow_font_reload_tier() * 实现(先 unload 旧再 load 新,释放旧 atlas 防大字库双驻留)。launcher 经 * meow_font_effective_paths_tiered() 按档解析大字库绝对路径并注入 MEOW_FONT_PNG/IDX。 * 既有 meow_font_* 符号(class_of/has_glyph/load_slot/config_multifont…)保留不动。 * 判缺字:meow_font_has_glyph(cp) 预判当前字库是否含该码位。 */ #define MEOW_FONT_TIER_COMMON 0 #define MEOW_FONT_TIER_GBK 1 #define MEOW_FONT_TIER_FULL 2 /* 设当前字体档(0/1/2,越界 clamp 到合法值),返回生效档。 * meow_ui_gfx.c 定义并触发 meow_font_reload_tier() 真重载(大字库切换释放旧 atlas)。 */ int meow_font_set_tier(int tier); /* 当前字体档(初始 = MEOW_FONT_TIER_COMMON;meow_ui_init 时读 MEOW_FONT_TIER env 对齐)。 */ int meow_font_tier(void); #ifdef __cplusplus } #endif #endif /* MEOW_UI_H */