1use ranim_core::{
2 animation::{AnimationCell, Eval},
3 core_item::vitem::DEFAULT_STROKE_WIDTH,
4 traits::{Empty, FillColor, Interpolatable, Partial, StrokeColor, StrokeWidth},
5 utils::rate_functions::smooth,
6};
7use tracing::warn;
8
9pub trait CreationRequirement: Clone + Partial + Empty + Interpolatable {}
13impl<T: Clone + Partial + Empty + Interpolatable> CreationRequirement for T {}
14
15pub trait CreationAnim<T: CreationRequirement + 'static> {
17 fn create(&mut self) -> AnimationCell<T>;
19 fn uncreate(&mut self) -> AnimationCell<T>;
21}
22
23impl<T: CreationRequirement + 'static> CreationAnim<T> for T {
24 fn create(&mut self) -> AnimationCell<T> {
25 Create::new(self.clone())
26 .into_animation_cell()
27 .with_rate_func(smooth)
28 .apply_to(self)
29 }
30 fn uncreate(&mut self) -> AnimationCell<T> {
31 UnCreate::new(self.clone())
32 .into_animation_cell()
33 .with_rate_func(smooth)
34 .apply_to(self)
35 }
36}
37
38pub trait WritingRequirement: CreationRequirement + StrokeWidth + StrokeColor + FillColor {}
41impl<T: CreationRequirement + StrokeWidth + StrokeColor + FillColor> WritingRequirement for T {}
42
43pub trait WritingAnim: WritingRequirement + Sized + 'static {
45 fn write(&mut self) -> AnimationCell<Self>;
47 fn unwrite(&mut self) -> AnimationCell<Self>;
49}
50
51impl<T: WritingRequirement + Sized + 'static> WritingAnim for T {
52 fn write(&mut self) -> AnimationCell<Self> {
53 Write::new(self.clone())
54 .into_animation_cell()
55 .with_rate_func(smooth)
56 .apply_to(self)
57 }
58 fn unwrite(&mut self) -> AnimationCell<Self> {
59 Unwrite::new(self.clone())
60 .into_animation_cell()
61 .with_rate_func(smooth)
62 .apply_to(self)
63 }
64}
65
66pub struct Create<T: CreationRequirement> {
73 pub original: T,
75}
76
77impl<T: CreationRequirement> Create<T> {
78 pub fn new(target: T) -> Self {
80 Self { original: target }
81 }
82}
83
84impl<T: CreationRequirement> Eval<T> for Create<T> {
85 fn eval_alpha(&self, alpha: f64) -> T {
86 if alpha == 0.0 {
87 T::empty()
88 } else if 0.0 < alpha && alpha < 1.0 {
89 self.original.get_partial_closed(0.0..alpha)
90 } else if alpha == 1.0 {
91 self.original.clone()
92 } else {
93 unreachable!()
94 }
95 }
96}
97
98pub struct UnCreate<T: CreationRequirement> {
102 pub original: T,
104}
105
106impl<T: CreationRequirement> UnCreate<T> {
107 pub fn new(target: T) -> Self {
109 Self { original: target }
110 }
111}
112
113impl<T: CreationRequirement> Eval<T> for UnCreate<T> {
114 fn eval_alpha(&self, mut alpha: f64) -> T {
115 if !(0.0..=1.0).contains(&alpha) {
116 warn!("the alpha is out of range: {alpha}, clampped to 0.0..=1.0");
117 alpha = alpha.clamp(0.0, 1.0)
118 }
119 if alpha == 0.0 {
121 self.original.clone()
122 } else if 0.0 < alpha && alpha < 1.0 {
123 self.original.get_partial_closed(0.0..1.0 - alpha)
124 } else if alpha == 1.0 {
125 T::empty()
126 } else {
127 panic!("the alpha is out of range: {alpha}");
128 }
129 }
130}
131
132pub struct Write<T: WritingRequirement> {
136 pub(crate) original: T,
137 pub(crate) outline: T,
138}
139
140impl<T: WritingRequirement> Write<T> {
141 pub fn new(target: T) -> Self {
143 let mut outline = target.clone();
144 outline.set_fill_opacity(0.0).set_stroke_opacity(1.0);
145 if outline.stroke_width() == 0.0 {
146 outline.set_stroke_width(DEFAULT_STROKE_WIDTH);
147 }
148 Self {
149 original: target,
150 outline,
151 }
152 }
153}
154
155impl<T: WritingRequirement> Eval<T> for Write<T> {
156 fn eval_alpha(&self, alpha: f64) -> T {
157 let alpha = alpha * 2.0;
158 if (0.0..1.0).contains(&alpha) {
159 self.outline.get_partial(0.0..alpha)
160 } else if alpha == 1.0 {
161 self.outline.clone()
162 } else if (1.0..2.0).contains(&alpha) {
163 self.outline.lerp(&self.original, alpha - 1.0)
164 } else if alpha == 2.0 {
165 self.original.clone()
166 } else {
167 unreachable!()
168 }
169 }
170}
171
172pub struct Unwrite<T: WritingRequirement> {
176 pub(crate) original: T,
177 pub(crate) outline: T,
178}
179
180impl<T: WritingRequirement> Unwrite<T> {
181 pub fn new(target: T) -> Self {
183 let mut outline = target.clone();
184 outline.set_fill_opacity(0.0).set_stroke_opacity(1.0);
185 if outline.stroke_width() == 0.0 {
186 outline.set_stroke_width(DEFAULT_STROKE_WIDTH);
187 }
188 Self {
189 original: target,
190 outline,
191 }
192 }
193}
194
195impl<T: WritingRequirement> Eval<T> for Unwrite<T> {
196 fn eval_alpha(&self, alpha: f64) -> T {
197 let alpha = alpha * 2.0;
198 if (0.0..1.0).contains(&alpha) {
199 self.original.lerp(&self.outline, alpha)
200 } else if alpha == 1.0 {
201 self.outline.clone()
202 } else if (1.0..2.0).contains(&alpha) {
203 self.outline.get_partial(0.0..2.0 - alpha)
204 } else if alpha == 2.0 {
205 T::empty()
206 } else if alpha == 0.0 {
207 self.original.clone()
208 } else {
209 panic!("the alpha is out of range: {alpha}");
210 }
211 }
212}