/// <summary>Creates a new animated property.</summary> /// <param name="animation">The animation that this property is a part of.</param> /// <param name="property">The property being animated.</param> /// <param name="targetValue">The value that this property will be when the animation is over.</param> /// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param> /// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param> /// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param> /// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param> public AnimatedProperty(UIAnimation animation, CssProperty property, int innerIndex, Css.Value targetValue, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor, bool updateCss) { Animation = animation; PropertyInfo = property; InnerIndex = innerIndex; Css.ValueType type = targetValue.Type; if (!Animation.ElementStyle.Properties.TryGetValue(property, out ValueObject)) { ComputedStyle computed = Animation.ElementStyle.Computed; if (computed != null && computed.Properties.TryGetValue(property, out ValueObject)) { // Let's derive from the computed form. ValueObject = ValueObject.Copy(); } else { ValueObject = new Css.Value(); if (innerIndex != -1 || type == Css.ValueType.Null) { type = Css.ValueType.Rectangle; } property.SetDefault(ValueObject, type); } Animation.ElementStyle.Properties[property] = ValueObject; } if (ValueObject.Type == Css.ValueType.Inherit) { // Special case - we need to duplicate it. Animation.ElementStyle.Properties[property] = ValueObject = ValueObject.Copy(); ValueObject.Type = type; } PropertyValueObject = ValueObject; if (innerIndex != -1) { Css.Value innerValue = ValueObject[innerIndex]; if (innerValue == null) { ValueObject[innerIndex] = innerValue = new Css.Value(); } ValueObject = innerValue; } // Set our starting value: ActiveValue = ValueObject.ToFloat(); Animate(Animation, targetValue, constantSpeedTime, timeToAccelerateFor, timeToDecelerateFor, updateCss); }
/// <summary>Animates this property now.</summary> /// <param name="animation">The animation that this property is a part of.</param> /// <param name="targetValue">The parsed value that this property will be when the animation is over.</param> /// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param> /// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param> /// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param> /// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param> public void Animate(UIAnimation animation, Css.Value targetValue, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor, bool updateCss) { Animation = animation; ValueObject.Type = targetValue.Type; Stage = 0; Speed = 0f; CurrentTime = 0f; UpdateCss = updateCss; PropertyAfter = PropertyBefore = null; // Find the max speed. This is what we accelerate to. // Speed (y) / time (x) graph: // /| |-| |\ // A B C. A = accelerate, b=constant, c=decelerate. // Max speed = top y value. // Distance travelled = area of the graph. This should match target - current value. TargetValue = targetValue.ToFloat(); float unitsDelta = TargetValue - ActiveValue; MaxSpeed = (unitsDelta * UI.RedrawRate) / ((0.5f * timeToAccelerateFor) + constantSpeedTime + (0.5f * timeToDecelerateFor)); if (timeToAccelerateFor == 0f) { // Skip acceleration stage. Stage = 1; Speed = MaxSpeed; } else { Acceleration = MaxSpeed * UI.RedrawRate / timeToAccelerateFor; } if (timeToDecelerateFor != 0f) { Deceleration = MaxSpeed * UI.RedrawRate / timeToDecelerateFor; } }