Files
AskaEth 4b094d62a5 sdk: 增量同步主仓新模块(box/anim/scroll/dispatch/listvirt/str/sb_icons/img)
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,剔除宿主测试二进制与编译产物。
2026-09-02 09:08:51 +08:00

129 lines
4.2 KiB
C
Raw Permalink 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.
/*
* 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);
}
}
}