ferroui_base/animation/
key_frame.rs1use crate::animation::{Cue, IAnimationSetter, KeySpline, TimeSpan};
2use crate::collections::FerroList;
3use crate::{ferro_class, ferro_impl_classes, instantiate, FerroObject, FerroObjectImpl, Ref};
4use std::cell::{Cell, RefCell};
5use std::rc::Rc;
6
7#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
9#[repr(i32)]
10pub(crate) enum KeyFrameTimingMode {
11 #[default]
12 Unset = 0,
13 TimeSpan = 1,
14 Cue = 2,
15}
16
17#[repr(C)]
19pub struct KeyFrame {
20 base: FerroObject,
21 k_time_span: Cell<TimeSpan>,
22 k_cue: Cell<Cue>,
23 k_key_spline: RefCell<Option<Ref<KeySpline>>>,
24 setters: FerroList<Rc<dyn IAnimationSetter>>,
25 timing_mode: Cell<KeyFrameTimingMode>,
26}
27
28ferro_class!(KeyFrame: FerroObject);
29crate::ferro_class_info!(KeyFrame { new: KeyFrame::new });
30ferro_impl_classes!(KeyFrame: FerroObjectImpl);
31
32impl KeyFrame {
33 pub fn construct() -> Self {
35 Self {
36 base: FerroObject::construct(),
37 k_time_span: Cell::new(TimeSpan::ZERO),
38 k_cue: Cell::new(Cue::default()),
39 k_key_spline: RefCell::new(None),
40 setters: FerroList::new(),
41 timing_mode: Cell::new(KeyFrameTimingMode::Unset),
42 }
43 }
44
45 pub fn new() -> Ref<Self> {
46 instantiate(Self::construct())
47 }
48
49 pub fn with_cue(cue: Cue, setters: impl IntoIterator<Item = Rc<dyn IAnimationSetter>>) -> Ref<Self> {
51 let result = Self::new();
52 result.set_cue(cue);
53 result.setters.add_range(setters);
54 result
55 }
56
57 pub fn with_key_time(key_time: TimeSpan, setters: impl IntoIterator<Item = Rc<dyn IAnimationSetter>>) -> Ref<Self> {
59 let result = Self::new();
60 result.set_key_time(key_time);
61 result.setters.add_range(setters);
62 result
63 }
64
65 pub fn setters(&self) -> FerroList<Rc<dyn IAnimationSetter>> {
68 self.setters.clone()
69 }
70
71 pub(crate) fn timing_mode(&self) -> KeyFrameTimingMode {
72 self.timing_mode.get()
73 }
74
75 pub fn key_time(&self) -> TimeSpan {
77 self.k_time_span.get()
78 }
79
80 pub fn set_key_time(&self, value: TimeSpan) {
83 if self.timing_mode.get() == KeyFrameTimingMode::Cue {
84 panic!("You can only set either KeyTime or Cue.");
85 }
86 self.timing_mode.set(KeyFrameTimingMode::TimeSpan);
87 self.k_time_span.set(value);
88 }
89
90 pub fn cue(&self) -> Cue {
92 self.k_cue.get()
93 }
94
95 pub fn set_cue(&self, value: Cue) {
98 if self.timing_mode.get() == KeyFrameTimingMode::TimeSpan {
99 panic!("You can only set either KeyTime or Cue.");
100 }
101 self.timing_mode.set(KeyFrameTimingMode::Cue);
102 self.k_cue.set(value);
103 }
104
105 pub fn key_spline(&self) -> Option<Ref<KeySpline>> {
107 self.k_key_spline.borrow().clone()
108 }
109
110 pub fn set_key_spline(&self, value: Option<Ref<KeySpline>>) {
113 let valid = value.as_ref().is_none_or(|value| value.is_valid());
114 *self.k_key_spline.borrow_mut() = value;
115 if !valid {
116 panic!("KeySpline must have X coordinates >= 0.0 and <= 1.0.");
117 }
118 }
119}