Browse Source

Fixes for animation registry

Nikita Tsukanov 2 years ago
parent
commit
14b8025d83

+ 3 - 2
samples/RenderDemo/Pages/CustomStringAnimator.cs

@@ -1,9 +1,10 @@
-using Avalonia.Animation;
+using System;
+using Avalonia.Animation;
 using Avalonia.Animation.Animators;
 
 namespace RenderDemo.Pages
 {
-    public class CustomStringAnimator : CustomAnimatorBase<string>
+    public class CustomStringAnimator : InterpolatingAnimator<string>
     {
         public override string Interpolate(double progress, string oldValue, string newValue)
         {

+ 94 - 0
src/Avalonia.Base/Animation/Animation.AnimatorRegistry.cs

@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Animation.Animators;
+using Avalonia.Media;
+
+namespace Avalonia.Animation;
+
+partial class Animation
+{
+    /// <summary>
+    /// Sets the value of the Animator attached property for a setter.
+    /// </summary>
+    /// <param name="setter">The animation setter.</param>
+    /// <param name="value">The property animator value.</param>
+    [Obsolete("CustomAnimatorBase will be removed before 11.0, use InterpolatingAnimator<T>", true)]
+    public static void SetAnimator(IAnimationSetter setter, CustomAnimatorBase value)
+    {
+        s_animators[setter] = (value.WrapperType, value.CreateWrapper);
+    }
+
+    /// <summary>
+    /// Sets the value of the Animator attached property for a setter.
+    /// </summary>
+    /// <param name="setter">The animation setter.</param>
+    /// <param name="value">The property animator value.</param>
+    public static void SetAnimator(IAnimationSetter setter, ICustomAnimator value)
+    {
+        s_animators[setter] = (value.WrapperType, value.CreateWrapper);
+    }
+
+    private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)>
+        Animators = new()
+        {
+            (prop =>(typeof(double).IsAssignableFrom(prop.PropertyType) && typeof(Transform).IsAssignableFrom(prop.OwnerType)),
+                typeof(TransformAnimator), () => new TransformAnimator()),
+            (prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator()),
+            (prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator()),
+            (prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator()),
+            (prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator()),
+            (prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator()), 
+            (prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator()), 
+            (prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator()), 
+            (prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator()),
+            (prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator()), 
+            (prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator()), 
+            (prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator()),
+        };
+
+    static Animation()
+    {
+        RegisterAnimator<IEffect?, EffectAnimator>();
+        RegisterAnimator<BoxShadow, BoxShadowAnimator>();
+        RegisterAnimator<BoxShadows, BoxShadowsAnimator>();
+        RegisterAnimator<IBrush?, BaseBrushAnimator>();
+        RegisterAnimator<CornerRadius, CornerRadiusAnimator>();
+        RegisterAnimator<Color, ColorAnimator>();
+        RegisterAnimator<Vector, VectorAnimator>();
+        RegisterAnimator<Point, PointAnimator>();
+        RegisterAnimator<Rect, RectAnimator>();
+        RegisterAnimator<RelativePoint, RelativePointAnimator>();
+        RegisterAnimator<Size, SizeAnimator>();
+        RegisterAnimator<Thickness, ThicknessAnimator>();
+    }
+
+    /// <summary>
+    /// Registers a <see cref="Animator{T}"/> that can handle
+    /// a value type that matches the specified condition.
+    /// </summary>
+    static void RegisterAnimator<T, TAnimator>()
+        where TAnimator : Animator<T>, new()
+    {
+        Animators.Insert(0,
+            (prop => typeof(T).IsAssignableFrom(prop.PropertyType), typeof(TAnimator), () => new TAnimator()));
+    }
+
+    public static void RegisterCustomAnimator<T, TAnimator>() where TAnimator : InterpolatingAnimator<T>, new()
+    {
+        Animators.Insert(0, (prop => typeof(T).IsAssignableFrom(prop.PropertyType),
+            typeof(InterpolatingAnimator<T>.AnimatorWrapper), () => new TAnimator().CreateWrapper()));
+    }
+
+    private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property)
+    {
+        foreach (var (condition, type, factory) in Animators)
+        {
+            if (condition(property))
+            {
+                return (type, factory);
+            }
+        }
+
+        return null;
+    }
+}

+ 1 - 58
src/Avalonia.Base/Animation/Animation.cs

@@ -1,12 +1,9 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Avalonia.Reactive;
 using System.Threading;
 using System.Threading.Tasks;
-
-using Avalonia.Animation.Animators;
 using Avalonia.Animation.Easings;
 using Avalonia.Data;
 using Avalonia.Metadata;
@@ -16,7 +13,7 @@ namespace Avalonia.Animation
     /// <summary>
     /// Tracks the progress of an animation.
     /// </summary>
-    public sealed class Animation : AvaloniaObject, IAnimation
+    public sealed partial class Animation : AvaloniaObject, IAnimation
     {
         /// <summary>
         /// Defines the <see cref="Duration"/> property.
@@ -195,60 +192,6 @@ namespace Avalonia.Animation
             return null;
         }
 
-        /// <summary>
-        /// Sets the value of the Animator attached property for a setter.
-        /// </summary>
-        /// <param name="setter">The animation setter.</param>
-        /// <param name="value">The property animator value.</param>
-        public static void SetAnimator(IAnimationSetter setter, CustomAnimatorBase value)
-        {
-            s_animators[setter] = (value.WrapperType, value.CreateWrapper);
-        }
-
-        private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)> Animators = new()
-        {
-            ( prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator() ),
-            ( prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator() ),
-            ( prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator() ),
-            ( prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator() ),
-            ( prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator() ),
-            ( prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator() ),
-            ( prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator() ),
-            ( prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator() ),
-            ( prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator() ),
-            ( prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator() ),
-            ( prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator() ),
-        };
-
-        /// <summary>
-        /// Registers a <see cref="Animator{T}"/> that can handle
-        /// a value type that matches the specified condition.
-        /// </summary>
-        /// <param name="condition">
-        /// The condition to which the <see cref="Animator{T}"/>
-        /// is to be activated and used.
-        /// </param>
-        /// <typeparam name="TAnimator">
-        /// The type of the animator to instantiate.
-        /// </typeparam>
-        internal static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition)
-            where TAnimator : IAnimator, new()
-        {
-            Animators.Insert(0, (condition, typeof(TAnimator), () => new TAnimator()));
-        }
-
-        private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property)
-        {
-            foreach (var (condition, type, factory) in Animators)
-            {
-                if (condition(property))
-                {
-                    return (type, factory);
-                }
-            }
-            return null;
-        }
-
         private (IList<IAnimator> Animators, IList<IDisposable> subscriptions) InterpretKeyframes(Animatable control)
         {
             var handlerList = new Dictionary<(Type type, AvaloniaProperty Property), Func<IAnimator>>();

+ 29 - 1
src/Avalonia.Base/Animation/ICustomAnimator.cs

@@ -1,14 +1,15 @@
 using System;
 using Avalonia.Animation.Animators;
-
 namespace Avalonia.Animation;
 
+[Obsolete("This class will be removed before 11.0, use InterpolatingAnimator<T>", true)]
 public abstract class CustomAnimatorBase
 {
     internal abstract IAnimator CreateWrapper();
     internal abstract Type WrapperType { get; }
 }
 
+[Obsolete("This class will be removed before 11.0, use InterpolatingAnimator<T>", true)]
 public abstract class CustomAnimatorBase<T> : CustomAnimatorBase
 {
     public abstract T Interpolate(double progress, T oldValue, T newValue);
@@ -25,6 +26,33 @@ public abstract class CustomAnimatorBase<T> : CustomAnimatorBase
             _parent = parent;
         }
         
+        public override T Interpolate(double progress, T oldValue, T newValue) => _parent.Interpolate(progress, oldValue, newValue);
+    }
+}
+
+public interface ICustomAnimator
+{
+    internal IAnimator CreateWrapper();
+    internal Type WrapperType { get; }
+}
+
+public abstract class InterpolatingAnimator<T> : ICustomAnimator
+{
+    public abstract T Interpolate(double progress, T oldValue, T newValue);
+
+    Type ICustomAnimator.WrapperType => typeof(AnimatorWrapper);
+    IAnimator ICustomAnimator.CreateWrapper() => new AnimatorWrapper(this);
+    internal IAnimator CreateWrapper() => new AnimatorWrapper(this);
+
+    internal class AnimatorWrapper : Animator<T>
+    {
+        private readonly InterpolatingAnimator<T> _parent;
+
+        public AnimatorWrapper(InterpolatingAnimator<T> parent)
+        {
+            _parent = parent;
+        }
+        
         public override T Interpolate(double progress, T oldValue, T newValue) => _parent.Interpolate(progress, oldValue, newValue);
     }
 }

