Skip to content

Commit

Permalink
Merge pull request #25 from stu98832/branch
Browse files Browse the repository at this point in the history
Improve animation. Fix ArgumentOutOfRangeException issue, TabPage animation issue.
  • Loading branch information
N-a-r-w-i-n authored Oct 17, 2019
2 parents 0555d16 + 97cf06b commit c0cdde3
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 155 deletions.
200 changes: 200 additions & 0 deletions MetroSet UI/Animates/Animate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
using MetroSet_UI.Enums;
using System;
using System.Windows.Forms;

namespace MetroSet_UI.Animates
{
// interpolation animate
public abstract class Animate<T> : IDisposable
{
/// <summary>
/// Call when animation update
/// </summary>
public Action<T> Update { get; set; }

/// <summary>
/// Call when animation complate
/// </summary>
public MethodInvoker Complete { get; set; }

#region Internal Vars
// a bad way to record time...
private DateTime _lastUpdateTime;
// I use timer instead of thread, so you can modify control without Control.Invoke
private Timer _animateTimer;
// reverse animate
private bool _reverse;
#endregion

#region Constructors
// choose best interval for yourself
public Animate(int updateInterval = 16)
{
_animateTimer = new Timer()
{
Interval = updateInterval,
Enabled = false,
};
_animateTimer.Tick += this.OnFrameUpdate;
_reverse = false;
Alpha = 0.0;
}
#endregion

#region Functions
// just set once, and use start, back or reverse to play animate
public void Setting(int duration, T initial, T end, EasingType easing = EasingType.Linear)
{
InitialValue = initial;
EndValue = end;
EasingType = easing;
Duration = duration;
}

// start animate with default setting
public void Start()
{
_reverse = false;
Alpha = 0.0;
Play();
}

// back animate with default setting
public void Back()
{
_reverse = true;
Alpha = 1.0;
Play();
}

// start animate with default setting
public void Start(int duration)
{
_reverse = false;
Alpha = 0.0;
Duration = duration;
Play();
}

// back animate with default setting
public void Back(int duration)
{
_reverse = true;
Alpha = 1.0;
Duration = duration;
Play();
}

// reverse animate
public void Reverse()
{
Reverse(!_reverse);
}

// reverse animate
public void Reverse(bool val)
{
_reverse = val;

if (!Active)
Play();
}

// play animate
public void Play()
{
_lastUpdateTime = DateTime.Now;
Active = true;
_animateTimer.Enabled = true;
_animateTimer.Start();
}

public void Pause()
{
_animateTimer.Stop();
_animateTimer.Enabled = false;
Active = false;
}

public void Stop()
{
Pause();
Alpha = _reverse ? 1.0 : 0.0;
}

// start animate with specific setting
public void Start(int duration, T initial, T end, EasingType easing = EasingType.Linear)
{
Setting(duration, initial, end, easing);
Start();
}

// back animate with specific setting
public void Back(int duration, T initial, T end, EasingType easing = EasingType.Linear)
{
Setting(duration, initial, end, easing);
Back();
}
#endregion

#region Events
// process frame
private void OnFrameUpdate(object sender, EventArgs e)
{
DateTime updateTime = DateTime.Now;
double elapsed;

if (Duration == 0)
elapsed = 1.0;
else
elapsed = (updateTime - _lastUpdateTime).TotalMilliseconds / Duration;

_lastUpdateTime = updateTime;
Alpha = Math.Max(0.0, Math.Min(Alpha + (_reverse ? -elapsed : elapsed), 1.0));

Update?.Invoke(Value);

if (Alpha == 0.0 || Alpha == 1.0)
{
Pause();
Complete?.Invoke();
}
}
#endregion

#region Properties
// progress. value between 0 and 1
public double Alpha { get; set; }

// animate duration
// recorded for calculating elapsed alpha
// if you use reverse animate when animate avtiving
// the real duration will different with the duration you set
public int Duration { get; set; }

// initial state of value
public T InitialValue { get; private set; }

public abstract T Value { get; }

// final state of value
public T EndValue { get; private set; }

// easing type
public EasingType EasingType { get; private set; }

// active if the animate is running
public bool Active { get; private set; }

// store you own variable here
public object Tag { get; set; }
#endregion

#region Dispose
public void Dispose()
{
_animateTimer.Dispose();
}
#endregion
}
}
15 changes: 15 additions & 0 deletions MetroSet UI/Animates/ColorAnimate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Drawing;

