feat: M6.10–M6.19 批量收编 + M6.19 推卡验收

- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘)
- OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复
- ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640
- 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫)
- 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
This commit is contained in:
AskaEth committed 2026-09-03 12:16:01 +08:00
1 parent c2ee7626a4
commit 3d70a3dd2c
176 files changed
+15507 -597

No files matched your search

+288 -33
View File
@@ -126,9 +126,12 @@ static const srow_t SMENU[] = {
/* M2.39 左缘返回手势已抽为共享函数 meow_edge_back()(meow_touch.h MEOW_EDGE_W/SWIPE 由
* 其定义),设置页运行期调用;此处不再定义独立 S_EDGE_W/S_SWIPE_THRESH。 */
#if 0 /* M7.2 回退位:旧「当前选中滑条行 track y」随旧手绘 draw_settings_page 退役
* (新路径在触摸按下时由 meow_listview hit 直接算 track 中心,无需全局记录)。 */
/* 当前选中行若是滑条:记录其 track 纵向位置,供触摸拖动命中判(x/w 为布局常量,
* 所有滑条行相同,可直接算;仅 y 随行变,故独立记录)。 */
static int s_sel_track_y = -1;
#endif
/* ---- 行高/位置/导航辅助 ---- */
@@ -206,6 +209,9 @@ static const char *const *s_row_presets(const srow_t *r, int *n)
}
#if 0 /* M7.2 回退位:旧「纯范围/选中可见滚动钳制 + 内容 y→行号」随旧手绘 draw_settings_page 退役
* (新路径滚动走 meow_scroll 包裹 meow_listview,钳制/命中/可见性由 SDK 接管)。
* 删除 #if 0 行并切回旧 draw_settings_page 路径即可恢复。 */
/* 滚动:纯范围钳制到 [0, 内容高度-视口高](列表拖动滚动用;不强制选中行可见) */
static int s_clamp_scroll_range(int scroll)
{
@@ -240,6 +246,7 @@ static int s_row_at_content_y(int cy)
if (pos >= s_vis_count()) return -1;
return s_vis_at(pos);
}
#endif /* M7.2 回退位:旧滚动钳制 + 内容 y→行号 */
/* ---- 值格式化/展示 ---- */
@@ -497,6 +504,9 @@ static int s_slider_val_from_x(const srow_t *r, int px)
}
#if 0 /* M7.2 回退位:旧手绘设置页主列表(手绘分组列表 + s_draw_switch/s_draw_slider + 自算滚动/命中)。
* 新路径走 meow_listview + meow_switch + meow_scroll + meow_select_show;删除 #if 0 行并把
* 下方「M7.2 SDK 路径」的 set_paint_page 调用切回 draw_settings_page 即可一键回退。 */
/* ---- 绘制设置页(整页画进 SDK back_buf;调用方再 meow_dirty_add 局部 + flush)---- */
static void draw_settings_page(int sel, int scroll_off)
{
@@ -596,6 +606,7 @@ static void draw_settings_page(int sel, int scroll_off)
ui_draw(fb_xres - 8 - ui_width(ver, 20), foot_y, ver, th->outline, 20);
}
}
#endif /* M7.2 回退位:旧手绘设置页主列表 */
/* M2.5x 多字体:class 行下拉的「跟随全局」选项(值=空串)在 write 路径经此映射回真实存储值。 */
@@ -658,7 +669,9 @@ static int s_dropdown(const srow_t *r)
}
if (n <= 0) return -1;
if (cur < 0 || cur >= n) cur = 0;
return s_dd_modal(r->label, item, n, cur);
/* M7.2:枚举/预设选择器迁 SDK meow_select_show(BottomSheet+单选列表,批次2 新控件),
* 替换自绘 s_dd_modal(后者仍供 about/网络列表/字体两级子菜单用,勿删)。 */
return meow_select_show(r->label, item, n, cur);
}
@@ -686,7 +699,7 @@ static void dd_modal_paint(const meow_ui_theme_t *th, int W, int H, int d_x, int
int cur_sel = (i == sel);
if (cur_sel) meow_ui_fill_rect_alpha(d_x + 4, ry, d_w - 8, opt_row, th->primary, 36);
ui_draw(d_x + 18, ry + (opt_row - meow_font_line_height(20)) / 2, item[i] ? item[i] : "",
cur_sel ? 0xFFFFFF : th->on_surface, 20);
cur_sel ? meow_theme_get()->onPrimary : th->on_surface, 20);
if (i == cur) meow_ui_fill_rect(d_x + d_w - 28, ry + (opt_row - 12) / 2, 12, 12, th->primary);
}
}
@@ -966,11 +979,228 @@ static int s_font_dropdown(const srow_t *r, char *out_val, int vlen)
}
/* ==================================================================
* M7.2 设置页渲染层迁移(主列表迁 SDK 控件):
* - 分组列表 → meow_listview(虚拟化 set_vsource 固定 item 池 + section 段头 + set_item_draw 自绘);
* - 开关行 → 行内真 meow_switch(池化,SDK 绘制 + 按压态);
* - 滑条行 → 行内嵌 meow_slider(自绘 track/thumb,保留既有 s_draw_slider 语义色;
* 「行内嵌自绘」,M7 定案允许)——拖动实时写 settings.conf(读改写单键,
* 经 meow_settings_set_*,勿整文件覆盖——音量存盘教训);
* - 枚举/预设 → SDK meow_select_show(BottomSheet+单选列表,替换自绘 s_dd_modal);
* - 信息/列表行 → 行 right 值 + chevron(SDK 主题语义色)。
* 滚动 → meow_scroll(跟手 track + 松手 fling,同 subpage.c M7.1a 语义;刻意不 set_snap)。
* 控件 lazy 创建一次(owner=SET_SENTINEL_ACT 哨兵),跨多次进入复用;数据/动作(s_commit、
* s_set_int_value、s_net_*、s_font_dropdown、s_dropdown)逻辑层不动,仅换渲染层 + 命中;
* run_settings_page 会话骨架(触摸/滚动/返回/IPC/电源键语义)不改。旧手绘 draw_settings_page
* + s_clamp_scroll + s_row_at_content_y 保留 #if 0 作回退位(M7 红线:一键回退)。
* ================================================================== */
#define SET_SENTINEL_ACT 0x53 /* 设置页哨兵 activity(不与 launcher 其它页冲突) */
#define SET_LIST_Y SET_CONTENT_Y /* 100:列表顶缘(顶栏/标题下) */
#define SET_FOOT_H 40 /* 底部返回/版本带高 */
#define SET_ITEM_H 68 /* MD3 行高(滑条行给 track 留位) */
#define SET_SLIDER_YOFF 45 /* 滑条行内 track 顶缘相对行顶(÷s_draw_slider h=6,中心=顶+3) */
#define SET_TRACK_CY 48 /* 滑条 track 中心相对行顶 y(=SET_SLIDER_YOFF+3,与绘制对齐) */
#define SET_SLIDER_LY 12 /* 滑条行 label 顶相对行顶 y(上移给 track 留位) */
#define SET_SWITCH_POOL 12
static meow_widget *g_set_lv = NULL; /* meow_listview(虚拟化) */
static meow_scroll *g_set_sc = NULL; /* 滚动物理 */
static meow_widget *g_set_sw[SET_SWITCH_POOL]; /* 行内开关池(真 meow_switch) */
static int g_set_sw_n = 0, g_set_sw_use = 0; /* 池创建数 / 本轮已用(每次整绘复位) */
static int g_set_lv_h = 0; /* 列表视口高(选中可见性 clamp 用) */
static int g_set_init = 0;
static void set_lv_rect(int *x, int *y, int *w, int *h)
{
if (x) *x = 0;
if (y) *y = SET_LIST_Y;
if (w) *w = fb_xres;
if (h) { int t = fb_yres - SET_LIST_Y - SET_FOOT_H; if (t < 0) t = 0; *h = t; }
}
static int set_lv_count(void *ctx) { (void)ctx; return s_vis_count(); }
/* 行填充(虚拟化 pool bind;段头行 section=1、enabled=1 供 SDK 命中/段头绘制) */
static void set_lv_bind(int idx, meow_lv_item *out, void *ctx)
{
(void)ctx;
memset(out, 0, sizeof *out);
out->icon_kind = MEOW_LIST_ICON_NONE;
out->enabled = 1;
if (idx < 0 || idx >= s_vis_count()) { out->title = ""; return; }
const srow_t *r = &SMENU[s_vis_at(idx)];
out->title = r->label ? r->label : "";
out->section = (r->ctrl == SC_HEADER) ? 1 : 0;
if (r->ctrl == SC_SWITCH) {
int on = 0; meow_settings_get_switch(r->key, &on);
out->right = MEOW_LIST_RIGHT_SWITCH; out->on = on;
}
}
/* 行内开关池:取下一个可用槽(每帧 set_lv_draw 顺序取用,整绘前复位 g_set_sw_use) */
static meow_widget *set_sw_take(void)
{
if (g_set_sw_use < g_set_sw_n) return g_set_sw[g_set_sw_use++];
if (g_set_sw_n >= SET_SWITCH_POOL) return NULL;
meow_widget *w = meow_switch_create(0, 0, 0);
if (w) { g_set_sw[g_set_sw_n++] = w; return g_set_sw[g_set_sw_use++]; }
return NULL;
}
/* 整行自绘(set_item_draw 覆盖默认 renderer;x=列表左缘、y=行顶、w/h=行全宽高,
* state=SELECTED/PRESSED/DISABLED 组合;颜色全取 meow_theme 语义色,无散落硬编码) */
static void set_lv_draw(int idx, int x, int y, int w, int h, int state, void *ctx)
{
(void)ctx; (void)h;
const meow_theme *mt = meow_theme_get();
if (idx < 0) return;
int si = s_vis_at(idx);
const srow_t *r = &SMENU[si];
int sel = (state & MEOW_LISTVIEW_ST_SELECTED);
int press = (state & MEOW_LISTVIEW_ST_PRESSED);
int dis = (state & MEOW_LISTVIEW_ST_DISABLED);
int thh = meow_ui_text_height(mt->font_body);
uint32_t textcol = sel ? mt->onPrimaryContainer : mt->onSurface;
uint32_t subcol = sel ? mt->onPrimaryContainer : mt->onSurfaceVariant;
if (r->ctrl == SC_HEADER) {
meow_ui_fill_rect(x, y, w, SET_ITEM_H, mt->surfaceContainerHigh);
int ty = y + (SET_ITEM_H - thh) / 2;
if (ty >= 0) meow_ui_text(x + 16, ty, r->label, mt->font_body, mt->primary);
meow_ui_fill_rect(x, y + SET_ITEM_H - 1, w, 1, mt->outlineVariant);
return;
}
if (sel) meow_ui_fill_rect(x, y, w, SET_ITEM_H, mt->primaryContainer);
else if (press) meow_ui_fill_rect_alpha(x, y, w, SET_ITEM_H, mt->primary, 26);
int ly = y + (SET_ITEM_H - thh) / 2; /* label 单行垂直居中 */
switch (r->ctrl) {
case SC_SWITCH: {
meow_ui_text(x + 16, ly, r->label, mt->font_body, textcol);
meow_widget *sw = set_sw_take();
if (sw) {
int on = 0; meow_settings_get_switch(r->key, &on);
meow_widget_set_rect(sw, x + w - 16 - 56, y + (SET_ITEM_H - 32) / 2, 56, 32);
meow_switch_set(sw, on);
meow_widget_draw(sw);
}
break;
}
case SC_SLIDER: {
/* label 上移一行,track 放行下方(中心=SET_SLIDER_YOFF+3=48),与拖动命中带对齐 */
meow_ui_text(x + 16, y + SET_SLIDER_LY, r->label, mt->font_body, textcol);
char vb[32]; s_fmt_value(r, vb, sizeof vb);
meow_ui_text(x + w - 16 - meow_ui_text_width(vb, mt->font_body), y + SET_SLIDER_LY, vb, mt->font_body, subcol);
int v = 0; meow_settings_get_int(r->key, &v);
/* 息屏时间为档位索引型(秒→索引 等距画);其余 clamp 到 [min,max] */
if (!strcmp(r->key, "display.screen_off_timeout")) v = s_time_tier_idx(v);
else { if (v < r->min) v = r->min; if (v > r->max) v = r->max; }
s_draw_slider(S_SLIDER_X, y + SET_SLIDER_YOFF, S_SLIDER_W, v, r->min, r->max, s_ui_theme());
break;
}
case SC_INFO: {
meow_ui_text(x + 16, ly, r->label, mt->font_body, textcol);
char vb[48]; s_net_get(r, vb, sizeof vb);
meow_ui_text(x + w - 16 - meow_ui_text_width(vb, mt->font_body), ly, vb, mt->font_body, subcol);
break;
}
case SC_LIST: {
meow_ui_text(x + 16, ly, r->label, mt->font_body, textcol);
char vb[48]; s_net_get(r, vb, sizeof vb);
int vx = x + w - 16 - 12 - meow_ui_text_width(vb, mt->font_body);
meow_ui_text(vx, ly, vb, mt->font_body, subcol);
s_draw_chevron(x + w - 16, y + SET_ITEM_H / 2, subcol);
break;
}
default: { /* SC_ENUM / SC_PRESET */
meow_ui_text(x + 16, ly, r->label, mt->font_body, textcol);
char vb[40]; s_display_value(r, vb, sizeof vb);
int vx = x + w - 16 - meow_ui_text_width(vb, mt->font_body);
meow_ui_text(vx, ly, vb, mt->font_body, subcol);
s_draw_chevron(vx - 8, y + SET_ITEM_H / 2, subcol);
break;
}
}
meow_ui_fill_rect(x, y + SET_ITEM_H - 1, w, 1, mt->outlineVariant);
if (dis) meow_ui_fill_rect_alpha(x, y, w, SET_ITEM_H, mt->onSurface, 90);
}
/* ---- meow_scroll 回调(包 listview)---- */
static void set_sc_set(void *ctx, int off) { (void)ctx; if (g_set_lv) meow_listview_set_scroll(g_set_lv, off); }
static int set_sc_max(void *ctx) { (void)ctx; return g_set_lv ? meow_listview_max_scroll(g_set_lv) : 0; }
static int set_sc_get(void *ctx) { (void)ctx; return g_set_lv ? meow_listview_scroll(g_set_lv) : 0; }
/* 列表区重绘(含内容底 + listview),供 fling/滚动局部刷。 */
static void set_redraw_region(void *ctx)
{
(void)ctx;
int lvx, lvy, lvw, lvh; set_lv_rect(&lvx, &lvy, &lvw, &lvh);
if (lvh <= 0) return;
const meow_ui_theme_t *th = s_ui_theme();
meow_ui_fill_rect(lvx, lvy, lvw, lvh, th->surface_variant);
if (g_set_lv) { g_set_sw_use = 0; meow_widget_draw(g_set_lv); }
meow_dirty_add(lvx, lvy, lvw, lvh);
meow_ui_flush();
}
/* 选中行可见性:滚动到选中行不越界(仅靠 tap 触发,选中行即在视野内,防御性兜底)。 */
static void set_ensure_sel_visible(int sel)
{
if (!g_set_lv) return;
int p = s_vis_of(sel); if (p < 0) return;
int scroll = meow_listview_scroll(g_set_lv);
int top = p * SET_ITEM_H, bot = top + SET_ITEM_H;
if (top < scroll) meow_listview_set_scroll(g_set_lv, top);
else if (bot > scroll + g_set_lv_h) meow_listview_set_scroll(g_set_lv, bot - g_set_lv_h);
}
/* 创建设置页控件集(owner=SET_SENTINEL_ACT;仅首进创建一次,跨次进入复用)。 */
static void set_widgets_create(void)
{
meow_ui_activity_push(SET_SENTINEL_ACT);
int lvx, lvy, lvw, lvh; set_lv_rect(&lvx, &lvy, &lvw, &lvh);
g_set_lv_h = lvh;
g_set_lv = meow_listview_create(lvx, lvy, lvw, lvh, 0, NULL, NULL, MEOW_LIST_SEL_SINGLE);
if (g_set_lv) {
meow_listview_set_vsource(g_set_lv, set_lv_count, set_lv_bind, NULL);
meow_listview_set_item_draw(g_set_lv, set_lv_draw, NULL);
meow_listview_set_item_h(g_set_lv, SET_ITEM_H);
/* 注:刻意不 set_snap —— SDK meow_scroll 的 snap 以「fling 起点」为吸附目标会往回拉 */
}
g_set_sc = meow_scroll_create(set_sc_set, set_sc_max, set_sc_get, set_redraw_region, NULL);
meow_ui_activity_pop();
g_set_init = 1;
}
/* 整页绘制(进 back_buf;调用方 meow_dirty_full/meow_dirty_add + flush)。sel=当前选中(SMENU 下标)。 */
static void set_paint_page(int sel)
{
const meow_ui_theme_t *th = s_ui_theme();
int W = fb_xres, H = fb_yres;
fill_rect(0, 0, W, H, th->surface);
draw_statusbar();
if (mfont_ready) ui_draw(24, 50, "系统设置", th->on_surface, 28);
else draw_text(24, 30, "SETTINGS", 3, th->on_surface);
fill_rect(0, 50 + (mfont_ready ? meow_font_line_height(28) : 24) + 2, W, 2, th->outline);
fill_rect(0, SET_CARD_Y, W, H - SET_CARD_Y, th->surface_variant);
if (g_set_lv) {
g_set_sw_use = 0;
int p = s_vis_of(sel); if (p >= 0) meow_listview_set_sel(g_set_lv, p);
meow_widget_draw(g_set_lv);
}
/* 底部:返回(左)+ 版本(右),复用应用列表底部对齐逻辑 */
char ver[32];
snprintf(ver, sizeof ver, "MeowOS v%s dev", g_meowos_version);
int foot_y = fb_yres - meow_font_line_height(20) - 8;
s_draw_chevron_left(SET_CARD_X + 12, foot_y + meow_font_line_height(20) / 2, th->on_surface_variant);
ui_draw(SET_CARD_X + 24, foot_y, "返回", th->on_surface_variant, 20);
ui_draw(fb_xres - 8 - ui_width(ver, 20), foot_y, ver, th->outline, 20);
}
/* ---- 运行设置页(独立子循环;run_menu 触摸命中设置行后调用)---- */
void run_settings_page(void)
{
int sel = s_first_setting();
int scroll_off = 0;
int H = fb_yres;
unsigned long long t_sets = now_ms(); /* M3 取证:进设置页耗时分段(真机核对用) */
@@ -1006,7 +1236,7 @@ void run_settings_page(void)
int drag = -1; /* 被拖动的行索引;-1=无 */
/* M2.37 列表拖动滚动状态 */
int scroll_drag = 0; /* 是否处于列表拖动滚动手势 */
int scroll_base = 0; /* 进入滚动时对应的 scroll_off 基准(连续跟手) */
int drag_last_y = 0; /* M7.2:滚动跟手增量基准(meow_scroll_track 速度采样) */
int scroll_y0 = 0; /* 按下原点纵向坐标 */
int scroll_invert = 0; /* M2.38 Bug4:滑动方向切换(input.swipe_invert;0=标准方向) */
int sel_changed = 0; /* 本轮是否改变了选中行(仅此场景才强制选中行可见) */
@@ -1024,8 +1254,9 @@ void run_settings_page(void)
* s_net_refresh_pump() 填充,draw 用缓存(g_net_*),数据变化即 need_paint。 */
s_net_sync_from_sys();
logmsg("settings entry: net toggle-sync+kick %llums", now_ms() - t_sets);
scroll_off = s_clamp_scroll(sel, scroll_off);
draw_settings_page(sel, scroll_off);
if (!g_set_init) set_widgets_create(); /* M7.2:lazy 建 SDK 控件集(一次,跨次进入复用) */
meow_ui_activity_push(SET_SENTINEL_ACT); /* 控件 owner 闸门打开(hit/按压态生效) */
set_paint_page(sel);
meow_dirty_full(); meow_ui_flush();
logmsg("settings entry: page shown in %llums", now_ms() - t_sets);
@@ -1074,8 +1305,7 @@ void run_settings_page(void)
touch_cooldown_until = now_ms() + 300;
td = 0; td_ok = 0; drag = -1; scroll_drag = 0; tlx = tly = -1;
logmsg("settings: auto screen-off -> input wake, stayed in settings page");
scroll_off = s_clamp_scroll_range(scroll_off);
draw_settings_page(sel, scroll_off);
set_paint_page(sel);
meow_dirty_full(); meow_ui_flush();
}
usleep(POLL_MS * 1000);
@@ -1206,34 +1436,47 @@ void run_settings_page(void)
else if (code == ABS_Y || code == ABS_MT_POSITION_Y) tly = val;
if (td && !td_ok && tlx >= 0 && tly >= 0) {
tdx = tlx; tdy = tly; td_ok = 1;
scroll_y0 = tdy; /* 列表拖动基准:按下原点(触发时才锁 scroll_base) */
/* 按下原点落在选中滑条 track 带内 → 开始拖动 */
if (SMENU[sel].ctrl == SC_SLIDER && s_sel_track_y >= 0 &&
tlx >= S_SLIDER_X - 12 && tlx <= S_SLIDER_X + S_SLIDER_W + 12 &&
tly >= s_sel_track_y - 14 && tly <= s_sel_track_y + 20) {
drag = sel;
const srow_t *r = &SMENU[sel];
int v = s_slider_val_from_x(r, tlx);
s_slider_set_from_track(r, v, 0);
need_paint = 1;
meow_input_touch_set(1, tdx, tdy, 0); /* 喂 SDK 输入态(行按压态渲染) */
scroll_y0 = tdy; /* 列表拖动基准:按下原点 */
/* 按下原点落在滑条行 track 带内 → 开始拖动(meow_listview hit 判行) */
int vp = g_set_lv ? meow_listview_hit(g_set_lv, tlx, tly) : -1;
if (vp >= 0 && drag < 0) {
const srow_t *rr = &SMENU[s_vis_at(vp)];
if (rr->ctrl == SC_SLIDER) {
int track_cy = SET_LIST_Y + vp * SET_ITEM_H -
meow_listview_scroll(g_set_lv) + SET_TRACK_CY;
if (tlx >= S_SLIDER_X - 12 && tlx <= S_SLIDER_X + S_SLIDER_W + 12 &&
tly >= track_cy - 14 && tly <= track_cy + 14) {
drag = s_vis_at(vp);
int v = s_slider_val_from_x(rr, tlx);
s_slider_set_from_track(rr, v, 0);
need_paint = 1;
}
}
}
}
/* M2.37 列表拖动滚动:非滑条行按下后纵向位移超阈值 → 进入列表滚动。
* scroll_base 在触发瞬间反推,保证进入滚动那一刻不跳变(连续跟手)。
* M2.38 Bug4:默认标准滑动(手指上滑 → scroll_off 增大 = 内容往下翻看后面项);
* 方向可经 input.swipe_invert 切换(1=反向:手指上滑 → 内容上移)。 */
/* M7.2 列表拖动滚动:非滑条行按下后纵向位移超阈值 → 进入列表滚动。
* 走 meow_scroll(跟手 track + 松手 fling),同 subpage.c M7.1a 语义;
* 方向经 input.swipe_invert 切换(默认手指上滑 → 内容下翻)。 */
if (td_ok && drag < 0 && !scroll_drag) {
int ddy = tly - scroll_y0;
if (ddy >= S_SCROLL_SLOP || ddy <= -S_SCROLL_SLOP) {
scroll_drag = 1;
meow_settings_get_bool("input.swipe_invert", &scroll_invert);
scroll_base = scroll_off + (scroll_invert ? -ddy : ddy);
meow_input_touch_set(0, 0, 0, 0); /* 滚动中不压行(清按压态) */
drag_last_y = tly;
}
}
if (scroll_drag && td_ok) {
int dydt = tly - scroll_y0;
scroll_off = s_clamp_scroll_range(scroll_base + (scroll_invert ? dydt : -dydt));
need_paint = 1;
int dydt = tly - drag_last_y; /* 本次位移增量(跟手) */
drag_last_y = tly;
int scdy = scroll_invert ? dydt : -dydt;
if (g_set_sc && scdy) meow_scroll_track(g_set_sc, scdy, now);
/* 列表滚动不在此即时重绘:整批事件末尾由下方「if (scroll_drag && td_ok)
* set_redraw_region」合并为一次视口局部重绘。此处若 set_redraw_region 且再设
* need_paint=1,底部 set_paint_page 会再走一遍整页重绘 + dirty_add(0,42,...)
* 近整屏 flush —— 快滑每帧整页重绘 → 卡顿,违背「局部脏区不整屏重绘」铁律;
* 且一个 poll 多个移动事件各自 flush 会多次 FBIO_WAITFORVSYNC 阻塞放大延迟。 */
}
if (drag >= 0 && td_ok) {
const srow_t *r = &SMENU[drag];
@@ -1250,6 +1493,7 @@ void run_settings_page(void)
}
} else if (!val && td) {
td = 0;
meow_input_touch_set(0, 0, 0, 0); /* 抬手:清 SDK 按压态 */
if (drag >= 0) { /* 滑条拖动结束 → 落盘 */
const srow_t *r = &SMENU[drag];
s_commit(r, 1);
@@ -1257,7 +1501,8 @@ void run_settings_page(void)
need_paint = 1;
} else if (scroll_drag) {
scroll_drag = 0; /* 列表滚动结束(已实时重绘),不再当 tap */
scroll_base = 0; scroll_y0 = 0;
if (g_set_sc) meow_scroll_fling(g_set_sc); /* 松手 fling(惯性 ease-out) */
scroll_y0 = 0;
need_paint = 1;
} else if (td_ok) {
int dx = tlx - tdx, dy = tly - tdy;
@@ -1276,8 +1521,10 @@ void run_settings_page(void)
if (tfd >= 0) { unsigned char e[16]; while (read(tfd, e, sizeof e) == 16) {} }
goto done;
}
int cy = ty - SET_CONTENT_Y + scroll_off;
int idx = s_row_at_content_y(cy);
/* M7.2:行命中走 meow_listview(含滚动换算 + 禁用/越界行不响应);
* 段头行 enabled=1 故 hit 亦命中 → 下方按 ctrl==SC_HEADER 分流。 */
int vp = g_set_lv ? meow_listview_hit(g_set_lv, tx, ty) : -1;
int idx = (vp >= 0) ? s_vis_at(vp) : -1;
if (idx >= 0 && !s_setting_idx(idx)) {
/* 点分组标题行 → 仅选中下一设置行 */
int ns = s_next_setting(idx);
@@ -1306,7 +1553,7 @@ void run_settings_page(void)
while (read(tfd, e, sizeof e) == 16) {}
}
td = 0; td_ok = 0; drag = -1; scroll_drag = 0;
scroll_base = 0; scroll_y0 = 0;
scroll_y0 = 0;
tdx = tdy = tlx = tly = -1;
touch_cooldown_until = now_ms() + 300;
memset(&kd_pwr, 0, sizeof kd_pwr);
@@ -1350,7 +1597,7 @@ void run_settings_page(void)
while (read(tfd, e, sizeof e) == 16) {}
}
td = 0; td_ok = 0; drag = -1; scroll_drag = 0;
scroll_base = 0; scroll_y0 = 0;
scroll_y0 = 0;
tdx = tdy = tlx = tly = -1;
touch_cooldown_until = now_ms() + 300;
/* 重置设置页按键防抖基线,防残边 */
@@ -1376,14 +1623,18 @@ void run_settings_page(void)
}
}
}
/* 列表拖动滚动:本批连续触摸事件合并为一次视口局部重绘(只刷列表区,
* 最多一次 present),不再触发 need_paint 整页重绘。scroll_drag/td_ok 在
* 抬手处置 0(抬手那轮已走 meow_scroll_fling + need_paint 整页),故此处只兜活动滚动。 */
if (scroll_drag && td_ok) set_redraw_region(NULL);
}
/* ---- 滚动 + 重绘 ---- */
if (need_paint) {
last_act = now;
/* 仅选中行变化时强制其可见;列表拖动滚动时保留用户滚到的位置,不把选中拉回视野 */
if (sel_changed) { scroll_off = s_clamp_scroll(sel, scroll_off); sel_changed = 0; }
draw_settings_page(sel, scroll_off);
if (sel_changed) { set_ensure_sel_visible(sel); sel_changed = 0; }
set_paint_page(sel);
/* 局部标脏:标题+卡片+滚动条+底部(y=42 以下全部,覆盖主题/选中/值变化),
* 状态栏(0-28)由 draw_statusbar/draw_clock 各自维护,不在此列。
* 选择器关闭后(after_modal)其全屏 dim 把状态栏也压暗了,须整帧重绘还原。 */
@@ -1408,9 +1659,13 @@ void run_settings_page(void)
fb_norm_buf0();
meow_ui_flush();
}
/* M7.2: 推进 fling/回弹动画(meow_scroll 惯性停;无动画零开销) */
meow_anim_tick();
usleep(POLL_MS * 1000);
}
done:
meow_input_touch_set(0, 0, 0, 0); /* M7.2 防残留按压态 */
meow_ui_activity_pop(); /* 关 owner 闸门(控件 owner 仍钉哨兵,复用) */
if (tfd >= 0) close(tfd);
kp_close(&kp_power); kp_close(&kp_keys);
logmsg("settings page closed");