using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using Timer = System.Windows.Forms.Timer; namespace HotelPms.Share.Windows.Animations { class AnimationManager { public bool InterruptAnimation { get; set; } public double Increment { get; set; } public double SecondaryIncrement { get; set; } public AnimationType AnimationType { get; set; } public bool Singular { get; set; } public delegate void AnimationFinished(object sender); public event AnimationFinished OnAnimationFinished; public delegate void AnimationProgress(object sender); public event AnimationProgress OnAnimationProgress; private readonly List _animationProgresses; private readonly List _animationSources; private readonly List _animationDirections; private readonly List _animationDatas; private const double MIN_VALUE = 0.00; private const double MAX_VALUE = 1.00; private readonly Timer _animationTimer = new Timer { Interval = 5, Enabled = false }; /// /// Constructor /// /// If true, only one animation is supported. The current animation will be replaced with the new one. If false, a new animation is added to the list. public AnimationManager(bool singular = true) { _animationProgresses = new List(); _animationSources = new List(); _animationDirections = new List(); _animationDatas = new List(); Increment = 0.03; SecondaryIncrement = 0.03; AnimationType = AnimationType.Linear; InterruptAnimation = true; Singular = singular; if (Singular) { _animationProgresses.Add(0); _animationSources.Add(new Point(0, 0)); _animationDirections.Add(AnimationDirection.In); } _animationTimer.Tick += AnimationTimerOnTick; } private void AnimationTimerOnTick(object sender, EventArgs eventArgs) { for (var i = 0; i < _animationProgresses.Count; i++) { UpdateProgress(i); if (!Singular) { if ((_animationDirections[i] == AnimationDirection.InOutIn && _animationProgresses[i] == MAX_VALUE)) { _animationDirections[i] = AnimationDirection.InOutOut; } else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingIn && _animationProgresses[i] == MIN_VALUE)) { _animationDirections[i] = AnimationDirection.InOutRepeatingOut; } else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingOut && _animationProgresses[i] == MIN_VALUE)) { _animationDirections[i] = AnimationDirection.InOutRepeatingIn; } else if ( (_animationDirections[i] == AnimationDirection.In && _animationProgresses[i] == MAX_VALUE) || (_animationDirections[i] == AnimationDirection.Out && _animationProgresses[i] == MIN_VALUE) || (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] == MIN_VALUE)) { _animationProgresses.RemoveAt(i); _animationSources.RemoveAt(i); _animationDirections.RemoveAt(i); _animationDatas.RemoveAt(i); } } else { if ((_animationDirections[i] == AnimationDirection.InOutIn && _animationProgresses[i] == MAX_VALUE)) { _animationDirections[i] = AnimationDirection.InOutOut; } else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingIn && _animationProgresses[i] == MAX_VALUE)) { _animationDirections[i] = AnimationDirection.InOutRepeatingOut; } else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingOut && _animationProgresses[i] == MIN_VALUE)) { _animationDirections[i] = AnimationDirection.InOutRepeatingIn; } } } OnAnimationProgress?.Invoke(this); } public bool IsAnimating() { return _animationTimer.Enabled; } public void StartNewAnimation(AnimationDirection animationDirection, object[] data = null) { StartNewAnimation(animationDirection, new Point(0, 0), data); } public void StartNewAnimation(AnimationDirection animationDirection, Point animationSource, object[] data = null) { if (!IsAnimating() || InterruptAnimation) { if (Singular && _animationDirections.Count > 0) { _animationDirections[0] = animationDirection; } else { _animationDirections.Add(animationDirection); } if (Singular && _animationSources.Count > 0) { _animationSources[0] = animationSource; } else { _animationSources.Add(animationSource); } if (!(Singular && _animationProgresses.Count > 0)) { switch (_animationDirections[_animationDirections.Count - 1]) { case AnimationDirection.InOutRepeatingIn: case AnimationDirection.InOutIn: case AnimationDirection.In: _animationProgresses.Add(MIN_VALUE); break; case AnimationDirection.InOutRepeatingOut: case AnimationDirection.InOutOut: case AnimationDirection.Out: _animationProgresses.Add(MAX_VALUE); break; default: throw new Exception("Invalid AnimationDirection"); } } if (Singular && _animationDatas.Count > 0) { _animationDatas[0] = data ?? new object[] { }; } else { _animationDatas.Add(data ?? new object[] { }); } } _animationTimer.Start(); } public void UpdateProgress(int index) { switch (_animationDirections[index]) { case AnimationDirection.InOutRepeatingIn: case AnimationDirection.InOutIn: case AnimationDirection.In: IncrementProgress(index); break; case AnimationDirection.InOutRepeatingOut: case AnimationDirection.InOutOut: case AnimationDirection.Out: DecrementProgress(index); break; default: throw new Exception("No AnimationDirection has been set"); } } private void IncrementProgress(int index) { _animationProgresses[index] += Increment; if (_animationProgresses[index] > MAX_VALUE) { _animationProgresses[index] = MAX_VALUE; for (int i = 0; i < GetAnimationCount(); i++) { if (_animationDirections[i] == AnimationDirection.InOutIn) return; if (_animationDirections[i] == AnimationDirection.InOutRepeatingIn) return; if (_animationDirections[i] == AnimationDirection.InOutRepeatingOut) return; if (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] != MAX_VALUE) return; if (_animationDirections[i] == AnimationDirection.In && _animationProgresses[i] != MAX_VALUE) return; } _animationTimer.Stop(); OnAnimationFinished?.Invoke(this); } } private void DecrementProgress(int index) { _animationProgresses[index] -= (_animationDirections[index] == AnimationDirection.InOutOut || _animationDirections[index] == AnimationDirection.InOutRepeatingOut) ? SecondaryIncrement : Increment; if (_animationProgresses[index] < MIN_VALUE) { _animationProgresses[index] = MIN_VALUE; for (var i = 0; i < GetAnimationCount(); i++) { if (_animationDirections[i] == AnimationDirection.InOutIn) return; if (_animationDirections[i] == AnimationDirection.InOutRepeatingIn) return; if (_animationDirections[i] == AnimationDirection.InOutRepeatingOut) return; if (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] != MIN_VALUE) return; if (_animationDirections[i] == AnimationDirection.Out && _animationProgresses[i] != MIN_VALUE) return; } _animationTimer.Stop(); OnAnimationFinished?.Invoke(this); } } public double GetProgress() { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationProgresses.Count == 0) throw new Exception("Invalid animation"); return GetProgress(0); } public double GetProgress(int index) { if (!(index < GetAnimationCount())) throw new IndexOutOfRangeException("Invalid animation index"); switch (AnimationType) { case AnimationType.Linear: return AnimationLinear.CalculateProgress(_animationProgresses[index]); case AnimationType.EaseInOut: return AnimationEaseInOut.CalculateProgress(_animationProgresses[index]); case AnimationType.EaseOut: return AnimationEaseOut.CalculateProgress(_animationProgresses[index]); case AnimationType.CustomQuadratic: return AnimationCustomQuadratic.CalculateProgress(_animationProgresses[index]); default: throw new NotImplementedException("The given AnimationType is not implemented"); } } public Point GetSource(int index) { if (!(index < GetAnimationCount())) throw new IndexOutOfRangeException("Invalid animation index"); return _animationSources[index]; } public Point GetSource() { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationSources.Count == 0) throw new Exception("Invalid animation"); return _animationSources[0]; } public AnimationDirection GetDirection() { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationDirections.Count == 0) throw new Exception("Invalid animation"); return _animationDirections[0]; } public AnimationDirection GetDirection(int index) { if (!(index < _animationDirections.Count)) throw new IndexOutOfRangeException("Invalid animation index"); return _animationDirections[index]; } public object[] GetData() { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationDatas.Count == 0) throw new Exception("Invalid animation"); return _animationDatas[0]; } public object[] GetData(int index) { if (!(index < _animationDatas.Count)) throw new IndexOutOfRangeException("Invalid animation index"); return _animationDatas[index]; } public int GetAnimationCount() { return _animationProgresses.Count; } public void SetProgress(double progress) { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationProgresses.Count == 0) throw new Exception("Invalid animation"); _animationProgresses[0] = progress; } public void SetDirection(AnimationDirection direction) { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationProgresses.Count == 0) throw new Exception("Invalid animation"); _animationDirections[0] = direction; } public void SetData(object[] data) { if (!Singular) throw new Exception("Animation is not set to Singular."); if (_animationDatas.Count == 0) throw new Exception("Invalid animation"); _animationDatas[0] = data; } } }