+ 0 - 7
src/Avalonia.Base/CornerRadius.cs

@@ -15,13 +15,6 @@ namespace Avalonia
 #endif
     readonly struct CornerRadius : IEquatable<CornerRadius>
     {
-        static CornerRadius()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<CornerRadiusAnimator>(prop => typeof(CornerRadius).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         public CornerRadius(double uniformRadius)
         {
             TopLeft = TopRight = BottomLeft = BottomRight = uniformRadius;

+ 0 - 6
src/Avalonia.Base/Media/BoxShadow.cs

@@ -16,12 +16,6 @@ namespace Avalonia.Media
         public Color Color { get; set; }
         public bool IsInset { get; set; }
 
-        static BoxShadow()
-        {
-            Animation.Animation.RegisterAnimator<BoxShadowAnimator>(prop =>
-                typeof(BoxShadow).IsAssignableFrom(prop.PropertyType));
-        }
-        
         public bool Equals(in BoxShadow other)
         {
             return OffsetX.Equals(other.OffsetX) && OffsetY.Equals(other.OffsetY) && Blur.Equals(other.Blur) && Spread.Equals(other.Spread) && Color.Equals(other.Color);

+ 0 - 6
src/Avalonia.Base/Media/BoxShadows.cs

@@ -10,12 +10,6 @@ namespace Avalonia.Media
         private readonly BoxShadow _first;
         private readonly BoxShadow[]? _list;
         public int Count { get; }
-
-        static BoxShadows()
-        {
-            Animation.Animation.RegisterAnimator<BoxShadowsAnimator>(prop =>
-                typeof(BoxShadows).IsAssignableFrom(prop.PropertyType));
-        }
         
         public BoxShadows(BoxShadow shadow)
         {

+ 0 - 5
src/Avalonia.Base/Media/Brush.cs

@@ -34,11 +34,6 @@ namespace Avalonia.Media
         /// </summary>
         public static readonly StyledProperty<RelativePoint> TransformOriginProperty =
             AvaloniaProperty.Register<Brush, RelativePoint>(nameof(TransformOrigin));
-        
-        static Brush()
-        {
-            Animation.Animation.RegisterAnimator<BaseBrushAnimator>(prop => typeof(IBrush).IsAssignableFrom(prop.PropertyType));
-        }
 
         /// <summary>
         /// Gets or sets the opacity of the brush.

+ 0 - 7
src/Avalonia.Base/Media/Color.cs

@@ -25,13 +25,6 @@ namespace Avalonia.Media
     {
         private const double byteToDouble = 1.0 / 255;
 
-        static Color()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<ColorAnimator>(prop => typeof(Color).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// Gets the Alpha component of the color.
         /// </summary>

+ 0 - 2
src/Avalonia.Base/Media/Effects/EffectAnimator.cs

@@ -63,8 +63,6 @@ internal class EffectAnimator : Animator<IEffect?>
         if(s_Registered)
             return;
         s_Registered = true;
-        Animation.RegisterAnimator<EffectAnimator>(prop =>
-            typeof(IEffect).IsAssignableFrom(prop.PropertyType));
     }
 }
 

+ 0 - 6
src/Avalonia.Base/Media/Transform.cs

@@ -15,12 +15,6 @@ namespace Avalonia.Media
     /// </summary>
     public abstract class Transform : Animatable, IMutableTransform, ICompositionRenderResource<ITransform>, ICompositorSerializable
     {
-        static Transform()
-        {
-            Animation.Animation.RegisterAnimator<TransformAnimator>(prop =>
-                typeof(ITransform).IsAssignableFrom(prop.OwnerType));
-        }
-
         internal Transform()
         {
             

+ 0 - 7
src/Avalonia.Base/Point.cs

@@ -16,13 +16,6 @@ namespace Avalonia
 #endif
     readonly struct Point : IEquatable<Point>
     {
-        static Point()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<PointAnimator>(prop => typeof(Point).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// The X position.
         /// </summary>

+ 0 - 5
src/Avalonia.Base/Rect.cs

@@ -11,11 +11,6 @@ namespace Avalonia
     /// </summary>
     public readonly struct Rect : IEquatable<Rect>
     {
-        static Rect()
-        {
-            Animation.Animation.RegisterAnimator<RectAnimator>(prop => typeof(Rect).IsAssignableFrom(prop.PropertyType));
-        }
-
         /// <summary>
         /// The X position.
         /// </summary>

+ 0 - 7
src/Avalonia.Base/RelativePoint.cs

@@ -54,13 +54,6 @@ namespace Avalonia
 
         private readonly RelativeUnit _unit;
 
-        static RelativePoint()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<RelativePointAnimator>(prop => typeof(RelativePoint).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="RelativePoint"/> struct.
         /// </summary>

+ 0 - 7
src/Avalonia.Base/Size.cs

@@ -15,13 +15,6 @@ namespace Avalonia
 #endif
     readonly struct Size : IEquatable<Size>
     {
-        static Size()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<SizeAnimator>(prop => typeof(Size).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// A size representing infinity.
         /// </summary>

+ 0 - 7
src/Avalonia.Base/Thickness.cs

@@ -15,13 +15,6 @@ namespace Avalonia
 #endif
     readonly struct Thickness : IEquatable<Thickness>
     {
-        static Thickness()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<ThicknessAnimator>(prop => typeof(Thickness).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// The thickness on the left.
         /// </summary>

+ 0 - 7
src/Avalonia.Base/Vector.cs

@@ -17,13 +17,6 @@ namespace Avalonia
 #endif
     readonly struct Vector : IEquatable<Vector>
     {
-        static Vector()
-        {
-#if !BUILDTASK
-            Animation.Animation.RegisterAnimator<VectorAnimator>(prop => typeof(Vector).IsAssignableFrom(prop.PropertyType));
-#endif
-        }
-
         /// <summary>
         /// The X component.
         /// </summary>