Jelajahi Sumber

- Initial implementation of ColorTransition.cs
- Added System.Numerics.Vectors in Avalonia.Base.
- Replaced AnimationPlayState in Animatable.cs with a DirectProperty.

Jumar Macato 7 tahun lalu
induk
melakukan
456c7c10c2

+ 11 - 5
src/Avalonia.Animation/Animatable.cs

@@ -27,19 +27,25 @@ namespace Avalonia.Animation
         /// <summary>
         /// Defines the <see cref="AnimationPlayState"/> property.
         /// </summary>
-        public static readonly StyledProperty<AnimationPlayState> AnimationPlayStateProperty =
-                AvaloniaProperty.Register<Animatable, AnimationPlayState>(nameof(AnimationPlayState));
+        public static readonly DirectProperty<Animatable, AnimationPlayState> AnimationPlayStateProperty =
+            AvaloniaProperty.RegisterDirect<Animatable, AnimationPlayState>(
+                nameof(AnimationPlayState),
+                o => o.AnimationPlayState,
+                (o, v) => o.AnimationPlayState = v);
 
         /// <summary>
         /// Gets or sets the state of the animation for this
         /// control.
         /// </summary>
         public AnimationPlayState AnimationPlayState
-        {
-            get { return GetValue(AnimationPlayStateProperty); }
-            set { SetValue(AnimationPlayStateProperty, value); }
+        { 
+            get { return _animationPlayState; }
+            set { SetAndRaise(AnimationPlayStateProperty, ref _animationPlayState, value); }
+        
         }
 
+        private AnimationPlayState _animationPlayState;
+
         /// <summary>
         /// Defines the <see cref="Transitions"/> property.
         /// </summary>

+ 34 - 0
src/Avalonia.Animation/ColorInterpolationMode.cs

@@ -0,0 +1,34 @@
+namespace Avalonia.Animation
+{
+    /// <summary>
+    /// Defines the intermediate color space
+    /// in which the color interpolation will be done.
+    /// </summary>
+    public enum ColorInterpolationMode
+    {
+        /// <summary>
+        /// Premultiply the alpha component and interpolate from RGB color space.
+        /// Fast but relatively accurate, perception-wise.
+        /// </summary>
+        PremultipliedRGB,
+
+        /// <summary>
+        /// Directly interpolate from RGB color space. 
+        /// Fastest but the least accurate, perception-wise.
+        /// </summary>
+        RGB,
+
+        /// <summary>
+        /// Converts RGB into HSV color space and interpolates. 
+        /// Slow but accurate, perception-wise.
+        /// </summary>
+        HSV,
+
+        /// <summary>
+        /// Converts RGB into HSV color space and interpolates. 
+        /// Slowest but the most accurate, perception-wise.
+        /// </summary>
+        LAB,
+
+    }
+}

+ 1 - 0
src/Avalonia.Animation/Keyframes/KeyFrames.cs

@@ -37,6 +37,7 @@ namespace Avalonia.Animation.Keyframes
 
             return obsMatch
                 .Where(p => p == true)
+                // Ignore triggers when global timers are paused.
                 .Where(p=> Timing.GetGlobalPlayState() != AnimationPlayState.Paused)
                 .Subscribe(_ =>
                 {

+ 1 - 1
src/Avalonia.Animation/Timing.cs

@@ -143,7 +143,7 @@ namespace Avalonia.Animation
         /// 0 being the start and 1 being the end. The observable is guaranteed to fire 0
         /// immediately on subscribe and 1 at the end of the duration.
         /// </remarks>
-        public static IObservable<double> GetTransitionsTimer(Animatable control, TimeSpan duration, TimeSpan delay)
+        public static IObservable<double> GetTransitionsTimer(Animatable control, TimeSpan duration, TimeSpan delay = default(TimeSpan))
         {
             var startTime = _transitionsFrameCount;
             var _duration = (ulong)(duration.Ticks / Tick.Ticks);

+ 2 - 2
src/Avalonia.Animation/Transitions/Transition.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Animation.Transitions
     /// <summary>
     /// Defines how a property should be animated using a transition.
     /// </summary>
-    public abstract class Transition<T> : ITransition
+    public abstract class Transition<T> : AvaloniaObject, ITransition
     {
         private AvaloniaProperty _prop;
         private Easing _easing;
@@ -59,7 +59,7 @@ namespace Avalonia.Animation.Transitions
         public abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
 
         /// <inheritdocs/>
-        public IDisposable Apply(Animatable control, object oldValue, object newValue)
+        public virtual IDisposable Apply(Animatable control, object oldValue, object newValue)
         {
             var transition = DoTransition(Timing.GetTransitionsTimer(control, Duration, TimeSpan.Zero), (T)oldValue, (T)newValue).Select(p => (object)p);
             return control.Bind(Property, transition, Data.BindingPriority.Animation);

+ 81 - 0
src/Avalonia.Visuals/Animation/Transitions/ColorTransition.cs

@@ -0,0 +1,81 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using Avalonia.Metadata;
+using System;
+using System.Reactive.Linq;
+using Avalonia.Media;
+using System.Numerics;
+
+namespace Avalonia.Animation.Transitions
+{
+    /// <summary>
+    /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="SolidColorBrush"/> types.
+    /// TODO: Must be refactored to handle object creation.
+    /// </summary>  
+    public class ColorTransition : Transition<SolidColorBrush>
+    {
+
+        /// <summary>
+        /// Defines the <see cref="AnimationPlayState"/> property.
+        /// </summary>
+        public static readonly DirectProperty<ColorTransition, ColorInterpolationMode> InterpolationModeProperty =
+            AvaloniaProperty.RegisterDirect<ColorTransition, ColorInterpolationMode>(
+                nameof(InterpolationMode),
+                o => o.InterpolationMode,
+                (o, v) => o.InterpolationMode = v);
+
+        /// <summary>
+        /// Gets or sets the state of the animation for this
+        /// control.
+        /// </summary>
+        public ColorInterpolationMode InterpolationMode
+        {
+            get { return _interpolationMode; }
+            set { SetAndRaise(InterpolationModeProperty, ref _interpolationMode, value); }
+        }
+
+        private ColorInterpolationMode _interpolationMode;
+  
+        public override IObservable<SolidColorBrush> DoTransition(IObservable<double> progress, SolidColorBrush oldValue, SolidColorBrush newValue)
+        {
+            var oldColor = new Vector4(oldValue.Color.A, oldValue.Color.R, oldValue.Color.G, oldValue.Color.B);
+            var newColor = new Vector4(newValue.Color.A, newValue.Color.R, newValue.Color.G, newValue.Color.B);
+            oldColor = oldColor / 255f;
+            newColor = newColor / 255f;
+            var deltaColor = newColor - oldColor;
+
+            switch (InterpolationMode)
+            {
+                case ColorInterpolationMode.PremultipliedRGB:
+                    
+                    var premultOV = new Vector4(1, oldColor.W, oldColor.W, oldColor.W);
+                    var premultNV = new Vector4(1, newColor.W, newColor.W, newColor.W);
+                    
+                    oldColor *= premultOV;
+                    newColor *= premultNV;
+
+                    return progress
+                    .Select(p =>
+                    {
+                        var time = (float)Easing.Ease(p);
+                        var interpolatedColor = (deltaColor * time) + oldColor;
+                        return new SolidColorBrush(Color.FromVector4(interpolatedColor, true));
+                    });
+
+                case ColorInterpolationMode.RGB:
+                    return progress
+                    .Select(p =>
+                    {
+                        var time = (float)Easing.Ease(p);
+                        var interpolatedColor = (deltaColor * time) + oldColor;
+                        return new SolidColorBrush(Color.FromVector4(interpolatedColor, true));
+                    });
+                default:
+                    throw new NotImplementedException($"{Enum.GetName(typeof(ColorInterpolationMode), InterpolationMode)} color interpolation is not supported.");
+            }
+
+        }
+ 
+    }
+}

+ 27 - 0
src/Avalonia.Visuals/Media/Color.cs

@@ -4,6 +4,7 @@
 using System;
 using System.Globalization;
 using System.Linq;
+using System.Numerics;
 using System.Reflection;
 
 namespace Avalonia.Media
@@ -81,6 +82,32 @@ namespace Avalonia.Media
             );
         }
 
+        /// <summary>
+        /// Creates a <see cref="Color"/> from a <see cref="Vector4"/>.
+        /// </summary>
+        /// <param name="value">The <see cref="Vector4"/> value.</param>
+        /// <param name="normalized">True if the color vector is normalized floats, false if it's bytes (0-255)</param>
+        /// <returns>The color.</returns>
+        public static Color FromVector4(Vector4 value, bool normalized)
+        {
+            if (normalized)
+            {
+                return new Color(
+                    (byte)(value.W * 255),
+                    (byte)(value.X * 255),
+                    (byte)(value.Y * 255),
+                    (byte)(value.Z * 255)
+                );
+            } else {
+                return new Color(
+                    (byte)(value.W),
+                    (byte)(value.X),
+                    (byte)(value.Y),
+                    (byte)(value.Z)
+                );
+            }
+
+        }
         /// <summary>
         /// Parses a color string.
         /// </summary>