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