diff --git a/meow_ui.h b/meow_ui.h index bc17e86..298e379 100644 --- a/meow_ui.h +++ b/meow_ui.h @@ -328,22 +328,24 @@ const char *meow_notify_urgency_str(meow_notify_urgency u); const char *meow_notify_category_str(meow_notify_category cat); /* ============================================================ */ -/* §10 字体分层 / 大字库(草案/待定案 —— 本批仅加声明/枚举/宏,不实现) */ +/* §10 字体分层 / 大字库(M2.5x:基座声明 + font 域已实现按档装载) */ /* ============================================================ */ /* 字体「档位」概念:launcher 按 app.json 声明的字库档("fonts":<档>)向 app 注入 - * MEOW_FONT_TIER=<0|1|2>;SDK(meow_ui_gfx / 后续 meow_font 大字库加载)据档选库: + * 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 扩展。 */ + * 大字库生成由 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 定义(只存档 + 触发重载请求);真正按档装载大字库由后续 font 代理实现。 */ + * 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); diff --git a/meow_ui_gfx.c b/meow_ui_gfx.c index c429599..d6a9798 100644 --- a/meow_ui_gfx.c +++ b/meow_ui_gfx.c @@ -77,8 +77,8 @@ static unsigned long long g_sbar_collapse_start_ms = 0; /* 本次过渡起始 /* ---- 字体档位(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 挂钩实现——此处仅记录档位不换库。 */ + * meow_font_set_tier/tier 暴露。按档装载大字库(GBK/Full)由 meow_font_reload_tier() + * 在 meow_font.c 实现;meow_font_set_tier() 在档位变化时经 env/settings 路由到该钩子真重载。 */ static int g_font_tier = MEOW_FONT_TIER_COMMON; /* ---- 帧率调度(A-1/A-2:从 launcher M2.16 迁入,刷新率调度归口 SDK)---- @@ -665,20 +665,32 @@ 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 的钩子处唤起(见下)。 */ +/* ---- 字体档位(公共 API,基座定义 + font 域真重载钩子)---- + * meow_font_tier()/meow_font_set_tier() 在 meow_ui_gfx.c 定义(符号唯一),font 代理勿在 + * meow_font.c 重复定义;大字库按档装载由 meow_font.c meow_font_reload_tier() 实现,并在 + * meow_font_set_tier() 处唤起(见下)。 */ int meow_font_tier(void) { return g_font_tier; } int meow_font_set_tier(int tier) { + int old = g_font_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)。 */ + /* 真重载(font 域钩子,M2.5x):按档装载大字库。launcher 已按档解析并注入 + * MEOW_FONT_PNG/IDX(tier>0 → GBK/Full 大字库绝对路径);重读 env 重载。 + * 无 env/失败 → 回退卡默认 MeowOS/fonts/default → 固件。 + * 大字库 atlas 大(GBK≈5-15MB+),meow_font_reload_tier 先 unload 旧再 load 新,防双驻留。 */ + const char *ep = getenv("MEOW_FONT_PNG"); + const char *ei = getenv("MEOW_FONT_IDX"); + if (ep && ep[0] && ei && ei[0] && meow_font_reload_tier(tier, ep, ei) == 0) + return g_font_tier; + if (meow_font_reload_tier(tier, MEOW_FONT_PNG_CARD, MEOW_FONT_IDX_CARD) == 0) + return g_font_tier; + if (meow_font_reload_tier(tier, MEOW_FONT_PNG_SYS, MEOW_FONT_IDX_SYS) == 0) + return g_font_tier; + g_font_tier = old; /* 全部失败 → 回退旧档(字库可能已不可用,5x7 点阵兜底,系统不死) */ return g_font_tier; } @@ -692,9 +704,9 @@ int meow_font_set_tier(int tier) 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)字库,档位仅记录。 */ + * 0=默认4K常用 1=大字库GBK 2=Full。launcher 已按档解析大字库路径并经 MEOW_FONT_PNG/IDX + * 注入(见 meow_font_effective_paths_tiered),故下方 meow_font_load(ep,ei) 即装载 + * 对应档位字库(tier>0 → GBK/Full 大字库);此处 read env 存档对齐公共 get/set。 */ const char *etr = getenv("MEOW_FONT_TIER"); if (etr && etr[0]) { g_font_tier = atoi(etr); diff --git a/meow_ui_input.c b/meow_ui_input.c index fed0fc6..7a155d2 100644 --- a/meow_ui_input.c +++ b/meow_ui_input.c @@ -38,6 +38,20 @@ #define QUEUE_N 128 #define MAX_DEVS 8 +/* ── 内部事件:系统级「下拉展开通知中心」(M2.5x 接线)── + * 触摸状态机在抬手判定处识别「SWIPE_DOWN 起始于顶部热区」后压入;事件循环按系统手势处理 + * (路由 meow_ui_sys_notif_pull),不下发给 APP 的 on_swipe(顶部热区为系统保留手势)。 + * 与左缘返回(SWIPE_LEFT)/ meow_ui_swipe_hint 互不影响——后者仍全屏生效,详见下方触摸机。 */ +#define MEOW_EV_NOTIF_PULL 5 + +/* 顶部下滑 → 通知中心判定:纵向 DOWN 手势的起点(origin_y)是否落在顶部热区内。 + * 热区由 meow_ui_statusbar_hotzone() 给出(非全屏=状态栏高、全屏=MEOW_SBAR_HOTZONE_FS、 + * 收合=提示线高)。供宿主单测直调(判据与触摸状态机共用)。 */ +int meow_ui_input_is_notif_pull(int origin_y, int hotzone) +{ + return origin_y >= 0 && origin_y < hotzone; +} + static int g_thread_started = 0; static pthread_t g_thread; static volatile int g_thread_run = 1; @@ -165,7 +179,14 @@ static void touch_release(void) } } else { int dir = mdy > 0 ? MEOW_SWIPE_DOWN : MEOW_SWIPE_UP; - push_ev(MEOW_EV_SWIPE, dir, ady > adx ? ady : adx); + /* 顶部下滑 → 通知中心(系统手势,不下发 APP):起点在顶部热区内才认。 + * 热区高度随状态变化(非全屏=整条状态栏、全屏=MEOW_SBAR_HOTZONE_FS 缩小、 + * 收合=提示线高)——全屏 app 只在顶部极窄热区被系统占用,故「不影响全屏 app」。 */ + if (dir == MEOW_SWIPE_DOWN && + meow_ui_input_is_notif_pull(t_dy, meow_ui_statusbar_hotzone())) + push_ev(MEOW_EV_NOTIF_PULL, t_dy, ady > adx ? ady : adx); + else + push_ev(MEOW_EV_SWIPE, dir, ady > adx ? ady : adx); } } else { push_ev(MEOW_EV_TAP, t_cx, t_cy); @@ -287,6 +308,11 @@ void meow_ui_run(const meow_ui_events *ev) } else if (e.a == MEOW_SWIPE_LEFT && sb_active) { meow_ui_request_exit(); } + } else if (e.type == MEOW_EV_NOTIF_PULL) { + if (in_startup) continue; /* 启动窗口顶区误触残留:丢弃,防进入即开通知中心 */ + /* 系统级「下拉展开通知中心」:起始于顶部热区的下滑为系统保留手势,不下发 + * APP on_swipe;路由到系统钩子(当前为记录占位,通知中心 UI 为后续里程碑)。 */ + meow_ui_sys_notif_pull(); } else if (e.type == MEOW_EV_SWIPE_PROGRESS) { if (in_startup) continue; /* 启动窗口进度条静音 */ int x0 = e.a, xc = e.b, dx = xc - x0; /* dx=当前X-按下X */ diff --git a/meow_ui_sys.c b/meow_ui_sys.c index c271f5e..e21900e 100644 --- a/meow_ui_sys.c +++ b/meow_ui_sys.c @@ -156,18 +156,31 @@ void meow_ui_set_fullscreen(int on) int meow_ui_statusbar_height(void) { - return meow_ui_sys_statusbar_active() ? MUI_SBAR_H : 0; + if (!meow_ui_sys_statusbar_active()) return 0; + return meow_ui_statusbar_collapsed() ? MUI_SBAR_COLLAPSE_H : MUI_SBAR_H; } /* ---- 内部(gfx/input 用) ---- */ int meow_ui_sys_statusbar_active(void) { - return g_statusbar_on && !g_fullscreen; + /* collapsed 视为状态栏仍激活(只留提示线):与 fullscreen 并存(全屏启 collapsed)—— + * 这样 gfx.c present() 的收合动画块会运行(驱动 g_sbar_collapse_h 插值),且顶部提示线 + * 正常绘制/热区可用。fullscreen 且不 collapsed → 整条隐藏(沉浸,inset=0),保持既有语义。 */ + return g_statusbar_on && (meow_ui_statusbar_collapsed() || !g_fullscreen); } int meow_ui_sys_statusbar_height(void) { - return meow_ui_sys_statusbar_active() ? MUI_SBAR_H : 0; + if (!meow_ui_sys_statusbar_active()) return 0; + return meow_ui_statusbar_collapsed() ? MUI_SBAR_COLLAPSE_H : MUI_SBAR_H; +} + +void meow_ui_sys_notif_pull(void) +{ + /* 系统级「下拉展开通知中心」手势接线(M2.5x):输入层识别出「起始于顶部热区的 + * SWIPE_DOWN」后路由到此。通知中心 UI 为后续里程碑——此处先落记录(避免哑无痕); + * 届时由对应代理在该入口挂真实展开逻辑(IPC SHOW_ACTIVITY / 覆盖层渲染)。 */ + meow_log(MEOW_LOG_WARN, "notif_pull: notification center TBD (wired)"); } int meow_ui_sys_statusbar_force(void) diff --git a/meow_ui_sys.h b/meow_ui_sys.h index 8caeb68..de80a7d 100644 --- a/meow_ui_sys.h +++ b/meow_ui_sys.h @@ -34,6 +34,13 @@ typedef struct meow_sys_state { #define MUI_SBAR_H 28 #define MUI_SBAR_FONT 20 +/* 收合(collapsed)状态下状态栏的有效加载高度(inset)= 顶部提示线高度(px)。 + * 收合=状态栏内容上移出屏、只留一条提示线:app 内容据此上移(非满 28), + * 形成「不完全沉浸(留提示线)」;与 fullscreen(整条隐藏、inset0)区别。 + * 取值沿用公共宏 MEOW_SBAR_HOTZONE_FS(=4,全屏时顶部热区/提示线的缩后高度), + * 具体绘制高度(gfx.c 的 MUI_SBAR_HINT_H=6)在渲染端,这里按提示线高度口径即可。 */ +#define MUI_SBAR_COLLAPSE_H MEOW_SBAR_HOTZONE_FS + /* 首次全量读取;失败仍返回 0(字段置 -1/0)。 */ int meow_ui_sys_init(void); @@ -43,12 +50,21 @@ void meow_ui_sys_refresh(void); /* 当前快照(内部只读)。 */ const meow_sys_state *meow_ui_sys_get(void); -/* 状态栏是否应绘制(= set_statusbar(1) 且 非 fullscreen)。 */ +/* 状态栏是否应绘制(= set_statusbar(1) 且 非 fullscreen),收合(collapsed)兼容: + * collapsed 视为状态栏仍在(只留提示线),故 collapsed 时即使 fullscreen 也返回 1, + * 让渲染端/输入层继续驱动上收动画与提示线;fullscreen 且不 collapsed → 0(整条隐藏, + * 沉浸,保持既有语义)。 */ int meow_ui_sys_statusbar_active(void); -/* 状态栏高度(px):active 时 28,否则 0(供 meow_ui_statusbar_height 用)。 */ +/* 状态栏有效高度(px,供 inset/提示条定位):active 时 28;collapsed 时=提示线高度 + * MUI_SBAR_COLLAPSE_H(非满 28,app 内容可上移);否则 0(供 meow_ui_statusbar_height 用)。 */ int meow_ui_sys_statusbar_height(void); +/* 系统级「下拉展开通知中心」手势挂钩(M2.5x 接线):输入层识别出「起始于顶部热区的 + * SWIPE_DOWN」后路由到这里。通知中心 UI 为后续里程碑,此入口作记录/占位;届时由对应 + * 代理在此挂真实展开逻辑(IPC SHOW_ACTIVITY / 覆盖层渲染)。 */ +void meow_ui_sys_notif_pull(void); + /* 自上次渲染后状态栏数据是否已变(1s 轻刷/显隐切换置位);读取即清除。 * 渲染后端 present() 用它决定是否重画顶部条(配合脏区/整帧判断)。 */ int meow_ui_sys_statusbar_force(void);