1use ranim_core::{
2 animation::Eval,
3 core_item::vitem::DEFAULT_STROKE_WIDTH,
4 traits::{Empty, FillColor, Interpolatable, Partial, StrokeColor, StrokeWidth},
5};
6use tracing::warn;
7
8pub trait CreationRequirement: Clone + Partial + Empty + Interpolatable {}
12impl<T: Clone + Partial + Empty + Interpolatable> CreationRequirement for T {}
13
14pub trait CreationAnim<T: CreationRequirement + 'static> {
16 fn create(&mut self) -> Create<T>;
18 fn uncreate(&mut self) -> UnCreate<T>;
20}
21
22impl<T: CreationRequirement + 'static> CreationAnim<T> for T {
23 fn create(&mut self) -> Create<T> {
24 Create::new(self.clone()).apply_to(self)
25 }
26 fn uncreate(&mut self) -> UnCreate<T> {
27 UnCreate::new(self.clone()).apply_to(self)
28 }
29}
30
31pub trait WritingRequirement: CreationRequirement + StrokeWidth + StrokeColor + FillColor {}
34impl<T: CreationRequirement + StrokeWidth + StrokeColor + FillColor> WritingRequirement for T {}
35
36pub trait WritingAnim: WritingRequirement + Sized + 'static {
38 fn write(&mut self) -> Write<Self>;
40 fn unwrite(&mut self) -> Unwrite<Self>;
42}
43
44impl<T: WritingRequirement + Sized + 'static> WritingAnim for T {
45 fn write(&mut self) -> Write<Self> {
46 Write::new(self.clone()).apply_to(self)
47 }
48 fn unwrite(&mut self) -> Unwrite<Self> {
49 Unwrite::new(self.clone()).apply_to(self)
50 }
51}
52
53pub struct Create<T: CreationRequirement> {
60 pub original: T,
62}
63
64impl<T: CreationRequirement> Create<T> {
65 pub fn new(target: T) -> Self {
67 Self { original: target }
68 }
69}
70
71impl<T: CreationRequirement> Eval for Create<T> {
72 type Output = T;
73
74 fn eval_alpha(&self, alpha: f64) -> Self::Output {
75 if alpha == 0.0 {
76 T::empty()
77 } else if 0.0 < alpha && alpha < 1.0 {
78 self.original.get_partial_closed(0.0..alpha)
79 } else if alpha == 1.0 {
80 self.original.clone()
81 } else {
82 unreachable!()
83 }
84 }
85}
86
87pub struct UnCreate<T: CreationRequirement> {
91 pub original: T,
93}
94
95impl<T: CreationRequirement> UnCreate<T> {
96 pub fn new(target: T) -> Self {
98 Self { original: target }
99 }
100}
101
102impl<T: CreationRequirement> Eval for UnCreate<T> {
103 type Output = T;
104
105 fn eval_alpha(&self, mut alpha: f64) -> Self::Output {
106 if !(0.0..=1.0).contains(&alpha) {
107 warn!("the alpha is out of range: {alpha}, clampped to 0.0..=1.0");
108 alpha = alpha.clamp(0.0, 1.0)
109 }
110 if alpha == 0.0 {
112 self.original.clone()
113 } else if 0.0 < alpha && alpha < 1.0 {
114 self.original.get_partial_closed(0.0..1.0 - alpha)
115 } else if alpha == 1.0 {
116 T::empty()
117 } else {
118 panic!("the alpha is out of range: {alpha}");
119 }
120 }
121}
122
123pub struct Write<T: WritingRequirement> {
127 pub(crate) original: T,
128 pub(crate) outline: T,
129}
130
131impl<T: WritingRequirement> Write<T> {
132 pub fn new(target: T) -> Self {
134 let mut outline = target.clone();
135 outline.set_fill_opacity(0.0).set_stroke_opacity(1.0);
136 if outline.stroke_width() == 0.0 {
137 outline.set_stroke_width(DEFAULT_STROKE_WIDTH);
138 }
139 Self {
140 original: target,
141 outline,
142 }
143 }
144}
145
146impl<T: WritingRequirement> Eval for Write<T> {
147 type Output = T;
148
149 fn eval_alpha(&self, alpha: f64) -> Self::Output {
150 let alpha = alpha * 2.0;
151 if (0.0..1.0).contains(&alpha) {
152 self.outline.get_partial(0.0..alpha)
153 } else if alpha == 1.0 {
154 self.outline.clone()
155 } else if (1.0..2.0).contains(&alpha) {
156 self.outline.lerp(&self.original, alpha - 1.0)
157 } else if alpha == 2.0 {
158 self.original.clone()
159 } else {
160 unreachable!()
161 }
162 }
163}
164
165pub struct Unwrite<T: WritingRequirement> {
169 pub(crate) original: T,
170 pub(crate) outline: T,
171}
172
173impl<T: WritingRequirement> Unwrite<T> {
174 pub fn new(target: T) -> Self {
176 let mut outline = target.clone();
177 outline.set_fill_opacity(0.0).set_stroke_opacity(1.0);
178 if outline.stroke_width() == 0.0 {
179 outline.set_stroke_width(DEFAULT_STROKE_WIDTH);
180 }
181 Self {
182 original: target,
183 outline,
184 }
185 }
186}
187
188impl<T: WritingRequirement> Eval for Unwrite<T> {
189 type Output = T;
190
191 fn eval_alpha(&self, alpha: f64) -> Self::Output {
192 let alpha = alpha * 2.0;
193 if (0.0..1.0).contains(&alpha) {
194 self.original.lerp(&self.outline, alpha)
195 } else if alpha == 1.0 {
196 self.outline.clone()
197 } else if (1.0..2.0).contains(&alpha) {
198 self.outline.get_partial(0.0..2.0 - alpha)
199 } else if alpha == 2.0 {
200 T::empty()
201 } else if alpha == 0.0 {
202 self.original.clone()
203 } else {
204 panic!("the alpha is out of range: {alpha}");
205 }
206 }
207}