public static T GetValue <T>(this AnimationInstance <T> animationInstance, T defaultSource, T defaultTarget) { T result = default(T); animationInstance.GetValue(ref defaultSource, ref defaultTarget, ref result); return(result); }
/// <summary> /// Unregisters the specified animation instance. /// </summary> /// <param name="animationInstance">The animation instance.</param> /// <remarks> /// <para> /// This method removes the specified animation tree from the animation system. If /// <see cref="AnimationInstance.AutoRecycleEnabled"/> is set on the root node of the animation /// tree, then all instances will be recycled. /// </para> /// <para> /// Adding and removing animation instances is usually controlled by /// <see cref="AnimationTransition"/> instances. /// </para> /// </remarks> /// <exception cref="ArgumentException"> /// Cannot remove <paramref name="animationInstance"/> from the animation system. The animation /// instance is not a root instance. /// </exception> internal void Remove(AnimationInstance animationInstance) { if (!animationInstance.IsRoot) throw new ArgumentException("Cannot remove animation instance from animation system because it is not the root instance."); // Remove animation instance. bool removed = _rootInstances.Remove(animationInstance); if (removed) { // Remove animation transitions, if any. StopTransitions(animationInstance); // Stop all secondary animations. animationInstance.StopSecondaryAnimations(this); // Remove animations from composition chains. animationInstance.RemoveFromCompositionChains(this); // Note: The instances are not unassigned from the properties. // Animations can be restart when using an animation controller. //animationInstance.Unassign(); // Reset animation time (State = Stopped). animationInstance.Time = null; // Recycle instance, if no longer needed. if (animationInstance.AutoRecycleEnabled) { // If the instance is in the completedInstances list, we need to wait // until the Completed events were fired in ApplyAnimations(). if (!_completedInstances.Contains(animationInstance)) animationInstance.Recycle(); } } }
/// <summary> /// Starts the animations using the specified transition. /// </summary> /// <param name="animationInstance">The animation instance.</param> /// <param name="transition"> /// The animation transition. (Can be <see langword="null"/>, in which case /// <see cref="AnimationTransitions.SnapshotAndReplace()"/> will be used.) /// </param> internal void StartAnimation(AnimationInstance animationInstance, AnimationTransition transition) { if (transition == null) transition = AnimationTransitions.SnapshotAndReplace(); transition.AnimationInstance = animationInstance; Add(transition); }
/// <summary> /// Determines the index of a specific item in the <see cref="IList{T}"/>. /// </summary> /// <param name="item"> /// The object to locate in the <see cref="IList{T}"/>. /// </param> /// <returns> /// The index of <paramref name="item"/> if found in the list; otherwise, -1. /// </returns> /// <exception cref="ArgumentException"> /// <paramref name="item"/> is not of type <see cref="AnimationInstance{T}"/>. /// </exception> int IList<AnimationInstance>.IndexOf(AnimationInstance item) { var animationInstance = item as AnimationInstance<T>; if (animationInstance == null) return -1; return IndexOf(animationInstance); }
/// <inheritdoc/> public AnimationInstance CreateInstance() { var animationInstance = AnimationInstance.Create(this); animationInstance.Children.Add(Timeline.CreateInstance()); return(animationInstance); }
/// <summary> /// Inserts an item to the <see cref="IList{T}"/> at the specified index. /// </summary> /// <param name="index"> /// The zero-based index at which <paramref name="item"/> should be inserted. /// </param> /// <param name="item"> /// The object to insert into the <see cref="IList{T}"/>. /// </param> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="index"/> is not a valid index in the <see cref="IList{T}"/>. /// </exception> /// <exception cref="NotSupportedException"> /// The <see cref="IList{T}"/> is read-only. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="item"/> is not of type <see cref="AnimationInstance{T}"/>. /// </exception> void IList<AnimationInstance>.Insert(int index, AnimationInstance item) { var animationInstance = item as AnimationInstance<T>; if (animationInstance == null) throw new ArgumentException("Cannot add animation instance to animation composition chain. The instance is not of the correct type.", "item"); Insert(index, animationInstance); }
/// <summary> /// Determines whether the <see cref="ICollection{T}"/> contains a specific value. /// </summary> /// <param name="item">The object to locate in the <see cref="ICollection{T}"/>.</param> /// <returns> /// <see langword="true"/> if <paramref name="item"/> is found in the /// <see cref="ICollection{T}"/>; otherwise, <see langword="false"/>. /// </returns> bool ICollection<AnimationInstance>.Contains(AnimationInstance item) { var animationInstance = item as AnimationInstance<T>; if (animationInstance == null) return false; return Contains(animationInstance); }
/// <summary> /// Removes the first occurrence of a specific object from the <see cref="ICollection{T}"/>. /// </summary> /// <param name="item">The object to remove from the <see cref="ICollection{T}"/>.</param> /// <returns> /// <see langword="true"/> if <paramref name="item"/> was successfully removed from the /// <see cref="ICollection{T}"/>; otherwise, <see langword="false"/>. This method also returns /// <see langword="false"/> if <paramref name="item"/> is not found in the original /// <see cref="ICollection{T}"/>. /// </returns> bool ICollection<AnimationInstance>.Remove(AnimationInstance item) { var animationInstance = item as AnimationInstance<T>; if (animationInstance == null) return false; return Remove(animationInstance); }
/// <summary> /// Adds an item to the <see cref="ICollection{T}"/>. /// </summary> /// <param name="item"> /// The object to add to the <see cref="ICollection{T}"/>. /// </param> /// <exception cref="ArgumentException"> /// <paramref name="item"/> is not of type <see cref="AnimationInstance{T}"/>. /// </exception> void ICollection<AnimationInstance>.Add(AnimationInstance item) { var animationInstance = item as AnimationInstance<T>; if (animationInstance == null) throw new ArgumentException("Cannot add animation instance to animation composition chain. The instance is not of the correct type.", "item"); Add(animationInstance); }
/// <summary> /// Gradually replaces the specified animation with the new animation. The new animation fades /// in over the specified duration. After this duration the previous animation is stopped and /// removed from the animation system. /// </summary> /// <param name="previousAnimation">The animation that should be replaced.</param> /// <param name="fadeInDuration">The duration over which the new animation fades in.</param> /// <returns>The <see cref="AnimationTransition"/>.</returns> public static AnimationTransition Replace(AnimationInstance previousAnimation, TimeSpan fadeInDuration) { if (fadeInDuration > TimeSpan.Zero) { return(new FadeInAndReplaceTransition(previousAnimation, fadeInDuration)); } return(new ReplaceTransition(previousAnimation)); }
/// <summary> /// Initializes a new instance of the <see cref="AnimationController"/> struct. /// </summary> internal AnimationController(AnimationManager animationManager, AnimationInstance animationInstance) { Debug.Assert(animationManager != null, "The animation system is null."); Debug.Assert(animationInstance != null, "The animation instance is null."); Debug.Assert(animationInstance.RunCount > 0, "The animation instance has an invalid RunCount."); _id = animationInstance.RunCount; _animationManager = animationManager; _animationInstance = animationInstance; }
/// <inheritdoc/> public AnimationInstance CreateInstance() { var animationInstance = AnimationInstance.Create(this); foreach (var timeline in _timelines) { animationInstance.Children.Add(timeline.CreateInstance()); } return(animationInstance); }
/// <summary> /// Removes the animation transitions controlling the given animation instance. /// </summary> /// <param name="animationInstance">The animation instance.</param> private void StopTransitions(AnimationInstance animationInstance) { for (int i = _transitions.Count - 1; i >= 0; i--) { if (i >= _transitions.Count) { // Multiple transitions were removed in the previous iteration. // --> Skip index. continue; } var transition = _transitions[i]; if (transition.AnimationInstance == animationInstance) Remove(transition); } }
/// <summary> /// Removes all animations before the specified animation. /// </summary> /// <param name="animationInstance">The animation instance.</param> internal void RemoveBefore(AnimationInstance animationInstance) { Debug.Assert(animationInstance.IsRoot, "The animation instance in RemoveBefore needs to be a root instance."); Debug.Assert(_tempProperties.Count == 0, "Temporary list of animatable properties has not been reset."); Debug.Assert(_tempInstances.Count == 0, "Temporary list of animation instances has not been reset."); // Get all animated properties. animationInstance.GetAssignedProperties(_tempProperties); // Collect all animation instances before animationInstance. foreach (var property in _tempProperties) { if (property == null) continue; int index; IAnimationCompositionChain compositionChain; _compositionChains.Get(property, out index, out compositionChain); if (compositionChain == null) continue; var numberOfInstances = compositionChain.Count; for (int i = 0; i < numberOfInstances; i++) { var instance = compositionChain[i]; var rootInstance = instance.GetRoot(); if (rootInstance == animationInstance) { // Break inner loop, continue with next composition chain. break; } if (!_tempInstances.Contains(rootInstance)) _tempInstances.Add(rootInstance); } } // Stop the found animation instances. foreach (var oldInstance in _tempInstances) Remove(oldInstance); _tempProperties.Clear(); _tempInstances.Clear(); }
/// <summary> /// Registers the specified animation instance. /// </summary> /// <param name="animationInstance">The animation instance.</param> /// <param name="handoffBehavior"> /// A value indicating how the new animations interact with existing ones. /// </param> /// <param name="previousInstance"> /// Optional: The animation instance after which <paramref name="animationInstance"/> will be /// added in the animation composition chain. If set to <see langword="null"/> /// <paramref name="animationInstance"/> will be appended at the end of the composition chain. /// This parameter is only relevant when <paramref name="handoffBehavior"/> is /// <see cref="HandoffBehavior.Compose"/>. /// </param> /// <remarks> /// <para> /// This method adds the specified animation tree (<paramref name="animationInstance"/> and all /// of its children) to the animation system. The animation system will from now on /// automatically advance and update the animations. /// </para> /// <para> /// Adding and removing animation instances is usually controlled by /// <see cref="AnimationTransition"/> instances. /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="animationInstance" /> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// Cannot add <paramref name="animationInstance"/> to animation system. The animation instance /// is already registered, or it is not a root instance. /// </exception> internal void Add(AnimationInstance animationInstance, HandoffBehavior handoffBehavior, AnimationInstance previousInstance) { if (animationInstance == null) throw new ArgumentNullException("animationInstance"); if (_rootInstances.Contains(animationInstance)) // TODO: This is slow if there are many animation instances! throw new ArgumentException("Cannot add animation instance to animation system. The animation instance is already registered."); if (!animationInstance.IsRoot) throw new ArgumentException("Cannot add animation instance to animation system because it is not a root instance. You need to disconnect the instance from its parent first."); _rootInstances.Add(animationInstance); // Normally, the time is NaN and starts to run now. (Unless the user has set a custom // time value.) if (animationInstance.Time == null) animationInstance.Time = TimeSpan.Zero; animationInstance.AddToCompositionChains(this, handoffBehavior, previousInstance); }
/// <summary> /// Resets this animation instance. /// </summary> internal void Reset() { Debug.Assert(SpeedProperty.IsAnimated == false, "The speed ratio is still animated. Make sure that all animations are stopped before recycling an animation instance!"); Debug.Assert(WeightProperty.IsAnimated == false, "The animation weight is still animated. Make sure that all animations are stopped before recycling an animation instance!"); Debug.Assert(State == AnimationState.Stopped, "Animation instance is still running."); _animation = null; _autoRecycleEnabled = false; _isPaused = false; _isStateValid = false; _parent = null; _state = AnimationState.Stopped; _time = null; _speedProperty.Value = 1.0f; _weightProperty.Value = 1.0f; _children.Clear(); Completed = null; // The animation instance requires a new ID: Increment RunCount. _runCount++; }
/// <summary> /// Replaces the specified animation with the new animation. The new animation takes effect /// immediately. The previous animation is stopped and removed from the animation system. /// </summary> /// <param name="previousAnimation">The animation that should be replaced.</param> /// <returns>The <see cref="AnimationTransition"/>.</returns> public static AnimationTransition Replace(AnimationInstance previousAnimation) { return(new ReplaceTransition(previousAnimation)); }
/// <summary> /// Throws an <see cref="InvalidOperationException"/>. /// </summary> /// <param name="index"> /// The zero-based index at which <paramref name="child"/> should be inserted. /// </param> /// <param name="child">The object to insert.</param> /// <exception cref="InvalidOperationException"> /// Cannot add animation instance. The current animation instance cannot have children. /// </exception> protected override void InsertItem(int index, AnimationInstance child) { throw new InvalidOperationException("Cannot add animation instance. The current animation instance cannot have children."); }
/// <inheritdoc/> public AnimationInstance CreateInstance() { return(AnimationInstance <T> .Create(this)); }
/// <summary> /// Combines the new animation with existing animations by inserting the new animation after the /// specified animation into the composition chains. The new animation takes effect immediately. /// </summary> /// <param name="previousAnimation"> /// The animation after which the new animation should be added. /// </param> /// <returns>The <see cref="AnimationTransition"/>.</returns> public static AnimationTransition Compose(AnimationInstance previousAnimation) { return(new ComposeTransition(previousAnimation)); }
/// <summary> /// Applies this animation tree to the assigned properties. /// </summary> /// <param name="animationManager">The <see cref="AnimationManager"/>.</param> /// <param name="handoffBehavior"> /// A value indicating how the new animations interact with existing ones. /// </param> /// <param name="previousInstance"> /// Optional: The animation instance after which this animation instance will be added in the /// animation composition chain. If set to <see langword="null"/> this animation instance will /// be appended at the end of the composition chain. This parameter is only relevant when /// <paramref name="handoffBehavior"/> is <see cref="HandoffBehavior.Compose"/>. /// </param> internal virtual void AddToCompositionChains(AnimationManager animationManager, HandoffBehavior handoffBehavior, AnimationInstance previousInstance) { foreach (var child in Children) { child.AddToCompositionChains(animationManager, handoffBehavior, previousInstance); } }
/// <inheritdoc/> internal override void AddToCompositionChains(AnimationManager animationManager, HandoffBehavior handoffBehavior, AnimationInstance previousInstance) { var property = Property; if (property == null) { return; } // Get (or create) the animation composition chain. var compositionChain = animationManager.GetCompositionChain(property, Animation.Traits, true); if (handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // Make a snapshot of the current animation value. compositionChain.TakeSnapshot(); } if (handoffBehavior == HandoffBehavior.Replace || handoffBehavior == HandoffBehavior.SnapshotAndReplace) { // Remove all previous animations. if (compositionChain.Count > 0) { var rootInstance = this.GetRoot(); for (int i = compositionChain.Count - 1; i >= 0; i--) { var animationInstance = compositionChain[i]; // Do not remove animation instances of the same animation tree! if (animationInstance.GetRoot() != rootInstance) { compositionChain.RemoveAt(i); } } } } AnimationInstance <T> referenceInstance = null; if (previousInstance != null) { // previousInstance is either a single animation instance or an animation tree that // should be replaced. Find the instance that is assigned to the current property. referenceInstance = previousInstance.GetAssignedInstance(Property) as AnimationInstance <T>; } if (referenceInstance == null) { // Add at the end of the animation composition chain. compositionChain.Add(this); } else { // Insert in animation composition chain at a certain index. int index = compositionChain.IndexOf(referenceInstance); if (index == -1) { // The referenceInstance has not been applied to the current property. compositionChain.Add(this); } else { // Insert after referenceInstance. index++; // Other animation instances of the same animation tree might have already been // inserted after referenceInstance. To maintain the correct order we need to add // this instance after the other instances of the same tree. var rootInstance = this.GetRoot(); var numberOfInstances = compositionChain.Count; while (index < numberOfInstances && compositionChain[index].GetRoot() == rootInstance) { index++; } compositionChain.Insert(index, this); } } }
/// <summary> /// Stops the specified animations. /// </summary> /// <param name="animationInstance">The animation instance.</param> internal void StopAnimation(AnimationInstance animationInstance) { if (animationInstance != null) Remove(animationInstance); }