view Implab.Fx/Animation.cs @ 138:f75cfa58e3d4 v2

added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
author cin
date Tue, 17 Feb 2015 18:16:26 +0300
parents dfa21d507bc5
children
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.ComponentModel;
using System.Diagnostics;

namespace Implab.Fx
{
    public delegate void AnimationStep<T>(T target, int elapsed, int duration);

    public class Animation<TArg> where TArg: class
    {
        int m_duration;
        int m_delay;
        int m_elapsed;
        int m_prevTicks;
        TArg m_arg;
        ISynchronizeInvoke m_syncronizationObject;

        public event AnimationStep<TArg> Step;

        Promise<TArg> m_promise;

        public Animation(TArg target, int duration, int delay)
        {
            if (duration <= 0)
                throw new ArgumentOutOfRangeException("duration");
            if (delay <= 0)
                throw new ArgumentOutOfRangeException("delay");

            m_arg = target;
            m_syncronizationObject = target as ISynchronizeInvoke;
            m_duration = duration;
            m_delay = delay;
            m_promise = new Promise<TArg>();
        }

        public Animation(TArg target)
            : this(target, 500, 30)
        {
        }

        public TArg Traget
        {
            get { return m_arg; }
        }

        public Promise<TArg> Play()
        {
            var timer = new Timer(m_delay);
            
            timer.AutoReset = false;
            timer.SynchronizingObject = m_syncronizationObject;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

            m_prevTicks = Environment.TickCount;

            timer.Start();

            return m_promise;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs args)
        {
            var timer = sender as Timer;

            var dt = Environment.TickCount - m_prevTicks;
            m_prevTicks = Environment.TickCount;

            m_elapsed += dt;

            if (m_elapsed > m_duration)
                m_elapsed = m_duration;

            try
            {
                var handler = Step;
                if (handler != null)
                    handler(m_arg, m_elapsed, m_duration);
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }

            if (m_elapsed < m_duration)
                timer.Start();
            else
            {
                timer.Dispose();
                m_promise.Resolve(m_arg);
            }
        }
    }
}