/// <summary>Interpolates, in a linear fashion, between the previous key frame value and the value of the current key frame, using the supplied progress increment. </summary>
 /// <param name="baseValue">The value to animate from.</param>
 /// <param name="keyFrameProgress">A value between 0.0 and 1.0, inclusive, that specifies the percentage of time that has elapsed for this key frame.</param>
 /// <returns>The output value of this key frame given the specified base value and progress.</returns>
 // Token: 0x06001727 RID: 5927 RVA: 0x00071D06 File Offset: 0x0006FF06
 protected override Thickness InterpolateValueCore(Thickness baseValue, double keyFrameProgress)
 {
     if (keyFrameProgress == 0.0)
     {
         return(baseValue);
     }
     if (keyFrameProgress == 1.0)
     {
         return(base.Value);
     }
     return(AnimatedTypeHelpers.InterpolateThickness(baseValue, base.Value, keyFrameProgress));
 }
Exemple #2
0
        private static bool ValidateFromToOrByValue(object value)
        {
            Int16?typedValue = (Int16?)value;

            if (typedValue.HasValue)
            {
                return(AnimatedTypeHelpers.IsValidAnimationValueInt16(typedValue.Value));
            }
            else
            {
                return(true);
            }
        }
        private static bool ValidateFromToOrByValue(object value)
        {
            Rotation3D typedValue = (Rotation3D)value;

            if (typedValue != null)
            {
                return(AnimatedTypeHelpers.IsValidAnimationValueRotation3D(typedValue));
            }
            else
            {
                return(true);
            }
        }
        private static bool ValidateFromToOrByValue(object value)
        {
            Thickness?typedValue = (Thickness?)value;

            if (typedValue.HasValue)
            {
                return(AnimatedTypeHelpers.IsValidAnimationValueThickness(typedValue.Value));
            }
            else
            {
                return(true);
            }
        }
        /// <summary>Uses splined interpolation to transition between the previous key frame value and the value of the current key frame.</summary>
        /// <param name="baseValue">The value to animate from.</param>
        /// <param name="keyFrameProgress">A value between 0.0 and 1.0, inclusive, that specifies the percentage of time that has elapsed for this key frame.</param>
        /// <returns>The output value of this key frame given the specified base value and progress.</returns>
        // Token: 0x0600172D RID: 5933 RVA: 0x00071D90 File Offset: 0x0006FF90
        protected override Thickness InterpolateValueCore(Thickness baseValue, double keyFrameProgress)
        {
            if (keyFrameProgress == 0.0)
            {
                return(baseValue);
            }
            if (keyFrameProgress == 1.0)
            {
                return(base.Value);
            }
            double splineProgress = this.KeySpline.GetSplineProgress(keyFrameProgress);

            return(AnimatedTypeHelpers.InterpolateThickness(baseValue, base.Value, splineProgress));
        }
Exemple #6
0
 /// <summary>
 /// Implemented to linearly interpolate between the baseValue and the
 /// Value of this KeyFrame using the keyFrameProgress.
 /// </summary>
 protected override Rect InterpolateValueCore(Rect baseValue, double keyFrameProgress)
 {
     if (keyFrameProgress == 0.0)
     {
         return(baseValue);
     }
     else if (keyFrameProgress == 1.0)
     {
         return(Value);
     }
     else
     {
         return(AnimatedTypeHelpers.InterpolateRect(baseValue, Value, keyFrameProgress));
     }
 }
Exemple #7
0
 /// <summary>
 /// Implemented to linearly interpolate between the baseValue and the
 /// Value of this KeyFrame using the keyFrameProgress.
 /// </summary>
 protected override Quaternion InterpolateValueCore(Quaternion baseValue, double keyFrameProgress)
 {
     if (keyFrameProgress == 0.0)
     {
         return(baseValue);
     }
     else if (keyFrameProgress == 1.0)
     {
         return(Value);
     }
     else
     {
         return(AnimatedTypeHelpers.InterpolateQuaternion(baseValue, Value, keyFrameProgress, UseShortestPath));
     }
 }
Exemple #8
0
        /// <summary>Interpolates, according to the easing function used, between the previous key frame value and the value of the current key frame, using the supplied progress increment.</summary>
        /// <param name="baseValue"> The value to animate from.</param>
        /// <param name="keyFrameProgress"> A value between 0.0 and 1.0, inclusive, that specifies the percentage of time that has elapsed for this key frame.</param>
        /// <returns>The output value of this key frame given the specified base value and progress.</returns>
        // Token: 0x06001736 RID: 5942 RVA: 0x00071E80 File Offset: 0x00070080
        protected override Thickness InterpolateValueCore(Thickness baseValue, double keyFrameProgress)
        {
            IEasingFunction easingFunction = this.EasingFunction;

            if (easingFunction != null)
            {
                keyFrameProgress = easingFunction.Ease(keyFrameProgress);
            }
            if (keyFrameProgress == 0.0)
            {
                return(baseValue);
            }
            if (keyFrameProgress == 1.0)
            {
                return(base.Value);
            }
            return(AnimatedTypeHelpers.InterpolateThickness(baseValue, base.Value, keyFrameProgress));
        }
