sdk/: - 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头 (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退; 全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势; LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定; DSD 音频格式等) - 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c - 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动; build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径; meow_ui_internal.h 去除 FreeType 内部声明 - meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议) - 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font 自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs examples/hello/: - 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含) docs / README / .gitignore: - docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API) - README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」 - .gitignore 补新增宿主测试二进制 验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
456 lines
20 KiB
C
456 lines
20 KiB
C
/* ui/demo/sdk2/sdk2.c — 控件库 Demo 页内「SDK 批次2 新控件」CONTAINER 子视图(agent-363)。
|
||
*
|
||
* 目标(SDK_VIEW_FRAMEWORK_DESIGN.md §B.4/§E③,同 list.c):把 demo 页底部的三个 SDK 批次2
|
||
* 新控件演示区块抽成一个 meow_view CONTAINER 子视图,挂到 demo ACTIVITY view 的 children:
|
||
* ① meow_select (§5.8.9 枚举/预设选择器:下拉模态 + 单选列表 + on_change 回调)
|
||
* ② meow_lazygrid (§12.4 2 维虚拟化宫格:非 meow_widget,on_draw 直绘 meow_lazygrid_draw)
|
||
* ③ meow_listview 左滑删除(§5.5 swipe-delete:swipe_begin/move/end + on_delete + 回弹/删除动画)
|
||
*
|
||
* 职责边界(诚实,与 list.c 同折中):
|
||
* - 本子视图承接三节**整体**:章节标题 + select 按钮 + 宫格 + swipe-列表 的创建/释放与视图态
|
||
* (grid 虚拟源/选中/滚动、swipe 行集/滚动、select 选中值)。控件**创建**在 demo_build_at 链路内
|
||
* (sdk2_build_at,owner=ACT_DEMO)、**释放**在 sdk2_release(demo_free_content 调)——与 list.c
|
||
* 相同折中:完整「控件归容器拥有」需 SDK 侧支持(本批冻结 patch_v2/sdk/)。
|
||
* - meow_lazygrid 是**非 meow_widget**:不注册 z 序/绘制注册表。本子视图 on_draw 直接调
|
||
* meow_lazygrid_draw(view → 注册表 → invalidate 链路,与 list 区块标题同法)。
|
||
* - 章节标题(三段)与 select 当前值文本也走 on_draw 直绘(列表区标题同法),不逐标题注册
|
||
* CUSTOM 绘制物;on_draw 是回调、view 不缓存像素(非保留,§5.8.7)。
|
||
* - 嵌套生命周期由 SDK view_enter/view_leave 递归驱动(随 demo 页进出,同 list.c);绘制经
|
||
* meow_draw_view_entered(含祖先已进入判定)在 meow_ui_paint_full/invalidate 触发。
|
||
*
|
||
* 事件接线(demo 页把 touch/tap/swipe 分发改派到本子视图,实现「子>父」命中):
|
||
* - tap → sdk2_hit (select 按钮 / 宫格 tap / 列表行 tap / 行左滑松手 swipe_end)
|
||
* - down → sdk2_down (宫格聚焦拖拽 / 列表行左滑 begin)
|
||
* - move → sdk2_move (宫格滚动 / 列表左滑 move 或列表竖向滚动)
|
||
* - swipe → sdk2_swipe (宫格/列表聚焦时滚自身;否则回退页面滚动)
|
||
*/
|
||
#include "hello_internal.h"
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
|
||
/* ---- 本子视图(CONTAINER,非页面:id 用越界值避免占用 g_view_by_id 顶层页槽位)---- */
|
||
static meow_view *g_sdk2_view = NULL;
|
||
|
||
/* ---- demo 内容布局常量(与 demo.c 一致):内容区 x16 宽 448 ---- */
|
||
#define S2_X 16
|
||
#define S2_W 448
|
||
#define S2_DCW 212
|
||
#define S2_DBH 44
|
||
#define S2_CH 52
|
||
|
||
/* 三节(章节标题几何在 sdk2_build_at 计算后存入,on_draw 直绘用;屏幕坐标)。 */
|
||
static int s2_t1_y, s2_t2_y, s2_t3_y; /* 三节标题 y(on_draw 直绘) */
|
||
|
||
/* ============================================================ */
|
||
/* ① meow_select — 枚举/预设选择器 */
|
||
/* ============================================================ */
|
||
static meow_widget *g_btn_sel = NULL; /* 「打开选择器」按钮(sdk2_release 释放) */
|
||
static meow_select *g_sel = NULL; /* 选择器实例(sdk2_view_create 建一次,destroy 释放) */
|
||
static rect_t r_selbtn = { 0, 0, 0, 0 };
|
||
static rect_t r_selval = { 0, 0, 0, 0 }; /* 当前选择值文本区(on_draw 直绘) */
|
||
static int g_sel_cur = 0; /* 当前选中项(跨重建保留;on_change 更新) */
|
||
|
||
static const char *g_sel_items[] = { /* 枚举演示:音频档位(对齐 M7.2 设置页采样率/码率) */
|
||
"Auto", "44.1kHz", "48kHz", "96kHz", "192kHz",
|
||
};
|
||
#define SEL_N ((int)(sizeof g_sel_items / sizeof g_sel_items[0]))
|
||
|
||
/* on_change 回调(meow_select_open 确认后触发:更新选中下标 + 重画值文本区)。 */
|
||
static void sdk2_sel_change(int idx, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
if (idx >= 0 && idx < SEL_N) g_sel_cur = idx;
|
||
if (r_selval.w > 0) meow_ui_invalidate(r_selval.x, r_selval.y, r_selval.w, r_selval.h);
|
||
}
|
||
|
||
/* 打开选择器(阻塞到确认/取消;on_change 已更新选中值)。 */
|
||
static void sdk2_select_open(void)
|
||
{
|
||
if (!g_sel) return;
|
||
int r = meow_select_open(g_sel);
|
||
meow_log(MEOW_LOG_INFO, "sdk2 select return=%d (%s)",
|
||
r, (r >= 0 && r < SEL_N) ? g_sel_items[r] : "cancel");
|
||
}
|
||
|
||
/* ============================================================ */
|
||
/* ② meow_lazygrid — 2 维虚拟化宫格(非 widget) */
|
||
/* ============================================================ */
|
||
static meow_lazygrid *g_grid = NULL;
|
||
static rect_t r_grid = { 0, 0, 0, 0 };
|
||
static int g_grid_scroll = 0; /* 跨重建保留:宫格滚动偏移 */
|
||
static int g_grid_sel = -1; /* 跨重建保留:选中项 */
|
||
static int g_drag_grid = 0; /* 触摸拖宫格(down 置位;move 滚动) */
|
||
static int g_grid_focus = 0; /* 1=宫格聚焦(swipe 滚宫格而非页面) */
|
||
static int g_grid_last_y = 0;
|
||
|
||
#define GRID_N 36 /* 总项数(count > 视口行数 → 可滚动) */
|
||
#define GRID_COLS 3
|
||
#define GRID_CW 138
|
||
#define GRID_CH 86
|
||
#define GRID_GAP 10
|
||
#define GRID_H 190
|
||
|
||
/* 虚拟源:count 总项数(实时查);bind 项进入视口时调一次(同 listview 池语义)。 */
|
||
static int grid_count(void *ctx) { (void)ctx; return GRID_N; }
|
||
static void grid_bind(int idx, meow_lazygrid_item *item, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
static char t[24], s[24];
|
||
snprintf(t, sizeof t, "App %d", idx);
|
||
snprintf(s, sizeof s, "v1.%d", idx);
|
||
memset(item, 0, sizeof *item);
|
||
item->title = t; item->subtitle = s;
|
||
item->enabled = (idx % 9 != 8); /* 演示禁用变淡(每 9 个禁用 1 个) */
|
||
}
|
||
|
||
/* 完全自绘 cell(set_item_draw):icon+label 风格,对齐主界面用途。 */
|
||
static void grid_cell(int idx, int x, int y, int w, int h, int st, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
const meow_theme *th = meow_theme_get();
|
||
int sel = st & MEOW_LAZYGRID_ST_SELECTED;
|
||
int dis = st & MEOW_LAZYGRID_ST_DISABLED;
|
||
uint32_t bg = sel ? th->primaryContainer : th->surfaceContainerLow;
|
||
uint32_t icon = dis ? th->onSurfaceVariant : th->primary;
|
||
uint32_t txt = sel ? th->onPrimaryContainer
|
||
: (dis ? th->onSurfaceVariant : th->onSurface);
|
||
meow_ui_fill_rect(x, y, w, h, bg); /* 格底卡片 */
|
||
/* icon 块(无图资源:主题 primary 方块代替主界面图标位) */
|
||
int isz = w / 3; if (isz > h / 2) isz = h / 2;
|
||
meow_ui_fill_rect(x + (w - isz) / 2, y + 10, isz, isz, icon);
|
||
/* 名 + 状态(底部两行,中心对齐) */
|
||
static char t[24], s[24];
|
||
snprintf(t, sizeof t, "App %d", idx);
|
||
snprintf(s, sizeof s, "v1.%d", idx);
|
||
int thh = meow_ui_text_height(th->font_body);
|
||
meow_ui_text_center(x + w / 2, y + h - thh - 22, t, th->font_body, txt);
|
||
meow_ui_text_center(x + w / 2, y + h - thh - 3, s, th->font_body, txt);
|
||
if (sel) meow_ui_draw_rect_round(x, y, w, h, th->radius_card, th->primary);
|
||
if (dis) meow_ui_fill_rect_alpha(x, y, w, h, th->onSurface, 90);
|
||
}
|
||
|
||
/* 宫格 tap:置选中 + 局部刷 + 日志。 */
|
||
static void grid_tap(int idx, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
g_grid_sel = idx;
|
||
meow_log(MEOW_LOG_INFO, "sdk2 grid tap idx=%d", idx);
|
||
if (r_grid.w > 0) meow_ui_invalidate(r_grid.x, r_grid.y, r_grid.w, r_grid.h);
|
||
}
|
||
|
||
/* ============================================================ */
|
||
/* ③ meow_listview 行左滑删除(swipe-delete) */
|
||
/* ============================================================ */
|
||
#define LV_MAX 9
|
||
static meow_widget *g_lv = NULL; /* W_LISTVIEW(注册表自动画:行 + 右露删除区) */
|
||
static rect_t r_lv = { 0, 0, 0, 0 };
|
||
static int g_lv_deleted[LV_MAX]; /* 1=已删除(行移除;count 实时收缩) */
|
||
static char g_lv_label[LV_MAX][24]; /* 行标题(bind 填充) */
|
||
static int g_lv_scroll = 0; /* 跨重建保留:列表滚动 */
|
||
static int g_lv_focus = 0; /* 1=swipe-list 聚焦(swipe 滚列表而非页面) */
|
||
static int g_lv_swipe = 0; /* 行左滑在途(swipe_begin 命中;hit 里 swipe_end) */
|
||
static int g_drag_lv = 0; /* 触摸拖列表(竖向滚动);d. 左滑时同置位 */
|
||
static int g_lv_last_y = 0;
|
||
#define LV_H 190
|
||
|
||
static int lv_count_remaining(void)
|
||
{
|
||
int n = 0;
|
||
for (int i = 0; i < LV_MAX; i++) if (!g_lv_deleted[i]) n++;
|
||
return n;
|
||
}
|
||
static int lv_count(void *ctx) { (void)ctx; return lv_count_remaining(); }
|
||
|
||
/* 显示下标(0..count-1)→ 源行 id(跳过已删除行)。删除后行前移,身份按源行稳定。 */
|
||
static int lv_real_index(int display)
|
||
{
|
||
if (display < 0) return -1;
|
||
int c = 0;
|
||
for (int i = 0; i < LV_MAX; i++) {
|
||
if (g_lv_deleted[i]) continue;
|
||
if (c == display) return i;
|
||
c++;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static void lv_bind(int idx, meow_lv_item *item, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
int real = lv_real_index(idx);
|
||
static char s[24];
|
||
memset(item, 0, sizeof *item);
|
||
snprintf(s, sizeof s, "swipe left");
|
||
item->title = (real >= 0) ? g_lv_label[real] : "";
|
||
item->subtitle = s;
|
||
item->icon_kind = (real >= 0 && real % 3 == 0) ? MEOW_LIST_ICON_FOLDER : MEOW_LIST_ICON_NONE;
|
||
item->right = MEOW_LIST_RIGHT_NONE;
|
||
item->enabled = 1;
|
||
}
|
||
/* on_delete(swipe 删除动画滑出完成回调):删除该显示下标对应的源行 + 局部刷。
|
||
* 注:swipe_end 传的是显示下标(含删除前定位的 swipe_idx);映射回源行 id 标记。 */
|
||
static void lv_delete(int idx, void *ctx)
|
||
{
|
||
(void)ctx;
|
||
int real = lv_real_index(idx);
|
||
if (real >= 0) g_lv_deleted[real] = 1;
|
||
meow_log(MEOW_LOG_INFO, "sdk2 swipe delete display=%d real=%d", idx, real);
|
||
if (g_lv && r_lv.w > 0) meow_ui_invalidate(r_lv.x, r_lv.y, r_lv.w, r_lv.h);
|
||
}
|
||
|
||
/* 建三节时填充行标题(demo_init 一次性;跨重建保留)。 */
|
||
static void sdk2_init_rows(void)
|
||
{
|
||
for (int i = 0; i < LV_MAX; i++) {
|
||
snprintf(g_lv_label[i], sizeof g_lv_label[i], "notif %d", i);
|
||
g_lv_deleted[i] = 0;
|
||
}
|
||
}
|
||
|
||
static int s2_built = 0; /* 1=本子视图内容已建(on_draw / 事件分发判空) */
|
||
|
||
/* ============================================================ */
|
||
/* 释放 / 建三节 */
|
||
/* ============================================================ */
|
||
|
||
/* 内容释放(demo_free_content 调):清引用(本子视图建的控件在 sdk2_release 释放)。 */
|
||
void sdk2_release(void)
|
||
{
|
||
if (g_grid) { meow_lazygrid_free(g_grid); g_grid = NULL; }
|
||
if (g_btn_sel) { meow_widget_free(g_btn_sel); g_btn_sel = NULL; }
|
||
if (g_lv) { meow_widget_free(g_lv); g_lv = NULL; }
|
||
r_selbtn = r_selval = r_grid = r_lv = RX(0, 0, 0, 0);
|
||
g_drag_grid = 0; g_grid_focus = 0; g_grid_last_y = 0;
|
||
g_lv_focus = 0; g_lv_swipe = 0; g_drag_lv = 0; g_lv_last_y = 0;
|
||
s2_built = 0;
|
||
if (g_sdk2_view) g_sdk2_view->x = g_sdk2_view->y = g_sdk2_view->w = g_sdk2_view->h = 0;
|
||
}
|
||
|
||
/* 内容重建后建三节(demo_build_at 调)。入参:yb_base=base 空间 y;ct/scroll 同 demo.c
|
||
* (SY(base)=ct+base-scroll)。返回下一 base y。 */
|
||
int sdk2_build_at(int yb_base, int ct, int scroll)
|
||
{
|
||
#define SY2(b) (ct + (b) - scroll)
|
||
int yb = yb_base;
|
||
|
||
/* ---- ① SELECT ---- */
|
||
s2_t1_y = SY2(yb);
|
||
yb += 26;
|
||
r_selbtn = RX(S2_X, SY2(yb), S2_DCW, S2_DBH);
|
||
g_btn_sel = meow_btn_create_variant(r_selbtn.x, r_selbtn.y, r_selbtn.w, r_selbtn.h,
|
||
"CHOOSE", MEOW_BTN_OUTLINED);
|
||
r_selval = RX(S2_X + S2_DCW + 14, SY2(yb) + 10, S2_W - S2_DCW - 14, 24);
|
||
yb += S2_CH;
|
||
|
||
/* ---- ② LAZYGRID ---- */
|
||
s2_t2_y = SY2(yb);
|
||
yb += 30;
|
||
r_grid = RX(S2_X, SY2(yb), S2_W, GRID_H);
|
||
g_grid = meow_lazygrid_create(r_grid.x, r_grid.y, r_grid.w, r_grid.h,
|
||
GRID_COLS, GRID_CW, GRID_CH, GRID_GAP);
|
||
if (g_grid) {
|
||
meow_lazygrid_set_vsource(g_grid, grid_count, grid_bind, NULL);
|
||
meow_lazygrid_set_item_draw(g_grid, grid_cell, NULL);
|
||
meow_lazygrid_set_empty_text(g_grid, "No apps");
|
||
meow_lazygrid_set_on_tap(g_grid, grid_tap, NULL);
|
||
meow_lazygrid_set_scroll(g_grid, g_grid_scroll);
|
||
meow_lazygrid_set_sel(g_grid, g_grid_sel);
|
||
}
|
||
yb += GRID_H + 30;
|
||
|
||
/* ---- ③ SWIPE-DELETE ---- */
|
||
s2_t3_y = SY2(yb);
|
||
yb += 26;
|
||
r_lv = RX(S2_X, SY2(yb), S2_W, LV_H);
|
||
g_lv = meow_listview_create(r_lv.x, r_lv.y, r_lv.w, r_lv.h, 0,
|
||
NULL, NULL, MEOW_LIST_SEL_NONE);
|
||
if (g_lv) {
|
||
meow_listview_set_item_h(g_lv, 48);
|
||
meow_listview_set_vsource(g_lv, lv_count, lv_bind, NULL);
|
||
meow_listview_set_item_renderer(g_lv, 2, 1, 0); /* 双行、左图标、无右尾件 */
|
||
meow_listview_set_empty_text(g_lv, "All rows deleted");
|
||
meow_listview_set_swipe_delete(g_lv, 1, lv_delete, NULL);
|
||
meow_listview_set_scroll(g_lv, g_lv_scroll);
|
||
}
|
||
yb += LV_H + 10;
|
||
|
||
if (g_sdk2_view) {
|
||
g_sdk2_view->x = S2_X; g_sdk2_view->y = s2_t1_y;
|
||
g_sdk2_view->w = S2_W; g_sdk2_view->h = (r_lv.y + r_lv.h) - s2_t1_y;
|
||
}
|
||
s2_built = 1;
|
||
return yb;
|
||
#undef SY2
|
||
}
|
||
|
||
/* ---- on_draw:三节标题 + select 当前值 + 宫格(非保留,invalidate 触发重画)---- */
|
||
static void sdk2_draw_on(meow_view *v, const meow_theme *th, void *ctx)
|
||
{
|
||
(void)v; (void)th; (void)ctx;
|
||
if (!s2_built) return;
|
||
const meow_theme *t = meow_theme_get();
|
||
meow_ui_text(S2_X, s2_t1_y, "SELECT (enum/preset)", 20, t->primary);
|
||
meow_ui_text(S2_X, s2_t2_y, "LAZYGRID (2D virtualized)", 20, t->primary);
|
||
meow_ui_text(S2_X, s2_t3_y, "LISTVIEW swipe-delete", 20, t->primary);
|
||
char buf[40];
|
||
snprintf(buf, sizeof buf, "sel = %s", g_sel_items[g_sel_cur]);
|
||
meow_ui_text(r_selval.x, r_selval.y, buf, 20, t->dim);
|
||
if (g_grid) meow_lazygrid_draw(g_grid, t);
|
||
}
|
||
|
||
/* ============================================================ */
|
||
/* 事件分发(demo 页转发) */
|
||
/* ============================================================ */
|
||
|
||
/* tap:select 按钮 → 打开模态;列表行左滑松手 → swipe_end;宫格 → tap_at;列表行 → tap。 */
|
||
int sdk2_hit(int x, int y)
|
||
{
|
||
if (!s2_built) return 0;
|
||
/* 行左滑【松手】最优先:滑动后手指可能已移出列表矩形(只判在途标志)。 */
|
||
if (g_lv && g_lv_swipe) {
|
||
meow_listview_set_scroll(g_lv, g_lv_scroll);
|
||
int c = meow_listview_swipe_end(g_lv, x, y); /* 判删/回弹;动画由 meow_anim_tick 推进 */
|
||
g_lv_swipe = 0;
|
||
if (c) return 1; /* 消费(删/回弹动画中);未滑动=0 落行选中 */
|
||
}
|
||
if (g_btn_sel && meow_widget_hit(g_btn_sel, x, y)) {
|
||
sdk2_select_open();
|
||
meow_ui_invalidate(r_selbtn.x, r_selbtn.y, r_selbtn.w, r_selbtn.h);
|
||
return 1;
|
||
}
|
||
if (g_grid && meow_lazygrid_hit(g_grid, x, y) >= 0) {
|
||
meow_lazygrid_tap_at(g_grid, x, y); /* 置选中 + grid_tap 回调 + 局部刷 */
|
||
return 1;
|
||
}
|
||
if (g_lv && meow_listview_hit(g_lv, x, y) >= 0) {
|
||
meow_listview_tap_at(g_lv, x, y); /* 行点击(演示选中)+ 局部刷 */
|
||
meow_ui_invalidate(r_lv.x, r_lv.y, r_lv.w, r_lv.h);
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* touch_down:命中区置拖拽/聚焦。宫格>列表。返回 1=本区消费。 */
|
||
int sdk2_down(int x, int y)
|
||
{
|
||
if (!s2_built) return 0;
|
||
/* 新手势先复位本子视图拖拽态:demo_touch_down 只复位 list/slider/page 标志,不触及 sdk2
|
||
* 的 g_drag_grid/g_drag_lv/g_lv_swipe(sdk2.c 内部,demo 页经 extern 看不到);不复位则上一条
|
||
* sdk2 拖拽残留会在本次「落页内容区」新手势的 move 里继续劫持页面拖动(sdk2_move 守卫误判)。 */
|
||
g_drag_grid = 0; g_drag_lv = 0; g_lv_swipe = 0;
|
||
if (g_grid && meow_lazygrid_hit(g_grid, x, y) >= 0) {
|
||
g_drag_grid = 1; g_grid_focus = 1; g_grid_last_y = y;
|
||
return 1;
|
||
}
|
||
if (g_lv && meow_listview_hit(g_lv, x, y) >= 0) {
|
||
meow_listview_set_scroll(g_lv, g_lv_scroll);
|
||
g_lv_swipe = meow_listview_swipe_begin(g_lv, x, y); /* 命中可滑行 → 1 */
|
||
g_lv_focus = 1; g_drag_lv = 1; g_lv_last_y = y;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* touch_move:宫格滚动 / 列表左滑 move(消费→不滚页面)或列表竖向滚动。返回 1=消费。 */
|
||
int sdk2_move(int x, int y)
|
||
{
|
||
if (!s2_built) return 0;
|
||
if (g_drag_grid && g_grid) {
|
||
int dy = y - g_grid_last_y; g_grid_last_y = y;
|
||
meow_lazygrid_scroll_by(g_grid, -dy);
|
||
g_grid_scroll = meow_lazygrid_scroll(g_grid);
|
||
if (r_grid.w > 0) meow_ui_invalidate(r_grid.x, r_grid.y, r_grid.w, r_grid.h);
|
||
return 1;
|
||
}
|
||
/* 列表滚动须在「本次手势命中列表」才消费(g_drag_lv,由 sdk2_down 命中列表置位)。
|
||
* 若仅因 g_lv 存在就无条件消费,会劫持 demo 页内容区拖拽(任何 move 都被这里吃掉,
|
||
* 页面永不滚动)——与 grid(g_drag_grid 守卫)同构;359 教训同源(SDK 控件局部刷对,
|
||
* 错在调用方控制流把页面滚动让给了控件)。 */
|
||
if (g_drag_lv && g_lv) {
|
||
if (g_lv_swipe) { /* 行左滑在途:喂 move;1=横向消费;0=纵向主导→取消本行 swipe */
|
||
meow_listview_set_scroll(g_lv, g_lv_scroll);
|
||
if (meow_listview_swipe_move(g_lv, x, y)) return 1;
|
||
g_lv_swipe = 0;
|
||
}
|
||
int dy = y - g_lv_last_y; g_lv_last_y = y; /* 竖向滚动(跟手) */
|
||
meow_listview_scroll_by(g_lv, -dy);
|
||
g_lv_scroll = meow_listview_scroll(g_lv);
|
||
if (r_lv.w > 0) meow_ui_invalidate(r_lv.x, r_lv.y, r_lv.w, r_lv.h);
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* swipe UP/DOWN:宫格/列表聚焦时滚自身(del 已按方向加权),1=已消费。 */
|
||
int sdk2_swipe(int del)
|
||
{
|
||
if (!s2_built) return 0;
|
||
if (g_grid_focus && g_grid) {
|
||
meow_lazygrid_scroll_by(g_grid, del);
|
||
g_grid_scroll = meow_lazygrid_scroll(g_grid);
|
||
if (r_grid.w > 0) meow_ui_invalidate(r_grid.x, r_grid.y, r_grid.w, r_grid.h);
|
||
return 1;
|
||
}
|
||
if (g_lv_focus && g_lv) {
|
||
meow_listview_scroll_by(g_lv, del);
|
||
g_lv_scroll = meow_listview_scroll(g_lv);
|
||
if (r_lv.w > 0) meow_ui_invalidate(r_lv.x, r_lv.y, r_lv.w, r_lv.h);
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 本次手势是否已被本子视图实时滚过(demo_swipe 早退用,防 on_swipe 二次滚动——同 list 的 g_drag_list)。 */
|
||
int sdk2_dragging(void)
|
||
{
|
||
return (g_drag_grid || g_drag_lv) ? 1 : 0;
|
||
}
|
||
|
||
/* ============================================================ */
|
||
/* 子视图生命周期(on_enter/on_leave 由 SDK 递归驱动;on_destroy 清引用) */
|
||
/* ============================================================ */
|
||
static void sdk2_page_enter(meow_view *v, void *ctx)
|
||
{
|
||
(void)v; (void)ctx;
|
||
meow_log(MEOW_LOG_INFO, "demo sdk2 view enter");
|
||
}
|
||
static void sdk2_page_leave(meow_view *v, void *ctx)
|
||
{
|
||
(void)v; (void)ctx;
|
||
meow_log(MEOW_LOG_INFO, "demo sdk2 view leave");
|
||
}
|
||
static void sdk2_page_destroy(meow_view *v, void *ctx)
|
||
{
|
||
(void)v; (void)ctx;
|
||
if (g_sel) { meow_select_free(g_sel); g_sel = NULL; }
|
||
s2_built = 0;
|
||
g_sdk2_view = NULL; /* meow_view_free 递归释放前清引用,防悬垂 */
|
||
}
|
||
|
||
meow_view *sdk2_view_create(void)
|
||
{
|
||
static const meow_view_hooks h = {
|
||
.on_enter = sdk2_page_enter,
|
||
.on_leave = sdk2_page_leave,
|
||
.on_destroy = sdk2_page_destroy,
|
||
.on_draw = sdk2_draw_on,
|
||
};
|
||
/* id 用非页面值:容器不占 g_view_by_id(那是 page_push/pop 顶层页查找表)。 */
|
||
g_sdk2_view = meow_view_create(0x2000, MEOW_VIEW_CONTAINER, &h, NULL);
|
||
/* meow_select 实例一次性创建(控制态随本子视图存活,不受内容重建影响);行标题一次性填充。 */
|
||
sdk2_init_rows();
|
||
if (g_sdk2_view && !g_sel) {
|
||
g_sel = meow_select_create("Sample rate", 0);
|
||
if (g_sel) {
|
||
for (int i = 0; i < SEL_N; i++) meow_select_add_item(g_sel, g_sel_items[i]);
|
||
meow_select_set_on_change(g_sel, sdk2_sel_change, NULL);
|
||
}
|
||
}
|
||
return g_sdk2_view;
|
||
}
|
||
meow_view *sdk2_view_get(void)
|
||
{
|
||
return g_sdk2_view;
|
||
}
|