Files
MeowOS-For-R3P2/patch_v2/hello_app/ui/demo.c
T
MeowOS 1d2496b38c refactor(hello): 视图框架批次② — hello.c 拆分为 app.c+ui/{home,full,demo}.c+ui/common/chrome.c+logic/{notify,state}.c(定案B: demo视图态留ui/;定案b: page导航包装activity栈);test_p1p2p3_repro 改多文件链接形态 (agent-177)
hello f45ba051→c06b3b4f; mipsel -Wall -Wextra 0 warning; 宿主 P1c/P2/P3+widgets 全 PASS
出入(诚实): view on_draw/on_event 路径暂未启用(注册表直绘已覆盖, on_draw 双画风险), 留批③实测; home/full 仍手绘未迁注册表
2026-08-31 03:31:09 +08:00

465 lines
23 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.c — 控件库 Demo 演示页(ACT_DEMO)view + 控制器。
*
* 内容控件以绝对坐标创建,页滚动 = 按「base_y - scroll」重建内容(owner=ACT_DEMO 不变);
* 各控件跨重建状态存 g_ds(App 持有),重建后恢复。绘制走 batch① 郑序注册表:demo_paint 调
* meow_ui_set_page_bg + meow_ui_paint_full(整帧按 z 重画:内容→标题/slider值→chrome 置顶),
* 局部刷新统一 meow_ui_invalidate(清底+按 z 重画相交绘制物)。旧 d_paint_region/d_redraw/
* d_rect_overlap(App 层郑栈重画)已删、下沉 SDK。
*
* 设计定案 B(SDK_VIEW_FRAMEWORK_DESIGN §B.3/F):demo 的 g_ds/g_drag_* /g_demo_scroll 等视图态
* 留本文件(不迁 logic);UI→业务只经 logic_* / notify_*。页面进入/离开经 meow_view_page_push/pop
* 驱动 on_enter/on_leave(demo_page_enter/leave)。
*/
#include "hello_internal.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/* 供 demo_content_tap / touch 回调用的前向声明 */
static void demo_slider_drag(int x);
static demo_ctrl g_demo_ctrl;
/* ---- demo 演示页状态 ---- */
int g_demo = 0; /* 1=处于 demo 演示页 */
int g_demo_scroll = 0; /* 内容区滚动偏移(base 空间 px) */
int g_demo_focus = 0; /* 1=LazyColumn 聚焦(swipe 滚列表而非页面) */
static int g_demo_fab = 0; /* FAB 点击计数反馈 */
static int g_demo_prog = 0; /* ProgressBar 动画当前值 0..100 */
static uint64_t g_demo_prog_last = 0;
static int g_demo_ct = 0; /* 内容视口顶(屏y = statusbar+56+8) */
static int g_demo_cb = 0; /* 内容视口底(屏y =608,NavBar 上方留白) */
static int g_demo_content_h = 0;/* 内容总高(base 空间;决定 max_scroll) */
/* M2.71-bug2/6:拖动过程(跟手)状态。on_touch_down 锁一种拖拽,on_touch_move 实时更新。 */
static int g_drag_slider = 0; /* 手指按在 slider */
int g_drag_list = 0; /* 手指按在 LazyColumn:拖拽滚列表 */
int g_drag_page = 0; /* 手指按在页内容(非 slider/list):拖拽滚页面 */
static int g_drag_list_last_y = 0; /* 列表拖拽上一帧 y */
static int g_drag_page_last_y = 0; /* 页面拖拽上一帧 y */
static int g_drag_page_delta = 0; /* 页面拖拽累计位移(节流重建,≥8px 才重建一次) */
/* SDK 控件不透明:App 自记几何,用于局部 flush / 命中 / scroll 重建。 */
/* demo 各控件跨重建保留的状态(app 持有;重建后按此恢复) */
static struct {
int sw_on; int slider; char tf[32];
int ck; int r1, r2; int btn[5]; int card; int tab; int list; int list_sel; int prog;
} g_ds = { .sw_on = 1, .slider = 40, .r1 = 1, .tab = 1, .list = 0, .list_sel = 0, .prog = 0 };
/* demo 内容布局常量(base 空间) */
#define DCL_X 16
#define DCR_X 252
#define DCW 212
#define DFW 448
#define DBH 44
#define DCH 52 /* 一行两列按钮步进 */
/* demo 内容槽:控件 + 其当前屏幕几何(rebuild 时重算) */
#define D_SLOT_MAX 64
static struct { meow_widget *w; rect_t r; } g_dslot[D_SLOT_MAX];
static int g_dslot_n = 0;
/* demo 分区小标题(纯文本,非控件;屏幕坐标在 rebuild 时算好) */
#define D_TITLE_MAX 16
static struct { int x, y; const char *s; } g_dtitle[D_TITLE_MAX];
static int g_dtitle_n = 0;
/* demo 交互组件引用(rebuild 时 g_* 与 r_* 同步重指/recompute;chrome 在 ui/common/chrome.c) */
static meow_widget *g_dbtn_b[5]; static rect_t r_btn[5]; /* Button 五型 */
static meow_widget *g_dbtn_d; /* DISABLED 按钮(禁用不命中,无需 rect) */
static meow_widget *g_dsw; static rect_t r_dsw; /* Switch */
static meow_widget *g_dslider; static rect_t r_slider, r_slider_txt; /* Slider + 值文本 */
static meow_widget *g_dtf; static rect_t r_dtf; /* TextField */
static meow_widget *g_dcb; static rect_t r_dcb; /* Checkbox */
static meow_widget *g_dr1, *g_dr2; rect_t r_dr1, r_dr2; /* Radio 单选组 */
static meow_widget *g_dprl; static rect_t r_prl; /* ProgressBar 线性 */
meow_widget *g_dprc; rect_t r_prc; /* ProgressBar 圆形 */
static meow_widget *g_dcard; static rect_t r_card; /* Card */
static meow_widget *g_dcard_btn; static rect_t r_cardbtn; /* Card 内容子按钮 */
static meow_widget *g_dbadge; /* Badge */
static meow_widget *g_dtab; static rect_t r_tab; /* TabBar */
static meow_widget *g_dbtn_dlg; static rect_t r_dlg; /* 打开 Dialog 的按钮 */
static meow_widget *g_dbtn_sheet; static rect_t r_sheet;/* 打开 BottomSheet 的按钮 */
meow_widget *g_dlc; rect_t r_list; /* LazyColumn */
/* ---- demo 分区标题/slider 值文本:注册为 CUSTOM 绘制物(§6.2 区域重画会重画它们)----
* 显式 z=D_TITLE_Z:> 一切自动 z(=127)、< chrome 置顶(999)。非控件直绘必须注册,否则
* meow_ui_invalidate 清底后会漏画。 */
#define D_TITLE_Z 128
static int g_dtitle_cid[D_TITLE_MAX]; /* 分区标题绘制物 id(rebuild 时注销/重注册) */
static int g_slider_cid = 0; /* slider 值文本绘制物 id */
/* CUSTOM 绘制回调:分区标题(ctx=title 下标,指向 g_dtitle[i]) */
static void demo_draw_title(void *ctx)
{
int i = (int)(intptr_t)ctx;
if (i < 0 || i >= g_dtitle_n) return;
const meow_theme *th = meow_theme_get();
meow_ui_text(g_dtitle[i].x, g_dtitle[i].y, g_dtitle[i].s, 20, th->primary);
}
/* CUSTOM 绘制回调:slider 当前值文本(bbox=r_slider_txt) */
static void demo_draw_slider_val(void *ctx)
{
(void)ctx;
if (!g_dslider) return;
const meow_theme *th = meow_theme_get();
char buf[28]; snprintf(buf, sizeof buf, "slider = %d", meow_slider_get(g_dslider));
meow_ui_text(r_slider_txt.x, r_slider_txt.y, buf, 20, th->dim);
}
/* ---- demo 构建/布局 ---- */
static void d_slot(meow_widget *w, rect_t r)
{
if (g_dslot_n < D_SLOT_MAX) { g_dslot[g_dslot_n].w = w; g_dslot[g_dslot_n].r = r; g_dslot_n++; }
}
static void d_title(int x, int y, const char *s)
{
if (g_dtitle_n < D_TITLE_MAX) {
int i = g_dtitle_n;
g_dtitle[i].x = x; g_dtitle[i].y = y; g_dtitle[i].s = s;
g_dtitle_n++;
int tw = meow_ui_text_width(s, 20);
int th = meow_ui_text_height(20);
g_dtitle_cid[i] = meow_draw_custom_register(D_TITLE_Z, x, y, tw, th,
demo_draw_title, (void *)(intptr_t)i);
}
}
/* LazyColumn 数据源(100 项虚拟化) */
static int demo_list_src(int idx, char *label, int len, void *ctx)
{
(void)ctx;
if (idx < 0 || idx >= 100) return 0;
snprintf(label, (size_t)len, "list item %d", idx);
return 1;
}
/* 释放当前全部内容控件(含 Card 的独立子按钮)与 CUSTOM 绘制物;chrome 不在其列。 */
static void demo_free_content(void)
{
for (int i = 0; i < g_dslot_n; i++) meow_widget_free(g_dslot[i].w);
g_dslot_n = 0;
if (g_dcard_btn) { meow_widget_free(g_dcard_btn); g_dcard_btn = NULL; }
for (int i = 0; i < g_dtitle_n; i++)
if (g_dtitle_cid[i] > 0) { meow_draw_unregister(g_dtitle_cid[i]); g_dtitle_cid[i] = 0; }
if (g_slider_cid > 0) { meow_draw_unregister(g_slider_cid); g_slider_cid = 0; }
g_dtitle_n = 0;
}
/* 按 scroll 重建全部内容控件(owner=ACT_DEMO:调用方须已 push ACT_DEMO)。
* 控件以绝对坐标创建于 (x, base_y - scroll),几何同步写入 r_* / 槽;状态从 g_ds 恢复。 */
static void demo_build_at(int scroll)
{
int ct = meow_ui_statusbar_height() + 56 + 8;
g_demo_ct = ct; g_demo_cb = 608;
g_dslot_n = 0; g_dtitle_n = 0;
int yb = 0;
#define SY(base) (ct + (base) - scroll) /* base 空间 → 屏幕 y */
#define SLOT(w,x,y,ww,hh) do { rect_t _r=RX(x,y,ww,hh); d_slot((w),_r); } while(0)
/* ---- Buttons(五型 + 禁用) ---- */
d_title(DCL_X, SY(yb), "BUTTONS 5-variants"); yb += 26;
r_btn[0] = RX(DCL_X, SY(yb), DCW, DBH); g_dbtn_b[0] = meow_btn_create_variant(r_btn[0].x, r_btn[0].y, DCW, DBH, "FILLED", MEOW_BTN_FILLED); SLOT(g_dbtn_b[0], r_btn[0].x, r_btn[0].y, r_btn[0].w, r_btn[0].h);
r_btn[1] = RX(DCR_X, SY(yb), DCW, DBH); g_dbtn_b[1] = meow_btn_create_variant(r_btn[1].x, r_btn[1].y, DCW, DBH, "TONAL", MEOW_BTN_TONAL); SLOT(g_dbtn_b[1], r_btn[1].x, r_btn[1].y, r_btn[1].w, r_btn[1].h);
yb += DCH;
r_btn[2] = RX(DCL_X, SY(yb), DCW, DBH); g_dbtn_b[2] = meow_btn_create_variant(r_btn[2].x, r_btn[2].y, DCW, DBH, "OUTLINED", MEOW_BTN_OUTLINED); SLOT(g_dbtn_b[2], r_btn[2].x, r_btn[2].y, r_btn[2].w, r_btn[2].h);
r_btn[3] = RX(DCR_X, SY(yb), DCW, DBH); g_dbtn_b[3] = meow_btn_create_variant(r_btn[3].x, r_btn[3].y, DCW, DBH, "TEXT", MEOW_BTN_TEXT); SLOT(g_dbtn_b[3], r_btn[3].x, r_btn[3].y, r_btn[3].w, r_btn[3].h);
yb += DCH;
r_btn[4] = RX(DCL_X, SY(yb), DCW, DBH); g_dbtn_b[4] = meow_btn_create_variant(r_btn[4].x, r_btn[4].y, DCW, DBH, "ELEVATED", MEOW_BTN_ELEVATED); SLOT(g_dbtn_b[4], r_btn[4].x, r_btn[4].y, r_btn[4].w, r_btn[4].h);
g_dbtn_d = meow_btn_create_variant(DCR_X, SY(yb), DCW, DBH, "DISABLED", MEOW_BTN_FILLED);
SLOT(g_dbtn_d, DCR_X, SY(yb), DCW, DBH);
meow_widget_set_enabled(g_dbtn_d, 0); /* 禁用态:不命中 + 变暗 */
yb += DCH;
for (int i = 0; i < 5; i++) meow_widget_set_selected(g_dbtn_b[i], g_ds.btn[i]);
SLOT(meow_divider_create(DCL_X, SY(yb), DFW, 0), DCL_X, SY(yb), DFW, 1); yb += 16;
/* ---- Input / State(Switch / Slider / TextField / Checkbox / Radio) ---- */
d_title(DCL_X, SY(yb), "INPUT & STATE"); yb += 26;
r_dsw = RX(DCL_X, SY(yb), 56, 32); g_dsw = meow_switch_create(r_dsw.x, r_dsw.y, g_ds.sw_on); SLOT(g_dsw, r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); yb += 44;
r_slider_txt = RX(DCL_X, SY(yb), 160, 24); yb += 24; /* 加宽到覆盖值文本全宽(防局部刷漏尾) */
r_slider = RX(DCL_X, SY(yb), DFW, 40); g_dslider = meow_slider_create(r_slider.x, r_slider.y, r_slider.w, 0, 100, g_ds.slider); SLOT(g_dslider, r_slider.x, r_slider.y, r_slider.w, r_slider.h); yb += 48;
g_slider_cid = meow_draw_custom_register(D_TITLE_Z, r_slider_txt.x, r_slider_txt.y,
r_slider_txt.w, r_slider_txt.h,
demo_draw_slider_val, NULL);
r_dtf = RX(DCL_X, SY(yb), DFW, 44); g_dtf = meow_textfield_create(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h, "Type here...", g_ds.tf, 32, MEOW_IME_ASCII); SLOT(g_dtf, r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h); yb += 54;
r_dcb = RX(DCL_X, SY(yb), 34, 34); g_dcb = meow_checkbox_create(r_dcb.x, r_dcb.y); SLOT(g_dcb, r_dcb.x, r_dcb.y, r_dcb.w, r_dcb.h);
r_dr1 = RX(DCR_X, SY(yb), 34, 34); g_dr1 = meow_radio_create(r_dr1.x, r_dr1.y); SLOT(g_dr1, r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h);
yb += 40;
r_dr2 = RX(DCR_X, SY(yb), 34, 34); g_dr2 = meow_radio_create(r_dr2.x, r_dr2.y); SLOT(g_dr2, r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h);
yb += 40;
meow_widget_set_selected(g_dcb, g_ds.ck);
meow_widget_set_selected(g_dr1, g_ds.r1);
meow_widget_set_selected(g_dr2, g_ds.r2);
/* ---- ProgressBar(线性 + 圆形,on_tick 动画) ---- */
d_title(DCL_X, SY(yb), "PROGRESS (animated)"); yb += 26;
r_prl = RX(DCL_X, SY(yb), DFW, 8); g_dprl = meow_progress_create(r_prl.x, r_prl.y, r_prl.w, r_prl.h, g_ds.prog); SLOT(g_dprl, r_prl.x, r_prl.y, r_prl.w, r_prl.h); yb += 16;
r_prc = RX(DCL_X + 400 + 17 - 20, SY(yb) + 17 - 20, 40, 40);
g_dprc = meow_progress_circular_create(r_prc.x + 20, r_prc.y + 20, 17, g_ds.prog);
SLOT(g_dprc, r_prc.x, r_prc.y, r_prc.w, r_prc.h); yb += 48;
/* ---- Container(Card / Badge / TabBar) ---- */
d_title(DCL_X, SY(yb), "CONTAINER"); yb += 26;
r_card = RX(DCL_X, SY(yb), DFW, 88); g_dcard = meow_card_create(r_card.x, r_card.y, r_card.w, r_card.h); SLOT(g_dcard, r_card.x, r_card.y, r_card.w, r_card.h);
r_cardbtn = RX(DCL_X + 16, SY(yb) + 20, DFW - 32, 40); g_dcard_btn = meow_btn_create_variant(r_cardbtn.x, r_cardbtn.y, r_cardbtn.w, r_cardbtn.h, "IN-CARD BUTTON", MEOW_BTN_TONAL);
meow_widget_set_selected(g_dcard_btn, g_ds.card);
meow_card_set_content(g_dcard, g_dcard_btn);
yb += 96;
g_dbadge = meow_badge_create(DCL_X + 60, SY(yb) + 10);
SLOT(g_dbadge, DCL_X + 52, SY(yb) + 2, 18, 18);
meow_badge_set(g_dbadge, 3);
yb += 30;
r_tab = RX(DCL_X, SY(yb), DFW, 36); g_dtab = meow_tabbar_create(r_tab.x, r_tab.y, r_tab.w, r_tab.h); SLOT(g_dtab, r_tab.x, r_tab.y, r_tab.w, r_tab.h);
meow_tabbar_add_tab(g_dtab, "Playlist");
meow_tabbar_add_tab(g_dtab, "Queue");
meow_tabbar_add_tab(g_dtab, "Now");
meow_tabbar_set_selected(g_dtab, g_ds.tab);
yb += 44;
/* ---- Modals(Dialog + BottomSheet) ---- */
d_title(DCL_X, SY(yb), "MODALS (blocking)"); yb += 26;
r_dlg = RX(DCL_X, SY(yb), DCW, DBH); g_dbtn_dlg = meow_btn_create_variant(r_dlg.x, r_dlg.y, r_dlg.w, r_dlg.h, "DIALOG", MEOW_BTN_OUTLINED); SLOT(g_dbtn_dlg, r_dlg.x, r_dlg.y, r_dlg.w, r_dlg.h);
r_sheet = RX(DCR_X, SY(yb), DCW, DBH); g_dbtn_sheet = meow_btn_create_variant(r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h, "SHEET", MEOW_BTN_OUTLINED); SLOT(g_dbtn_sheet, r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h);
yb += DCH;
/* ---- LazyColumn(100 项列表滚动) ---- */
d_title(DCL_X, SY(yb), "LIST (LazyColumn, tap+swipe)"); yb += 26;
r_list = RX(DCL_X, SY(yb), DFW, 150); g_dlc = meow_lazycolumn_create(r_list.x, r_list.y, r_list.w, r_list.h, 40, 100, demo_list_src, NULL);
SLOT(g_dlc, r_list.x, r_list.y, r_list.w, r_list.h);
meow_list_set_scroll(g_dlc, g_ds.list);
meow_list_set_selected(g_dlc, g_ds.list_sel); /* M2.71-bug8:跨重建保留选中行 */
yb += 158;
g_demo_content_h = yb;
#undef SY
#undef SLOT
}
/* demo 全页重绘:整帧按 z 序重画全部(set_page_bg 清底 + 注册表按 z 升序)。 */
void demo_paint(void)
{
const meow_theme *th = meow_theme_get();
meow_ui_set_page_bg(th->bg); /* 页面底 = 主题 bg(区域/整帧重画清底用) */
meow_ui_paint_full(); /* 整帧按 z 序重画 */
}
/* 重建内容到指定 scroll(clamp 到 [0, max_scroll]);进入/滚动共用 */
void demo_rebuild_to(int scroll)
{
int vp_h = g_demo_cb - g_demo_ct;
int maxs = g_demo_content_h - vp_h;
if (maxs < 0) maxs = 0;
if (scroll < 0) scroll = 0;
if (scroll > maxs) scroll = maxs;
demo_free_content();
demo_build_at(scroll);
g_demo_scroll = scroll;
demo_paint();
}
/* ---- demo 交互 ---- */
/* 局部刷新统一走 SDK meow_ui_invalidate(清底 + 按 z 重画相交绘制物 + 上屏)。 */
static void d_toggle_sel(meow_widget *w, rect_t r)
{
if (!w) return;
meow_widget_set_selected(w, !meow_widget_selected(w));
meow_ui_invalidate(r.x, r.y, r.w, r.h);
}
/* Tap:落点在内容控件上,返回 1=已消费 */
static int demo_content_tap(int x, int y)
{
g_demo_focus = 0; /* 默认切回页滚动;仅命中列表时改置 1 */
for (int i = 0; i < 5; i++)
if (meow_widget_hit(g_dbtn_b[i], x, y)) { d_toggle_sel(g_dbtn_b[i], r_btn[i]); g_ds.btn[i] = meow_widget_selected(g_dbtn_b[i]); return 1; }
if (meow_widget_hit(g_dr1, x, y)) { meow_widget_set_selected(g_dr1, 1); meow_widget_set_selected(g_dr2, 0); g_ds.r1 = 1; g_ds.r2 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; }
if (meow_widget_hit(g_dr2, x, y)) { meow_widget_set_selected(g_dr2, 1); meow_widget_set_selected(g_dr1, 0); g_ds.r2 = 1; g_ds.r1 = 0; meow_ui_invalidate(r_dr1.x, r_dr1.y, r_dr1.w, r_dr1.h); meow_ui_invalidate(r_dr2.x, r_dr2.y, r_dr2.w, r_dr2.h); return 1; }
if (meow_widget_hit(g_dcb, x, y)) { d_toggle_sel(g_dcb, r_dcb); g_ds.ck = meow_widget_selected(g_dcb); return 1; }
if (meow_widget_hit(g_dsw, x, y)) { g_ds.sw_on = !meow_switch_get(g_dsw); meow_switch_set(g_dsw, g_ds.sw_on); meow_ui_invalidate(r_dsw.x, r_dsw.y, r_dsw.w, r_dsw.h); return 1; }
if (meow_widget_hit(g_dslider, x, y)) { demo_slider_drag(x); return 1; }
if (meow_widget_hit(g_dtf, x, y)) {
meow_textfield_activate(g_dtf); /* 阻塞 IME,返回后刷新 + 状态回写 */
strncpy(g_ds.tf, meow_textfield_text(g_dtf), sizeof g_ds.tf - 1);
g_ds.tf[sizeof g_ds.tf - 1] = 0;
meow_ui_invalidate(r_dtf.x, r_dtf.y, r_dtf.w, r_dtf.h);
return 1;
}
if (meow_widget_hit(g_dcard_btn, x, y)) { d_toggle_sel(g_dcard_btn, r_cardbtn); g_ds.card = meow_widget_selected(g_dcard_btn); return 1; }
if (g_dtab) {
int t = meow_tabbar_hit(g_dtab, x, y);
if (t >= 0) { g_ds.tab = t; meow_tabbar_set_selected(g_dtab, t); meow_ui_invalidate(r_tab.x, r_tab.y, r_tab.w, r_tab.h); return 1; }
}
if (meow_widget_hit(g_dbtn_dlg, x, y)) { meow_dialog_show(g_dlg); meow_log(MEOW_LOG_INFO, "dialog result=%d", meow_dialog_result(g_dlg)); meow_ui_invalidate(r_dlg.x, r_dlg.y, r_dlg.w, r_dlg.h); return 1; }
if (meow_widget_hit(g_dbtn_sheet, x, y)) { int r = meow_sheet_open(g_sheet); meow_log(MEOW_LOG_INFO, "sheet result=%d", r); meow_ui_invalidate(r_sheet.x, r_sheet.y, r_sheet.w, r_sheet.h); return 1; }
if (meow_widget_hit(g_dlc, x, y)) {
g_demo_focus = 1;
int li = meow_list_tap_at(g_dlc, x, y); /* M2.71-bug8:命中行→置选中并高亮 */
if (li >= 0) { g_ds.list_sel = li; meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); }
return 1;
}
return 0;
}
/* demo 页 on_tap 分发(chrome → 内容) */
void demo_on_tap(int x, int y)
{
if (g_tb) {
int ah = meow_topappbar_hit(g_tb, x, y);
if (ah == MEOW_TOPBAR_BACK) { meow_view_page_pop(); return; }
}
if (g_fab && meow_widget_hit(g_fab, x, y)) {
g_demo_fab++;
char lb[16]; snprintf(lb, sizeof lb, "+%d", g_demo_fab);
meow_widget_free(g_fab);
g_fab = meow_fab_create(r_fab.x, r_fab.y, 56, lb);
meow_widget_set_z(g_fab, 999); /* 重建后重挂顶:新 entry 自动 z 低,须显式置顶 */
meow_ui_invalidate(r_fab.x, r_fab.y, r_fab.w, r_fab.h); /* 重画 FAB 及其下重叠 z 栈 */
return;
}
if (g_nav) {
int idx = meow_navigationbar_hit(g_nav, x, y);
if (idx >= 0) { meow_navigationbar_set_selected(g_nav, idx); meow_ui_invalidate(r_nav.x, r_nav.y, r_nav.w, r_nav.h); return; }
}
demo_content_tap(x, y);
}
/* demo 页 on_tick:ProgressBar 动画(局部刷,~120ms 步进) */
void demo_tick(uint64_t now)
{
if (g_demo_prog_last == 0) g_demo_prog_last = now;
if (now - g_demo_prog_last < 120) return;
g_demo_prog_last = now;
g_ds.prog = (g_ds.prog + 3) % 101;
g_demo_prog = g_ds.prog;
meow_progress_set(g_dprl, g_demo_prog); meow_ui_invalidate(r_prl.x, r_prl.y, r_prl.w, r_prl.h);
meow_progress_set(g_dprc, g_demo_prog); meow_ui_invalidate(r_prc.x, r_prc.y, r_prc.w, r_prc.h);
}
/* 按触碰 X 落 slider 值并局部刷(按下即定位 + 拖动实时,M2.71-bug2) */
static void demo_slider_drag(int x)
{
int frac = x - r_slider.x; if (frac < 0) frac = 0; if (frac > r_slider.w) frac = r_slider.w;
g_ds.slider = frac * 100 / r_slider.w;
meow_slider_set(g_dslider, g_ds.slider);
meow_ui_invalidate(r_slider.x, r_slider.y, r_slider.w, r_slider.h);
meow_ui_invalidate(r_slider_txt.x, r_slider_txt.y, r_slider_txt.w, r_slider_txt.h); /* 重画值文本 */
}
/* demo 页 on_touch_down:锁一种拖拽(slider > list > 页内容)。 */
void demo_touch_down(int x, int y)
{
g_drag_slider = 0; g_drag_list = 0; g_drag_page = 0; g_drag_page_delta = 0;
if (!g_demo) return;
if (meow_widget_hit(g_dslider, x, y)) { g_drag_slider = 1; demo_slider_drag(x); return; }
if (g_dlc && meow_widget_hit(g_dlc, x, y)) {
g_demo_focus = 1; g_drag_list = 1; g_drag_list_last_y = y; return;
}
g_demo_focus = 0;
if (y >= g_demo_ct && y < g_demo_cb && x >= 0 && x < meow_ui_width()) {
g_drag_page = 1; g_drag_page_last_y = y;
}
}
/* demo 页 on_touch_move:拖动过程实时更新(slider 值 / 列表滚动 / 页面滚动节流重建)。 */
void demo_touch_move(int x, int y)
{
if (!g_demo) return;
if (g_drag_slider) { demo_slider_drag(x); return; }
if (g_drag_list) {
int dy = y - g_drag_list_last_y; g_drag_list_last_y = y;
if (dy) { meow_list_scroll_by(g_dlc, -dy); g_ds.list = meow_list_scroll(g_dlc); meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); }
return;
}
if (g_drag_page) {
int dy = y - g_drag_page_last_y; g_drag_page_last_y = y;
g_drag_page_delta += -dy; /* 手指上移(y 减) → scroll 增(显示更低内容),与 on_swipe 一致 */
if (g_drag_page_delta >= 8 || g_drag_page_delta <= -8) {
demo_rebuild_to(g_demo_scroll + g_drag_page_delta);
g_drag_page_delta = 0;
}
}
}
/* demo 页 on_swipe:LEFT=回 home;UP/DOWN=列表聚焦滚列表,否则页滚动。 */
void demo_swipe(int dir, int dist)
{
if (dir == MEOW_SWIPE_LEFT) { meow_view_page_pop(); return; }
if (dir != MEOW_SWIPE_UP && dir != MEOW_SWIPE_DOWN) return;
if (g_drag_page || g_drag_list) return; /* 本次手势已实时跟手滚动过 */
int del = (dir == MEOW_SWIPE_UP) ? dist : -dist; /* 手指上移 → 偏移增大 */
if (g_demo_focus && g_dlc) {
meow_list_scroll_by(g_dlc, del);
g_ds.list = meow_list_scroll(g_dlc);
meow_ui_invalidate(r_list.x, r_list.y, r_list.w, r_list.h); /* 列表区局部刷新 */
} else {
demo_rebuild_to(g_demo_scroll + del);
}
}
/* ---- demo 页 view(on_enter/on_leave/on_destroy 驱动进入/离开/释放)---- */
static void demo_page_enter(meow_view *v, void *ctx)
{
(void)v;
((demo_ctrl *)ctx)->active = 1;
g_demo = 1;
g_demo_focus = 0;
demo_rebuild_to(0);
meow_log(MEOW_LOG_INFO, "demo enter scroll=0");
}
static void demo_page_leave(meow_view *v, void *ctx)
{
(void)v;
((demo_ctrl *)ctx)->active = 0;
g_demo = 0;
}
static void demo_page_destroy(meow_view *v, void *ctx)
{
(void)v; (void)ctx;
demo_free_content(); /* 内容控件 + CUSTOM 标题/slider值 */
chrome_free(); /* chrome(TopAppBar / NavigationBar / FAB) */
}
void demo_init(void)
{
meow_ui_activity_push(ACT_DEMO);
chrome_create(); /* chrome 位置/置顶在 chrome.c */
demo_build_at(0);
meow_ui_activity_pop();
g_demo_scroll = 0;
}
int demo_is_active(void)
{
return g_demo;
}
/* demo view:on_create 建 chrome+内容(一次,owner=ACT_DEMO);进入时 rebuild 到顶。 */
static void demo_page_create(meow_view *v, void *ctx)
{
(void)v;
((demo_ctrl *)ctx)->view = v;
demo_init();
}
meow_view *demo_view_create(void)
{
static const meow_view_hooks h = {
.on_create = demo_page_create,
.on_enter = demo_page_enter,
.on_leave = demo_page_leave,
.on_destroy = demo_page_destroy,
};
return meow_view_create(ACT_DEMO, MEOW_VIEW_ACTIVITY, &h, &g_demo_ctrl);
}