|
|
|
@ -1,6 +1,7 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Reactive.Disposables; |
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
|
|
|
|
using Avalonia.Logging; |
|
|
|
using Avalonia.Media; |
|
|
|
|
|
|
|
@ -16,8 +17,6 @@ namespace Avalonia.Animation.Animators |
|
|
|
/// </summary>
|
|
|
|
public class BaseBrushAnimator : Animator<IBrush?> |
|
|
|
{ |
|
|
|
private IAnimator? _targetAnimator; |
|
|
|
|
|
|
|
private static readonly List<(Func<Type, bool> Match, Type AnimatorType)> _brushAnimators = |
|
|
|
new List<(Func<Type, bool> Match, Type AnimatorType)>(); |
|
|
|
|
|
|
|
@ -42,41 +41,127 @@ namespace Avalonia.Animation.Animators |
|
|
|
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, |
|
|
|
IObservable<bool> match, Action onComplete) |
|
|
|
{ |
|
|
|
_targetAnimator = CreateAnimatorFromType(this[0].Value.GetType()); |
|
|
|
if (TryCreateCustomRegisteredAnimator(out var animator) |
|
|
|
|| TryCreateGradientAnimator(out animator) |
|
|
|
|| TryCreateSolidColorBrushAnimator(out animator)) |
|
|
|
{ |
|
|
|
return animator.Apply(animation, control, clock, match, onComplete); |
|
|
|
} |
|
|
|
|
|
|
|
Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log( |
|
|
|
this, |
|
|
|
"The animation's keyframe value types set is not supported."); |
|
|
|
|
|
|
|
return base.Apply(animation, control, clock, match, onComplete); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Fallback implementation of <see cref="IBrush"/> animation.
|
|
|
|
/// </summary>
|
|
|
|
public override IBrush? Interpolate(double progress, IBrush? oldValue, IBrush? newValue) => progress >= 0.5 ? newValue : oldValue; |
|
|
|
|
|
|
|
if (_targetAnimator != null) |
|
|
|
private bool TryCreateGradientAnimator([NotNullWhen(true)] out IAnimator? animator) |
|
|
|
{ |
|
|
|
IGradientBrush? firstGradient = null; |
|
|
|
foreach (var keyframe in this) |
|
|
|
{ |
|
|
|
foreach (var keyframe in this) |
|
|
|
if (keyframe.Value is IGradientBrush gradientBrush) |
|
|
|
{ |
|
|
|
_targetAnimator.Add(keyframe); |
|
|
|
firstGradient = gradientBrush; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (firstGradient is null) |
|
|
|
{ |
|
|
|
animator = null; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
_targetAnimator.Property = this.Property; |
|
|
|
var gradientAnimator = new IGradientBrushAnimator(); |
|
|
|
gradientAnimator.Property = Property; |
|
|
|
|
|
|
|
return _targetAnimator.Apply(animation, control, clock, match, onComplete); |
|
|
|
foreach (var keyframe in this) |
|
|
|
{ |
|
|
|
if (keyframe.Value is ISolidColorBrush solidColorBrush) |
|
|
|
{ |
|
|
|
gradientAnimator.Add(new AnimatorKeyFrame(typeof(IGradientBrushAnimator), keyframe.Cue, keyframe.KeySpline) |
|
|
|
{ |
|
|
|
Value = IGradientBrushAnimator.ConvertSolidColorBrushToGradient(firstGradient, solidColorBrush) |
|
|
|
}); |
|
|
|
} |
|
|
|
else if (keyframe.Value is IGradientBrush) |
|
|
|
{ |
|
|
|
gradientAnimator.Add(new AnimatorKeyFrame(typeof(IGradientBrushAnimator), keyframe.Cue, keyframe.KeySpline) |
|
|
|
{ |
|
|
|
Value = keyframe.Value |
|
|
|
}); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
animator = null; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Logger.TryGet(LogEventLevel.Error, LogArea.Animations)?.Log( |
|
|
|
this, |
|
|
|
"The animation's keyframe values didn't match any brush animators registered in BaseBrushAnimator."); |
|
|
|
|
|
|
|
return Disposable.Empty; |
|
|
|
animator = gradientAnimator; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override IBrush? Interpolate(double progress, IBrush? oldValue, IBrush? newValue) => null; |
|
|
|
private bool TryCreateSolidColorBrushAnimator([NotNullWhen(true)] out IAnimator? animator) |
|
|
|
{ |
|
|
|
var solidColorBrushAnimator = new ISolidColorBrushAnimator(); |
|
|
|
solidColorBrushAnimator.Property = Property; |
|
|
|
|
|
|
|
foreach (var keyframe in this) |
|
|
|
{ |
|
|
|
if (keyframe.Value is ISolidColorBrush) |
|
|
|
{ |
|
|
|
solidColorBrushAnimator.Add(new AnimatorKeyFrame(typeof(ISolidColorBrushAnimator), keyframe.Cue, keyframe.KeySpline) |
|
|
|
{ |
|
|
|
Value = keyframe.Value |
|
|
|
}); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
animator = null; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal static IAnimator? CreateAnimatorFromType(Type type) |
|
|
|
animator = solidColorBrushAnimator; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryCreateCustomRegisteredAnimator([NotNullWhen(true)] out IAnimator? animator) |
|
|
|
{ |
|
|
|
foreach (var (match, animatorType) in _brushAnimators) |
|
|
|
if (_brushAnimators.Count > 0) |
|
|
|
{ |
|
|
|
if (!match(type)) |
|
|
|
continue; |
|
|
|
var firstKeyType = this[0].Value.GetType(); |
|
|
|
foreach (var (match, animatorType) in _brushAnimators) |
|
|
|
{ |
|
|
|
if (!match(firstKeyType)) |
|
|
|
continue; |
|
|
|
|
|
|
|
return (IAnimator)Activator.CreateInstance(animatorType); |
|
|
|
animator = (IAnimator)Activator.CreateInstance(animatorType); |
|
|
|
if (animator != null) |
|
|
|
{ |
|
|
|
animator.Property = Property; |
|
|
|
foreach (var keyframe in this) |
|
|
|
{ |
|
|
|
animator.Add(new AnimatorKeyFrame(animatorType, keyframe.Cue, keyframe.KeySpline) |
|
|
|
{ |
|
|
|
Value = keyframe.Value |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
animator = null; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|