feat(motion): M305 —— 列表增删(错位淡入/退场后才移除)+ 进度插值(到点一次收束)

- 新轨道两条:components/motion/pump/{rows,progress}.rs(纯算术,连拍 advance(dt) 可判)
  · rows:两条清单(画出来的顺序 / 真值)+ 逐行可见度;退场行钉在原位、走完才移除
  · progress:真实读数一跳,画出来的值沿 short4 追上去;到 100% 一次脉冲(0→1→0,不循环)
- 接线:pages/download/model.rs::from_snapshot(scope 内唯一 update 侧入口)
  · 行清单 observe → 差分;退场行的数据进 leaving 池(否则退场行画不出来)
  · 进度 observe(key = 版本 id)
- 视图:rows/list.rs 换成 keyed::Column(按 id 做连续匹配)+ 逐行 revealed(裁切框收放)
  + 同色遮罩淡出;install.rs 画插值后的值 + 收束
- MotionScale::NONE:不插轨道、不留幽灵,值严格等于最终值、零采样
- 顺手:rows/tests.rs 重新挂上 mod(此前一直没编译),i18n 扫描补两个新文件

判据:motion::tests::{rows,progress}、rows/motion_tests(Tree::diff 后未变行状态盒不变)、
出图 DevDocs/artifacts/m305(probe.py 量行距与墨色)
This commit is contained in:
AskaEth committed 2026-11-13 21:42:18 +08:00
1 parent b9536c5833
commit ae33674293
24 files changed
+2175 -153

No files matched your search

@@ -0,0 +1,34 @@
//! **颜色预合成**(M305):把 α 在令牌层算掉,渲染器只收实色。
//!
//! ## 这条纪律是什么(D27)
//!
//! 「CPU 档零半透明」:整窗重绘里每多一层半透明,软件渲染就多一遍混合。仓内唯一的 α 出口是
//! **令牌层预合成**(`c.with_alpha(α).over(底)`,见 `interaction::disabled` 与
//! `dialog/view.rs::backdrop_color_at`):产物**恒不透明**。
//! `interaction/mod.rs` 的用例把这条钉成硬线(「为了淡出改用 `Color { a: 0.5 }`」直接红)。
//!
//! 本模块只剩一件工具:[`mix`]——两个**不透明**色之间按进度插值,用于「进度条到达 100% 时那一下
//! 强调收束」(`feedback/progress.rs::linear_with`)。它不改几何、不改厚度,所以**不引起重排**。
//!
//! ## 为什么这里没有「整行淡出」
//!
//! 列表行的淡出走的是 `motion/reveal.rs` 的收尾遮罩(原因写在那里:`Element<'a>` 借 `&'a Ui`,
//! 视图函数里现造的「淡化版 Ui」撑不到返回;把它泄漏成 `'static` 会让每帧每行泄漏一份 49 色方案)。
//! 行内容因此**永远逐像素实色绘制**,只有裁切框与那一层遮罩在变。
use unlucky_design::color::Color;
/// 两个**不透明**颜色之间按 `t` 的插值(预合成口径,同 [`faded`] 的纪律)。
///
/// 用在「进度条收束」这类没有背景色可叠的地方:`to.with_alpha(t).over(from)` 得到的是
/// 「把 `to` 按 t 盖在 `from` 上」的**实色**,产物恒不透明(D27);端点 `t = 0` / `1`
/// 逐位等于入参(不是「差不多相等」)。返回 iced 色值(组件层的取色口径)。
pub fn mix(from: Color, to: Color, t: f32) -> iced::Color {
if t <= 0.0 {
return crate::theme::to_iced(from);
}
if t >= 1.0 {
return crate::theme::to_iced(to);
}
crate::theme::to_iced(to.with_alpha(t).over(from))
}