Files
MeowOS-SDK/examples/hello/ui/demo/sdk2/sdk2.c
T
AskaEth c0396e40ce sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓
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;工作区无生成物。
2026-09-04 18:05:36 +08:00

456 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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;
}