/// <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)); }
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)); }
/// <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)); } }
/// <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)); } }
/// <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)); }
// 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); }
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()); }
/// <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)))); }
/// <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); }
// 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)); }
/// <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()); } }