namespace MetroSet_UI.Animates
{
public class ColorAnimate : Animate<Color>
{
public override Color Value =>
Color.FromArgb(
(byte)Interpolation.ValueAt(InitialValue.A, EndValue.A, Alpha, EasingType),
(byte)Interpolation.ValueAt(InitialValue.R, EndValue.R, Alpha, EasingType),
(byte)Interpolation.ValueAt(InitialValue.G, EndValue.G, Alpha, EasingType),
(byte)Interpolation.ValueAt(InitialValue.B, EndValue.B, Alpha, EasingType)
);
}
}
8 changes: 8 additions & 0 deletions MetroSet UI/Animates/DoubleAnimat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace MetroSet_UI.Animates
{
public class DoubleAnimate : Animate<double>
{
public override double Value =>
Interpolation.ValueAt(InitialValue, EndValue, Alpha, EasingType);
}
}
8 changes: 8 additions & 0 deletions MetroSet UI/Animates/IntAnimate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace MetroSet_UI.Animates
{
public class IntAnimate : Animate<int>
{
public override int Value =>
(int)Interpolation.ValueAt(InitialValue, EndValue, Alpha, EasingType);
}
}
112 changes: 112 additions & 0 deletions MetroSet UI/Animates/Interpolation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using MetroSet_UI.Enums;

namespace MetroSet_UI.Animates
{
// for animate
public class Interpolation
{
public static double ValueAt(double initial, double end, double alpha, EasingType easing)
{
switch (easing)
{
default:
case EasingType.None:
case EasingType.Linear:
return (end * alpha) + (initial * (1 - alpha));
case EasingType.QuadIn:
{
double factor = alpha * alpha;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuadOut:
{
double factor = (2 - alpha) * alpha;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuadInOut:
{
double mid = initial + (end - initial) / 2.0;
if (alpha <= 0.5)
return ValueAt(initial, mid, alpha * 2, EasingType.QuadIn);
else
return ValueAt(mid, end, (alpha - 0.5) * 2, EasingType.QuadOut);
}
case EasingType.CubeIn:
{
double factor = alpha * alpha * alpha;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.CubeOut:
{
double factor = -(alpha - 1);
factor = -(factor * factor * factor) + 1;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.CubeInOut:
{
double mid = initial + (end - initial) / 2.0;
if (alpha <= 0.5)
return ValueAt(initial, mid, alpha * 2, EasingType.CubeIn);
else
return ValueAt(mid, end, (alpha - 0.5) * 2, EasingType.CubeOut);
}
case EasingType.QuartIn:
{
double factor = alpha * alpha * alpha * alpha;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuartOut:
{
double factor = -(alpha - 1);
factor = 1-(factor * factor * factor * factor);
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuartInOut:
{
double mid = initial + (end - initial) / 2.0;
if (alpha <= 0.5)
return ValueAt(initial, mid, alpha * 2, EasingType.QuartIn);
else
return ValueAt(mid, end, (alpha - 0.5) * 2, EasingType.QuartOut);
}
case EasingType.QuintIn:
{
double factor = alpha * alpha * alpha * alpha * alpha;
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuintOut:
{
double factor = -(alpha - 1);
factor = 1-(factor * factor * factor * factor * factor);
return (end * factor) + (initial * (1 - factor));
}
case EasingType.QuintInOut:
{
double mid = initial + (end - initial) / 2.0;
if (alpha <= 0.5)
return ValueAt(initial, mid, alpha / 0.5, EasingType.QuintIn);
else
return ValueAt(mid, end, (alpha - 0.5) / 0.5, EasingType.QuintOut);
}
case EasingType.SineIn:
{
double factor = 1 - Math.Cos(Math.PI / 2 * alpha);
return (end * factor) + (initial * (1 - factor));
}
case EasingType.SineOut:
{
double factor = Math.Sin(Math.PI / 2 * alpha);
return (end * factor) + (initial * (1 - factor));
}
case EasingType.SineInOut:
{
if (alpha <= 0.5)
return ValueAt(initial, (initial + end) / 2.0, alpha * 2, EasingType.SineIn);
else
return ValueAt((initial + end) / 2.0, end, (alpha-0.5) * 2, EasingType.SineOut);
}
}
}
}
}
13 changes: 13 additions & 0 deletions MetroSet UI/Animates/PointFAnimate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Drawing;

namespace MetroSet_UI.Animates
{
public class PointFAnimate : Animate<PointF>
{
public override PointF Value =>
new PointF(
(float)Interpolation.ValueAt(InitialValue.X, EndValue.X, Alpha, EasingType),
(float)Interpolation.ValueAt(InitialValue.Y, EndValue.Y, Alpha, EasingType)
);
}
}
13 changes: 13 additions & 0 deletions MetroSet UI/Animates/SizeFAnimate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Drawing;

namespace MetroSet_UI.Animates
{
public class SizeFAnimate : Animate<SizeF>
{
public override SizeF Value =>
new SizeF(
(float)Interpolation.ValueAt(InitialValue.Width, EndValue.Width, Alpha, EasingType),
(float)Interpolation.ValueAt(InitialValue.Height, EndValue.Height, Alpha, EasingType)
);
}
}
Loading

0 comments on commit c0cdde3

Please sign in to comment.