根治「焦点/事件穿透」一类反复 bug。此前命中/捕获/消费/层间隔离各处 ad-hoc; 现上收为单一仲裁者(meow_ui_input.c),公共 API 只追加、不删改既有签名。 分发模型: - 触摸沿 z 序自顶向下命中(meow_draw_hit_topdown,owner==active+enable 过滤); - 命中即消费;模态层永远先审(meow_ui_modal_begin/end/active/depth); - down 捕获(meow_ui_gesture_begin/owner/end):命中目标捕获手势直到 up,防滑出误触下层; - 模态存在时下层完全收不到事件——hit_topdown 恒返回模态哨兵(背板消费,不透传); - meow_ui_run 在 TOUCH_DOWN 自动 begin、TAP/SWIPE/LONG_PRESS/NOTIF_PULL 自动 end。 焦点模型: - 唯一持有者(meow_ui_focus_acquire/release/owner/tap); - 点非 focus 区域→释放并通知(meow_ui_focus_tap,list 焦点残留根治); - 滚动容器(list/listview)tap_at 命中行自动 acquire,点外由 run 的 focus_tap 释放; - lost 回调(meow_ui_focus_set_lost_cb)通知转移。 迁移(行为修复,正常交互语义不变): - dialog/sheet → meow_ui_modal_begin/end(模态期下层收不到;叠黑由既有整帧快照+卡片仅重绘保证); - list/listview tap → meow_ui_focus_acquire; - 注入/叠加让位(overlay_input_suppressed)与模态层隔离互补,语义不变。 验证:新穿透矩阵 test_meow_ui_dispatch(M1 模态点下层不触发 / M2 弹层叠开两层层隔离 / M3 捕获手势滑出不误触 / M4 list 焦点点外释放)ALL PASS; 全量回归 widgets/ime_fix/pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/ p1p2p3_repro/box/anim/scroll/sdk_input_keys 全 PASS;交叉 -Wall -Wextra 0 warning。 meow_ui.a 新 md5:a9fcfb6eeb07ddbdd48039df4f8f18ce(主会话统一重链,本仓未重链 App)
396 lines
17 KiB
C
396 lines
17 KiB
C
/*
|
||
* meow_ui_dialog.c — §5.8.6 模态控件化(App 层,非系统叠加):Dialog / BottomSheet。
|
||
*
|
||
* 复用 §5.6 B③ 弹窗 / §5.7 B④ 底部面板模板(与 launcher s_dd_modal 同构):遮罩压暗 +
|
||
* 圆角卡片 + 标题 + 内容 + 操作;返回手势=取消;不压状态栏。阻塞式(内层 meow_input_pop
|
||
* 轮询,与 meow_ui_text_input 同构),打开前排空残留触摸(goodix 长尾免疫)。
|
||
* 命中一律用抬手最新坐标;即画即显(打开一次性绘制,仅高亮变化才重绘,逐帧不重画静态内容)。
|
||
*
|
||
* 属 App 层模态:不注册进系统顶条/通知中心渲染(系统级控件归属不动)。物理键在 B1 未下发
|
||
* 给 App(on_key 无键),故本层关闭途径=触摸 + 左缘返回手势;音量/电源高亮导航为后续批次。
|
||
*/
|
||
#include "meow_ui.h"
|
||
#include "meow_ui_internal.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
#define MEOW_MODAL_MAX_ITEMS 32
|
||
#define MEOW_MODAL_ROW 48
|
||
#define MEOW_MODAL_BTN 44
|
||
|
||
/* M2.71-bug3:模态(Dialog/BottomSheet)背景快照/恢复。
|
||
* 旧实现直接往 back_buf 画 scrim+卡片并 flush:①每次 open 再现叠一层 α150 遮罩(叠加变黑);
|
||
* ②关闭后 scrim+卡片像素留在屏上(残影);③要整屏刷新才盖掉。此处 open 前把整帧背景拍下,
|
||
* 关闭后回填 + 整帧上屏 → scrim 每次只叠一层、关闭即还原、无残留。 */
|
||
static unsigned char *g_modal_cap = NULL;
|
||
static int g_modal_cap_line = 0, g_modal_cap_h = 0, g_modal_cap_bpp = 0;
|
||
|
||
static void modal_capture(void)
|
||
{
|
||
unsigned char *bb = meow_ui_back_buf();
|
||
int line = meow_ui_back_buf_pitch();
|
||
int h = meow_ui_height();
|
||
int bpp = meow_ui_back_buf_bpp();
|
||
if (!bb || line <= 0 || h <= 0) { g_modal_cap = NULL; return; }
|
||
size_t n = (size_t)line * (size_t)h;
|
||
if (!g_modal_cap || g_modal_cap_line != line || g_modal_cap_h != h || g_modal_cap_bpp != bpp) {
|
||
free(g_modal_cap);
|
||
g_modal_cap = (unsigned char *)malloc(n);
|
||
g_modal_cap_line = line; g_modal_cap_h = h; g_modal_cap_bpp = bpp;
|
||
}
|
||
if (g_modal_cap) memcpy(g_modal_cap, bb, n);
|
||
}
|
||
|
||
static void modal_restore(void)
|
||
{
|
||
unsigned char *bb = meow_ui_back_buf();
|
||
if (!g_modal_cap || !bb) return;
|
||
size_t n = (size_t)g_modal_cap_line * (size_t)g_modal_cap_h;
|
||
memcpy(bb, g_modal_cap, n);
|
||
meow_gfx_mark_full();
|
||
meow_ui_flush();
|
||
}
|
||
|
||
/* ---- Dialog ---- */
|
||
struct meow_dialog {
|
||
meow_dlg_t type;
|
||
char title[96];
|
||
char items[MEOW_MODAL_MAX_ITEMS][64];
|
||
int nitems;
|
||
int cur; /* SELECT 预选/高亮项 */
|
||
int result;
|
||
int done;
|
||
meow_ime_ctx ime; /* INPUT 型(拷贝) */
|
||
int has_ime;
|
||
meow_ime_ctx *ime_orig; /* INPUT:App 传入的原始 ctx(回写最终文本,App 关闭后可读回) */
|
||
};
|
||
|
||
/* 卡片几何:返回标题之后内容起点(行/按钮相对坐标)。 */
|
||
typedef struct { int dx,dy,dw,dh; int row_y,rowh; int btn_y,btn_w,btn_h; } dlg_geom;
|
||
|
||
static void dlg_calc(meow_dialog *d, const meow_theme *th, dlg_geom *g)
|
||
{
|
||
int W = meow_ui_width(), H = meow_ui_height();
|
||
int sb = meow_ui_statusbar_height(); if (sb < 0) sb = 0;
|
||
int pad = 24;
|
||
int tH = meow_ui_text_height(th->font_title);
|
||
int bH = meow_ui_text_height(th->font_body);
|
||
int select = (d->type == MEOW_DLG_SELECT);
|
||
int nrows = select ? d->nitems : 0;
|
||
int nmsg = (d->type == MEOW_DLG_INFO) ? (d->nitems > 0 ? d->nitems : 1)
|
||
: (select ? 0 : (d->nitems > 0 ? d->nitems : 1));
|
||
int have_btns = !select;
|
||
g->dw = 348; if (g->dw > W - 40) g->dw = W - 40;
|
||
g->dx = (W - g->dw) / 2;
|
||
int content = nrows * MEOW_MODAL_ROW + nmsg * (bH + 8);
|
||
g->dh = pad + tH + 12 + content + pad + (have_btns ? 16 + MEOW_MODAL_BTN : 0);
|
||
int avail = H - sb - 20;
|
||
if (g->dh > avail) g->dh = avail;
|
||
g->dy = (H - g->dh) / 2; if (g->dy < sb) g->dy = sb;
|
||
g->row_y = g->dy + pad + tH + 12;
|
||
g->rowh = (MEOW_MODAL_ROW < 0) ? 40 : MEOW_MODAL_ROW;
|
||
g->btn_y = g->row_y + content + 16;
|
||
g->btn_h = MEOW_MODAL_BTN;
|
||
g->btn_w = (g->dw - 2 * pad - 12) / 2;
|
||
}
|
||
|
||
/* 只画卡片内容(不含遮罩)——供「仅高亮变化」时重绘卡片区,不会把遮罩再叠一层(防叠加变黑)。 */
|
||
static void dlg_card(meow_dialog *d, const meow_theme *th, const dlg_geom *g)
|
||
{
|
||
int pad = 24;
|
||
meow_gfx_fill_round(g->dx, g->dy, g->dw, g->dh, th->radius_card, th->surfaceContainerHighest);
|
||
meow_ui_draw_rect_round(g->dx, g->dy, g->dw, g->dh, th->radius_card, th->outline);
|
||
meow_ui_text(g->dx + pad, g->dy + pad, d->title, th->font_title, th->onSurface);
|
||
|
||
if (d->type == MEOW_DLG_SELECT) {
|
||
for (int i = 0; i < d->nitems; i++) {
|
||
int ry = g->row_y + i * g->rowh;
|
||
if (ry + g->rowh > g->dy + g->dh - 12) break;
|
||
if (i == d->cur) {
|
||
meow_ui_fill_rect(g->dx + 8, ry, g->dw - 16, g->rowh, th->primary);
|
||
meow_ui_text(g->dx + pad, ry + (g->rowh - meow_ui_text_height(th->font_body)) / 2,
|
||
d->items[i], th->font_body, 0xFFFFFF);
|
||
} else {
|
||
meow_ui_text(g->dx + pad, ry + (g->rowh - meow_ui_text_height(th->font_body)) / 2,
|
||
d->items[i], th->font_body, th->onSurface);
|
||
}
|
||
meow_ui_fill_rect(g->dx + pad, ry + g->rowh - 1, g->dw - 2 * pad, 1, th->outlineVariant);
|
||
}
|
||
} else {
|
||
/* INFO/CONFIRM:正文行;INPUT:文本预览 */
|
||
int nmsg = (d->type == MEOW_DLG_INFO) ? (d->nitems > 0 ? d->nitems : 1)
|
||
: (d->nitems > 0 ? d->nitems : 1);
|
||
int y = g->row_y;
|
||
if (d->type == MEOW_DLG_INPUT) {
|
||
char buf[300];
|
||
snprintf(buf, sizeof buf, "%s", d->ime.buf[0] ? d->ime.buf : "(tap OK to edit...)");
|
||
meow_ui_text(g->dx + pad, y, buf, th->font_body, th->onSurfaceVariant);
|
||
} else {
|
||
for (int i = 0; i < nmsg; i++) {
|
||
if (i < d->nitems && d->items[i][0])
|
||
meow_ui_text(g->dx + pad, y, d->items[i], th->font_body, th->onSurfaceVariant);
|
||
y += meow_ui_text_height(th->font_body) + 8;
|
||
}
|
||
}
|
||
/* 取消(左,text 型)/ 确定(右,filled) */
|
||
int bx = g->dx + pad, cx = bx + g->btn_w + 12, by = g->btn_y;
|
||
meow_ui_draw_rect_round(bx, by, g->btn_w, g->btn_h, 10, th->primary);
|
||
meow_ui_text_center(bx + g->btn_w / 2, by + (g->btn_h - meow_ui_text_height(th->font_body)) / 2,
|
||
"CANCEL", th->font_body, th->primary);
|
||
meow_gfx_fill_round(cx, by, g->btn_w, g->btn_h, 10, th->primary);
|
||
meow_ui_text_center(cx + g->btn_w / 2, by + (g->btn_h - meow_ui_text_height(th->font_body)) / 2,
|
||
"OK", th->font_body, th->onPrimary);
|
||
}
|
||
}
|
||
|
||
/* 整帧绘制:遮罩 + 卡片。 */
|
||
static void dlg_paint(meow_dialog *d, const meow_theme *th)
|
||
{
|
||
meow_ui_fill_rect_alpha(0, 0, meow_ui_width(), meow_ui_height(), 0x000000, 150); /* 遮罩压暗 */
|
||
dlg_geom g;
|
||
dlg_calc(d, th, &g);
|
||
dlg_card(d, th, &g);
|
||
}
|
||
|
||
/* 仅重绘卡片区(遮罩不变),flush 卡片矩形:高亮变化用,不叠加遮罩。 */
|
||
static void dlg_repaint(meow_dialog *d, const meow_theme *th)
|
||
{
|
||
dlg_geom g;
|
||
dlg_calc(d, th, &g);
|
||
dlg_card(d, th, &g);
|
||
meow_ui_flush_region(g.dx, g.dy, g.dw, g.dh);
|
||
}
|
||
|
||
/* M2.71-IME-fix:dialog INPUT 的 on_change——实时把 IME 文本回写进 d->ime.buf(dialog 内部拷贝),
|
||
* 并重绘卡片预览区,使用户边打字边看到当前文本。ESC/点背景(result=0)关闭后 d->ime.buf 仍是
|
||
* 最新文本(否则 meow_ime_close(0) 不回写 buf → 文本丢失)。d->ime.buf 是 dialog 内部缓冲
|
||
* (非 App 持有);App 的最终文本经 ime_orig 在关闭时回写(见 OK 按钮处理)。 */
|
||
static void dlg_ime_change_cb(const char *text, void *ctx)
|
||
{
|
||
meow_dialog *d = (meow_dialog *)ctx;
|
||
if (!d) return;
|
||
if (text) {
|
||
strncpy(d->ime.buf, text, sizeof d->ime.buf - 1);
|
||
d->ime.buf[sizeof d->ime.buf - 1] = 0;
|
||
}
|
||
const meow_theme *th = meow_theme_get();
|
||
dlg_repaint(d, th);
|
||
}
|
||
|
||
/* 准备好 dialog 的 IME 上下文:无论 App 传入(set_ime)或内部兜底(show 的默认 ctx),
|
||
* 都由 dialog 接管 on_change/ctx,以支持 dlg_ime_change_cb 的实时回写。 */
|
||
static void dlg_prep_ime(meow_dialog *d)
|
||
{
|
||
d->ime.on_change = dlg_ime_change_cb;
|
||
d->ime.ctx = d;
|
||
}
|
||
|
||
meow_dialog *meow_dialog_create(meow_dlg_t t, const char *title)
|
||
{
|
||
meow_dialog *d = (meow_dialog *)calloc(1, sizeof *d);
|
||
if (!d) return NULL;
|
||
d->type = t;
|
||
if (title) { strncpy(d->title, title, sizeof d->title - 1); d->title[sizeof d->title - 1] = 0; }
|
||
d->cur = -1; d->result = 0; d->done = 0;
|
||
return d;
|
||
}
|
||
void meow_dialog_set_items(meow_dialog *d, const char *const *item, int n, int cur)
|
||
{
|
||
if (!d) return;
|
||
d->nitems = 0;
|
||
if (item) for (int i = 0; i < n && i < MEOW_MODAL_MAX_ITEMS; i++)
|
||
if (item[i]) { strncpy(d->items[d->nitems], item[i], 63); d->items[d->nitems][63] = 0; d->nitems++; }
|
||
d->cur = cur;
|
||
}
|
||
void meow_dialog_set_ime(meow_dialog *d, meow_ime_ctx *ime)
|
||
{
|
||
if (!d || !ime) return;
|
||
d->ime = *ime;
|
||
d->ime_orig = ime; /* M2.71-IME-fix:记住 App 原始 ctx,关闭时回写最终文本 */
|
||
d->has_ime = 1;
|
||
dlg_prep_ime(d); /* dialog 接管 on_change:实时回写 d->ime.buf + 重绘卡片 */
|
||
}
|
||
|
||
void meow_dialog_close(meow_dialog *d)
|
||
{
|
||
if (d) d->done = 1;
|
||
}
|
||
|
||
void meow_dialog_show(meow_dialog *d)
|
||
{
|
||
if (!d) return;
|
||
const meow_theme *th = meow_theme_get();
|
||
/* INPUT 型若未带 ime,用空 ctx 兜底 */
|
||
if (d->type == MEOW_DLG_INPUT && !d->has_ime) {
|
||
memset(&d->ime, 0, sizeof d->ime);
|
||
d->ime.maxlen = 255;
|
||
d->ime_orig = NULL; /* 无 App 原始 ctx,关闭时不回写 */
|
||
dlg_prep_ime(d);
|
||
}
|
||
meow_input_start();
|
||
meow_input_drain(); /* 排空残留触摸(goodix 长尾) */
|
||
d->done = 0; d->result = 0;
|
||
/* §6.4:模态作用域——本层打开期间下层(view/widget)完全收不到触摸;点卡片外由背板消费
|
||
* (d->done=1 result=0 取消),不透传。嵌套弹层 depth 递增。 */
|
||
meow_ui_modal *m = meow_ui_modal_begin();
|
||
modal_capture(); /* M2.71-bug3:拍下背景,关闭即还原(scrim 只叠一层/无残影);
|
||
* 嵌套模态在各自打开时拍「当前已渲染帧」,故两层弹开不叠黑。 */
|
||
dlg_paint(d, th);
|
||
meow_ui_flush();
|
||
|
||
while (!d->done) {
|
||
meow_input_ev e;
|
||
while (meow_input_pop(&e)) {
|
||
meow_ui_activity_ping(); /* M2.71-bug5:模态期间交互也重置息屏计时 */
|
||
if (e.type == MEOW_EV_TAP) {
|
||
int x = e.a, y = e.b;
|
||
dlg_geom g;
|
||
dlg_calc(d, th, &g);
|
||
int in_card = x >= g.dx && x < g.dx + g.dw && y >= g.dy && y < g.dy + g.dh;
|
||
if (!in_card) { d->done = 1; d->result = 0; break; } /* 遮罩外=取消 */
|
||
if (d->type == MEOW_DLG_SELECT) {
|
||
/* M2.71-bug3:点项 → 立即刷「选中」高亮(不下线、不叠加遮罩);
|
||
* 再点同一项 → 确认(返回该项下标)。点卡片外=取消。 */
|
||
int idx = (y - g.row_y) / g.rowh;
|
||
if (idx >= 0 && idx < d->nitems) {
|
||
if (idx == d->cur) { d->result = idx; d->done = 1; }
|
||
else { d->cur = idx; dlg_repaint(d, th); }
|
||
}
|
||
break;
|
||
}
|
||
/* 非选择:按钮命中 */
|
||
int pad = 24, by = g.btn_y;
|
||
int bx = g.dx + pad, cx = bx + g.btn_w + 12;
|
||
if (y >= by && y < by + g.btn_h) {
|
||
if (x >= bx && x < bx + g.btn_w) { /* CANCEL */
|
||
d->done = 1; d->result = 0;
|
||
} else if (x >= cx && x < cx + g.btn_w) { /* OK */
|
||
if (d->type == MEOW_DLG_INPUT) {
|
||
d->result = meow_ui_text_input(&d->ime); /* 阻塞编辑 */
|
||
/* M2.71-IME-fix:回车只提交不关(键盘仍开);文本经 on_change 已实时
|
||
* 写进 d->ime.buf。这里无论 result=0/1 都把最终文本回写 App 原始 ctx,
|
||
* 保证 ESC/点背景(result=0)关闭后 App 仍能读到编辑结果(不再丢失)。 */
|
||
if (d->ime_orig) {
|
||
strncpy(d->ime_orig->buf, d->ime.buf, sizeof d->ime_orig->buf - 1);
|
||
d->ime_orig->buf[sizeof d->ime_orig->buf - 1] = 0;
|
||
}
|
||
} else {
|
||
d->result = (d->type == MEOW_DLG_CONFIRM) ? 1 : 1;
|
||
}
|
||
d->done = 1;
|
||
}
|
||
break;
|
||
}
|
||
} else if (e.type == MEOW_EV_SWIPE && e.a == MEOW_SWIPE_LEFT) {
|
||
d->done = 1; d->result = 0; /* 返回=取消 */
|
||
}
|
||
}
|
||
if (d->done) break;
|
||
usleep(16000);
|
||
}
|
||
meow_ui_modal_end(m); /* §6.4:关闭模态作用域(下层恢复接收触摸) */
|
||
modal_restore(); /* M2.71-bug3:关闭还原背景,无残影 */
|
||
}
|
||
|
||
int meow_dialog_result(meow_dialog *d) { return d ? d->result : 0; }
|
||
int meow_dialog_confirm(meow_dialog *d)
|
||
{
|
||
if (!d || d->type != MEOW_DLG_CONFIRM) return 0;
|
||
meow_dialog_show(d);
|
||
return d->result == 1;
|
||
}
|
||
void meow_dialog_free(meow_dialog *d) { if (d) free(d); }
|
||
|
||
/* ---- BottomSheet ---- */
|
||
struct meow_sheet {
|
||
char title[96];
|
||
char items[MEOW_MODAL_MAX_ITEMS][64];
|
||
int nitems;
|
||
int h;
|
||
int result;
|
||
int done;
|
||
};
|
||
|
||
static int sheet_h(meow_sheet *s, const meow_theme *th)
|
||
{
|
||
int H = meow_ui_height();
|
||
int sb = meow_ui_statusbar_height(); if (sb < 0) sb = 0;
|
||
int avail = H - sb - 20;
|
||
int title_h = meow_ui_text_height(th->font_title);
|
||
int min_h = 24 + title_h + 12 + MEOW_MODAL_ROW + 20;
|
||
int want = (s->h > 0) ? s->h : min_h;
|
||
int est = 24 + title_h + 12 + s->nitems * MEOW_MODAL_ROW + 20;
|
||
if (est > want) want = est;
|
||
if (want > avail) want = avail;
|
||
if (want < min_h) want = min_h < avail ? min_h : avail;
|
||
return want;
|
||
}
|
||
|
||
meow_sheet *meow_sheet_create(const char *title, int h)
|
||
{
|
||
meow_sheet *s = (meow_sheet *)calloc(1, sizeof *s);
|
||
if (!s) return NULL;
|
||
if (title) { strncpy(s->title, title, sizeof s->title - 1); s->title[sizeof s->title - 1] = 0; }
|
||
s->h = h > 0 ? h : 0;
|
||
return s;
|
||
}
|
||
int meow_sheet_add_item(meow_sheet *s, const char *label)
|
||
{
|
||
if (!s || s->nitems >= MEOW_MODAL_MAX_ITEMS) return -1;
|
||
if (label) { strncpy(s->items[s->nitems], label, 63); s->items[s->nitems][63] = 0; }
|
||
int idx = s->nitems;
|
||
s->nitems++;
|
||
return idx;
|
||
}
|
||
int meow_sheet_open(meow_sheet *s)
|
||
{
|
||
if (!s) return -1;
|
||
const meow_theme *th = meow_theme_get();
|
||
meow_input_start();
|
||
meow_input_drain();
|
||
s->done = 0; s->result = -1;
|
||
int W = meow_ui_width(), H = meow_ui_height();
|
||
int ph = sheet_h(s, th);
|
||
int py = H - ph, pad = 24;
|
||
meow_ui_modal *m = meow_ui_modal_begin(); /* §6.4:模态作用域(下层收不到触摸) */
|
||
modal_capture(); /* M2.71-bug3:拍下背景,关闭即还原(scrim 只叠一层/无残影) */
|
||
/* 首次绘制:遮罩 + 底部面板(顶部圆角) */
|
||
meow_ui_fill_rect_alpha(0, 0, W, H, 0x000000, 150);
|
||
meow_gfx_fill_round(0, py, W, ph, th->radius_card, th->surfaceContainerHighest);
|
||
meow_ui_text(pad, py + pad, s->title, th->font_title, th->onSurface);
|
||
for (int i = 0; i < s->nitems; i++) {
|
||
int ry = py + pad + meow_ui_text_height(th->font_title) + 12 + i * MEOW_MODAL_ROW;
|
||
if (ry + MEOW_MODAL_ROW > H - 8) break;
|
||
meow_ui_text(pad, ry + (MEOW_MODAL_ROW - meow_ui_text_height(th->font_body)) / 2,
|
||
s->items[i], th->font_body, th->onSurface);
|
||
meow_ui_fill_rect(pad, ry + MEOW_MODAL_ROW - 1, W - 2 * pad, 1, th->outlineVariant);
|
||
}
|
||
meow_ui_flush();
|
||
|
||
while (!s->done) {
|
||
meow_input_ev e;
|
||
while (meow_input_pop(&e)) {
|
||
meow_ui_activity_ping(); /* M2.71-bug5:模态期间交互也重置息屏计时 */
|
||
if (e.type == MEOW_EV_TAP) {
|
||
int y = e.b;
|
||
if (y < py) { s->done = 1; s->result = -1; break; } /* 点面板外=取消 */
|
||
int title_h = meow_ui_text_height(th->font_title);
|
||
int cy = py + pad + title_h + 12;
|
||
int idx = (y - cy) / MEOW_MODAL_ROW;
|
||
if (idx >= 0 && idx < s->nitems) { s->result = idx; s->done = 1; }
|
||
break;
|
||
} else if (e.type == MEOW_EV_SWIPE && e.a == MEOW_SWIPE_LEFT) {
|
||
s->done = 1; s->result = -1;
|
||
}
|
||
}
|
||
if (s->done) break;
|
||
usleep(16000);
|
||
}
|
||
meow_ui_modal_end(m); /* §6.4:关闭模态作用域 */
|
||
modal_restore(); /* M2.71-bug3:关闭还原背景,无残影 */
|
||
return s->result;
|
||
}
|
||
void meow_sheet_free(meow_sheet *s) { if (s) free(s); }
|