Files
HandyControl/src/Shared/HandyControl_Shared/Media/Animation/GeometryAnimation.cs
T
2021-09-14 23:41:35 +08:00

181 lines
6.2 KiB
C#

using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using HandyControl.Data;
using HandyControl.Tools;
// ReSharper disable PossibleInvalidOperationException
namespace HandyControl.Media.Animation
{
public class GeometryAnimation : GeometryAnimationBase
{
private string[] _strings;
private double[] _numbersFrom;
private double[] _numbersTo;
private double[] _numbersAccumulator;
public GeometryAnimation()
{
}
public GeometryAnimation(string fromValue, string toValue) : this()
{
From = Geometry.Parse(fromValue);
To = Geometry.Parse(toValue);
}
private void UpdateValue()
{
if (_numbersFrom == null || _numbersTo == null || _numbersFrom.Length != _numbersTo.Length) return;
_numbersAccumulator = new double[_numbersFrom.Length];
for (var i = 0; i < _numbersFrom.Length; i++)
{
_numbersAccumulator[i] = _numbersTo[i] - _numbersFrom[i];
}
}
public GeometryAnimation(Geometry fromValue, Geometry toValue) : this()
{
From = fromValue;
To = toValue;
}
public GeometryAnimation(Geometry fromValue, Geometry toValue, Duration duration) : this()
{
From = fromValue;
To = toValue;
Duration = duration;
}
public GeometryAnimation(Geometry fromValue, Geometry toValue, Duration duration, FillBehavior fillBehavior) : this()
{
From = fromValue;
To = toValue;
Duration = duration;
FillBehavior = fillBehavior;
}
public new GeometryAnimation Clone() => (GeometryAnimation) base.Clone();
protected override Freezable CreateInstanceCore() => new GeometryAnimation();
protected override Geometry GetCurrentValueCore(Geometry defaultOriginValue, Geometry defaultDestinationValue, AnimationClock animationClock)
{
if (_numbersAccumulator == null)
{
if (_numbersFrom == null)
{
var geometryStr = defaultOriginValue.ToString(CultureInfo.InvariantCulture);
AnimationHelper.DecomposeGeometryStr(geometryStr, out _numbersFrom);
}
if (_numbersTo == null)
{
var geometryStr = defaultDestinationValue.ToString(CultureInfo.InvariantCulture);
AnimationHelper.DecomposeGeometryStr(geometryStr, out _numbersTo);
_strings = Regex.Split(geometryStr, RegexPatterns.DigitsPattern);
}
UpdateValue();
}
if (_numbersAccumulator == null) return defaultOriginValue;
var progress = animationClock.CurrentProgress.Value;
var easingFunction = EasingFunction;
if (easingFunction != null)
{
progress = easingFunction.Ease(progress);
}
var accumulated = new double[_numbersAccumulator.Length];
if (IsCumulative)
{
var currentRepeat = (double) (animationClock.CurrentIteration - 1);
if (currentRepeat > 0.0)
{
accumulated = new double[_numbersAccumulator.Length];
for (var i = 0; i < _numbersAccumulator.Length; i++)
{
accumulated[i] = _numbersAccumulator[i] * currentRepeat;
}
}
}
var numbers = new double[_numbersAccumulator.Length];
for (var i = 0; i < _numbersAccumulator.Length; i++)
{
numbers[i] = accumulated[i] + _numbersFrom[i] + _numbersAccumulator[i] * progress;
}
return AnimationHelper.ComposeGeometry(_strings, numbers);
}
public static readonly DependencyProperty FromProperty = DependencyProperty.Register(
"From", typeof(Geometry), typeof(GeometryAnimation), new PropertyMetadata(default(Geometry), OnFromChanged));
private static void OnFromChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = (GeometryAnimation) d;
if (e.NewValue is Geometry geometry)
{
AnimationHelper.DecomposeGeometryStr(geometry.ToString(CultureInfo.InvariantCulture), out obj._numbersFrom);
obj.UpdateValue();
}
}
public Geometry From
{
get => (Geometry) GetValue(FromProperty);
set => SetValue(FromProperty, value);
}
public static readonly DependencyProperty ToProperty = DependencyProperty.Register(
"To", typeof(Geometry), typeof(GeometryAnimation), new PropertyMetadata(default(Geometry), OnToChanged));
private static void OnToChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = (GeometryAnimation) d;
if (e.NewValue is Geometry geometry)
{
var geometryStr = geometry.ToString(CultureInfo.InvariantCulture);
AnimationHelper.DecomposeGeometryStr(geometryStr, out obj._numbersTo);
obj._strings = Regex.Split(geometryStr, RegexPatterns.DigitsPattern);
obj.UpdateValue();
}
}
public Geometry To
{
get => (Geometry) GetValue(ToProperty);
set => SetValue(ToProperty, value);
}
public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register(
"EasingFunction", typeof(IEasingFunction), typeof(GeometryAnimation), new PropertyMetadata(default(IEasingFunction)));
public IEasingFunction EasingFunction
{
get => (IEasingFunction) GetValue(EasingFunctionProperty);
set => SetValue(EasingFunctionProperty, value);
}
public bool IsCumulative
{
get => (bool) GetValue(IsCumulativeProperty);
set => SetValue(IsCumulativeProperty, ValueBoxes.BooleanBox(value));
}
}
}