using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Logging;
using Avalonia.Media;
#nullable enable
namespace Avalonia.Animation.Animators
{
///
/// Animator that handles all animations on properties
/// with as their type and
/// redirect them to the properly registered
/// animators in this class.
///
public class BaseBrushAnimator : Animator
{
private static readonly List<(Func Match, Type AnimatorType)> _brushAnimators =
new List<(Func Match, Type AnimatorType)>();
///
/// Register an that handles a specific
/// 's descendant value type.
///
///
/// The condition to which the
/// is to be activated and used.
///
///
/// The type of the animator to instantiate.
///
public static void RegisterBrushAnimator(Func condition)
where TAnimator : IAnimator, new()
{
_brushAnimators.Insert(0, (condition, typeof(TAnimator)));
}
///
public override IDisposable? Apply(Animation animation, Animatable control, IClock? clock,
IObservable match, Action? onComplete)
{
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);
}
///
/// Fallback implementation of animation.
///
public override IBrush? Interpolate(double progress, IBrush? oldValue, IBrush? newValue) => progress >= 0.5 ? newValue : oldValue;
private bool TryCreateGradientAnimator([NotNullWhen(true)] out IAnimator? animator)
{
IGradientBrush? firstGradient = null;
foreach (var keyframe in this)
{
if (keyframe.Value is IGradientBrush gradientBrush)
{
firstGradient = gradientBrush;
break;
}
}
if (firstGradient is null)
{
animator = null;
return false;
}
var gradientAnimator = new GradientBrushAnimator();
gradientAnimator.Property = Property;
foreach (var keyframe in this)
{
if (keyframe.Value is ISolidColorBrush solidColorBrush)
{
gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), keyframe.Cue, keyframe.KeySpline)
{
Value = GradientBrushAnimator.ConvertSolidColorBrushToGradient(firstGradient, solidColorBrush)
});
}
else if (keyframe.Value is IGradientBrush)
{
gradientAnimator.Add(new AnimatorKeyFrame(typeof(GradientBrushAnimator), keyframe.Cue, keyframe.KeySpline)
{
Value = keyframe.Value
});
}
else
{
animator = null;
return false;
}
}
animator = gradientAnimator;
return true;
}
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;
}
}
animator = solidColorBrushAnimator;
return true;
}
private bool TryCreateCustomRegisteredAnimator([NotNullWhen(true)] out IAnimator? animator)
{
if (_brushAnimators.Count > 0 && this[0].Value?.GetType() is Type firstKeyType)
{
foreach (var (match, animatorType) in _brushAnimators)
{
if (!match(firstKeyType))
continue;
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;
}
}
}
animator = null;
return false;
}
}
}