Exemple #9
0
        // Token: 0x06001776 RID: 6006 RVA: 0x00072E5C File Offset: 0x0007105C
        private void ResolvePacedKeyTimes()
        {
            int num  = 1;
            int num2 = this._sortedResolvedKeyFrames.Length - 1;

            do
            {
                if (this._keyFrames[num].KeyTime.Type == KeyTimeType.Paced)
                {
                    int           num3            = num;
                    List <double> list            = new List <double>();
                    TimeSpan      resolvedKeyTime = this._sortedResolvedKeyFrames[num - 1]._resolvedKeyTime;
                    double        num4            = 0.0;
                    Thickness     from            = this._keyFrames[num - 1].Value;
                    do
                    {
                        Thickness value = this._keyFrames[num].Value;
                        num4 += AnimatedTypeHelpers.GetSegmentLengthThickness(from, value);
                        list.Add(num4);
                        from = value;
                        num++;
                    }while (num < num2 && this._keyFrames[num].KeyTime.Type == KeyTimeType.Paced);
                    num4 += AnimatedTypeHelpers.GetSegmentLengthThickness(from, this._keyFrames[num].Value);
                    TimeSpan timeSpan = this._sortedResolvedKeyFrames[num]._resolvedKeyTime - resolvedKeyTime;
                    int      i        = 0;
                    int      num5     = num3;
                    while (i < list.Count)
                    {
                        this._sortedResolvedKeyFrames[num5]._resolvedKeyTime = resolvedKeyTime + TimeSpan.FromMilliseconds(list[i] / num4 * timeSpan.TotalMilliseconds);
                        i++;
                        num5++;
                    }
                }
                else
                {
                    num++;
                }
            }while (num < num2);
        }
Exemple #10
0
        private async void InterpolateAccentColorAsync(Color accentColor)
        {
            await Task.Run(async() =>
            {
                int loop     = 0;
                int loopMax  = 30;
                var oldColor = (Color)Application.Current.Resources["RG_AccentColor"];

                while (loop < loopMax)
                {
                    loop++;
                    Color color = AnimatedTypeHelpers.InterpolateColor(oldColor, accentColor, loop / (double)loopMax);

                    Application.Current.Resources["RG_AccentColor"] = color;
                    Application.Current.Resources["RG_AccentBrush"] = new SolidColorBrush(color);
                    await Task.Delay(7);
                }
            });

            // Re-apply theme to ensure brushes referencing AccentColor are updated
            this.ReApplyTheme();
            this.OnColorSchemeChanged(new EventArgs());
        }
