diff --git a/meow_ui.h b/meow_ui.h index 3614006..e7372c3 100644 --- a/meow_ui.h +++ b/meow_ui.h @@ -333,6 +333,41 @@ 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); +/* ============================================================ */ +/* §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 域已实现按档装载) */ /* ============================================================ */ diff --git a/meow_ui_gfx.c b/meow_ui_gfx.c index 082d937..e26f796 100644 --- a/meow_ui_gfx.c +++ b/meow_ui_gfx.c @@ -361,19 +361,22 @@ void meow_ui_swipe_hint(int x) * 有状态栏(非全屏)→ y = 状态栏高度;收合(collapsed)→ y=提示线下缘 * (MUI_SBAR_COLLAPSE_H,与提示线不重叠);无状态栏(全屏/隐藏)→ y=0。 */ int hy = meow_ui_statusbar_height(); - /* x<0 视为清空(条长 0);条长上限=屏宽。 */ - if (x < 0) x = 0; - if (x > g_xres) x = g_xres; - /* 只按「新旧长度的差」增量绘制,避免整段重涂背景色: - * - 伸长:仅补画新增段(旧段已是 accent,不再用 bg 重涂——否则 app 底色≠theme bg - * 时会在旧段留下 bg 色块,就是残留残条); - * - 回缩/清空:仅把「超出新长度」的尾部填回背景色(实时回缩)。 */ - if (x > g_hint_last) { - meow_ui_fill_rect(g_hint_last, hy, x - g_hint_last, MUI_HINT_H, th->accent); - } else if (x < g_hint_last) { - meow_ui_fill_rect(x, hy, g_hint_last - x, MUI_HINT_H, th->bg); + /* 单一实现(与非全屏 Hello 完全一致,全屏仅 hy 不同):grow 画 0..x、shrunk 先清旧长 + * 再画 0..x、x<=0 清空。x<0 视为清空;条长上限=屏宽。 */ + if (x > 0) { + if (x > g_xres) x = g_xres; + /* 往回滑(新长度 < 上次)时,先清掉「上次画到旧长度、但本次超出的部分」, + * 否则条只增不减(右滑变长、左滑回缩实时可见)。 */ + if (g_hint_last > x) meow_ui_fill_rect(0, hy, g_hint_last, MUI_HINT_H, th->bg); + /* 条色取主题前景(fg):fg 定义为与背景对比,能同时覆盖「非全屏(底=主题bg)」与 + * 「全屏 Hello 类(底=主题accent)」两种情况——accent 在 Hello 全屏 accent 底上同色不可见。 */ + meow_ui_fill_rect(0, hy, x, MUI_HINT_H, th->fg); + g_hint_last = x; + } else if (g_hint_last > 0) { + /* 手指回原点/抬手未达标/抬手达标:清掉此前画的条(填回背景色) */ + meow_ui_fill_rect(0, hy, g_hint_last, MUI_HINT_H, th->bg); + g_hint_last = 0; } - g_hint_last = x; /* 不发 flush:由调用方 meow_ui_flush_region(0,0,宽,6) 只刷顶部条 */ } diff --git a/meow_ui_input.c b/meow_ui_input.c index c964f8c..1f27d2d 100644 --- a/meow_ui_input.c +++ b/meow_ui_input.c @@ -125,7 +125,6 @@ static int t_press_valid = 0; /* BTN_TOUCH=1 已见(本次按下的 gate static int t_dx = 0, t_dy = 0; /* 按下原点(BTN_TOUCH 后首个有效 ABS 锁定) */ static int t_cx = 0, t_cy = 0; /* 当前坐标(-1=本次尚未见到有效坐标) */ static int t_origin_valid = 0; /* 原点是否已锁定 */ -static int t_gmax_dx = 0; /* 本手势「最大右移位移」(t_cx-t_dx 的最大值,条长上限) */ /* 按下边沿:只标记按下,绝不用传入坐标立即锁原点(避免用上一手势残留坐标当原点)。 * t_cx/t_cy 归 -1 —— 本次手势以「无坐标」起步,只接受随后到来的有效 ABS。 */ @@ -137,7 +136,6 @@ static void touch_press(int x, int y) t_origin_valid = 0; t_cx = -1; t_cy = -1; t_dx = 0; t_dy = 0; - t_gmax_dx = 0; /* 新手势:最大右移位移清零(条长从 0 计) */ } /* 由 ABS_X/ABS_Y 驱动:若本次按下且原点未锁且坐标有效 → 锁原点;再更新当前坐标。 */ static void touch_update(int x, int y) @@ -147,17 +145,13 @@ static void touch_update(int x, int y) } if (x >= 0) t_cx = x; if (y >= 0) t_cy = y; - if (t_down && t_origin_valid) { - int dx = t_cx - t_dx; - if (dx > t_gmax_dx) t_gmax_dx = dx; /* 记录本手势已达的最大右移位移(条长上限) */ - } } static void touch_release(void) { if (!t_down) return; t_down = 0; t_press_valid = 0; /* 本次按下从未锁到有效坐标(幽灵触摸/坐标未就绪):丢弃,且清空全部轨迹。 */ - if (!t_origin_valid) { t_cx = t_cy = -1; t_dx = t_dy = 0; t_gmax_dx = 0; return; } + if (!t_origin_valid) { t_cx = t_cy = -1; t_dx = t_dy = 0; return; } t_origin_valid = 0; int mdx = t_cx - t_dx, mdy = t_cy - t_dy; int adx = mdx < 0 ? -mdx : mdx, ady = mdy < 0 ? -mdy : mdy; @@ -169,8 +163,7 @@ static void touch_release(void) * 被手势级清空,绝不继承上一手势坐标,确保: * ① 中部右滑不会误判成左缘返回(t_dx>=EDGE_W); * ② 先点中部再侧滑不返回(原点锁定在中部,>=EDGE_W),符合「必须从左缘起划」; - * ③ 返回判定要求右移严格正向(t_cx-t_dx>=0 且 ≥SWIPE_THRESH),杜绝「向左划也误返回」; - * 左划过程仅让进度条实时回缩,不额外生长(过程见上方 MEOW_EV_SWIPE_PROGRESS)。 + * ③ 右移严格正向(t_cx-t_dx>=0),杜绝「向左划也出条/误返回」。 * SDK 统一上报为 MEOW_SWIPE_LEFT(设计"左滑=返回"契约,hello 用 on_swipe(LEFT) 退出)。 * * 屏幕中部滑动不是返回手势:中部右滑→RIGHT(内容导航),中部左滑→非返回(落 TAP, @@ -199,7 +192,7 @@ static void touch_release(void) push_ev(MEOW_EV_TAP, t_cx, t_cy); } /* 手势级干净起点:清空全部轨迹,下一手势从零开始,杜绝污染无自愈。 */ - t_cx = t_cy = -1; t_dx = t_dy = 0; t_gmax_dx = 0; + t_cx = t_cy = -1; t_dx = t_dy = 0; } /* ---- 输入线程:poll 所有 event 设备 + 解析 ---- */ @@ -231,22 +224,14 @@ static void *input_thread(void *arg) if (code == ABS_X || code == ABS_MT_POSITION_X) { if (t_down) touch_update(val, t_cy); /* 锁原点+更新当前(t_down 时才驱动) */ else t_cx = val; - /* 左滑进度实时上报(视觉条)。抬手触发仍由 touch_release 判定;这里只报过程。 - * 修复要点(左缘返回滑条 bug): - * ① 双向上报(不再要求 t_cx>t_dx):向右→条伸长、向左→条实时回缩, - * 摒弃「只在返回瞬间闪末帧 / 反向才出条」; - * ② 仅左缘起手(t_dx= 0 && t_dx < EDGE_W) { - int dx = t_cx - t_dx; - if (dx > t_gmax_dx) t_gmax_dx = dx; - int len = dx < 0 ? 0 : dx; - if (len > t_gmax_dx) len = t_gmax_dx; - push_ev(MEOW_EV_SWIPE_PROGRESS, t_dx, len); - } + /* 左滑进度实时上报(视觉条):原点确实在左缘(t_dxt_dx)——grow/回缩全程由「非全屏已验证的同一条路径」驱动,全屏仅 + * 垂直位置 hy 不同(hy=meow_ui_statusbar_height()),别无全屏特判。 + * 抬手触发仍由 touch_release 判定;这里只报过程(事件载荷 b=当前X)。 + * t_dx 是本次按下后首个有效 ABS 锁定的真实按下点(非残留),且每次抬手已 + * 清空,杜绝「中部点一下出条 / 向左划也出条」。 */ + if (t_down && t_origin_valid && t_dx >= 0 && t_dx < EDGE_W && t_cx > t_dx) + push_ev(MEOW_EV_SWIPE_PROGRESS, t_dx, t_cx); } else if (code == ABS_Y || code == ABS_MT_POSITION_Y) { if (t_down) touch_update(t_cx, val); else t_cy = val; @@ -335,17 +320,17 @@ void meow_ui_run(const meow_ui_events *ev) meow_ui_sys_notif_pull(); } else if (e.type == MEOW_EV_SWIPE_PROGRESS) { if (in_startup) continue; /* 启动窗口进度条静音 */ - /* e.a=按下X(t_dx),e.b=条长 len(输入层已 clamp 到「本手势最大右移位移」且≥0)。 - * SDK 自动画顶部条:从 x=0 画到 len(右移位移),向右伸长、向左实时回缩。 - * M2.5x/A-13:全屏/收合下「左缘返回手势保留」,顶部动态提示条仍需绘制——不再以 - * meow_ui_sys_statusbar_active()(全屏/隐藏=0)开关,否则全屏时滑条完全不显示。 - * 条位 y=meow_ui_statusbar_height():非全屏=状态栏下沿、全屏=0、收合=提示线下缘 - * (MUI_SBAR_COLLAPSE_H),与提示线不重叠加。APP 若注册 on_swipe_progress 仍可自绘 - * (系统条照常画);递交给 app 的是 (len-x_start) 使 x_start+dx==len,与系统条同长。 */ - int len = e.b; - meow_ui_swipe_hint(len); + int x0 = e.a, xc = e.b, dx = xc - x0; /* dx=当前X-按下X */ + /* SDK 自动画顶部条:长度=手指当前 X(=距左缘距离,向内划长度随位移增长)。 + * 全屏/收合下「左缘返回手势保留」,顶部动态提示条(meow_ui_swipe_hint)照常绘制 + * (与 agent-108:不再以 meow_ui_sys_statusbar_active()(全屏/隐藏=0)开关,否则 + * 全屏时滑条完全不显示)。条位 y=meow_ui_statusbar_height():非全屏=状态栏下沿 + * (28)、全屏=顶部、收合=提示线下缘(MUI_SBAR_COLLAPSE_H),与提示线不重叠加—— + * 全屏与非全屏共用同一条绘制/进度路径,只 hy 不同,无全屏特有的坐标/方向/最大值逻辑。 + * APP 若注册 on_swipe_progress 仍可自绘(系统条照常画;x_start+dx==当前X,幂等)。 */ + meow_ui_swipe_hint(xc); if (g_events_set && g_events.on_swipe_progress) - g_events.on_swipe_progress(e.a, len - e.a); + g_events.on_swipe_progress(x0, dx); meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6); } }