protected NormalizedKeyFrameAnimationBuilder(string property, TimeSpan?delay, TimeSpan duration, RepeatOption repeat)
 {
     this.property = property;
     this.delay    = delay;
     this.duration = duration;
     this.repeat   = repeat;
 }
 private sealed record AnimationFactory <T>(
     string Property,
     T To,
     T?From,
     TimeSpan Delay,
     TimeSpan Duration,
     RepeatOption Repeat,
     EasingType EasingType,
     EasingMode EasingMode)
     : ICompositionAnimationFactory, IXamlAnimationFactory
        /// <summary>
        /// Gets a <see cref="Timeline"/> instance representing the animation to start.
        /// </summary>
        /// <typeparam name="TKeyFrame">The type of keyframes being used to define the animation.</typeparam>
        /// <param name="target">The target <see cref="DependencyObject"/> instance to animate.</param>
        /// <param name="property">The target property to animate.</param>
        /// <param name="delay">The optional initial delay for the animation.</param>
        /// <param name="duration">The animation duration.</param>
        /// <param name="repeat">The <see cref="RepeatOption"/> value for the animation</param>
        /// <param name="keyFrames">The list of keyframes to use to build the animation.</param>
        /// <returns>A <see cref="Timeline"/> instance with the specified animation.</returns>
        public static Timeline GetAnimation <TKeyFrame>(
            DependencyObject target,
            string property,
            TimeSpan?delay,
            TimeSpan duration,
            RepeatOption repeat,
            ReadOnlySpan <TKeyFrame> keyFrames)
            where TKeyFrame : struct, IKeyFrameInfo
        {
            Timeline animation;

            if (typeof(T) == typeof(float))
            {
                DoubleAnimationUsingKeyFrames doubleAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    doubleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <float>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = doubleAnimation;
            }
            else if (typeof(T) == typeof(double))
            {
                DoubleAnimationUsingKeyFrames doubleAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    doubleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <double>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = doubleAnimation;
            }
            else if (typeof(T) == typeof(Point))
            {
                PointAnimationUsingKeyFrames pointAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    pointAnimation.KeyFrames.Add(new EasingPointKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <Point>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = pointAnimation;
            }
            else if (typeof(T) == typeof(Color))
            {
                ColorAnimationUsingKeyFrames colorAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    colorAnimation.KeyFrames.Add(new EasingColorKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <Color>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = colorAnimation;
            }
            else if (typeof(T) == typeof(object))
            {
                ObjectAnimationUsingKeyFrames objectAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    objectAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame()
                    {
                        KeyTime = keyFrame.GetTimedProgress(duration),
                        Value   = keyFrame.GetValueAs <object>()
                    });
                }

                animation = objectAnimation;
            }
            else
            {
                return(ThrowHelper.ThrowInvalidOperationException <Timeline>("Invalid animation type"));
            }

            animation.BeginTime      = delay;
            animation.RepeatBehavior = repeat.ToRepeatBehavior();

            Storyboard.SetTarget(animation, target);
            Storyboard.SetTargetProperty(animation, property);

            return(animation);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="TimedKeyFrameAnimationBuilder{T}.Xaml"/> class.
 /// </summary>
 /// <inheritdoc cref="TimedKeyFrameAnimationBuilder{T}"/>
 public Xaml(string property, TimeSpan?delay, RepeatOption repeat)
     : base(property, delay, repeat)
 {
 }
 protected TimedKeyFrameAnimationBuilder(string property, TimeSpan?delay, RepeatOption repeat)
 {
     this.property = property;
     this.delay    = delay;
     this.repeat   = repeat;
 }
 public Composition(string property, TimeSpan?delay, RepeatOption repeat, AnimationDelayBehavior delayBehavior)
     : base(property, delay, repeat)
 {
     this.delayBehavior = delayBehavior;
 }
        /// <summary>
        /// Gets a <see cref="Timeline"/> instance representing the animation to start.
        /// </summary>
        /// <typeparam name="TKeyFrame">The type of keyframes being used to define the animation.</typeparam>
        /// <param name="target">The target <see cref="DependencyObject"/> instance to animate.</param>
        /// <param name="property">The target property to animate.</param>
        /// <param name="delay">The optional initial delay for the animation.</param>
        /// <param name="duration">The animation duration.</param>
        /// <param name="repeat">The <see cref="RepeatOption"/> value for the animation</param>
        /// <param name="keyFrames">The list of keyframes to use to build the animation.</param>
        /// <returns>A <see cref="Timeline"/> instance with the specified animation.</returns>
        public static Timeline GetAnimation <TKeyFrame>(
            DependencyObject target,
            string property,
            TimeSpan?delay,
            TimeSpan duration,
            RepeatOption repeat,
            ArraySegment <TKeyFrame> keyFrames)
            where TKeyFrame : struct, IKeyFrameInfo
        {
            Timeline animation;

            if (typeof(T) == typeof(float))
            {
                DoubleAnimationUsingKeyFrames doubleAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    doubleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <float>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = doubleAnimation;
            }
            else if (typeof(T) == typeof(double))
            {
                DoubleAnimationUsingKeyFrames doubleAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    doubleAnimation.KeyFrames.Add(new EasingDoubleKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <double>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = doubleAnimation;
            }
            else if (typeof(T) == typeof(Point))
            {
                PointAnimationUsingKeyFrames pointAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    pointAnimation.KeyFrames.Add(new EasingPointKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <Point>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = pointAnimation;
            }
            else if (typeof(T) == typeof(Color))
            {
                ColorAnimationUsingKeyFrames colorAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    colorAnimation.KeyFrames.Add(new EasingColorKeyFrame()
                    {
                        KeyTime        = keyFrame.GetTimedProgress(duration),
                        Value          = keyFrame.GetValueAs <Color>(),
                        EasingFunction = keyFrame.EasingType.ToEasingFunction(keyFrame.EasingMode)
                    });
                }

                animation = colorAnimation;
            }
            else if (typeof(T) == typeof(object))
            {
                ObjectAnimationUsingKeyFrames objectAnimation = new() { EnableDependentAnimation = true };

                foreach (var keyFrame in keyFrames)
                {
                    objectAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame()
                    {
                        KeyTime = keyFrame.GetTimedProgress(duration),
                        Value   = keyFrame.GetValueAs <object>()
                    });
                }

                animation = objectAnimation;
            }
            else
            {
        public static CompositionAnimation GetAnimation <TKeyFrame>(
            CompositionObject target,
            string property,
            TimeSpan?delay,
            TimeSpan duration,
            RepeatOption repeat,
            ArraySegment <TKeyFrame> keyFrames)
            where TKeyFrame : struct, IKeyFrameInfo
        {
            KeyFrameAnimation animation;

            if (typeof(T) == typeof(bool))
            {
                BooleanKeyFrameAnimation boolAnimation = target.Compositor.CreateBooleanKeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(boolAnimation, duration))
                    {
                        continue;
                    }

                    boolAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <bool>());
                }

                animation = boolAnimation;
            }
            else if (typeof(T) == typeof(float))
            {
                ScalarKeyFrameAnimation scalarAnimation = target.Compositor.CreateScalarKeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(scalarAnimation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        scalarAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <float>());
                    }
                    else
                    {
                        scalarAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <float>(), easingFunction);
                    }
                }

                animation = scalarAnimation;
            }
            else if (typeof(T) == typeof(double))
            {
                ScalarKeyFrameAnimation scalarAnimation = target.Compositor.CreateScalarKeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(scalarAnimation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        scalarAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), (float)keyFrame.GetValueAs <double>());
                    }
                    else
                    {
                        scalarAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), (float)keyFrame.GetValueAs <double>(), easingFunction);
                    }
                }

                animation = scalarAnimation;
            }
            else if (typeof(T) == typeof(Vector2))
            {
                Vector2KeyFrameAnimation vector2Animation = target.Compositor.CreateVector2KeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(vector2Animation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        vector2Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector2>());
                    }
                    else
                    {
                        vector2Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector2>(), easingFunction);
                    }
                }

                animation = vector2Animation;
            }
            else if (typeof(T) == typeof(Vector3))
            {
                Vector3KeyFrameAnimation vector3Animation = target.Compositor.CreateVector3KeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(vector3Animation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        vector3Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector3>());
                    }
                    else
                    {
                        vector3Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector3>(), easingFunction);
                    }
                }

                animation = vector3Animation;
            }
            else if (typeof(T) == typeof(Vector4))
            {
                Vector4KeyFrameAnimation vector4Animation = target.Compositor.CreateVector4KeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(vector4Animation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        vector4Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector4>());
                    }
                    else
                    {
                        vector4Animation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Vector4>(), easingFunction);
                    }
                }

                animation = vector4Animation;
            }
            else if (typeof(T) == typeof(Color))
            {
                ColorKeyFrameAnimation colorAnimation = target.Compositor.CreateColorKeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(colorAnimation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        colorAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Color>());
                    }
                    else
                    {
                        colorAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Color>(), easingFunction);
                    }
                }

                animation = colorAnimation;
            }
            else if (typeof(T) == typeof(Quaternion))
            {
                QuaternionKeyFrameAnimation quaternionAnimation = target.Compositor.CreateQuaternionKeyFrameAnimation();

                foreach (var keyFrame in keyFrames)
                {
                    if (keyFrame.TryInsertExpressionKeyFrame(quaternionAnimation, duration))
                    {
                        continue;
                    }

                    CompositionEasingFunction?easingFunction = target.Compositor.TryCreateEasingFunction(keyFrame.EasingType, keyFrame.EasingMode);

                    if (easingFunction is null)
                    {
                        quaternionAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Quaternion>());
                    }
                    else
                    {
                        quaternionAnimation.InsertKeyFrame(keyFrame.GetNormalizedProgress(duration), keyFrame.GetValueAs <Quaternion>(), easingFunction);
                    }
                }

                animation = quaternionAnimation;
            }
            else
            {
                throw new InvalidOperationException("Invalid animation type");
            }

            animation.Duration = duration;

            if (delay.HasValue)
            {
                animation.DelayTime = delay !.Value;
            }

            animation.Target = property;
            (animation.IterationBehavior, animation.IterationCount) = repeat.ToBehaviorAndCount();

            return(animation);
        }
 public Composition(string property, TimeSpan?delay, TimeSpan duration, RepeatOption repeat)
     : base(property, delay, duration, repeat)
 {
 }