基座+设计文档(三特性): meow_ui.h 字体档/状态栏收合API + launcher fonts/fullscreen解析+env注入+通知dump钩子 + meow_ui_gfx.c 收合渲染+字体档; spec-ref/SYSTEM_SETTINGS/APPS/NOTIFICATION 三特性设计落档
This commit is contained in:
1 parent
9b8a1e5c8b
commit
0b4d1d3215
8 files changed
+297
-25
No files matched your search
Binary file not shown.
@@ -915,6 +915,20 @@ static int meow_font_effective_paths(char *out_png, int plen, char *out_idx, int
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 【tier 选择入口,font 域占位】按字体档位取「当前生效字体」png/idx,供 launch_app 注入
|
||||
* MEOW_FONT_PNG/IDX/APP(配合 MEOW_FONT_TIER)。基座只实现 tier=COMMON(=meow_font_effective_paths);
|
||||
* tier>0 的大字库(GBK/Full)绝对路径由后续 font 代理据此演进填充(约定 MeowOS/fonts/<family>/
|
||||
* <tier>/…,或 settings 键 font.tier_gbk / font.tier_full —— 见 MEOW_APP_SDK.md 字体分层)。
|
||||
* 未实现前暂回退全局字体。返回 0 成功,-1 无可用。 */
|
||||
static int meow_font_effective_paths_tiered(int tier, char *out_png, int plen,
|
||||
char *out_idx, int ilen, char *out_family, int flen)
|
||||
{
|
||||
if (tier == MEOW_FONT_TIER_COMMON || tier < MEOW_FONT_TIER_COMMON)
|
||||
return meow_font_effective_paths(out_png, plen, out_idx, ilen, out_family, flen);
|
||||
/* TODO(font 代理):按 tier 解析大字库绝对路径(GBK/Full);暂回退全局(tier0)。 */
|
||||
return meow_font_effective_paths(out_png, plen, out_idx, ilen, out_family, flen);
|
||||
}
|
||||
|
||||
/* M2.5x 多字体:从 settings 读 display.multi_font + 6 类 font.class_*,把各自相对路径按卡根
|
||||
* 解析为绝对路径,去重装载到 meow_font 槽位(同 family 去重 & ≤4 套上限由
|
||||
* meow_font_config_multifont 统一处理)。仅当全局字库已装载(mfont_ready / slot0)时生效;
|
||||
@@ -1308,6 +1322,7 @@ struct meow_route {
|
||||
char act[16]; /* route 键后缀,如 "nowplaying" */
|
||||
char chain[MEOW_CHAIN_MAX]; /* 如 "home;search;nowplaying" */
|
||||
int keep_awake; /* M2.17:该 activity 常亮(app.json awake.<id>=1 / route.<id>.keep_awake=1) */
|
||||
int fullscreen; /* 活动级全屏声名(app.json route.<id>.fullscreen=1;M3 活动切换时消费) */
|
||||
};
|
||||
|
||||
/* 服务行:service.<svc>=mode:restart:max:window_ms(M1 仅解析存储,M4 保活) */
|
||||
@@ -1328,6 +1343,8 @@ struct app {
|
||||
/* ---- 阶段 D · M1:app.json 路由/框架/服务/图标(scan_apps 解析)---- */
|
||||
char framework; /* '1'=framework=true(看门狗返回发 SIGUSR1) */
|
||||
char immersive; /* '1'=immersive=true(隐藏虚拟返回键,返回手势归 SDK) */
|
||||
char fullscreen; /* '1'=app.json fullscreen=true(注入 MEOW_FULLSCREEN=1,SDK 预先设全屏) */
|
||||
char fonts; /* 字库档:0=默认4K常用 1=大字库GBK 2=Full(app.json "fonts";注入 MEOW_FONT_TIER) */
|
||||
char icon[129]; /* icon= 路径 */
|
||||
int nroute; /* route.<id> 行数 */
|
||||
struct meow_route routes[MEOW_MAX_ROUTES];
|
||||
@@ -1805,6 +1822,8 @@ static void meow_parse_app_json(FILE *f, struct app *a)
|
||||
char name[17] = "", exec[129] = "", icon[129] = "";
|
||||
char package[MEOW_APP_ID_MAX] = "";
|
||||
int fram = 0, immersive = 0;
|
||||
int fullscreen = 0; /* app.json fullscreen=<true|1>(注入 MEOW_FULLSCREEN env,SDK 预先设全屏) */
|
||||
int fonts = 0, fonts_set = 0; /* app.json "fonts":<档>(0=默认4K常用 1=大字库GBK 2=Full;缺省 0) */
|
||||
struct app tmp;
|
||||
memset(&tmp, 0, sizeof tmp);
|
||||
while (fgets(buf, sizeof buf, f)) {
|
||||
@@ -1816,8 +1835,8 @@ static void meow_parse_app_json(FILE *f, struct app *a)
|
||||
char *rp = strstr(buf, "route.");
|
||||
if (rp && tmp.nroute < MEOW_MAX_ROUTES) {
|
||||
rp += 6; /* 跳过 "route." */
|
||||
int idl = 0; char id[16] = "";
|
||||
while (*rp && *rp != '"' && *rp != ':' && *rp != '=' && idl < 15)
|
||||
int idl = 0; char id[32] = ""; /* 读满整键(识别 ".fullscreen" 后缀,cap 31) */
|
||||
while (*rp && *rp != '"' && *rp != ':' && *rp != '=' && idl < 31)
|
||||
id[idl++] = *rp++;
|
||||
id[idl] = 0;
|
||||
if (idl > 0) {
|
||||
@@ -1826,16 +1845,30 @@ static void meow_parse_app_json(FILE *f, struct app *a)
|
||||
if (*vp == ':' || *vp == '=') vp++;
|
||||
while (*vp == ' ' || *vp == '\t') vp++;
|
||||
if (*vp == '"') vp++;
|
||||
int vl = 0; char chain[MEOW_CHAIN_MAX] = "";
|
||||
while (*vp && *vp != '"' && *vp != ',' && *vp != '\n' &&
|
||||
*vp != '\r' && vl < MEOW_CHAIN_MAX - 1)
|
||||
chain[vl++] = *vp++;
|
||||
chain[vl] = 0;
|
||||
while (vl > 0 && (chain[vl - 1] == ' ' || chain[vl - 1] == '\t'))
|
||||
chain[--vl] = 0;
|
||||
strncpy(tmp.routes[tmp.nroute].act, id, 15);
|
||||
strncpy(tmp.routes[tmp.nroute].chain, chain, MEOW_CHAIN_MAX - 1);
|
||||
tmp.nroute++;
|
||||
/* route.<id>.fullscreen=<on>:活动级全屏声明(M1 顺带;M3 活动切换时消费)。
|
||||
* 命中既有 route.<id> 置 fullscreen;不新建 route(避免 id 被截断误建 "…fulls")。 */
|
||||
if (idl >= 11 && !strcmp(id + idl - 11, ".fullscreen")) {
|
||||
id[idl - 11] = 0; /* 去掉 ".fullscreen" 还原 act */
|
||||
char v[8] = ""; int k = 0;
|
||||
while (*vp && *vp != '"' && *vp != ',' && *vp != '\n' &&
|
||||
*vp != '\r' && k < 7) v[k++] = *vp++;
|
||||
v[k] = 0;
|
||||
int on = (!strcmp(v, "1") || !strcmp(v, "true") || !strcmp(v, "yes"));
|
||||
for (int i = 0; i < tmp.nroute; i++)
|
||||
if (!strcmp(tmp.routes[i].act, id)) { tmp.routes[i].fullscreen = on; break; }
|
||||
} else {
|
||||
int vl = 0; char chain[MEOW_CHAIN_MAX] = "";
|
||||
while (*vp && *vp != '"' && *vp != ',' && *vp != '\n' &&
|
||||
*vp != '\r' && vl < MEOW_CHAIN_MAX - 1)
|
||||
chain[vl++] = *vp++;
|
||||
chain[vl] = 0;
|
||||
while (vl > 0 && (chain[vl - 1] == ' ' || chain[vl - 1] == '\t'))
|
||||
chain[--vl] = 0;
|
||||
strncpy(tmp.routes[tmp.nroute].act, id, 15);
|
||||
tmp.routes[tmp.nroute].act[15] = 0; /* 显式收尾(原依赖 id 读长 ≤15) */
|
||||
strncpy(tmp.routes[tmp.nroute].chain, chain, MEOW_CHAIN_MAX - 1);
|
||||
tmp.nroute++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* awake.<id>=1(M2.17 keep_awake:该 activity 常亮,超时不自动息屏)。
|
||||
@@ -1881,6 +1914,29 @@ static void meow_parse_app_json(FILE *f, struct app *a)
|
||||
immersive = 1;
|
||||
}
|
||||
}
|
||||
/* fullscreen=true(app 级:注入 MEOW_FULLSCREEN=1,SDK 端 meow_ui_init 预先设全屏)。
|
||||
* 与 immersive 是两回事:fullscreen 隐藏状态栏/沉浸,immersive 关虚拟返回键。 */
|
||||
if (!fullscreen && strstr(buf, "fullscreen")) {
|
||||
char v[8] = "";
|
||||
if (json_str(buf, "fullscreen", v, sizeof v) > 0) {
|
||||
if (!strcmp(v, "true") || !strcmp(v, "1") || !strcmp(v, "yes"))
|
||||
fullscreen = 1;
|
||||
}
|
||||
}
|
||||
/* "fonts":<档>(字库档:0=默认4K常用 1=大字库GBK 2=Full;可选,缺省 0)。
|
||||
* launcher 注入 MEOW_FONT_TIER;大字库装载由后续 font 代理实现。 */
|
||||
if (!fonts_set && strstr(buf, "fonts")) {
|
||||
char v[8] = "";
|
||||
if (json_str(buf, "fonts", v, sizeof v) > 0) {
|
||||
if (!strcmp(v, "common") || !strcmp(v, "0")) fonts = 0;
|
||||
else if (!strcmp(v, "gbk") || !strcmp(v, "1")) fonts = 1;
|
||||
else if (!strcmp(v, "full") || !strcmp(v, "2")) fonts = 2;
|
||||
else fonts = atoi(v); /* 数字兜底(越界收敛到 [0,2]) */
|
||||
if (fonts < 0) fonts = 0;
|
||||
if (fonts > 2) fonts = 2;
|
||||
fonts_set = 1;
|
||||
}
|
||||
}
|
||||
/* service.<svc>=mode:restart:max:window_ms(M1 解析存储,保活 M4) */
|
||||
char *sp = strstr(buf, "service.");
|
||||
if (sp && tmp.nsvc < MEOW_MAX_SVCS) {
|
||||
@@ -1911,6 +1967,8 @@ static void meow_parse_app_json(FILE *f, struct app *a)
|
||||
strncpy(a->package, package, sizeof a->package - 1);
|
||||
a->framework = fram ? '1' : 0;
|
||||
a->immersive = immersive ? '1' : 0;
|
||||
a->fullscreen = fullscreen ? '1' : 0; /* 注入 MEOW_FULLSCREEN env */
|
||||
a->fonts = (char)(fonts < 0 ? 0 : (fonts > 2 ? 2 : fonts)); /* 注入 MEOW_FONT_TIER env */
|
||||
strncpy(a->icon, icon, 128);
|
||||
a->nroute = tmp.nroute;
|
||||
if (tmp.nroute) memcpy(a->routes, tmp.routes, sizeof(a->routes[0]) * (size_t)tmp.nroute);
|
||||
@@ -2263,6 +2321,19 @@ static void settings_sync_cache_listener(const char *key)
|
||||
else if (!strcmp(key, "power.forceoff_ms")) { int v; if (meow_settings_get_int("power.forceoff_ms", &v) == 0) power_forceoff_ms = v; }
|
||||
}
|
||||
|
||||
/* ---- 通知 dump 回调占位(通知#6 转储 TF 卡;接线/占位,不做 TF 写)----
|
||||
* meow_notif 在 TTL 到点(meow_notif_tick,§8 10s)调用此回调归档一条通知,随后释放槽。
|
||||
* 基座只把回调挂上来(见 settings_load 的 meow_notif_set_dump_cb);真实 TF 落盘
|
||||
* (按 NOTIFICATION_SYSTEM.md §8 / TF_CARD_LAYOUT.md 写 <卡>/MeowOS/notify/...)由后续
|
||||
* 通知代理在回调体内实现。注意 meow_notif.c 的 archive_one 自身已 log 一行 "dump: ...",
|
||||
* 故本回调保持轻量(避免重复刷屏),落盘逻辑填在下方 TODO 处。 */
|
||||
static void notif_dump_tf_placeholder(const meow_notif_t *n)
|
||||
{
|
||||
(void)n;
|
||||
/* TODO(通知代理, M2c):在此写 TF 卡 <MeowOS>/notify/<date>/<id>.json 等;
|
||||
* 基座不实现,仅保留挂接点(触发时机=meow_notif_tick 内 10s 到点/止机转储)。 */
|
||||
}
|
||||
|
||||
/* 启动加载(M2.11/M2.24):统一由 meow_settings 后端读 settings.conf;
|
||||
* 此处仅注册监听(一次性)+ 把 backend 当前值同步到缓存全局。重载(应用期
|
||||
* watchdog 可能改音量)等价于 meow_settings_init() + 手动同步。 */
|
||||
@@ -2271,6 +2342,7 @@ static void settings_load(void)
|
||||
{
|
||||
meow_settings_init(); /* 幂等:注册默认 + 读 settings.conf */
|
||||
meow_notif_init(); /* M2a:通知存储初始化(幂等,读 notify.* 配额) */
|
||||
meow_notif_set_dump_cb(notif_dump_tf_placeholder); /* 基座(通知#6):挂 dump 回调(TF 转储占位,M2c 落盘由后续代理实现) */
|
||||
if (!settings_cache_registered) {
|
||||
meow_settings_add_listener(settings_sync_cache_listener);
|
||||
settings_cache_registered = 1;
|
||||
@@ -6732,8 +6804,10 @@ static int launch_app(struct app *a)
|
||||
char env_app[MEOW_APP_ID_MAX + 16], env_lvl[48];
|
||||
char env_fpng[400], env_fidx[400], env_fapp[96];
|
||||
char env_mf[24];
|
||||
char env_tier[24];
|
||||
char env_fs[20];
|
||||
char env_cls[MEOW_FCLS_COUNT][2][400];
|
||||
char *envp[32]; /* PATH,HOME,log_dir,log_app,log_lvl,font 全局(3),多字体(1),class(≤12),data,cache */
|
||||
char *envp[40]; /* PATH,HOME,log_dir,log_app,log_lvl,font 全局(3),多字体(1),tier(1),class(≤12),fullscreen(1),data,cache */
|
||||
int ne = 0;
|
||||
const char *cp = getenv("PATH");
|
||||
snprintf(env_path, sizeof env_path, "PATH=%s", cp ? cp : "/usr/bin:/bin");
|
||||
@@ -6772,8 +6846,13 @@ static int launch_app(struct app *a)
|
||||
meow_settings_get_bool("display.multi_font", &mf_on);
|
||||
snprintf(env_mf, sizeof env_mf, "MEOW_MULTI_FONT=%d", mf_on ? 1 : 0);
|
||||
envp[ne++] = env_mf;
|
||||
have_global = (meow_font_effective_paths(fpng, sizeof fpng, fidx, sizeof fidx,
|
||||
fam, sizeof fam) == 0);
|
||||
/* M2.x(基座):字库档 MEOW_FONT_TIER=<0|1|2> —— 按 app.json "fonts" 声明注入;
|
||||
* 0=默认4K常用(未声明/缺省),1=大字库GBK,2=Full。SDK meow_ui_gfx 读入存档,
|
||||
* 真正按档装载大字库由后续 font 代理实现(见 meow_font_effective_paths_tiered)。 */
|
||||
snprintf(env_tier, sizeof env_tier, "MEOW_FONT_TIER=%d", a->fonts);
|
||||
envp[ne++] = env_tier;
|
||||
have_global = (meow_font_effective_paths_tiered(a->fonts, fpng, sizeof fpng,
|
||||
fidx, sizeof fidx, fam, sizeof fam) == 0);
|
||||
if (have_global) {
|
||||
snprintf(env_fpng, sizeof env_fpng, "MEOW_FONT_PNG=%s", fpng);
|
||||
snprintf(env_fidx, sizeof env_fidx, "MEOW_FONT_IDX=%s", fidx);
|
||||
@@ -6801,6 +6880,14 @@ static int launch_app(struct app *a)
|
||||
envp[ne++] = env_cls[c][1];
|
||||
}
|
||||
}
|
||||
/* 全屏声明:app.json "fullscreen"(app 级)→ 注入 MEOW_FULLSCREEN=1,SDK 端
|
||||
* meow_ui_init 据此预先设全屏。基座只接 app 级;活动级 route.<id>.fullscreen
|
||||
* (meow_route.fullscreen)在 M3 活动切换时由后续代理消费(此处暂不下发)。
|
||||
* 未声明则不注入(SDK 默认非全屏)。 */
|
||||
if (a->fullscreen) {
|
||||
snprintf(env_fs, sizeof env_fs, "MEOW_FULLSCREEN=1");
|
||||
envp[ne++] = env_fs;
|
||||
}
|
||||
char pkg[64];
|
||||
if (meow_pkg_name(a->exec, pkg, sizeof pkg) == 0) {
|
||||
snprintf(env_data, sizeof env_data, "MEOW_DATA_DIR=/usr/data/mnt/sd_0/MeowData/%s/data", pkg);
|
||||
|
||||
@@ -175,6 +175,24 @@ void meow_ui_set_fullscreen(int on);
|
||||
* 全屏/隐藏时返回 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 最小可用) */
|
||||
/* ============================================================ */
|
||||
@@ -309,6 +327,27 @@ int meow_notify_has_active(void); /* 1=尚有活动通知,0=无 *
|
||||
const char *meow_notify_urgency_str(meow_notify_urgency u);
|
||||
const char *meow_notify_category_str(meow_notify_category cat);
|
||||
|
||||
/* ============================================================ */
|
||||
/* §10 字体分层 / 大字库(草案/待定案 —— 本批仅加声明/枚举/宏,不实现) */
|
||||
/* ============================================================ */
|
||||
/* 字体「档位」概念: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 域代理据此在 meow_font.c / gen_font.py 实现大字库生成与按档装载。
|
||||
* 既有 meow_font_* 符号(class_of/has_glyph/load_slot/config_multifont…)保留不动;
|
||||
* 大字库装载以 set_tier/tier 作为入口,或由后续代理按 meow_font_config_multifont 扩展。 */
|
||||
#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 定义(只存档 + 触发重载请求);真正按档装载大字库由后续 font 代理实现。 */
|
||||
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
|
||||
|
||||
+127
-5
@@ -63,6 +63,24 @@ static int g_dirty_full = 1;
|
||||
|
||||
static char *g_dump_path = NULL;
|
||||
|
||||
/* ---- 状态栏「上收出屏只留提示线」(collapsed,基座)----
|
||||
* g_sbar_collapsed = 目标态(1=上收);g_sbar_collapse_h = 当前实际上收偏移
|
||||
* (0..MUI_SBAR_H:0=完全展开,MUI_SBAR_H=内容全部上移出屏、仅留提示线)。
|
||||
* 基座让 meow_ui_statusbar_set_collapsed(on) 立即生效(true→只画提示线/内容上移);
|
||||
* 过渡(每帧插值)留待后续代理或经 meow_ui_statusbar_animate(ms) 启用的简易线性逼近。 */
|
||||
#define MUI_SBAR_HINT_H 6 /* 上收状态下顶部提示线高(px) */
|
||||
static int g_sbar_collapsed = 0; /* 目标:1=上收 */
|
||||
static int g_sbar_collapse_h = 0; /* 当前上收偏移(0..MUI_SBAR_H) */
|
||||
static int g_sbar_collapse_anim_ms = 0; /* 过渡时长(0=瞬切);meow_ui_statusbar_animate 设置 */
|
||||
static int g_sbar_collapse_from_h = 0; /* 本次过渡起点偏移 */
|
||||
static unsigned long long g_sbar_collapse_start_ms = 0; /* 本次过渡起始(monotonic ms) */
|
||||
|
||||
/* ---- 字体档位(MEOW_FONT_TIER,基座存档 + 公共 get/set)----
|
||||
* launcher 按 app.json "fonts":<档> 注入 MEOW_FONT_TIER=<0|1|2>;SDK 读入并以
|
||||
* meow_font_set_tier/tier 暴露。真正按档装载大字库(GBK/Full)由后续 font 代理在
|
||||
* meow_font.c / meow_gfx_load_multifont 挂钩实现——此处仅记录档位不换库。 */
|
||||
static int g_font_tier = MEOW_FONT_TIER_COMMON;
|
||||
|
||||
/* ---- 帧率调度(A-1/A-2:从 launcher M2.16 迁入,刷新率调度归口 SDK)----
|
||||
* meow_ui_flush()/present() 的 fps 档位与自适应降档 governor。launcher 不再自带
|
||||
* 一套帧率门控;launcher 与 app 统一走这里 → 全局观感/刷新率一致。
|
||||
@@ -499,6 +517,71 @@ static void dump_ppm(void)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* ================= 状态栏「上收出屏只留提示线」(collapsed,基座) ================= */
|
||||
/* 每帧推进上收/恢复:向目标偏移(collapsed→MUI_SBAR_H、否则→0)线性逼近;
|
||||
* 无过渡时长(g_sbar_collapse_anim_ms<=0)= 一步到位(基座默认)。动画插值骨架在此,
|
||||
* 后续代理可换缓动/每帧步进。 */
|
||||
static void statusbar_collapse_step(void)
|
||||
{
|
||||
int tgt = g_sbar_collapsed ? MUI_SBAR_H : 0;
|
||||
if (g_sbar_collapse_h == tgt) return;
|
||||
if (g_sbar_collapse_anim_ms <= 0) { g_sbar_collapse_h = tgt; return; }
|
||||
unsigned long long now = now_ms();
|
||||
unsigned long long el = now - g_sbar_collapse_start_ms;
|
||||
int span = g_sbar_collapse_anim_ms;
|
||||
if ((int)el >= span) { g_sbar_collapse_h = tgt; return; }
|
||||
int delta = tgt - g_sbar_collapse_from_h;
|
||||
g_sbar_collapse_h = g_sbar_collapse_from_h +
|
||||
(int)((long long)delta * (long long)el / (long long)span);
|
||||
}
|
||||
|
||||
/* 上收中是否需要逐帧重画(动画未达目标位置时置位,强制每帧推进)。 */
|
||||
static int statusbar_collapse_in_transition(void)
|
||||
{
|
||||
int tgt = g_sbar_collapsed ? MUI_SBAR_H : 0;
|
||||
return g_sbar_collapse_h != tgt;
|
||||
}
|
||||
|
||||
/* 上收状态栏:内容整体上移出屏(不画时钟/电量),仅在顶部画一条「提示线」。
|
||||
* 与 meow_ui_swipe_hint(左滑返回进度条,5px,动态)不同:此线是「状态栏可下拉还原」的
|
||||
* 常驻提示(主题强调色下边缘)。原状态栏整块清回主题背景,避免残影(app inset 之内)。 */
|
||||
static void statusbar_collapsed_render(int h)
|
||||
{
|
||||
(void)h;
|
||||
const meow_theme *th = meow_theme_get();
|
||||
int w = meow_ui_width();
|
||||
/* h 越大内容越贴顶;基座:折叠态整块清底 + 顶部提示线(提示线下缘=主题 accent) */
|
||||
meow_ui_fill_rect(0, 0, w, MUI_SBAR_H, th->bg);
|
||||
meow_ui_fill_rect(0, MUI_SBAR_HINT_H - 1, w, 1, th->accent);
|
||||
}
|
||||
|
||||
/* ---- 公共 API(基座实现;动画插值骨架见 statusbar_collapse_step)---- */
|
||||
void meow_ui_statusbar_set_collapsed(int on)
|
||||
{
|
||||
int tgt = on ? 1 : 0;
|
||||
if (tgt == g_sbar_collapsed) return;
|
||||
g_sbar_collapsed = tgt;
|
||||
g_sbar_collapse_from_h = g_sbar_collapse_h;
|
||||
g_sbar_collapse_start_ms = now_ms();
|
||||
dirty_full(); /* 顶栏显隐/上收变化 → 全帧重画 */
|
||||
}
|
||||
|
||||
int meow_ui_statusbar_collapsed(void) { return g_sbar_collapsed; }
|
||||
|
||||
void meow_ui_statusbar_animate(int ms)
|
||||
{
|
||||
g_sbar_collapse_anim_ms = (ms > 0) ? ms : 0; /* 0=瞬切(基座默认) */
|
||||
}
|
||||
|
||||
int meow_ui_statusbar_hotzone(void)
|
||||
{
|
||||
/* 非全屏=整条状态栏可视;全屏时缩小到 MEOW_SBAR_HOTZONE_FS(保留一处下拉入口)。
|
||||
* 上收(collapsed、非全屏)时热区=提示线下缘高度。全屏态由 meow_ui_sys 维护。 */
|
||||
if (meow_ui_sys_statusbar_active())
|
||||
return g_sbar_collapsed ? MUI_SBAR_HINT_H : MUI_SBAR_H;
|
||||
return MEOW_SBAR_HOTZONE_FS;
|
||||
}
|
||||
|
||||
/* 顶部状态栏条是否被本次脏区触及(含整帧):触及或数据已变(force)才需要重画顶条。 */
|
||||
static int statusbar_touched(void)
|
||||
{
|
||||
@@ -519,13 +602,20 @@ static void present(void)
|
||||
if (!g_refresh_always_max) {
|
||||
if (g_last_present_ms && now - g_last_present_ms < (unsigned long long)period) return;
|
||||
}
|
||||
/* 全局状态栏(A-0):上屏前把状态栏画进 back_buf 顶部 MUI_SBAR_H 行(z 最顶)。
|
||||
/* 全局状态栏(A-0)+ 上收(collapsed)基座:上屏前把状态栏画进 back_buf 顶部 MUI_SBAR_H 行。
|
||||
* 全屏/隐藏时 active()==0 不画(沉浸),app 内容可占满整屏。触发条件:
|
||||
* 数据已变(1s 轻刷/显隐切换) 或 顶条被 app 内容触及(含整帧清+绘,未 inset 时被顶条覆盖)。
|
||||
* 无需每帧重画——app 局部刷新不触及顶条时,back_buf/screen 顶条保持不变,省一次 blit。 */
|
||||
* 数据已变(1s 轻刷/显隐切换) / 顶条被 app 内容触及 / 上收动画未到位(逐帧推进)。
|
||||
* 展开态仍走 meow_ui_sys_statusbar_render()(meow_ui_sys.c 不改,留给后续代理);
|
||||
* 上收折叠态(collapse_h>=MUI_SBAR_H)由基座只画提示线(内容上移出屏)。 */
|
||||
if (meow_ui_sys_statusbar_active() &&
|
||||
(meow_ui_sys_statusbar_force() || statusbar_touched()))
|
||||
meow_ui_sys_statusbar_render();
|
||||
(meow_ui_sys_statusbar_force() || statusbar_touched() ||
|
||||
statusbar_collapse_in_transition())) {
|
||||
statusbar_collapse_step();
|
||||
if (g_sbar_collapse_h >= MUI_SBAR_H)
|
||||
statusbar_collapsed_render(g_sbar_collapse_h);
|
||||
else
|
||||
meow_ui_sys_statusbar_render();
|
||||
}
|
||||
if (g_fb_mem) {
|
||||
ioctl(g_fb_fd, FBIO_WAITFORVSYNC, 0); /* 等垂直同步 */
|
||||
unsigned long long tbg = now_ms();
|
||||
@@ -575,6 +665,23 @@ unsigned long long meow_ui_frames_presented(void) { return g_frames_presented; }
|
||||
int meow_gfx_is_device(void) { return g_fb_mem != NULL; }
|
||||
int meow_gfx_mfont_ready(void) { return g_mfont_ready; }
|
||||
|
||||
/* ---- 字体档位(公共 API,基座定义)----
|
||||
* 注意:meow_font_tier()/meow_font_set_tier() 已在 meow_ui_gfx.c 定义(符号唯一),
|
||||
* 后续 font 代理勿在 meow_font.c 重复定义;可在 meow_font.c 实现「按档装载大字库」并在
|
||||
* meow_font_set_tier 的钩子处唤起(见下)。 */
|
||||
int meow_font_tier(void) { return g_font_tier; }
|
||||
|
||||
int meow_font_set_tier(int tier)
|
||||
{
|
||||
if (tier < MEOW_FONT_TIER_COMMON) tier = MEOW_FONT_TIER_COMMON;
|
||||
if (tier > MEOW_FONT_TIER_FULL) tier = MEOW_FONT_TIER_FULL;
|
||||
if (tier == g_font_tier) return g_font_tier;
|
||||
g_font_tier = tier;
|
||||
/* TBD(基座):真正按档装载大字库(meow_font_load_tier 或 config_multifont 扩展)由
|
||||
* 后续 font 代理在 meow_font.c 实现;此处仅记录档位 + 标记重载(下一轮 load 读 tier)。 */
|
||||
return g_font_tier;
|
||||
}
|
||||
|
||||
/* ================= 初始化/销毁 ================= */
|
||||
/* 字库加载优先级(M2.x):
|
||||
* 1) 环境变量 MEOW_FONT_PNG/MEOW_FONT_IDX(launcher 注入的「当前生效字体」= 系统 font.file)
|
||||
@@ -584,6 +691,16 @@ int meow_gfx_mfont_ready(void) { return g_mfont_ready; }
|
||||
* 全失败 → g_mfont_ready=0,text_draw 回退 5x7 点阵(系统不死)。 */
|
||||
static int load_font(void)
|
||||
{
|
||||
/* 字体档位(MEOW_FONT_TIER env,由 launcher 按 app.json "fonts" 注入):
|
||||
* 0=默认4K常用 1=大字库GBK 2=Full。基座只读入存档 + 对齐公共 get/set;
|
||||
* 真正按档装载大字库(GBK/Full 的字库路径/面)由后续 font 代理在 meow_font.c /
|
||||
* meow_gfx_load_multifont 挂钩实现——此处仍先装载默认(tier0)字库,档位仅记录。 */
|
||||
const char *etr = getenv("MEOW_FONT_TIER");
|
||||
if (etr && etr[0]) {
|
||||
g_font_tier = atoi(etr);
|
||||
if (g_font_tier < MEOW_FONT_TIER_COMMON) g_font_tier = MEOW_FONT_TIER_COMMON;
|
||||
if (g_font_tier > MEOW_FONT_TIER_FULL) g_font_tier = MEOW_FONT_TIER_FULL;
|
||||
}
|
||||
const char *ep = getenv("MEOW_FONT_PNG");
|
||||
const char *ei = getenv("MEOW_FONT_IDX");
|
||||
if (ep && ep[0] && ei && ei[0] && meow_font_load(ep, ei) == 0) return 1;
|
||||
@@ -677,6 +794,11 @@ int meow_ui_init(const meow_ui_opts *opts)
|
||||
g_init_ok = 1;
|
||||
dirty_full();
|
||||
meow_ui_sys_init(); /* A-0:系统状态读取器首刷(电量/WiFi/蓝牙/音量),状态栏就绪 */
|
||||
/* 全屏预置(基座):launcher 按 app.json "fullscreen" 注入 MEOW_FULLSCREEN=1,SDK 据此
|
||||
* 预先设全屏(隐藏整条状态栏/沉浸,statusbar_active()==0、statusbar_height()==0)。
|
||||
* 未注入/非"1"=非全屏(默认)。放在 sys_init 后使首帧即为全屏态。 */
|
||||
const char *efs = getenv("MEOW_FULLSCREEN");
|
||||
if (efs && efs[0] == '1') meow_ui_set_fullscreen(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user