1 module sbylib.graphics.action.animation;
2 
3 public import std.datetime;
4 public import sbylib.graphics.action.interpolation : Interpolation;
5 import sbylib.graphics.action.action : IAction, ImplAction;
6 
7 class Animation(T) : IAction {
8     private T delegate() getValue;
9     private void delegate(T) setValue;
10     private void delegate(float) updateFunction;
11     private Duration _period;
12 
13     mixin ImplAction;
14 
15     this(T delegate() getter, void delegate(T) setter) {
16         this.getValue = getter;
17         this.setValue = setter;
18     }
19 
20     this(ref T value) {
21         this.getValue = () => value;
22         this.setValue = (T v) { value = v; };
23     }
24 
25     Animation to(T arrival) {
26         import std.typecons : Nullable, nullable;
27 
28         Nullable!T departure;
29         updateFunction = (float t) {
30             if (departure.isNull) departure = getValue().nullable;
31             setValue(T(departure.get() + (arrival - departure.get()) * t));
32         };
33 
34         return this;
35     }
36 
37     Animation interpolate(Interpolation i) {
38         const b = updateFunction;
39         updateFunction = (float t) => b(i(t));
40         return this;
41     }
42 
43     Animation period(Duration period) {
44         this._period = period;
45         return this;
46     }
47 
48     override void start() {
49         import std.datetime : Clock;
50         import sbylib.event : when, then, until, Frame, finish;
51 
52         auto starttime = Clock.currTime;
53 
54         auto event = when(Frame).then({
55             auto t = cast(float)(Clock.currTime - starttime).total!("msecs") / _period.total!("msecs");
56             updateFunction(t);
57         })
58         .until(() => Clock.currTime > starttime + _period || killed);
59 
60         when(event.finish).then({
61             this.notifyFinish();
62         });
63     }
64 }