|
|
|
@ -19,7 +19,7 @@ namespace Avalonia.Animation |
|
|
|
/// <summary>
|
|
|
|
/// List of type-converted keyframes.
|
|
|
|
/// </summary>
|
|
|
|
private readonly SortedList<double, (T, bool isNeutral)> _convertedKeyframes = new SortedList<double, (T, bool)>(); |
|
|
|
private readonly SortedList<double, (AnimatorKeyFrame, bool isNeutral)> _convertedKeyframes = new SortedList<double, (AnimatorKeyFrame, bool)>(); |
|
|
|
|
|
|
|
private bool _isVerfifiedAndConverted; |
|
|
|
|
|
|
|
@ -38,7 +38,7 @@ namespace Avalonia.Animation |
|
|
|
public virtual IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch) |
|
|
|
{ |
|
|
|
if (!_isVerfifiedAndConverted) |
|
|
|
VerifyConvertKeyFrames(animation); |
|
|
|
VerifyConvertKeyFrames(); |
|
|
|
|
|
|
|
return obsMatch |
|
|
|
// Ignore triggers when global timers are paused.
|
|
|
|
@ -59,7 +59,7 @@ namespace Avalonia.Animation |
|
|
|
/// <param name="t">The time parameter, relative to the total animation time</param>
|
|
|
|
protected (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double t) |
|
|
|
{ |
|
|
|
KeyValuePair<double, (T, bool)> firstCue, lastCue; |
|
|
|
KeyValuePair<double, (AnimatorKeyFrame frame, bool isNeutral)> firstCue, lastCue; |
|
|
|
int kvCount = _convertedKeyframes.Count; |
|
|
|
if (kvCount > 2) |
|
|
|
{ |
|
|
|
@ -88,7 +88,9 @@ namespace Avalonia.Animation |
|
|
|
double t0 = firstCue.Key; |
|
|
|
double t1 = lastCue.Key; |
|
|
|
var intraframeTime = (t - t0) / (t1 - t0); |
|
|
|
return (intraframeTime, new KeyFramePair<T>(firstCue, lastCue)); |
|
|
|
var firstFrameData = (firstCue.Value.frame.GetTypedValue<T>(), firstCue.Value.isNeutral); |
|
|
|
var lastFrameData = (lastCue.Value.frame.GetTypedValue<T>(), lastCue.Value.isNeutral); |
|
|
|
return (intraframeTime, new KeyFramePair<T>(firstFrameData, lastFrameData)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -115,24 +117,11 @@ namespace Avalonia.Animation |
|
|
|
/// <summary>
|
|
|
|
/// Verifies and converts keyframe values according to this class's target type.
|
|
|
|
/// </summary>
|
|
|
|
private void VerifyConvertKeyFrames(Animation animation) |
|
|
|
private void VerifyConvertKeyFrames() |
|
|
|
{ |
|
|
|
var typeConv = TypeDescriptor.GetConverter(typeof(T)); |
|
|
|
|
|
|
|
foreach (AnimatorKeyFrame k in this) |
|
|
|
foreach (AnimatorKeyFrame keyframe in this) |
|
|
|
{ |
|
|
|
if (k.Value == null) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException($"KeyFrame value can't be null."); |
|
|
|
} |
|
|
|
if (!typeConv.CanConvertTo(k.Value.GetType())) |
|
|
|
{ |
|
|
|
throw new InvalidCastException($"KeyFrame value doesnt match property type."); |
|
|
|
} |
|
|
|
|
|
|
|
T convertedValue = (T)typeConv.ConvertTo(k.Value, typeof(T)); |
|
|
|
|
|
|
|
_convertedKeyframes.Add(k.Cue.CueValue, (convertedValue, false)); |
|
|
|
_convertedKeyframes.Add(keyframe.Cue.CueValue, (keyframe, false)); |
|
|
|
} |
|
|
|
|
|
|
|
AddNeutralKeyFramesIfNeeded(); |
|
|
|
@ -159,19 +148,19 @@ namespace Avalonia.Animation |
|
|
|
} |
|
|
|
|
|
|
|
if (!hasStartKey || !hasEndKey) |
|
|
|
AddNeutralKeyFrames(hasStartKey, hasEndKey, _convertedKeyframes); |
|
|
|
AddNeutralKeyFrames(hasStartKey, hasEndKey); |
|
|
|
} |
|
|
|
|
|
|
|
private void AddNeutralKeyFrames(bool hasStartKey, bool hasEndKey, IDictionary<double, (T, bool)> convertedKeyframes) |
|
|
|
private void AddNeutralKeyFrames(bool hasStartKey, bool hasEndKey) |
|
|
|
{ |
|
|
|
if (!hasStartKey) |
|
|
|
{ |
|
|
|
convertedKeyframes.Add(0.0d, (default(T), true)); |
|
|
|
_convertedKeyframes.Add(0.0d, (new AnimatorKeyFrame { Value = default(T) }, true)); |
|
|
|
} |
|
|
|
|
|
|
|
if (!hasEndKey) |
|
|
|
{ |
|
|
|
convertedKeyframes.Add(1.0d, (default(T), true)); |
|
|
|
_convertedKeyframes.Add(1.0d, (new AnimatorKeyFrame { Value = default(T) }, true)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|