Exemple #11
0
        /// <summary>
        /// Calculates the value this animation believes should be the current value for the property.
        /// </summary>
        /// <param name="defaultOriginValue">
        /// This value is the suggested origin value provided to the animation
        /// to be used if the animation does not have its own concept of a
        /// start value. If this animation is the first in a composition chain
        /// this value will be the snapshot value if one is available or the
        /// base property value if it is not; otherise this value will be the
        /// value returned by the previous animation in the chain with an
        /// animationClock that is not Stopped.
        /// </param>
        /// <param name="defaultDestinationValue">
        /// This value is the suggested destination value provided to the animation
        /// to be used if the animation does not have its own concept of an
        /// end value. This value will be the base value if the animation is
        /// in the first composition layer of animations on a property;
        /// otherwise this value will be the output value from the previous
        /// composition layer of animations for the property.
        /// </param>
        /// <param name="animationClock">
        /// This is the animationClock which can generate the CurrentTime or
        /// CurrentProgress value to be used by the animation to generate its
        /// output value.
        /// </param>
        /// <returns>
        /// The value this animation believes should be the current value for the property.
        /// </returns>
        protected override Int16 GetCurrentValueCore(Int16 defaultOriginValue, Int16 defaultDestinationValue, AnimationClock animationClock)
        {
            Debug.Assert(animationClock.CurrentState != ClockState.Stopped);

            if (!_isAnimationFunctionValid)
            {
                ValidateAnimationFunction();
            }

            double progress = animationClock.CurrentProgress.Value;

            IEasingFunction easingFunction = EasingFunction;

            if (easingFunction != null)
            {
                progress = easingFunction.Ease(progress);
            }

            Int16 from        = new Int16();
            Int16 to          = new Int16();
            Int16 accumulated = new Int16();
            Int16 foundation  = new Int16();

            // need to validate the default origin and destination values if
            // the animation uses them as the from, to, or foundation values
            bool validateOrigin      = false;
            bool validateDestination = false;

            switch (_animationType)
            {
            case AnimationType.Automatic:

                from = defaultOriginValue;
                to   = defaultDestinationValue;

                validateOrigin      = true;
                validateDestination = true;

                break;

            case AnimationType.From:

                from = _keyValues[0];
                to   = defaultDestinationValue;

                validateDestination = true;

                break;

            case AnimationType.To:

                from = defaultOriginValue;
                to   = _keyValues[0];

                validateOrigin = true;

                break;

            case AnimationType.By:

                // According to the SMIL specification, a By animation is
                // always additive.  But we don't force this so that a
                // user can re-use a By animation and have it replace the
                // animations that precede it in the list without having
                // to manually set the From value to the base value.

                to         = _keyValues[0];
                foundation = defaultOriginValue;

                validateOrigin = true;

                break;

            case AnimationType.FromTo:

                from = _keyValues[0];
                to   = _keyValues[1];

                if (IsAdditive)
                {
                    foundation     = defaultOriginValue;
                    validateOrigin = true;
                }

                break;

            case AnimationType.FromBy:

                from = _keyValues[0];
                to   = AnimatedTypeHelpers.AddInt16(_keyValues[0], _keyValues[1]);

                if (IsAdditive)
                {
                    foundation     = defaultOriginValue;
                    validateOrigin = true;
                }

                break;

            default:

                Debug.Fail("Unknown animation type.");

                break;
            }

            if (validateOrigin &&
                !AnimatedTypeHelpers.IsValidAnimationValueInt16(defaultOriginValue))
            {
                throw new InvalidOperationException(
                          SR.Get(
                              SRID.Animation_Invalid_DefaultValue,
                              this.GetType(),
                              "origin",
                              defaultOriginValue.ToString(CultureInfo.InvariantCulture)));
            }

            if (validateDestination &&
                !AnimatedTypeHelpers.IsValidAnimationValueInt16(defaultDestinationValue))
            {
                throw new InvalidOperationException(
                          SR.Get(
                              SRID.Animation_Invalid_DefaultValue,
                              this.GetType(),
                              "destination",
                              defaultDestinationValue.ToString(CultureInfo.InvariantCulture)));
            }


            if (IsCumulative)
            {
                double currentRepeat = (double)(animationClock.CurrentIteration - 1);

                if (currentRepeat > 0.0)
                {
                    Int16 accumulator = AnimatedTypeHelpers.SubtractInt16(to, from);

                    accumulated = AnimatedTypeHelpers.ScaleInt16(accumulator, currentRepeat);
                }
            }

            // return foundation + accumulated + from + ((to - from) * progress)

            return(AnimatedTypeHelpers.AddInt16(
                       foundation,
                       AnimatedTypeHelpers.AddInt16(
                           accumulated,
                           AnimatedTypeHelpers.InterpolateInt16(from, to, progress))));
        }
