1 #pragma once
2 
3 #include <algorithm>
4 #include <cstdint>
5 #include <functional>
6 #include "Common/TimeUtil.h"
7 #include "Common/UI/View.h"
8 
9 namespace UI {
10 
11 // This is the class to use in Update().
12 class Tween {
13 public:
Tween(float duration,float (* curve)(float))14 	explicit Tween(float duration, float (*curve)(float)) : duration_(duration), curve_(curve) {
15 		start_ = time_now_d();
16 	}
~Tween()17 	virtual ~Tween() {
18 	}
19 
20 	// Actually apply the tween to a view.
21 	void Apply(View *view);
22 
Finished()23 	bool Finished() {
24 		return finishApplied_ && time_now_d() >= start_ + delay_ + duration_;
25 	}
26 
Persist()27 	void Persist() {
28 		persists_ = true;
29 	}
Persists()30 	bool Persists() {
31 		return persists_;
32 	}
33 
Delay(float s)34 	void Delay(float s) {
35 		delay_ = s;
36 	}
37 
38 	virtual void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) = 0;
39 
40 	Event Finish;
41 
42 protected:
DurationOffset()43 	float DurationOffset() {
44 		return (time_now_d() - start_) - delay_;
45 	}
46 
Position()47 	float Position() {
48 		return curve_(std::min(1.0f, DurationOffset() / duration_));
49 	}
50 
51 	virtual void DoApply(View *view, float pos) = 0;
52 
53 	double start_;
54 	float duration_;
55 	float delay_ = 0.0f;
56 	bool finishApplied_ = false;
57 	bool persists_ = false;
58 	bool valid_ = false;
59 	float (*curve_)(float);
60 };
61 
62 // This is the class all tweens inherit from.  Shouldn't be used directly, see below.
63 // Note: Value cannot safely be a pointer (without overriding PersistData.)
64 template <typename Value>
65 class TweenBase: public Tween {
66 public:
67 	TweenBase(float duration, float (*curve)(float) = [](float f) { return f; })
Tween(duration,curve)68 		: Tween(duration, curve) {
69 	}
70 	TweenBase(Value from, Value to, float duration, float (*curve)(float) = [](float f) { return f; })
Tween(duration,curve)71 		: Tween(duration, curve), from_(from), to_(to) {
72 		valid_ = true;
73 	}
74 
75 	// Use this to change the destination value.
76 	// Useful when a state flips while the tween is half-way through.
77 	void Divert(const Value &newTo, float newDuration = -1.0f) {
78 		const Value newFrom = valid_ ? Current(Position()) : newTo;
79 
80 		// Are we already part way through another transition?
81 		if (time_now_d() < start_ + delay_ + duration_ && valid_) {
82 			if (newTo == to_) {
83 				// Already on course.  Don't change.
84 				return;
85 			} else if (newTo == from_ && duration_ > 0.0f) {
86 				// Reversing, adjust start_ to be smooth from the current value.
87 				float newOffset = duration_ - std::max(0.0f, DurationOffset());
88 				if (newDuration >= 0.0f) {
89 					newOffset *= newDuration / duration_;
90 				}
91 				start_ = time_now_d() - newOffset - delay_;
92 			} else if (time_now_d() <= start_ + delay_) {
93 				// Start the delay over again.
94 				start_ = time_now_d();
95 			} else {
96 				// Since we've partially animated to the other value, skip delay.
97 				start_ = time_now_d() - delay_;
98 			}
99 		} else {
100 			// Already finished, so restart.
101 			start_ = time_now_d();
102 			finishApplied_ = false;
103 		}
104 
105 		from_ = newFrom;
106 		to_ = newTo;
107 		valid_ = true;
108 		if (newDuration >= 0.0f) {
109 			duration_ = newDuration;
110 		}
111 	}
112 
113 	// Stop animating the value.
Stop()114 	void Stop() {
115 		Reset(Current(Position()));
116 	}
117 
118 	// Use when the value is explicitly reset.  Implicitly stops the tween.
Reset(const Value & newFrom)119 	void Reset(const Value &newFrom) {
120 		from_ = newFrom;
121 		to_ = newFrom;
122 		valid_ = true;
123 	}
124 
FromValue()125 	const Value &FromValue() const {
126 		return from_;
127 	}
ToValue()128 	const Value &ToValue() const {
129 		return to_;
130 	}
CurrentValue()131 	Value CurrentValue() {
132 		return Current(Position());
133 	}
134 
135 	void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override;
136 
137 protected:
138 	virtual Value Current(float pos) = 0;
139 
140 	Value from_;
141 	Value to_;
142 };
143 
144 // Generic - subclass this for specific color handling.
145 class ColorTween : public TweenBase<uint32_t> {
146 public:
147 	using TweenBase::TweenBase;
148 
149 protected:
150 	uint32_t Current(float pos) override;
151 };
152 
153 class TextColorTween : public ColorTween {
154 public:
155 	using ColorTween::ColorTween;
156 
157 protected:
158 	void DoApply(View *view, float pos) override;
159 };
160 
161 class CallbackColorTween : public ColorTween {
162 public:
163 	using ColorTween::ColorTween;
164 
SetCallback(const std::function<void (View * v,uint32_t c)> & cb)165 	void SetCallback(const std::function<void(View *v, uint32_t c)> &cb) {
166 		callback_ = cb;
167 	}
168 
169 protected:
170 	void DoApply(View *view, float pos) override;
171 
172 	std::function<void(View *v, uint32_t c)> callback_;
173 };
174 
175 class VisibilityTween : public TweenBase<Visibility> {
176 public:
177 	using TweenBase::TweenBase;
178 
179 protected:
180 	void DoApply(View *view, float pos) override;
181 
182 	Visibility Current(float pos) override;
183 };
184 
185 class AnchorTranslateTween : public TweenBase<Point> {
186 public:
187 	using TweenBase::TweenBase;
188 
189 protected:
190 	void DoApply(View *view, float pos) override;
191 
192 	Point Current(float pos) override;
193 };
194 
195 }  // namespace
196