M2.60→M2.61 骨架: SDK Activity 栈 + 控件归属(agent-122) + 按钮去圈/即时重绘(agent-119) + SDK 模板文档(agent-121)
- SDK §6.1 三层控件模型: Activity栈(push/pop/active) + 页面控件归属 owner + meow_ui_global_* 骨架(②) + 系统级仅内部接口(③) - meow_widget 加 owner; live_btn_hit/meow_widget_hit 仅 active activity 命中; touch_refresh stale 保护 - 根治"全屏页触摸主页按钮闪现"(跨页面控件残留); 控件对象复用弹栈不重建 - hello 迁移双 Activity(home/full): 全屏左滑=弹栈回主页, 根左滑=退出 - agent-119 按钮去圈(纯色accent+黑12/24%)+即时局部重绘保留; agent-121 SDK模板§5.3-5.7
This commit is contained in:
1 parent
07c556e907
commit
6824defdf9
13 files changed
+613
-23
No files matched your search
Binary file not shown.
@@ -28,6 +28,12 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
/* §6.1 ①:Activity 归属。主界面(根,stack 空时 active()=0)绑定全部按钮控件;
|
||||
* 全屏沉浸页为独立 Activity(无控件)——触摸它绝不命中主界面按钮(根治跨页残留)。
|
||||
* 进全屏 meow_ui_activity_push(ACT_FULL),退出 pop 回根(主界面按钮恢复可点,对象复用)。 */
|
||||
#define ACT_HOME 0
|
||||
#define ACT_FULL 1
|
||||
|
||||
static meow_widget *g_btn;
|
||||
static meow_widget *g_nbtn[6]; /* 通知触发按钮行 */
|
||||
static meow_widget *g_cancel; /* 取消最近一条通知 */
|
||||
@@ -128,13 +134,19 @@ static void notif_cancel(void)
|
||||
* - fullscreen(1) + collapsed(1):状态栏「上收出屏只留提示线」(不完全沉浸,inset=4px),
|
||||
* 顶部提示线热区仍可下拉,左缘返回手势(app 已注册 on_swipe)仍生效——SDK 自动处理,非 app 拦截;
|
||||
* - fullscreen(0) + collapsed(0):恢复整条状态栏主界面。
|
||||
* SDK 基座默认瞬切(g_sbar_collapse_anim_ms=0);如需过渡动画可先 meow_ui_statusbar_animate(ms)。 */
|
||||
* SDK 基座默认瞬切(g_sbar_collapse_anim_ms=0);如需过渡动画可先 meow_ui_statusbar_animate(ms)。
|
||||
* §6.1 ①:全屏 = 独立 Activity——进时压栈 ACT_FULL(主界面控件因 owner=ACT_HOME 不再参与命中,
|
||||
* 根治「全屏页触摸到主页按钮区域闪现」);退时弹栈回根,主界面按钮恢复可点(对象复用零重建)。 */
|
||||
static void set_fullscreen(int on)
|
||||
{
|
||||
g_fullscreen = on ? 1 : 0;
|
||||
meow_ui_set_fullscreen(g_fullscreen);
|
||||
meow_ui_statusbar_set_collapsed(g_fullscreen);
|
||||
meow_log(MEOW_LOG_INFO, g_fullscreen ? "fullscreen ON (collapsed)" : "fullscreen OFF (restore)");
|
||||
if (on) meow_ui_activity_push(ACT_FULL);
|
||||
else meow_ui_activity_pop();
|
||||
meow_log(MEOW_LOG_INFO, g_fullscreen ? "fullscreen ON (collapsed), activity->%d"
|
||||
: "fullscreen OFF (restore), activity->%d",
|
||||
meow_ui_activity_active());
|
||||
}
|
||||
|
||||
static void redraw(void)
|
||||
@@ -219,7 +231,12 @@ static void on_swipe_progress(int x_start, int dx)
|
||||
static void on_swipe(int dir, int dx, int dy)
|
||||
{
|
||||
(void)dx; (void)dy;
|
||||
if (dir == MEOW_SWIPE_LEFT) { meow_log(MEOW_LOG_INFO, "exit:swipe"); meow_ui_request_exit(); }
|
||||
if (dir == MEOW_SWIPE_LEFT) {
|
||||
/* §6.1 导航栈语义:非根(全屏)→ 左滑返回主页(pop),不退出;根 → 退出回应用列表。
|
||||
* 保证 on_swipe(LEFT) 在沉浸页=退出全屏回主页,而非直接退出整个 app。 */
|
||||
if (g_fullscreen) { set_fullscreen(0); redraw(); }
|
||||
else { meow_log(MEOW_LOG_INFO, "exit:swipe"); meow_ui_request_exit(); }
|
||||
}
|
||||
}
|
||||
|
||||
static void on_tick(void)
|
||||
|
||||
Binary file not shown.
@@ -10,7 +10,7 @@ AR="${AR:-/usr/bin/ar}" # 系统 GNU ar 即可归档 mipsel ELF 对象(架
|
||||
rm -f meow_ui.a *.o
|
||||
|
||||
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
||||
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol stb_image"
|
||||
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global stb_image"
|
||||
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
||||
for f in $OBJS; do
|
||||
echo "== cc $f =="
|
||||
|
||||
@@ -156,6 +156,43 @@ void meow_ui_request_exit(void); /* 请求退出(相当于返回/
|
||||
* x<=0 时清掉此前画的条(填回背景色)。不发 flush,由调用方 meow_ui_flush_region 上屏。 */
|
||||
void meow_ui_swipe_hint(int x);
|
||||
|
||||
/* ============================================================ */
|
||||
/* §6.1 控件生命周期与归属(Activity 栈 + 三层控件模型) [源:2026-08-30] */
|
||||
/* ============================================================ */
|
||||
/* 根治「跨页面控件残留」:控件命中/绘制必须严格绑定其所属页面,否则会出现
|
||||
* "按钮已不可见但仍被触摸命中"(如全屏页触摸到主页按钮位置闪现 accent 底)。
|
||||
*
|
||||
* 三层职责(从 App 到系统,风险从低到高):
|
||||
* ① 页面控件:归属唯一 owner Activity;命中/实时按压只在「当前 active Activity
|
||||
* 的控件集」里生效。对象不销毁(同 Activity 内复用),弹栈回来自动恢复 →
|
||||
* 回页面零重建。
|
||||
* ② App 跨 Activity 控件(SDK 托管):钉在 App 的 Activity 栈之上、跨 Activity 常驻,
|
||||
* 逻辑/渲染由 SDK 调度。本轮为「可用骨架」(见上 API 注释),待 B2 细化。
|
||||
* ③ 系统级控件(状态栏/通知中心/返回滑条/电源菜单):仅框架内部,无公共 API(不开放)。
|
||||
*
|
||||
* 触摸命中分流顺序:③ 系统全局 → ② App 全局 → ① 当前 active Activity 页面控件;
|
||||
* 某层命中即消费,否则落到下一层。 */
|
||||
|
||||
/* ① Activity 栈。控件创建时绑定「当前 active Activity」为 owner;弹栈回来自动恢复。
|
||||
* 栈空时 active() 返回 0(根/default Activity),故未显式管理栈的 App 默认所有控件
|
||||
* 归属根 Activity 0。push 新 Activity(进子页/全屏)、pop 回上级(回根)。 */
|
||||
void meow_ui_activity_push(int id);
|
||||
void meow_ui_activity_pop(void);
|
||||
int meow_ui_activity_active(void); /* 当前 active activity id(栈空=0) */
|
||||
|
||||
/* ② App 跨 Activity 控件(SDK 托管,骨架)。SDK 维护全局控件列表:
|
||||
* - 渲染:每帧(有脏区需上屏时,meow_ui_gfx present())在 active activity 内容之上、
|
||||
* 全局状态栏之下调用 render_cb(跨 Activity 常驻);
|
||||
* - 触摸:TAP 先给 global hit_cb(返回 1=消费),否则落到 active activity 页面控件。
|
||||
* 逻辑/渲染由 SDK 调度,App 只需声明。注:骨架,待 B2 细化。 */
|
||||
typedef void (*meow_global_render_fn)(void *ctx); /* 每次渲染帧回调(SDK 调用) */
|
||||
typedef int (*meow_global_hit_fn)(void *ctx, int x, int y); /* 命中返回1=消费 */
|
||||
void meow_ui_global_add(int id, meow_global_render_fn r, meow_global_hit_fn h, void *ctx);
|
||||
void meow_ui_global_remove(int id);
|
||||
|
||||
/* ③ 系统级控件:状态栏/通知中心/左缘返回滑条/电源菜单等全局叠加层——仅 SDK 内部接口,
|
||||
* 不向用户 App 开放任何公共悬浮/叠加层 API。既有状态栏/返回滑条逻辑(§3.1)不动。 */
|
||||
|
||||
/* ============================================================ */
|
||||
/* §3.1 全局状态栏 / 全屏(A-0,SDK 系统级组件) */
|
||||
/* ============================================================ */
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* meow_ui_activity.c — Activity 栈(§6.1 ①)。
|
||||
*
|
||||
* 控件严格归属创建它的 Activity;命中/实时按压只在「当前 active Activity」的控件集里
|
||||
* 生效(见 meow_ui_widget.c 的 owner 绑定 + live_btn_hit/meow_widget_hit 过滤)。
|
||||
* 栈空时 active() 返回 0(根/default Activity)。
|
||||
*
|
||||
* 依赖:无(纯静态数组 + 无外部符号),宿主/真机均可链入,便于单测。
|
||||
* 语义:push = 压栈(新 Activity 成为 active); pop = 弹栈(回上级,栈空则停在根 0)。
|
||||
*/
|
||||
#include "meow_ui.h"
|
||||
|
||||
#define MEOW_ACT_MAX 32
|
||||
|
||||
static int g_act[MEOW_ACT_MAX];
|
||||
static int g_act_n = 0;
|
||||
|
||||
void meow_ui_activity_push(int id)
|
||||
{
|
||||
if (g_act_n >= MEOW_ACT_MAX)
|
||||
return; /* 栈满:静默钳制(骨架级,不崩) */
|
||||
g_act[g_act_n++] = id;
|
||||
}
|
||||
|
||||
void meow_ui_activity_pop(void)
|
||||
{
|
||||
if (g_act_n > 0) g_act_n--;
|
||||
}
|
||||
|
||||
int meow_ui_activity_active(void)
|
||||
{
|
||||
return g_act_n > 0 ? g_act[g_act_n - 1] : 0;
|
||||
}
|
||||
@@ -652,6 +652,10 @@ static void present(void)
|
||||
if (!g_refresh_always_max) {
|
||||
if (g_last_present_ms && now - g_last_present_ms < (unsigned long long)period) return;
|
||||
}
|
||||
/* §6.1 ②:App 跨 Activity 全局控件(SDK 托管骨架)。在 active activity 内容之上、
|
||||
* 全局状态栏之下绘制——跨 Activity 常驻,仅在有帧需上屏(已过帧率门控)时调用。
|
||||
* render_cb 内的 meow_ui_* 绘制会自行标脏,随下方 dirty 列表一并上屏。 */
|
||||
meow_ui_global_render();
|
||||
/* 全局状态栏(A-0)+ 上收(collapsed)基座:上屏前把状态栏画进 back_buf 顶部行。
|
||||
* 展开态=整条(MUI_SBAR_H 行);收合态只占/清「提示线」区域(MUI_SBAR_COLLAPSE_H 行),
|
||||
* app 内容(inset=提示线高)可上移到提示线下缘,无 28px 空条。全屏/隐藏时 active()==0
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* meow_ui_global.c — App 跨 Activity 控件(§6.1 ②,SDK 托管骨架)。
|
||||
*
|
||||
* SDK 维护一个全局控件列表(钉在 App 的 Activity 栈之上、跨 Activity 常驻):
|
||||
* - 渲染:meow_ui_gfx present() 每帧在 active activity 内容之上、全局状态栏之下调
|
||||
* meow_ui_global_render()(遍历列表调 render_cb);
|
||||
* - 触摸:meow_ui_input TAP 分发先给 meow_ui_global_hit(x,y)——命中返回 1=消费,
|
||||
* 否则落到 active activity 页面控件(①)。
|
||||
*
|
||||
* 骨架(待 B2 细化):无 z 序细分/无按压态管理/无命中区排布——App 的 render/hit 回调
|
||||
* 自行决定绘制与命中。跨 Activity 常驻由「列表不随 Activity 栈变化」天然保证。
|
||||
*/
|
||||
#include "meow_ui.h"
|
||||
|
||||
#define MEOW_GLOBAL_MAX 16
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
meow_global_render_fn render;
|
||||
meow_global_hit_fn hit;
|
||||
void *ctx;
|
||||
} gentry;
|
||||
|
||||
static gentry g_globals[MEOW_GLOBAL_MAX];
|
||||
static int g_global_n = 0;
|
||||
|
||||
void meow_ui_global_add(int id, meow_global_render_fn r, meow_global_hit_fn h, void *ctx)
|
||||
{
|
||||
for (int i = 0; i < g_global_n; i++)
|
||||
if (g_globals[i].id == id) return; /* 同 id 幂等(重复 add 不新增,骨架) */
|
||||
if (g_global_n >= MEOW_GLOBAL_MAX) return;
|
||||
g_globals[g_global_n].id = id;
|
||||
g_globals[g_global_n].render = r;
|
||||
g_globals[g_global_n].hit = h;
|
||||
g_globals[g_global_n].ctx = ctx;
|
||||
g_global_n++;
|
||||
}
|
||||
|
||||
void meow_ui_global_remove(int id)
|
||||
{
|
||||
for (int i = 0; i < g_global_n; i++) {
|
||||
if (g_globals[i].id == id) {
|
||||
g_globals[i] = g_globals[--g_global_n];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void meow_ui_global_render(void)
|
||||
{
|
||||
for (int i = 0; i < g_global_n; i++)
|
||||
if (g_globals[i].render) g_globals[i].render(g_globals[i].ctx);
|
||||
}
|
||||
|
||||
int meow_ui_global_hit(int x, int y)
|
||||
{
|
||||
for (int i = 0; i < g_global_n; i++)
|
||||
if (g_globals[i].hit && g_globals[i].hit(g_globals[i].ctx, x, y))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -310,6 +310,10 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
startup_cooldown_until = now_ms() + STARTUP_COOLDOWN_MS; /* M2.22(C):启动窗口丢弃 SWIPE */
|
||||
|
||||
while (!g_exit) {
|
||||
/* agent-119:实时触摸按压/按住/释放 → 即时重绘命中按钮区(不等 app 重绘)。
|
||||
* IME 打开时软键盘为覆盖层且拦截触摸,不驱动背后按钮视觉,跳过。 */
|
||||
if (!meow_ime_active()) meow_widget_touch_refresh();
|
||||
|
||||
meow_input_ev e;
|
||||
int got = 0;
|
||||
while (meow_input_pop(&e)) {
|
||||
@@ -323,6 +327,9 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
meow_ui_swipe_hint(-1);
|
||||
meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6);
|
||||
if (meow_ime_active() && meow_ime_handle_tap(e.a, e.b)) continue;
|
||||
/* §6.1 触摸分流:③ 系统全局(IME/状态栏…已在上面消费) → ② App 全局控件
|
||||
* (命中返回 1=消费,否则落到 ① active Activity 页面控件)。 */
|
||||
if (meow_ui_global_hit(e.a, e.b)) continue;
|
||||
if (g_events_set && g_events.on_tap) g_events.on_tap(e.a, e.b);
|
||||
} else if (e.type == MEOW_EV_KEY) {
|
||||
if (g_events_set && g_events.on_key) g_events.on_key(e.a, e.b);
|
||||
|
||||
@@ -64,6 +64,19 @@ unsigned int meow_input_touch_hold_ms(void); /* 按下已持续毫秒
|
||||
* (把按下时刻回拨),便于测按住态;down=0 复位。设备运行时无调用方。 */
|
||||
void meow_input_touch_set(int down, int x, int y, unsigned hold_ms);
|
||||
|
||||
/* ---- 控件层实时刷新(meow_ui_widget.c)----
|
||||
* 每帧由 meow_ui_run 调用(主线程):实时触摸按下/释放/按住达阈值时,重绘命中的按钮区
|
||||
* 并局部上屏,让按压/按住/释放视觉即时反映,无需 app 在 on_tick/on_tap 重绘(agent-119)。
|
||||
* 仅作用于 SDK 控件按钮(meow_widget_draw 的 W_BTN);app 纯自绘不适用。 */
|
||||
void meow_widget_touch_refresh(void);
|
||||
|
||||
/* ---- App 跨 Activity 全局控件(meow_ui_global.c,§6.1 ②骨架)----
|
||||
* 渲染帧(meow_ui_gfx present())在 active activity 内容之上、全局状态栏之下调用
|
||||
* meow_ui_global_render;触摸 TAP 分发先给 meow_ui_global_hit(命中返回 1=消费,
|
||||
* 否则落到 active activity 页面控件)。跨 Activity 常驻,由 SDK 调度。 */
|
||||
void meow_ui_global_render(void);
|
||||
int meow_ui_global_hit(int x, int y);
|
||||
|
||||
/* ---- IME(meow_ui_ime.c)---- */
|
||||
/* 当前是否显示软键盘。 */
|
||||
int meow_ime_active(void);
|
||||
|
||||
+121
-19
@@ -11,7 +11,7 @@
|
||||
|
||||
enum { W_BTN = 0, W_SLIDER = 1, W_SWITCH = 2, W_LIST = 3 };
|
||||
|
||||
/* 按钮「按住」(长按)判定阈值(ms):超过即进入更强态(更深状态层 + 描边环)。
|
||||
/* 按钮「按住」(长按)判定阈值(ms):超过即进入更强态(更深状态层)。
|
||||
* 视觉区分「短按按下」与「按住」;触发语义不变(on_tap 仍按抬手判定)。 */
|
||||
#define MEOW_BTN_HOLD_MS 500u
|
||||
|
||||
@@ -28,6 +28,7 @@ static uint32_t blend_color(uint32_t c, uint32_t o, int t)
|
||||
struct meow_widget {
|
||||
int type;
|
||||
int x, y, w, h;
|
||||
int owner; /* §6.1 ①:创建时绑定的 Activity;命中只在 owner==active 才生效 */
|
||||
char label[128];
|
||||
int pressed; /* 按钮按下视觉态 */
|
||||
int min, max, val; /* 滑条 */
|
||||
@@ -37,12 +38,105 @@ struct meow_widget {
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
/* ---- 实时按压即时刷新(agent-119)----
|
||||
* 按压/按住视觉由 meow_widget_draw 读实时触摸(meow_input_touch_*)呈现,但 app 只在
|
||||
* on_tick(1s)/on_tap 重绘 → 快速点/按住时按压态刷新滞后/漏。此处在 SDK 触摸按下/释放/
|
||||
* 按住达阈值时主动重绘命中的按钮区域并局部上屏(不等 app 重绘),即时反映按下变深/
|
||||
* 释放恢复,连续快速点击每按都反映。仅针对 SDK 控件按钮(W_BTN);app 纯自绘不适用。
|
||||
* 语义不变:on_tap / meow_btn_pressed / meow_widget_hit 零改动;非按钮区域不动。 */
|
||||
#define MEOW_LIVE_BTN_MAX 64
|
||||
static meow_widget *g_live_btns[MEOW_LIVE_BTN_MAX];
|
||||
static int g_live_btn_n = 0;
|
||||
static meow_widget *g_live_btn = NULL; /* 实时按压中最上层按钮(无 = NULL) */
|
||||
static int g_live_prev_hold = 0; /* 该按钮上次渲染是否为按住态 */
|
||||
|
||||
static void live_btn_register(meow_widget *w)
|
||||
{
|
||||
if (!w || w->type != W_BTN) return;
|
||||
for (int i = 0; i < g_live_btn_n; i++)
|
||||
if (g_live_btns[i] == w) return;
|
||||
if (g_live_btn_n < MEOW_LIVE_BTN_MAX) g_live_btns[g_live_btn_n++] = w;
|
||||
}
|
||||
|
||||
static void live_btn_unregister(meow_widget *w)
|
||||
{
|
||||
for (int i = 0; i < g_live_btn_n; i++) {
|
||||
if (g_live_btns[i] == w) {
|
||||
g_live_btns[i] = g_live_btns[--g_live_btn_n];
|
||||
if (g_live_btn == w) g_live_btn = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (g_live_btn == w) g_live_btn = NULL;
|
||||
}
|
||||
|
||||
/* 命中:返回坐标所在的「当前 active Activity」的最上层按钮(创建序 = 绘制序,最后者在上)。
|
||||
* §6.1 ①:仅扫描 owner == 当前 active Activity 的按钮 —— 非 active Activity 的控件
|
||||
* 绝不参与命中(根治 agent-119 遗留的「全屏页触摸到主页按钮位置 → 闪现 accent 底」)。 */
|
||||
static meow_widget *live_btn_hit(int x, int y)
|
||||
{
|
||||
int active = meow_ui_activity_active();
|
||||
meow_widget *r = NULL;
|
||||
for (int i = 0; i < g_live_btn_n; i++) {
|
||||
meow_widget *w = g_live_btns[i];
|
||||
if (w->owner != active) continue; /* 非 active activity:跳过 */
|
||||
if (x >= w->x && x < w->x + w->w && y >= w->y && y < w->y + w->h)
|
||||
r = w; /* 越后创建越上:保留最后命中 */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* 重绘并局部刷新一个按钮区(绘制内部调 meow_gfx_fill_round 已标脏;flush_region 合区+上屏)。 */
|
||||
static void live_btn_redraw(meow_widget *w)
|
||||
{
|
||||
if (!w) return;
|
||||
meow_widget_draw(w);
|
||||
meow_ui_flush_region(w->x, w->y, w->w, w->h);
|
||||
}
|
||||
|
||||
/* 由 meow_ui_run 每帧调用(主线程):检测实时触摸状态迁移,即时重绘命中按钮的按压/按住/
|
||||
* 释放,不等 app on_tick/on_tap。仅在触摸状态相对上次渲染发生变化时动作(非全屏、省性能)。 */
|
||||
void meow_widget_touch_refresh(void)
|
||||
{
|
||||
int active = meow_ui_activity_active();
|
||||
/* §6.1 ①:若当前按住按钮已不属于 active activity(按压期间发生了 Activity 切换,
|
||||
* 例如点 FULLSCREEN 后进入全屏),静默清引用——不绘制、不闪现(否则会在新页面底上
|
||||
* 画出旧按钮的 accent 残留)。 */
|
||||
if (g_live_btn && g_live_btn->owner != active) {
|
||||
g_live_btn = NULL;
|
||||
g_live_prev_hold = 0;
|
||||
}
|
||||
int down = meow_input_touch_down();
|
||||
meow_widget *hit = down ? live_btn_hit(meow_input_touch_x(), meow_input_touch_y()) : NULL;
|
||||
int hold = down && hit && meow_input_touch_hold_ms() >= MEOW_BTN_HOLD_MS;
|
||||
|
||||
if (!down) {
|
||||
/* 释放:把最近按压按钮恢复为常态 */
|
||||
if (g_live_btn) { live_btn_redraw(g_live_btn); g_live_btn = NULL; }
|
||||
g_live_prev_hold = 0;
|
||||
return;
|
||||
}
|
||||
if (hit != g_live_btn) {
|
||||
/* 按下/滑至新按钮:先恢复旧(若手指滑离),再按压新 */
|
||||
if (g_live_btn) live_btn_redraw(g_live_btn);
|
||||
g_live_btn = hit;
|
||||
g_live_prev_hold = hold;
|
||||
if (hit) live_btn_redraw(hit);
|
||||
} else if (hit && hold != g_live_prev_hold) {
|
||||
/* 同一按钮按住达阈值:升级到更强态 */
|
||||
live_btn_redraw(hit);
|
||||
g_live_prev_hold = hold;
|
||||
}
|
||||
}
|
||||
|
||||
meow_widget *meow_btn_create(int x, int y, int w, int h, const char *label)
|
||||
{
|
||||
meow_widget *t = (meow_widget *)calloc(1, sizeof *t);
|
||||
if (!t) return NULL;
|
||||
t->type = W_BTN; t->x = x; t->y = y; t->w = w; t->h = h;
|
||||
t->owner = meow_ui_activity_active(); /* §6.1 ①:绑定当前 active Activity */
|
||||
if (label) { strncpy(t->label, label, sizeof t->label - 1); t->label[sizeof t->label - 1] = 0; }
|
||||
live_btn_register(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -51,6 +145,7 @@ meow_widget *meow_slider_create(int x, int y, int w, int min, int max, int val)
|
||||
meow_widget *t = (meow_widget *)calloc(1, sizeof *t);
|
||||
if (!t) return NULL;
|
||||
t->type = W_SLIDER; t->x = x; t->y = y; t->w = w; t->h = 40;
|
||||
t->owner = meow_ui_activity_active();
|
||||
t->min = min; t->max = (max > min) ? max : min + 1; t->val = (val < min) ? min : (val > t->max) ? t->max : val;
|
||||
return t;
|
||||
}
|
||||
@@ -60,6 +155,7 @@ meow_widget *meow_switch_create(int x, int y, int on)
|
||||
meow_widget *t = (meow_widget *)calloc(1, sizeof *t);
|
||||
if (!t) return NULL;
|
||||
t->type = W_SWITCH; t->x = x; t->y = y; t->w = 56; t->h = 32;
|
||||
t->owner = meow_ui_activity_active();
|
||||
t->on = on ? 1 : 0;
|
||||
return t;
|
||||
}
|
||||
@@ -70,11 +166,17 @@ meow_widget *meow_list_create(int x, int y, int w, int h, int count,
|
||||
meow_widget *t = (meow_widget *)calloc(1, sizeof *t);
|
||||
if (!t) return NULL;
|
||||
t->type = W_LIST; t->x = x; t->y = y; t->w = w; t->h = h;
|
||||
t->owner = meow_ui_activity_active();
|
||||
t->count = count; t->src = src; t->ctx = ctx; t->sel = 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
void meow_widget_free(meow_widget *w) { if (w) free(w); }
|
||||
void meow_widget_free(meow_widget *w)
|
||||
{
|
||||
if (!w) return;
|
||||
live_btn_unregister(w);
|
||||
free(w);
|
||||
}
|
||||
|
||||
static int hit(meow_widget *w, int x, int y)
|
||||
{
|
||||
@@ -82,7 +184,13 @@ static int hit(meow_widget *w, int x, int y)
|
||||
return x >= w->x && x < w->x + w->w && y >= w->y && y < w->y + w->h;
|
||||
}
|
||||
|
||||
int meow_widget_hit(meow_widget *w, int x, int y) { return hit(w, x, y); }
|
||||
int meow_widget_hit(meow_widget *w, int x, int y)
|
||||
{
|
||||
if (!w) return 0;
|
||||
/* §6.1 ①:页面控件只对自身 Activity 负责,不跨页面复用命中。 */
|
||||
if (w->owner != meow_ui_activity_active()) return 0;
|
||||
return hit(w, x, y);
|
||||
}
|
||||
int meow_btn_pressed(meow_widget *w) { return w && w->type == W_BTN ? w->pressed : 0; }
|
||||
|
||||
void meow_slider_set(meow_widget *w, int val)
|
||||
@@ -112,22 +220,16 @@ void meow_widget_draw(meow_widget *w)
|
||||
meow_input_touch_y() >= w->y && meow_input_touch_y() < w->y + w->h;
|
||||
int press = w->pressed || live;
|
||||
int hold = live && meow_input_touch_hold_ms() >= MEOW_BTN_HOLD_MS;
|
||||
if (hold) {
|
||||
/* 按住:更强态——更深状态层 + 内缩圆角描边环(浅 accent),贴 MD3 强调;
|
||||
* 动效取舍:状态层按规范即时切换(MD3 ripple 属额外动画,依赖 on_tick 逐帧,
|
||||
* 非本「加视觉态」范围),不做 1-2 帧插值。 */
|
||||
uint32_t hbg = blend_color(th->accent, 0x000000, 24);
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, 10, hbg);
|
||||
if (w->w > 6 && w->h > 6)
|
||||
meow_ui_draw_rect_round(w->x + 1, w->y + 1, w->w - 2, w->h - 2, 9,
|
||||
blend_color(th->accent, 0xFFFFFF, 45));
|
||||
} else if (press) {
|
||||
/* 按下:轻状态层(accent 向黑调 12%,即变深/偏移),释放恢复;MD3 表面按压。 */
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, 10,
|
||||
blend_color(th->accent, 0x000000, 12));
|
||||
} else {
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, 10, th->accent);
|
||||
}
|
||||
/* 纯色状态层(无描边环、无分层):一层即满,深浅二态均由 accent 向黑调出。
|
||||
* 常态=accent、按下=accent+黑12%、按住=accent+黑24%。整体一层不「先底色再套圈」。 */
|
||||
uint32_t bg;
|
||||
if (hold)
|
||||
bg = blend_color(th->accent, 0x000000, 24);
|
||||
else if (press)
|
||||
bg = blend_color(th->accent, 0x000000, 12);
|
||||
else
|
||||
bg = th->accent;
|
||||
meow_gfx_fill_round(w->x, w->y, w->w, w->h, 10, bg);
|
||||
meow_ui_text_center(w->x + w->w / 2, w->y + (w->h - meow_ui_text_height(th->font_body)) / 2,
|
||||
w->label, th->font_body, 0xFFFFFF);
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user