Exemple #12
0
        /// <summary> Calculates a value that represents the current value of the property being animated, as determined by this instance of <see cref="T:System.Windows.Media.Animation.ThicknessAnimationUsingKeyFrames" />.</summary>
        /// <param name="defaultOriginValue">The suggested origin value, used if the animation does not have its own explicitly set start value.</param>
        /// <param name="defaultDestinationValue">The suggested destination value, used if the animation does not have its own explicitly set end value.</param>
        /// <param name="animationClock">An <see cref="T:System.Windows.Media.Animation.AnimationClock" /> that generates the <see cref="P:System.Windows.Media.Animation.Clock.CurrentTime" /> or <see cref="P:System.Windows.Media.Animation.Clock.CurrentProgress" /> used by the host animation.</param>
        /// <returns>The calculated value of the property, as determined by the current instance.</returns>
        // Token: 0x06001767 RID: 5991 RVA: 0x00072800 File Offset: 0x00070A00
        protected sealed override Thickness GetCurrentValueCore(Thickness defaultOriginValue, Thickness defaultDestinationValue, AnimationClock animationClock)
        {
            if (this._keyFrames == null)
            {
                return(defaultDestinationValue);
            }
            if (!this._areKeyTimesValid)
            {
                this.ResolveKeyTimes();
            }
            if (this._sortedResolvedKeyFrames == null)
            {
                return(defaultDestinationValue);
            }
            TimeSpan value = animationClock.CurrentTime.Value;
            int      num   = this._sortedResolvedKeyFrames.Length;
            int      num2  = num - 1;
            int      i;

            for (i = 0; i < num; i++)
            {
                if (!(value > this._sortedResolvedKeyFrames[i]._resolvedKeyTime))
                {
                    break;
                }
            }
            while (i < num2 && value == this._sortedResolvedKeyFrames[i + 1]._resolvedKeyTime)
            {
                i++;
            }
            Thickness thickness;

            if (i == num)
            {
                thickness = this.GetResolvedKeyFrameValue(num2);
            }
            else if (value == this._sortedResolvedKeyFrames[i]._resolvedKeyTime)
            {
                thickness = this.GetResolvedKeyFrameValue(i);
            }
            else
            {
                Thickness baseValue;
                double    keyFrameProgress;
                if (i == 0)
                {
                    if (this.IsAdditive)
                    {
                        baseValue = AnimatedTypeHelpers.GetZeroValueThickness(defaultOriginValue);
                    }
                    else
                    {
                        baseValue = defaultOriginValue;
                    }
                    keyFrameProgress = value.TotalMilliseconds / this._sortedResolvedKeyFrames[0]._resolvedKeyTime.TotalMilliseconds;
                }
                else
                {
                    int      num3            = i - 1;
                    TimeSpan resolvedKeyTime = this._sortedResolvedKeyFrames[num3]._resolvedKeyTime;
                    baseValue = this.GetResolvedKeyFrameValue(num3);
                    TimeSpan timeSpan  = value - resolvedKeyTime;
                    TimeSpan timeSpan2 = this._sortedResolvedKeyFrames[i]._resolvedKeyTime - resolvedKeyTime;
                    keyFrameProgress = timeSpan.TotalMilliseconds / timeSpan2.TotalMilliseconds;
                }
                thickness = this.GetResolvedKeyFrame(i).InterpolateValue(baseValue, keyFrameProgress);
            }
            if (this.IsCumulative)
            {
                double num4 = (double)(animationClock.CurrentIteration - 1).Value;
                if (num4 > 0.0)
                {
                    thickness = AnimatedTypeHelpers.AddThickness(thickness, AnimatedTypeHelpers.ScaleThickness(this.GetResolvedKeyFrameValue(num2), num4));
                }
            }
            if (this.IsAdditive)
            {
                return(AnimatedTypeHelpers.AddThickness(defaultOriginValue, thickness));
            }
            return(thickness);
        }
Exemple #13
0
        // Token: 0x06001745 RID: 5957 RVA: 0x00072464 File Offset: 0x00070664
        private static bool ValidateFromToOrByValue(object value)
        {
            Thickness?thickness = (Thickness?)value;

            return(thickness == null || AnimatedTypeHelpers.IsValidAnimationValueThickness(thickness.Value));
        }
