diff options
Diffstat (limited to 'Software/Visual_Studio/Tango.AnimatedGif/ImageAnimationController.cs')
| -rw-r--r-- | Software/Visual_Studio/Tango.AnimatedGif/ImageAnimationController.cs | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.AnimatedGif/ImageAnimationController.cs b/Software/Visual_Studio/Tango.AnimatedGif/ImageAnimationController.cs new file mode 100644 index 000000000..239af9c8b --- /dev/null +++ b/Software/Visual_Studio/Tango.AnimatedGif/ImageAnimationController.cs @@ -0,0 +1,192 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Media.Animation; + +namespace Tango.AnimatedGif +{ + /// <summary> + /// Provides a way to pause, resume or seek a GIF animation. + /// </summary> + public class ImageAnimationController : IDisposable + { + private static readonly DependencyPropertyDescriptor _sourceDescriptor; + + static ImageAnimationController() + { + _sourceDescriptor = DependencyPropertyDescriptor.FromProperty(Image.SourceProperty, typeof (Image)); + } + + private readonly Image _image; + private readonly ObjectAnimationUsingKeyFrames _animation; + private readonly AnimationClock _clock; + private readonly ClockController _clockController; + + + public double SpeedRatio + { + get + { + return _clockController.SpeedRatio; + } + set + { + _clockController.SpeedRatio = value; + } + } + + internal ImageAnimationController(Image image, ObjectAnimationUsingKeyFrames animation, bool autoStart) + { + _image = image; + _animation = animation; + _animation.Completed += AnimationCompleted; + _clock = _animation.CreateClock(); + _clockController = _clock.Controller; + _sourceDescriptor.AddValueChanged(image, ImageSourceChanged); + + // ReSharper disable once PossibleNullReferenceException + _clockController.Pause(); + + _image.ApplyAnimationClock(Image.SourceProperty, _clock); + + if (autoStart) + _clockController.Resume(); + } + + void AnimationCompleted(object sender, EventArgs e) + { + _image.RaiseEvent(new System.Windows.RoutedEventArgs(ImageBehavior.AnimationCompletedEvent, _image)); + } + + private void ImageSourceChanged(object sender, EventArgs e) + { + OnCurrentFrameChanged(); + } + + /// <summary> + /// Returns the number of frames in the image. + /// </summary> + public int FrameCount + { + get { return _animation.KeyFrames.Count; } + } + + /// <summary> + /// Returns the duration of the animation. + /// </summary> + public TimeSpan Duration + { + get + { + return _animation.Duration.HasTimeSpan + ? _animation.Duration.TimeSpan + : TimeSpan.Zero; + } + } + + /// <summary> + /// Returns a value that indicates whether the animation is paused. + /// </summary> + public bool IsPaused + { + get { return _clock.IsPaused; } + } + + /// <summary> + /// Returns a value that indicates whether the animation is complete. + /// </summary> + public bool IsComplete + { + get { return _clock.CurrentState == ClockState.Filling; } + } + + /// <summary> + /// Seeks the animation to the specified frame index. + /// </summary> + /// <param name="index">The index of the frame to seek to</param> + public void GotoFrame(int index) + { + var frame = _animation.KeyFrames[index]; + _clockController.Seek(frame.KeyTime.TimeSpan, TimeSeekOrigin.BeginTime); + } + + /// <summary> + /// Returns the current frame index. + /// </summary> + public int CurrentFrame + { + get + { + var time = _clock.CurrentTime; + var frameAndIndex = + _animation.KeyFrames + .Cast<ObjectKeyFrame>() + .Select((f, i) => new { Time = f.KeyTime.TimeSpan, Index = i }) + .FirstOrDefault(fi => fi.Time >= time); + if (frameAndIndex != null) + return frameAndIndex.Index; + return -1; + } + } + + /// <summary> + /// Pauses the animation. + /// </summary> + public void Pause() + { + _clockController.Pause(); + } + + /// <summary> + /// Starts or resumes the animation. If the animation is complete, it restarts from the beginning. + /// </summary> + public void Play() + { + _clockController.Resume(); + } + + /// <summary> + /// Raised when the current frame changes. + /// </summary> + public event EventHandler CurrentFrameChanged; + + private void OnCurrentFrameChanged() + { + EventHandler handler = CurrentFrameChanged; + if (handler != null) handler(this, EventArgs.Empty); + } + + /// <summary> + /// Finalizes the current object. + /// </summary> + ~ImageAnimationController() + { + Dispose(false); + } + + /// <summary> + /// Disposes the current object. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Disposes the current object + /// </summary> + /// <param name="disposing">true to dispose both managed an unmanaged resources, false to dispose only managed resources</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _image.BeginAnimation(Image.SourceProperty, null); + _animation.Completed -= AnimationCompleted; + _sourceDescriptor.RemoveValueChanged(_image, ImageSourceChanged); + _image.Source = null; + } + } + } +}
\ No newline at end of file |
