Files
2025-07-14 12:03:59 +02:00

364 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace MaterialSkin.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<double> _animationProgresses;
private readonly List<Point> _animationSources;
private readonly List<AnimationDirection> _animationDirections;
private readonly List<object[]> _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 };
/// <summary>
/// Constructor
/// </summary>
/// <param name="singular">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.</param>
public AnimationManager(bool singular = true)
{
_animationProgresses = new List<double>();
_animationSources = new List<Point>();
_animationDirections = new List<AnimationDirection>();
_animationDatas = new List<object[]>();
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;
}
}
}