Exemple #14
0
        /// <summary>Calculates a value that represents the current value of the property being animated, as determined by the <see cref="T:System.Windows.Media.Animation.ThicknessAnimation" />. </summary>
        /// <param name="defaultOriginValue">The suggested origin value, used if the animation does not have its own explicitly set start value.</param>
        /// <param name="defaultDestinationValue">The suggested destination value, used if the animation does not have its own explicitly set end value.</param>
        /// <param name="animationClock">An <see cref="T:System.Windows.Media.Animation.AnimationClock" /> that generates the <see cref="P:System.Windows.Media.Animation.Clock.CurrentTime" /> or <see cref="P:System.Windows.Media.Animation.Clock.CurrentProgress" /> used by the animation.</param>
        /// <returns>The calculated value of the property, as determined by the current animation.</returns>
        // Token: 0x06001742 RID: 5954 RVA: 0x00072068 File Offset: 0x00070268
        protected override Thickness GetCurrentValueCore(Thickness defaultOriginValue, Thickness defaultDestinationValue, AnimationClock animationClock)
        {
            if (!this._isAnimationFunctionValid)
            {
                this.ValidateAnimationFunction();
            }
            double          num            = animationClock.CurrentProgress.Value;
            IEasingFunction easingFunction = this.EasingFunction;

            if (easingFunction != null)
            {
                num = easingFunction.Ease(num);
            }
            Thickness thickness  = default(Thickness);
            Thickness thickness2 = default(Thickness);
            Thickness value      = default(Thickness);
            Thickness value2     = default(Thickness);
            bool      flag       = false;
            bool      flag2      = false;

            switch (this._animationType)
            {
            case AnimationType.Automatic:
                thickness  = defaultOriginValue;
                thickness2 = defaultDestinationValue;
                flag       = true;
                flag2      = true;
                break;

            case AnimationType.From:
                thickness  = this._keyValues[0];
                thickness2 = defaultDestinationValue;
                flag2      = true;
                break;

            case AnimationType.To:
                thickness  = defaultOriginValue;
                thickness2 = this._keyValues[0];
                flag       = true;
                break;

            case AnimationType.By:
                thickness2 = this._keyValues[0];
                value2     = defaultOriginValue;
                flag       = true;
                break;

            case AnimationType.FromTo:
                thickness  = this._keyValues[0];
                thickness2 = this._keyValues[1];
                if (this.IsAdditive)
                {
                    value2 = defaultOriginValue;
                    flag   = true;
                }
                break;

            case AnimationType.FromBy:
                thickness  = this._keyValues[0];
                thickness2 = AnimatedTypeHelpers.AddThickness(this._keyValues[0], this._keyValues[1]);
                if (this.IsAdditive)
                {
                    value2 = defaultOriginValue;
                    flag   = true;
                }
                break;
            }
            if (flag && !AnimatedTypeHelpers.IsValidAnimationValueThickness(defaultOriginValue))
            {
                throw new InvalidOperationException(SR.Get("Animation_Invalid_DefaultValue", new object[]
                {
                    base.GetType(),
                    "origin",
                    defaultOriginValue.ToString(CultureInfo.InvariantCulture)
                }));
            }
            if (flag2 && !AnimatedTypeHelpers.IsValidAnimationValueThickness(defaultDestinationValue))
            {
                throw new InvalidOperationException(SR.Get("Animation_Invalid_DefaultValue", new object[]
                {
                    base.GetType(),
                    "destination",
                    defaultDestinationValue.ToString(CultureInfo.InvariantCulture)
                }));
            }
            if (this.IsCumulative)
            {
                double num2 = (double)(animationClock.CurrentIteration - 1).Value;
                if (num2 > 0.0)
                {
                    Thickness value3 = AnimatedTypeHelpers.SubtractThickness(thickness2, thickness);
                    value = AnimatedTypeHelpers.ScaleThickness(value3, num2);
                }
            }
            return(AnimatedTypeHelpers.AddThickness(value2, AnimatedTypeHelpers.AddThickness(value, AnimatedTypeHelpers.InterpolateThickness(thickness, thickness2, num))));
        }
        /// <summary>
        /// Calculates the value this animation believes should be the current value for the property.
        /// </summary>
        /// <param name="defaultOriginValue">
        /// This value is the suggested origin value provided to the animation
        /// to be used if the animation does not have its own concept of a
        /// start value. If this animation is the first in a composition chain
        /// this value will be the snapshot value if one is available or the
        /// base property value if it is not; otherise this value will be the
        /// value returned by the previous animation in the chain with an
        /// animationClock that is not Stopped.
        /// </param>
        /// <param name="defaultDestinationValue">
        /// This value is the suggested destination value provided to the animation
        /// to be used if the animation does not have its own concept of an
        /// end value. This value will be the base value if the animation is
        /// in the first composition layer of animations on a property;
        /// otherwise this value will be the output value from the previous
        /// composition layer of animations for the property.
        /// </param>
        /// <param name="animationClock">
        /// This is the animationClock which can generate the CurrentTime or
        /// CurrentProgress value to be used by the animation to generate its
        /// output value.
        /// </param>
        /// <returns>
        /// The value this animation believes should be the current value for the property.
        /// </returns>
        protected sealed override Color GetCurrentValueCore(
            Color defaultOriginValue,
            Color defaultDestinationValue,
            AnimationClock animationClock)
        {
            Debug.Assert(animationClock.CurrentState != ClockState.Stopped);

            if (_keyFrames == null)
            {
                return(defaultDestinationValue);
            }

            // We resolved our KeyTimes when we froze, but also got notified
            // of the frozen state and therefore invalidated ourselves.
            if (!_areKeyTimesValid)
            {
                ResolveKeyTimes();
            }

            if (_sortedResolvedKeyFrames == null)
            {
                return(defaultDestinationValue);
            }

            TimeSpan currentTime      = animationClock.CurrentTime.Value;
            Int32    keyFrameCount    = _sortedResolvedKeyFrames.Length;
            Int32    maxKeyFrameIndex = keyFrameCount - 1;

            Color currentIterationValue;

            Debug.Assert(maxKeyFrameIndex >= 0, "maxKeyFrameIndex is less than zero which means we don't actually have any key frames.");

            Int32 currentResolvedKeyFrameIndex = 0;

            // Skip all the key frames with key times lower than the current time.
            // currentResolvedKeyFrameIndex will be greater than maxKeyFrameIndex
            // if we are past the last key frame.
            while (currentResolvedKeyFrameIndex < keyFrameCount &&
                   currentTime > _sortedResolvedKeyFrames[currentResolvedKeyFrameIndex]._resolvedKeyTime)
            {
                currentResolvedKeyFrameIndex++;
            }

            // If there are multiple key frames at the same key time, be sure to go to the last one.
            while (currentResolvedKeyFrameIndex < maxKeyFrameIndex &&
                   currentTime == _sortedResolvedKeyFrames[currentResolvedKeyFrameIndex + 1]._resolvedKeyTime)
            {
                currentResolvedKeyFrameIndex++;
            }

            if (currentResolvedKeyFrameIndex == keyFrameCount)
            {
                // Past the last key frame.
                currentIterationValue = GetResolvedKeyFrameValue(maxKeyFrameIndex);
            }
            else if (currentTime == _sortedResolvedKeyFrames[currentResolvedKeyFrameIndex]._resolvedKeyTime)
            {
                // Exactly on a key frame.
                currentIterationValue = GetResolvedKeyFrameValue(currentResolvedKeyFrameIndex);
            }
            else
            {
                // Between two key frames.
                Double currentSegmentProgress = 0.0;
                Color  fromValue;

                if (currentResolvedKeyFrameIndex == 0)
                {
                    // The current key frame is the first key frame so we have
                    // some special rules for determining the fromValue and an
                    // optimized method of calculating the currentSegmentProgress.

                    // If we're additive we want the base value to be a zero value
                    // so that if there isn't a key frame at time 0.0, we'll use
                    // the zero value for the time 0.0 value and then add that
                    // later to the base value.
                    if (IsAdditive)
                    {
                        fromValue = AnimatedTypeHelpers.GetZeroValueColor(defaultOriginValue);
                    }
                    else
                    {
                        fromValue = defaultOriginValue;
                    }

                    // Current segment time divided by the segment duration.
                    // Note: the reason this works is that we know that we're in
                    // the first segment, so we can assume:
                    //
                    // currentTime.TotalMilliseconds                                  = current segment time
                    // _sortedResolvedKeyFrames[0]._resolvedKeyTime.TotalMilliseconds = current segment duration

                    currentSegmentProgress = currentTime.TotalMilliseconds
                                             / _sortedResolvedKeyFrames[0]._resolvedKeyTime.TotalMilliseconds;
                }
                else
                {
                    Int32    previousResolvedKeyFrameIndex = currentResolvedKeyFrameIndex - 1;
                    TimeSpan previousResolvedKeyTime       = _sortedResolvedKeyFrames[previousResolvedKeyFrameIndex]._resolvedKeyTime;

                    fromValue = GetResolvedKeyFrameValue(previousResolvedKeyFrameIndex);

                    TimeSpan segmentCurrentTime = currentTime - previousResolvedKeyTime;
                    TimeSpan segmentDuration    = _sortedResolvedKeyFrames[currentResolvedKeyFrameIndex]._resolvedKeyTime - previousResolvedKeyTime;

                    currentSegmentProgress = segmentCurrentTime.TotalMilliseconds
                                             / segmentDuration.TotalMilliseconds;
                }

                currentIterationValue = GetResolvedKeyFrame(currentResolvedKeyFrameIndex).InterpolateValue(fromValue, currentSegmentProgress);
            }



            // If we're cumulative, we need to multiply the final key frame
            // value by the current repeat count and add this to the return
            // value.
            if (IsCumulative)
            {
                Double currentRepeat = (Double)(animationClock.CurrentIteration - 1);

                if (currentRepeat > 0.0)
                {
                    currentIterationValue = AnimatedTypeHelpers.AddColor(
                        currentIterationValue,
                        AnimatedTypeHelpers.ScaleColor(GetResolvedKeyFrameValue(maxKeyFrameIndex), currentRepeat));
                }
            }

            // If we're additive we need to add the base value to the return value.
            if (IsAdditive)
            {
                return(AnimatedTypeHelpers.AddColor(defaultOriginValue, currentIterationValue));
            }


            return(currentIterationValue);
        }
        public override async Task ApplyColorSchemeAsync(string selectedColorScheme, bool followWindowsColor, bool followAlbumCoverColor, bool isViewModelLoaded = false)
        {
            this.FollowWindowsColor    = followWindowsColor;
            this.followAlbumCoverColor = followAlbumCoverColor;

            Color accentColor = default(Color);
            bool  applySelectedColorScheme = false;

            try
            {
                if (followWindowsColor)
                {
                    accentColor = (Color)ColorConverter.ConvertFromString(GetWindowsDWMColor());
                }
                else if (followAlbumCoverColor)
                {
                    byte[] artwork = await this.metadataService.GetArtworkAsync(this.playbackService.CurrentTrack.Value.Path);

                    if (artwork?.Length > 0)
                    {
                        await Task.Run(() => accentColor = ImageUtils.GetDominantColor(artwork));
                    }
                    else
                    {
                        applySelectedColorScheme = true;
                    }
                }
                else
                {
                    applySelectedColorScheme = true;
                }
            }
            catch (Exception)
            {
                applySelectedColorScheme = true;
            }

            if (applySelectedColorScheme)
            {
                ColorScheme cs = this.GetColorScheme(selectedColorScheme);
                accentColor = (Color)ColorConverter.ConvertFromString(cs.AccentColor);
            }
            else
            {
                accentColor = HSLColor.Normalize(accentColor, 30);
            }

            if (!isViewModelLoaded)
            {
                await Task.Run(() =>
                {
                    int loop = 0;
                    // TODO:
                    // System.Timers.Timer cannot work in actual time, it's much slower
                    // than DispatcherTimer, if we can find some way to fix time by not
                    // using DispatcherTimer, loopMax should be set to 50 to enhance gradient
                    int loopMax  = 30;
                    var oldColor = (Color)Application.Current.Resources["RG_AccentColor"];
                    if (applyColorSchemeTimer != null)
                    {
                        applyColorSchemeTimer.Stop();
                        applyColorSchemeTimer = null;
                    }
                    applyColorSchemeTimer = new Timer()
                    {
                        Interval = colorSchemeTimeoutSeconds * 1000d / loopMax
                    };
                    applyColorSchemeTimer.Elapsed += (_, __) =>
                    {
                        loop++;
                        var color = AnimatedTypeHelpers.InterpolateColor(oldColor, accentColor, loop / (double)loopMax);
                        Application.Current.Resources["RG_AccentColor"] = color;
                        Application.Current.Resources["RG_AccentBrush"] = new SolidColorBrush(color);
                        if (loop == loopMax)
                        {
                            if (applyColorSchemeTimer != null)
                            {
                                applyColorSchemeTimer.Stop();
                                applyColorSchemeTimer = null;
                            }

                            // Re-apply theme to ensure brushes referencing AccentColor are updated
                            this.ReApplyTheme();
                            this.OnColorSchemeChanged(new EventArgs());
                        }
                    };
                    applyColorSchemeTimer.Start();
                });
            }
            else
            {
                Application.Current.Resources["RG_AccentColor"] = accentColor;
                Application.Current.Resources["RG_AccentBrush"] = new SolidColorBrush(accentColor);

                // Re-apply theme to ensure brushes referencing AccentColor are updated
                this.ReApplyTheme();
                this.OnColorSchemeChanged(new EventArgs());
            }
        }
        /// <summary>
        /// This should only be called from ResolveKeyTimes and only at the
        /// appropriate time.
        /// </summary>
        private void ResolvePacedKeyTimes()
        {
            Debug.Assert(_keyFrames != null && _keyFrames.Count > 2,
                         "Caller must guard against calling this method when there are insufficient keyframes.");

            // If the first key frame is paced its key time has already
            // been resolved, so we start at index 1.

            int index            = 1;
            int maxKeyFrameIndex = _sortedResolvedKeyFrames.Length - 1;

            do
            {
                if (_keyFrames[index].KeyTime.Type == KeyTimeType.Paced)
                {
                    //
                    // We've found a paced key frame so this is the
                    // beginning of a paced block.
                    //

                    // The first paced key frame in this block.
                    int firstPacedBlockKeyFrameIndex = index;

                    // List of segment lengths for this paced block.
                    List <Double> segmentLengths = new List <Double>();

                    // The resolved key time for the key frame before this
                    // block which we'll use as our starting point.
                    TimeSpan prePacedBlockKeyTime = _sortedResolvedKeyFrames[index - 1]._resolvedKeyTime;

                    // The total of the segment lengths of the paced key
                    // frames in this block.
                    Double totalLength = 0.0;

                    // The key value of the previous key frame which will be
                    // used to determine the segment length of this key frame.
                    Color prevKeyValue = _keyFrames[index - 1].Value;

                    do
                    {
                        Color currentKeyValue = _keyFrames[index].Value;

                        // Determine the segment length for this key frame and
                        // add to the total length.
                        totalLength += AnimatedTypeHelpers.GetSegmentLengthColor(prevKeyValue, currentKeyValue);

                        // Temporarily store the distance into the total length
                        // that this key frame represents in the resolved
                        // key times array to be converted to a resolved key
                        // time outside of this loop.
                        segmentLengths.Add(totalLength);

                        // Prepare for the next iteration.
                        prevKeyValue = currentKeyValue;
                        index++;
                    }while (index < maxKeyFrameIndex &&
                            _keyFrames[index].KeyTime.Type == KeyTimeType.Paced);

                    // index is currently set to the index of the key frame
                    // after the last paced key frame.  This will always
                    // be a valid index because we limit ourselves with
                    // maxKeyFrameIndex.

                    // We need to add the distance between the last paced key
                    // frame and the next key frame to get the total distance
                    // inside the key frame block.
                    totalLength += AnimatedTypeHelpers.GetSegmentLengthColor(prevKeyValue, _keyFrames[index].Value);

                    // Calculate the time available in the resolved key time space.
                    TimeSpan pacedBlockDuration = _sortedResolvedKeyFrames[index]._resolvedKeyTime - prePacedBlockKeyTime;

                    // Convert lengths in segmentLengths list to resolved
                    // key times for the paced key frames in this block.
                    for (int i = 0, currentKeyFrameIndex = firstPacedBlockKeyFrameIndex; i < segmentLengths.Count; i++, currentKeyFrameIndex++)
                    {
                        // The resolved key time for each key frame is:
                        //
                        // The key time of the key frame before this paced block
                        // + ((the percentage of the way through the total length)
                        //    * the resolved key time space available for the block)
                        _sortedResolvedKeyFrames[currentKeyFrameIndex]._resolvedKeyTime = prePacedBlockKeyTime + TimeSpan.FromMilliseconds(
                            (segmentLengths[i] / totalLength) * pacedBlockDuration.TotalMilliseconds);
                    }
                }
                else
                {
                    index++;
                }
            }while (index < maxKeyFrameIndex);
        }
        public async Task ApplyColorScheme(bool iFollowWindowsColor, bool isViewModelLoaded = false, string iSelectedColorScheme = "")
        {
            this.followWindowsColor = iFollowWindowsColor;

            Color accentColor = default(Color);

            if (this.followWindowsColor)
            {
                try
                {
                    // This should never fail. But just in case, don't apply the ColorScheme
                    accentColor = (Color)ColorConverter.ConvertFromString(GetWindowsDWMColor());
                }
                catch (Exception)
                {
                    return;
                }
            }
            else
            {
                ColorScheme cs = this.GetColorScheme(iSelectedColorScheme);

                try
                {
                    // This can fail if the user created a XML file with incorrect color codes. In case this fails, don't apply the ColorScheme
                    accentColor = (Color)ColorConverter.ConvertFromString(cs.AccentColor);
                }
                catch (Exception)
                {
                    return;
                }
            }

            if (!isViewModelLoaded)
            {
                await Task.Run(() =>
                {
                    int loop = 0;
                    // TODO:
                    // System.Timers.Timer cannot work in actual time, it's much slower
                    // than DispatcherTimer, if we can find some way to fix time by not
                    // using DispatcherTimer, loopMax should be set to 50 to enhance gradient
                    int loopMax  = 30;
                    var oldColor = (Color)Application.Current.Resources["RG_AccentColor"];
                    if (applyColorSchemeTimer != null)
                    {
                        applyColorSchemeTimer.Stop();
                        applyColorSchemeTimer = null;
                    }
                    applyColorSchemeTimer = new Timer()
                    {
                        Interval = colorSchemeTimeoutSeconds * 1000d / loopMax
                    };
                    applyColorSchemeTimer.Elapsed += (_, __) =>
                    {
                        loop++;
                        var color = AnimatedTypeHelpers.InterpolateColor(oldColor, accentColor, loop / (double)loopMax);
                        Application.Current.Resources["RG_AccentColor"] = color;
                        Application.Current.Resources["RG_AccentBrush"] = new SolidColorBrush(color);
                        if (loop == loopMax)
                        {
                            applyColorSchemeTimer.Stop();
                            applyColorSchemeTimer = null;

                            // Re-apply theme to ensure brushes referencing AccentColor are updated
                            this.ReApplyTheme();
                            this.ColorSchemeChanged(this, new EventArgs());
                        }
                    };
                    applyColorSchemeTimer.Start();
                });
            }
            else
            {
                Application.Current.Resources["RG_AccentColor"] = accentColor;
                Application.Current.Resources["RG_AccentBrush"] = new SolidColorBrush(accentColor);

                // Re-apply theme to ensure brushes referencing AccentColor are updated
                this.ReApplyTheme();
                this.ColorSchemeChanged(this, new EventArgs());
            }
        }