1use eazy_core::Curve;
7use eazy_core::Easing;
8
9use crate::callback::Callbacks;
10use crate::control::Controllable;
11use crate::control::Direction;
12use crate::control::TweenState;
13use crate::repeat::Repeat;
14use crate::repeat::RepeatConfig;
15use crate::value::Tweenable;
16
17#[derive(Debug, Clone)]
33pub struct Tween<T: Tweenable> {
34 from: T,
36 to: T,
38 duration: f32,
40 elapsed: f32,
42 delay: f32,
44 delay_remaining: f32,
46 easing: Easing,
48 state: TweenState,
50 direction: Direction,
52 repeat_config: RepeatConfig,
54 iteration: u32,
56 time_scale: f32,
58 callbacks: Callbacks,
60 started: bool,
62}
63
64impl<T: Tweenable> Tween<T> {
65 pub fn new(from: T, to: T, duration: f32) -> Self {
67 Self {
68 from,
69 to,
70 duration: duration.max(0.0),
71 elapsed: 0.0,
72 delay: 0.0,
73 delay_remaining: 0.0,
74 easing: Easing::Linear,
75 state: TweenState::Idle,
76 direction: Direction::Forward,
77 repeat_config: RepeatConfig::default(),
78 iteration: 0,
79 time_scale: 1.0,
80 callbacks: Callbacks::default(),
81 started: false,
82 }
83 }
84
85 pub fn to(from: T, to: T) -> TweenBuilder<T> {
89 TweenBuilder::new(from, to)
90 }
91
92 pub fn from(from: T, to: T) -> TweenBuilder<T> {
96 TweenBuilder::new(from, to)
97 }
98
99 pub fn from_to(from: T, to: T) -> TweenBuilder<T> {
101 TweenBuilder::new(from, to)
102 }
103
104 pub fn from_value(&self) -> T {
108 self.from
109 }
110
111 pub fn to_value(&self) -> T {
113 self.to
114 }
115
116 pub fn value(&self) -> T {
120 let progress = self.eased_progress();
121
122 if self.repeat_config.should_reverse(self.iteration) {
124 self.to.lerp(self.from, progress)
125 } else {
126 self.from.lerp(self.to, progress)
127 }
128 }
129
130 pub fn raw_progress(&self) -> f32 {
132 if self.duration == 0.0 {
133 1.0
134 } else {
135 (self.elapsed / self.duration).clamp(0.0, 1.0)
136 }
137 }
138
139 pub fn eased_progress(&self) -> f32 {
141 let raw = self.raw_progress();
142
143 let directed = if self.direction.is_reverse() {
145 1.0 - raw
146 } else {
147 raw
148 };
149
150 self.easing.y(directed)
151 }
152
153 pub fn iteration(&self) -> u32 {
155 self.iteration
156 }
157
158 pub fn is_yoyo_reversed(&self) -> bool {
160 self.repeat_config.should_reverse(self.iteration)
161 }
162
163 pub fn set_easing(&mut self, easing: Easing) {
167 self.easing = easing;
168 }
169
170 pub fn set_repeat(&mut self, config: RepeatConfig) {
172 self.repeat_config = config;
173 }
174
175 pub fn set_delay(&mut self, delay: f32) {
177 self.delay = delay.max(0.0);
178
179 if self.state == TweenState::Idle {
180 self.delay_remaining = self.delay;
181 }
182 }
183
184 pub fn set_callbacks(&mut self, callbacks: Callbacks) {
186 self.callbacks = callbacks;
187 }
188
189 fn handle_completion(&mut self) {
192 if self.repeat_config.repeat.can_repeat(self.iteration) {
194 self.iteration += 1;
195 self.elapsed = 0.0;
196 self.delay_remaining = self.repeat_config.delay;
197 self.callbacks.fire_repeat();
198 } else {
199 self.state = TweenState::Complete;
200 self.callbacks.fire_complete();
201 }
202 }
203}
204
205impl<T: Tweenable> Controllable for Tween<T> {
206 fn play(&mut self) {
207 match self.state {
208 TweenState::Idle => {
209 self.state = TweenState::Playing;
210 self.delay_remaining = self.delay;
211 self.started = false;
212 }
213 TweenState::Paused => {
214 self.state = TweenState::Playing;
215 }
216 TweenState::Complete => {
217 self.restart();
219 }
220 TweenState::Playing => {
221 }
223 }
224 }
225
226 fn pause(&mut self) {
227 if self.state == TweenState::Playing {
228 self.state = TweenState::Paused;
229 }
230 }
231
232 fn resume(&mut self) {
233 if self.state == TweenState::Paused {
234 self.state = TweenState::Playing;
235 }
236 }
237
238 fn reverse(&mut self) {
239 self.direction.toggle();
240 }
241
242 fn restart(&mut self) {
243 self.elapsed = 0.0;
244 self.iteration = 0;
245 self.delay_remaining = self.delay;
246 self.started = false;
247 self.state = TweenState::Playing;
248 }
249
250 fn seek(&mut self, time: f32) {
251 self.elapsed = time.clamp(0.0, self.duration);
252 }
253
254 fn kill(&mut self) {
255 self.state = TweenState::Idle;
256 self.elapsed = 0.0;
257 self.iteration = 0;
258 self.delay_remaining = self.delay;
259 self.started = false;
260 }
261
262 fn progress(&self) -> f32 {
263 self.raw_progress()
264 }
265
266 fn set_progress(&mut self, progress: f32) {
267 self.elapsed = progress.clamp(0.0, 1.0) * self.duration;
268 }
269
270 fn duration(&self) -> f32 {
271 self.duration
272 }
273
274 fn elapsed(&self) -> f32 {
275 self.elapsed
276 }
277
278 fn state(&self) -> TweenState {
279 self.state
280 }
281
282 fn direction(&self) -> Direction {
283 self.direction
284 }
285
286 fn time_scale(&self) -> f32 {
287 self.time_scale
288 }
289
290 fn set_time_scale(&mut self, scale: f32) {
291 self.time_scale = scale.max(0.0);
292 }
293
294 fn tick(&mut self, delta: f32) -> bool {
295 if self.state != TweenState::Playing {
296 return self.state.is_active();
297 }
298
299 let scaled_delta = delta * self.time_scale;
300
301 if self.delay_remaining > 0.0 {
303 self.delay_remaining -= scaled_delta;
304
305 if self.delay_remaining > 0.0 {
306 return true;
307 }
308
309 let overflow = -self.delay_remaining;
311
312 self.delay_remaining = 0.0;
313 self.elapsed += overflow;
314 } else {
315 self.elapsed += scaled_delta;
316 }
317
318 if !self.started {
320 self.started = true;
321 self.callbacks.fire_start();
322 }
323
324 self.callbacks.fire_update();
326
327 if self.elapsed >= self.duration {
329 self.elapsed = self.duration;
330 self.handle_completion();
331 }
332
333 self.state.is_active()
334 }
335}
336
337#[derive(Debug, Clone)]
339pub struct TweenBuilder<T: Tweenable> {
340 tween: Tween<T>,
341}
342
343impl<T: Tweenable> TweenBuilder<T> {
344 pub fn new(from: T, to: T) -> Self {
346 Self {
347 tween: Tween::new(from, to, 1.0),
348 }
349 }
350
351 pub fn duration(mut self, secs: f32) -> Self {
353 self.tween.duration = secs.max(0.0);
354 self
355 }
356
357 pub fn easing(mut self, easing: Easing) -> Self {
359 self.tween.easing = easing;
360 self
361 }
362
363 pub fn repeat(mut self, repeat: impl Into<Repeat>) -> Self {
365 self.tween.repeat_config.repeat = repeat.into();
366 self
367 }
368
369 pub fn yoyo(mut self, enabled: bool) -> Self {
371 self.tween.repeat_config.yoyo = enabled;
372 self
373 }
374
375 pub fn repeat_delay(mut self, delay: f32) -> Self {
377 self.tween.repeat_config.delay = delay;
378 self
379 }
380
381 pub fn delay(mut self, delay: f32) -> Self {
383 self.tween.delay = delay.max(0.0);
384 self.tween.delay_remaining = self.tween.delay;
385 self
386 }
387
388 pub fn time_scale(mut self, scale: f32) -> Self {
390 self.tween.time_scale = scale.max(0.0);
391 self
392 }
393
394 pub fn on_start<F>(mut self, f: F) -> Self
396 where
397 F: Fn() + Send + Sync + 'static,
398 {
399 self.tween.callbacks.on_start = Some(crate::callback::Callback::sync(f));
400 self
401 }
402
403 pub fn on_update<F>(mut self, f: F) -> Self
405 where
406 F: Fn() + Send + Sync + 'static,
407 {
408 self.tween.callbacks.on_update = Some(crate::callback::Callback::sync(f));
409 self
410 }
411
412 pub fn on_complete<F>(mut self, f: F) -> Self
414 where
415 F: Fn() + Send + Sync + 'static,
416 {
417 self.tween.callbacks.on_complete = Some(crate::callback::Callback::sync(f));
418 self
419 }
420
421 pub fn on_repeat<F>(mut self, f: F) -> Self
423 where
424 F: Fn() + Send + Sync + 'static,
425 {
426 self.tween.callbacks.on_repeat = Some(crate::callback::Callback::sync(f));
427 self
428 }
429
430 pub fn build(self) -> Tween<T> {
432 self.tween
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 #[test]
441 fn test_basic_tween() {
442 let mut tween = Tween::new(0.0_f32, 100.0, 1.0);
443
444 tween.play();
445
446 assert_eq!(tween.value(), 0.0);
447
448 tween.tick(0.5);
449 assert!((tween.value() - 50.0).abs() < 0.001);
450
451 tween.tick(0.5);
452 assert_eq!(tween.value(), 100.0);
453 assert!(tween.state().is_complete());
454 }
455
456 #[test]
457 fn test_tween_builder() {
458 let tween = Tween::to(0.0_f32, 100.0)
459 .duration(2.0)
460 .easing(Easing::InOutQuadratic)
461 .delay(0.5)
462 .build();
463
464 assert_eq!(tween.duration(), 2.0);
465 assert_eq!(tween.delay, 0.5);
466 }
467
468 #[test]
469 fn test_repeat() {
470 let mut tween =
471 Tween::to(0.0_f32, 100.0).duration(1.0).repeat(2u32).build();
472
473 tween.play();
474 tween.tick(1.0); assert_eq!(tween.iteration(), 1);
476 assert!(tween.state().is_active());
477
478 tween.tick(1.0); assert_eq!(tween.iteration(), 2);
480 assert!(tween.state().is_active());
481
482 tween.tick(1.0); assert!(tween.state().is_complete());
484 }
485
486 #[test]
487 fn test_yoyo() {
488 let mut tween = Tween::to(0.0_f32, 100.0)
489 .duration(1.0)
490 .repeat(1u32)
491 .yoyo(true)
492 .build();
493
494 tween.play();
495
496 tween.tick(0.5);
498 assert!((tween.value() - 50.0).abs() < 0.001);
499
500 tween.tick(0.5);
501 assert_eq!(tween.iteration(), 1);
502
503 tween.tick(0.5);
505 assert!((tween.value() - 50.0).abs() < 0.001);
506 }
507
508 #[test]
509 fn test_delay() {
510 let mut tween = Tween::to(0.0_f32, 100.0).duration(1.0).delay(0.5).build();
511
512 tween.play();
513
514 tween.tick(0.25);
515 assert_eq!(tween.elapsed(), 0.0); tween.tick(0.25);
518 assert_eq!(tween.elapsed(), 0.0); tween.tick(0.25);
521 assert!(tween.elapsed() > 0.0);
523 }
524
525 #[test]
526 fn test_time_scale() {
527 let mut tween = Tween::to(0.0_f32, 100.0)
528 .duration(1.0)
529 .time_scale(2.0)
530 .build();
531
532 tween.play();
533 tween.tick(0.25); assert!((tween.elapsed() - 0.5).abs() < 0.001);
536 }
537
538 #[test]
539 fn test_seek() {
540 let mut tween = Tween::new(0.0_f32, 100.0, 1.0);
541
542 tween.seek(0.75);
543 assert!((tween.value() - 75.0).abs() < 0.001);
544 }
545
546 #[test]
547 fn test_array_tween() {
548 let mut tween = Tween::new([0.0_f32, 0.0, 0.0], [100.0, 200.0, 300.0], 1.0);
549
550 tween.play();
551 tween.tick(0.5);
552
553 let value = tween.value();
554
555 assert!((value[0] - 50.0).abs() < 0.001);
556 assert!((value[1] - 100.0).abs() < 0.001);
557 assert!((value[2] - 150.0).abs() < 0.001);
558 }
559}