1use std::{any::Any, sync::Arc};
2
3use crate::{
4 Extract,
5 animation::{AnimationSpan, EvalResult, Evaluator},
6 primitives::Primitives,
7 utils::calculate_hash,
8};
9
10pub trait TimelineFunc: Any {
13 fn start_sec(&self) -> Option<f64>;
15 fn end_sec(&self) -> Option<f64>;
17 fn range_sec(&self) -> Option<std::ops::Range<f64>> {
19 let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
20 return None;
21 };
22 Some(start..end)
23 }
24 fn seal(&mut self);
26 fn cur_sec(&self) -> f64;
28 fn forward(&mut self, secs: f64);
30 fn forward_to(&mut self, target_sec: f64) {
32 let duration = target_sec - self.cur_sec();
33 if duration > 0.0 {
34 self.forward(duration);
35 }
36 }
37 fn show(&mut self);
39 fn hide(&mut self);
41 fn get_animation_infos(&self) -> Vec<AnimationInfo>;
43 fn type_name(&self) -> &str;
45
46 fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(EvalResult<Primitives>, u64)>;
49}
50
51pub trait TimelinesFunc {
54 fn seal(&mut self);
56 fn max_total_secs(&self) -> f64;
58 fn sync(&mut self);
60 fn forward(&mut self, secs: f64);
62 fn forward_to(&mut self, target_sec: f64);
64}
65
66impl<I: ?Sized, T: TimelineFunc> TimelinesFunc for I
67where
68 for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
69 for<'a> &'a I: IntoIterator<Item = &'a T>,
70{
71 fn seal(&mut self) {
72 self.into_iter().for_each(|timeline: &mut T| {
73 timeline.seal();
74 });
75 }
76 fn max_total_secs(&self) -> f64 {
77 self.into_iter()
78 .map(|timeline: &T| timeline.cur_sec())
79 .max_by(|a, b| a.partial_cmp(b).unwrap())
80 .unwrap()
81 }
82 fn sync(&mut self) {
83 let max_elapsed_secs = self.max_total_secs();
84 self.into_iter().for_each(|timeline: &mut T| {
85 timeline.forward_to(max_elapsed_secs);
86 });
87 }
88 fn forward(&mut self, secs: f64) {
89 self.into_iter()
90 .for_each(|timeline: &mut T| timeline.forward(secs));
91 }
92 fn forward_to(&mut self, target_sec: f64) {
93 self.into_iter().for_each(|timeline: &mut T| {
94 timeline.forward_to(target_sec);
95 });
96 }
97}
98
99impl TimelineFunc for Box<dyn TimelineFunc> {
100 fn start_sec(&self) -> Option<f64> {
101 self.as_ref().start_sec()
102 }
103 fn end_sec(&self) -> Option<f64> {
104 self.as_ref().end_sec()
105 }
106 fn seal(&mut self) {
107 self.as_mut().seal()
108 }
109 fn cur_sec(&self) -> f64 {
110 self.as_ref().cur_sec()
111 }
112 fn forward(&mut self, secs: f64) {
113 self.as_mut().forward(secs)
114 }
115 fn show(&mut self) {
116 self.as_mut().show()
117 }
118 fn hide(&mut self) {
119 self.as_mut().hide()
120 }
121 fn get_animation_infos(&self) -> Vec<AnimationInfo> {
122 self.as_ref().get_animation_infos()
123 }
124 fn type_name(&self) -> &str {
125 self.as_ref().type_name()
126 }
127 fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(EvalResult<Primitives>, u64)> {
131 self.as_ref().eval_primitives_at_sec(target_sec)
132 }
133}
134
135#[derive(Default)]
140pub struct ItemDynTimelines {
141 inner: Vec<Box<dyn TimelineFunc>>,
142}
143
144impl TimelineFunc for ItemDynTimelines {
145 fn start_sec(&self) -> Option<f64> {
146 self.get_dyn().start_sec()
147 }
148 fn end_sec(&self) -> Option<f64> {
149 self.get_dyn().end_sec()
150 }
151 fn seal(&mut self) {
152 self.get_dyn_mut().seal();
153 }
154 fn cur_sec(&self) -> f64 {
155 self.get_dyn().cur_sec()
156 }
157 fn forward(&mut self, duration_secs: f64) {
158 self.get_dyn_mut().forward(duration_secs);
159 }
160 fn show(&mut self) {
161 self.get_dyn_mut().show();
162 }
163 fn hide(&mut self) {
164 self.get_dyn_mut().hide();
165 }
166 fn get_animation_infos(&self) -> Vec<AnimationInfo> {
167 self.inner
168 .iter()
169 .flat_map(|timeline| timeline.get_animation_infos())
170 .collect()
171 }
172 fn type_name(&self) -> &str {
173 self.get_dyn().type_name()
174 }
175 fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(EvalResult<Primitives>, u64)> {
176 self.eval_primitives_at_sec(target_sec)
177 }
178}
179
180impl ItemDynTimelines {
181 pub fn new() -> Self {
183 Self::default()
184 }
185 pub fn push<T: Extract + Clone + 'static>(&mut self, timeline: ItemTimeline<T>) {
187 self.inner.push(Box::new(timeline));
188 }
189 pub fn eval_primitives_at_alpha(&self, alpha: f64) -> Option<(EvalResult<Primitives>, u64)> {
191 let target_sec = self.inner.max_total_secs() * alpha;
192 self.eval_primitives_at_sec(target_sec)
193 }
194 pub fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(EvalResult<Primitives>, u64)> {
196 let (timeline_idx, timeline) = self.inner.iter().enumerate().find(|(idx, timeline)| {
200 timeline
201 .range_sec()
202 .map(|range| {
203 range.contains(&target_sec)
204 || *idx == self.inner.len() - 1 && range.end == target_sec
205 })
206 .unwrap_or(false)
207 })?;
208
209 timeline
210 .eval_primitives_at_sec(target_sec)
211 .map(|(res, idx)| (res, calculate_hash(&(timeline_idx, idx))))
212 }
213}
214
215impl ItemDynTimelines {
216 pub fn get_dyn(&self) -> &dyn TimelineFunc {
218 self.inner.last().unwrap()
220 }
221 pub fn get_dyn_mut(&mut self) -> &mut dyn TimelineFunc {
223 self.inner.last_mut().unwrap()
225 }
226 pub fn get<T: 'static>(&self) -> &ItemTimeline<T> {
230 (self.inner.last().unwrap().as_ref() as &dyn Any)
232 .downcast_ref()
233 .unwrap()
234 }
235 pub fn get_mut<T: 'static>(&mut self) -> &mut ItemTimeline<T> {
239 (self.inner.last_mut().unwrap().as_mut() as &mut dyn Any)
241 .downcast_mut()
242 .unwrap()
243 }
244 pub fn apply_map<T: Extract + Clone + 'static, E: Extract + Clone + 'static>(
254 &mut self,
255 map_fn: impl FnOnce(T) -> E,
256 ) {
257 let (state, end_sec, is_showing) = {
258 let timeline = self.get_mut::<T>();
259 let is_showing = timeline.planning_static_start_sec.is_some();
260 timeline.seal();
261 (
262 timeline.snapshot().clone(),
263 timeline.end_sec().unwrap_or(timeline.cur_sec()),
264 is_showing,
265 )
266 };
267 let new_state = map_fn(state);
268 let mut new_timeline = ItemTimeline::new(new_state);
269 new_timeline.forward_to(end_sec);
270 if is_showing {
271 new_timeline.show();
272 }
273 self.inner.push(Box::new(new_timeline));
274 }
275}
276
277pub struct ItemTimeline<T> {
281 type_name: String,
282 anims: Vec<(AnimationSpan<T>, std::ops::Range<f64>)>,
283
284 cur_sec: f64,
286 state: T,
288 planning_static_start_sec: Option<f64>,
291}
292impl<T: 'static> ItemTimeline<T> {
295 pub fn new(state: T) -> Self {
301 Self {
302 type_name: std::any::type_name::<T>().to_string(),
303 anims: vec![],
304 cur_sec: 0.0,
306 state,
307 planning_static_start_sec: None,
308 }
309 }
310}
311
312pub struct AnimationInfo {
314 pub anim_name: String,
316 pub range: std::ops::Range<f64>,
318}
319
320impl<T: Extract + Any + Clone + 'static> TimelineFunc for ItemTimeline<T> {
321 fn start_sec(&self) -> Option<f64> {
322 self.start_sec()
323 }
324 fn end_sec(&self) -> Option<f64> {
325 self.end_sec()
326 }
327 fn seal(&mut self) {
328 self._submit_planning_static_anim();
330 }
331 fn cur_sec(&self) -> f64 {
332 self.cur_sec
333 }
334 fn show(&mut self) {
336 self.show();
337 }
338 fn hide(&mut self) {
339 self.hide();
340 }
341 fn forward(&mut self, duration_secs: f64) {
342 self.forward(duration_secs);
343 }
344 fn get_animation_infos(&self) -> Vec<AnimationInfo> {
345 self.anims
347 .iter()
348 .map(|(anim, range)| AnimationInfo {
349 anim_name: anim.type_name().to_string(),
350 range: range.clone(),
351 })
352 .collect()
354 }
355 fn type_name(&self) -> &str {
356 &self.type_name
357 }
358 fn eval_primitives_at_sec(&self, target_sec: f64) -> Option<(EvalResult<Primitives>, u64)> {
363 self.eval_at_sec(target_sec)
364 .map(|(res, idx)| (res.map(|res| res.extract_to_primitives()), idx))
365 }
366}
367
368impl<T: Clone + 'static> ItemTimeline<T> {
369 pub fn start_sec(&self) -> Option<f64> {
371 self.anims.first().map(|(_, range)| range.start)
372 }
373 pub fn end_sec(&self) -> Option<f64> {
375 self.anims.last().map(|(_, range)| range.end)
376 }
377 pub fn cur_sec(&self) -> f64 {
379 self.cur_sec
380 }
381 pub fn snapshot_ref(&self) -> &T {
383 &self.state
384 }
385 pub fn snapshot(&self) -> T {
387 self.state.clone()
388 }
389 pub fn with_snapshot<R>(&mut self, f: impl Fn(&mut Self, T) -> R) -> R {
391 let state = self.snapshot();
392 f(self, state)
393 }
394 pub fn update(&mut self, state: T) -> &mut Self {
396 self.update_with(|s| *s = state)
397 }
398 pub fn update_with(&mut self, update_func: impl FnOnce(&mut T)) -> &mut Self {
400 let showing = self._submit_planning_static_anim();
401 update_func(&mut self.state);
402 if showing {
403 self.show();
404 }
405 self
406 }
407 pub fn show(&mut self) -> &mut Self {
411 if self.planning_static_start_sec.is_none() {
412 self.planning_static_start_sec = Some(self.cur_sec)
413 }
414 self
415 }
416 pub fn hide(&mut self) -> &mut Self {
420 self._submit_planning_static_anim();
422 self
423 }
424 pub fn forward(&mut self, secs: f64) -> &mut Self {
426 self.cur_sec += secs;
427 self
428 }
429 pub fn forward_to(&mut self, target_sec: f64) -> &mut Self {
431 if target_sec > self.cur_sec {
432 self.forward(target_sec - self.cur_sec);
433 }
434 self
435 }
436 fn _submit_planning_static_anim(&mut self) -> bool {
437 if let Some(start) = self.planning_static_start_sec.take() {
439 self.anims.push((
440 AnimationSpan::from_evaluator(Evaluator::Static(Arc::new(self.state.clone()))),
441 start..self.cur_sec,
442 ));
443 return true;
444 }
445 false
446 }
447 pub fn play_with(&mut self, anim_func: impl FnOnce(T) -> AnimationSpan<T>) -> &mut Self {
449 self.play(anim_func(self.state.clone()))
450 }
451 pub fn play(&mut self, anim: AnimationSpan<T>) -> &mut Self {
453 self._submit_planning_static_anim();
454 let res = anim.eval_alpha(1.0).into_owned();
455 let duration = anim.duration_secs;
456 let end = self.cur_sec + duration;
457 self.anims.push((anim, self.cur_sec..end));
458 self.cur_sec = end;
459 self.update(res);
460 self.show();
461 self
462 }
463 pub fn eval_at_alpha(&self, alpha: f64) -> Option<(EvalResult<T>, u64)> {
465 let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
466 return None;
467 };
468 self.eval_at_sec(alpha * (end - start) + start)
469 }
470 pub fn eval_at_sec(&self, target_sec: f64) -> Option<(EvalResult<T>, u64)> {
472 let (Some(start), Some(end)) = (self.start_sec(), self.end_sec()) else {
473 return None;
474 };
475
476 if !(start..=end).contains(&target_sec) {
477 return None;
478 }
479
480 self.anims
481 .iter()
482 .enumerate()
483 .find_map(|(idx, (anim, range))| {
484 if range.contains(&target_sec)
485 || (idx == self.anims.len() - 1 && target_sec == range.end)
486 {
487 Some((idx, anim, range))
488 } else {
489 None
490 }
491 })
492 .map(|(idx, anim, range)| {
493 let alpha = (target_sec - range.start) / (range.end - range.start);
494 (anim.eval_alpha(alpha), idx as u64)
495 })
496 }
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use crate::{primitives::vitem::VItemPrimitive, timeline::ItemTimeline};
503
504 #[test]
505 fn test_item_timeline() {
506 let vitem = VItemPrimitive {
507 points2d: vec![],
508 fill_rgbas: vec![],
509 stroke_rgbas: vec![],
510 stroke_widths: vec![],
511 };
512 let mut timeline = ItemTimeline::new(vitem.clone());
513 assert!(timeline.eval_at_alpha(0.0).is_none());
514 timeline.show();
515 timeline.forward(1.0);
516 timeline.seal();
517
518 assert_eq!(timeline.start_sec(), Some(0.0));
519 assert_eq!(timeline.end_sec(), Some(1.0));
520
521 let (res, _) = timeline.eval_at_alpha(0.0).unwrap();
522 assert_eq!(res.as_ref(), &vitem);
523 let (res, _) = timeline.eval_at_alpha(0.5).unwrap();
524 assert_eq!(res.as_ref(), &vitem);
525 let (res, _) = timeline.eval_at_alpha(1.0).unwrap();
526 assert_eq!(res.as_ref(), &vitem);
527 }
528
529 #[test]
530 fn test_item_dyn_timelines() {
531 let vitem = VItemPrimitive {
532 points2d: vec![],
533 fill_rgbas: vec![],
534 stroke_rgbas: vec![],
535 stroke_widths: vec![],
536 };
537 let mut timeline = ItemDynTimelines::new();
538 timeline.push(ItemTimeline::new(vitem.clone()));
539 assert!(timeline.eval_primitives_at_alpha(0.0).is_none());
540
541 timeline.get_dyn_mut().show();
542 timeline.get_dyn_mut().forward(1.0);
543 timeline.get_dyn_mut().seal();
544
545 assert_eq!(timeline.get_dyn().start_sec(), Some(0.0));
546 assert_eq!(timeline.get_dyn().end_sec(), Some(1.0));
547
548 let (res, _) = timeline.eval_primitives_at_alpha(0.0).unwrap();
549 assert_eq!(res.as_ref(), &Primitives::VItemPrimitive(vec![vitem]));
550 }
551}