subtree pull sdk 来自主仓 pub/sdk(主仓 commit 68ce46a 等)。新增: - 布局引擎 meow_ui_box / 动画基座 meow_ui_anim / 滚动物理 meow_ui_scroll - §6.4 事件分发形式化 / W_LISTVIEW 虚拟化多行 / meow_str 字符串资源 i18n - sb_icons 动作图标扩充 + topbar 位图图标 / meow_img_downscale - tools/ 图标生成脚本与 SVG 源 - 对应宿主 test_*.c 与 demo_box_scroll.c build_sdk.sh 冲突解析:保留公开仓自包含版(vendored meow_font + -Iinclude -I.), OBJS 手工并入 4 个新模块(meow_ui_box/anim/scroll/str)。保留 vendored meow_font.c/ meow_ipc.h/meow_font.h/meow_notif.h,剔除宿主测试二进制与编译产物。
129 lines
4.2 KiB
C
129 lines
4.2 KiB
C
/*
|
||
* meow_ui_anim.c — 动画基座 + UI 节拍器(§12.2)。
|
||
*
|
||
* 时间驱动 tween:start 记录起始时刻(meow_ui_time_ms,单调),tick 按经过时间求 t,
|
||
* 代入 ease 得 v = from + (to-from)*ease(t),回调 update;t 到 1 → 回调 done(canceled=0) 并回收。
|
||
* 取消 → 回调 done(canceled=1) 并回收。静态池(≤MEOW_ANIM_MAX),热路径零 malloc。
|
||
* 无动画时 meow_anim_tick() 仅查活动计数即返回(零开销)。
|
||
*
|
||
* 节拍挂接:由 meow_ui_run 主循环(on_tick 之后)与 meow_ui_feed_tick(阻塞 IME 循环)调用,
|
||
* 不引入常驻高频轮询。modal/dialog 阻塞循环不喂 tick(动画暂停,符合「模态期不做动画」惯例)。
|
||
*/
|
||
#include "meow_ui.h"
|
||
#include "include/meow_ui_anim.h"
|
||
#include <string.h>
|
||
|
||
struct meow_anim {
|
||
int active;
|
||
float from, to;
|
||
uint32_t duration_ms;
|
||
meow_ease ease;
|
||
uint64_t start_ms;
|
||
float value;
|
||
int region_set;
|
||
int rx, ry, rw, rh;
|
||
meow_anim_update_fn update;
|
||
meow_anim_done_fn done;
|
||
void *ctx;
|
||
};
|
||
|
||
static struct meow_anim g_pool[MEOW_ANIM_MAX];
|
||
static unsigned g_active = 0; /* 活动动画计数(0 = 空闲,tick 直退) */
|
||
|
||
/* ---- 缓动 ---- */
|
||
float meow_ease_apply(meow_ease e, float t)
|
||
{
|
||
if (e == MEOW_EASE_OUT) {
|
||
/* ease-out quad */
|
||
float u = 1.0f - t;
|
||
return 1.0f - u * u;
|
||
}
|
||
if (e == MEOW_EASE_IN_OUT) {
|
||
/* ease-in-out quad */
|
||
if (t < 0.5f) return 2.0f * t * t;
|
||
float u = -2.0f * t + 2.0f;
|
||
return 1.0f - u * u * 0.5f;
|
||
}
|
||
if (e == MEOW_EASE_OVERSHOOT) {
|
||
/* ease-out-back(越过目标再回稳);t=1 → 恰为 1 */
|
||
const float c1 = 1.70158f;
|
||
const float c3 = c1 + 1.0f;
|
||
float u = t - 1.0f;
|
||
return 1.0f + c3 * u * u * u + c1 * u * u;
|
||
}
|
||
/* MEOW_EASE_LINEAR */
|
||
return t;
|
||
}
|
||
|
||
/* ---- 生命周期 ---- */
|
||
meow_anim *meow_anim_start(const meow_anim_desc *d)
|
||
{
|
||
if (!d) return NULL;
|
||
for (int i = 0; i < MEOW_ANIM_MAX; i++) {
|
||
struct meow_anim *a = &g_pool[i];
|
||
if (a->active) continue;
|
||
a->active = 1;
|
||
a->from = d->from;
|
||
a->to = d->to;
|
||
a->duration_ms = d->duration_ms ? d->duration_ms : 1; /* 0 → 瞬发(下一 tick 完成) */
|
||
a->ease = d->ease;
|
||
a->start_ms = meow_ui_time_ms();
|
||
a->update = d->update;
|
||
a->done = d->done;
|
||
a->ctx = d->ctx;
|
||
a->region_set = 0;
|
||
a->value = d->from;
|
||
g_active++;
|
||
if (a->update) a->update(a, a->value, a->ctx); /* 起始帧回调(t=0) */
|
||
return a;
|
||
}
|
||
return NULL; /* 池满 */
|
||
}
|
||
|
||
void meow_anim_cancel(meow_anim *a)
|
||
{
|
||
if (!a || !a->active) return;
|
||
a->active = 0;
|
||
if (g_active > 0) g_active--;
|
||
if (a->done) a->done(a, 1, a->ctx);
|
||
}
|
||
|
||
int meow_anim_active(meow_anim *a) { return (a && a->active) ? 1 : 0; }
|
||
float meow_anim_value(meow_anim *a) { return a ? a->value : 0.0f; }
|
||
|
||
void meow_anim_set_region(meow_anim *a, int x, int y, int w, int h)
|
||
{
|
||
if (!a) return;
|
||
if (x < 0) { a->region_set = 0; return; }
|
||
a->region_set = 1;
|
||
a->rx = x; a->ry = y; a->rw = w > 0 ? w : 0; a->rh = h > 0 ? h : 0;
|
||
}
|
||
|
||
/* ---- 节拍器 ---- */
|
||
unsigned meow_anim_count(void) { return (unsigned)g_active; }
|
||
|
||
void meow_anim_tick(void)
|
||
{
|
||
if (g_active == 0) return; /* 无动画:零开销直接返回 */
|
||
uint64_t now = meow_ui_time_ms();
|
||
for (int i = 0; i < MEOW_ANIM_MAX; i++) {
|
||
struct meow_anim *a = &g_pool[i];
|
||
if (!a->active) continue;
|
||
uint64_t elapsed = now - a->start_ms;
|
||
float t = (float)(elapsed) / (float)a->duration_ms;
|
||
int finished = (t >= 1.0f);
|
||
if (t > 1.0f) t = 1.0f;
|
||
if (t < 0.0f) t = 0.0f;
|
||
float v = a->from + (a->to - a->from) * meow_ease_apply(a->ease, t);
|
||
a->value = v;
|
||
if (a->update) a->update(a, v, a->ctx);
|
||
if (a->region_set && a->rw > 0 && a->rh > 0)
|
||
meow_ui_flush_region(a->rx, a->ry, a->rw, a->rh); /* 只刷动画影响区 */
|
||
if (finished) {
|
||
a->active = 0;
|
||
if (g_active > 0) g_active--;
|
||
if (a->done) a->done(a, 0, a->ctx);
|
||
}
|
||
}
|
||
}
|