/// <summary>
        /// It makes snapshot of the control before updating. It requires EndUpdate calling.
        /// </summary>
        /// <param name="control">Target control</param>
        /// <param name="parallel">Allows to animate it same time as other animations</param>
        /// <param name="animation">Personal animation</param>
        /// <param name="clipRectangle">Clip rectangle for animation</param>
        public void BeginUpdate(Control control, bool parallel = false, ZeroitAnimate_Animation animation = null, Rectangle clipRectangle = default(Rectangle))
        {
            AddToQueue(control, AnimateMode.BeginUpdate, parallel, animation, clipRectangle);

            bool wait = false;

            do
            {
                wait = false;
                lock (queue)
                    foreach (var item in queue)
                    {
                        if (item.control == control && item.mode == AnimateMode.BeginUpdate)
                        {
                            if (item.controller == null)
                            {
                                wait = true;
                            }
                        }
                    }

                if (wait)
                {
                    System.Windows.Forms.Application.DoEvents();
                }
            } while (wait);
        }
        /// <summary>
        /// Does the blind.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoBlind(NonLinearTransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            if (animation.BlindCoeff == PointF.Empty)
            {
                return;
            }

            var pixels = e.Pixels;
            var sx     = e.ClientRectangle.Width;
            var sy     = e.ClientRectangle.Height;
            var s      = e.Stride;
            var kx     = animation.BlindCoeff.X;
            var ky     = animation.BlindCoeff.Y;
            var a      = (int)((sx * kx + sy * ky) * (1 - e.CurrentTime));

            for (int x = 0; x < sx; x++)
            {
                for (int y = 0; y < sy; y++)
                {
                    int i = y * s + x * bytesPerPixel;
                    var d = x * kx + y * ky - a;
                    if (d >= 0)
                    {
                        pixels[i + 3] = (byte)0;
                    }
                }
            }
        }
        /// <summary>
        /// Does the rotate.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoRotate(TransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            var rect   = e.ClientRectangle;
            var center = new PointF(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);

            e.Matrix.Translate(center.X, center.Y);
            if (e.CurrentTime > animation.RotateLimit)
            {
                e.Matrix.Rotate(360 * (e.CurrentTime - animation.RotateLimit) * animation.RotateCoeff);
            }
            e.Matrix.Translate(-center.X, -center.Y);
        }
        /// <summary>
        /// Creates the double bitmap.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="mode">The mode.</param>
        /// <param name="animation">The animation.</param>
        /// <param name="clipRect">The clip rect.</param>
        /// <returns>Controller.</returns>
        private Controller CreateDoubleBitmap(Control control, AnimateMode mode, ZeroitAnimate_Animation animation, Rectangle clipRect)
        {
            var controller = new Controller(control, mode, animation, TimeStep, clipRect);

            controller.TransfromNeeded += OnTransformNeeded;
            if (NonLinearTransfromNeeded != null)
            {
                controller.NonLinearTransfromNeeded += OnNonLinearTransfromNeeded;
            }
            controller.MouseDown          += OnMouseDown;
            controller.DoubleBitmap.Cursor = Cursor;
            controller.FramePainted       += OnFramePainted;
            return(controller);
        }
        /// <summary>
        /// Does the leaf.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoLeaf(NonLinearTransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            if (animation.LeafCoeff == 0f)
            {
                return;
            }

            var pixels = e.Pixels;
            var sx     = e.ClientRectangle.Width;
            var sy     = e.ClientRectangle.Height;
            var s      = e.Stride;
            var a      = (int)((sx + sy) * (1 - e.CurrentTime * e.CurrentTime));

            var count = pixels.Length;

            for (int x = 0; x < sx; x++)
            {
                for (int y = 0; y < sy; y++)
                {
                    int i = y * s + x * bytesPerPixel;
                    if (x + y >= a)
                    {
                        var newX = a - y;
                        var newY = a - x;
                        var d    = a - x - y;
                        if (d < -20)
                        {
                            d = -20;
                        }

                        int newI = newY * s + newX * bytesPerPixel;
                        if (newX >= 0 && newY >= 0)
                        {
                            if (newI >= 0 && newI < count)
                            {
                                if (pixels[i + 3] > 0)
                                {
                                    pixels[newI + 0] = (byte)Math.Min(255, d + 250 + pixels[i + 0] / 10);
                                    pixels[newI + 1] = (byte)Math.Min(255, d + 250 + pixels[i + 1] / 10);
                                    pixels[newI + 2] = (byte)Math.Min(255, d + 250 + pixels[i + 2] / 10);
                                    pixels[newI + 3] = 230;
                                }
                            }
                        }
                        pixels[i + 3] = (byte)(0);
                    }
                }
            }
        }
 /// <summary>
 /// Adds the specified a.
 /// </summary>
 /// <param name="a">a.</param>
 public void Add(ZeroitAnimate_Animation a)
 {
     SlideCoeff         = new PointF(SlideCoeff.X + a.SlideCoeff.X, SlideCoeff.Y + a.SlideCoeff.Y);
     RotateCoeff       += a.RotateCoeff;
     RotateLimit       += a.RotateLimit;
     ScaleCoeff         = new PointF(ScaleCoeff.X + a.ScaleCoeff.X, ScaleCoeff.Y + a.ScaleCoeff.Y);
     TransparencyCoeff += a.TransparencyCoeff;
     LeafCoeff         += a.LeafCoeff;
     MosaicShift        = new PointF(MosaicShift.X + a.MosaicShift.X, MosaicShift.Y + a.MosaicShift.Y);
     MosaicCoeff        = new PointF(MosaicCoeff.X + a.MosaicCoeff.X, MosaicCoeff.Y + a.MosaicCoeff.Y);
     MosaicSize        += a.MosaicSize;
     BlindCoeff         = new PointF(BlindCoeff.X + a.BlindCoeff.X, BlindCoeff.Y + a.BlindCoeff.Y);
     TimeCoeff         += a.TimeCoeff;
     Padding           += a.Padding;
 }
        /// <summary>
        /// Does the flip.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoFlip(TransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            var cy = e.ClientRectangle.Height / 5;

            var sy = 1 - 2 * e.CurrentTime;

            if (sy < 0.01f && sy > -0.01f)
            {
                sy = 0.01f;
            }

            e.Matrix.Translate(0, cy);
            e.Matrix.Scale(1, sy);
            e.Matrix.Translate(0, -cy);
        }
        /// <summary>
        /// Initializes this instance.
        /// </summary>
        protected virtual void Init()
        {
            AnimationType    = Zeroit.Framework.Transitions.AnimationType.VertSlide;
            DefaultAnimation = new ZeroitAnimate_Animation();
            MaxAnimationTime = 1500;
            TimeStep         = 0.02f;
            Interval         = 10;
            _width           = 200;
            _height          = 200;

            Disposed += new EventHandler(Animator_Disposed);

            timer          = new System.Windows.Forms.Timer();
            timer.Tick    += new EventHandler(timer_Tick);
            timer.Interval = 1;
            timer.Start();
        }
        /// <summary>
        /// Does the scale.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoScale(TransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            var rect   = e.ClientRectangle;
            var center = new PointF(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);

            e.Matrix.Translate(center.X, center.Y);
            var kx = 1f - animation.ScaleCoeff.X * e.CurrentTime;
            var ky = 1f - animation.ScaleCoeff.X * e.CurrentTime;

            if (Math.Abs(kx) <= 0.001f)
            {
                kx = 0.001f;
            }
            if (Math.Abs(ky) <= 0.001f)
            {
                ky = 0.001f;
            }
            e.Matrix.Scale(kx, ky);
            e.Matrix.Translate(-center.X, -center.Y);
        }
        /// <summary>
        /// Does the transparent.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoTransparent(NonLinearTransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            if (animation.TransparencyCoeff == 0f)
            {
                return;
            }
            var opacity = 1f - animation.TransparencyCoeff * e.CurrentTime;

            if (opacity < 0f)
            {
                opacity = 0f;
            }
            if (opacity > 1f)
            {
                opacity = 1f;
            }

            var pixels = e.Pixels;

            for (int counter = 0; counter < pixels.Length; counter += bytesPerPixel)
            {
                pixels[counter + 3] = (byte)(pixels[counter + 3] * opacity);
            }
        }
        /// <summary>
        /// Does the slide.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        public static void DoSlide(TransfromNeededEventArg e, ZeroitAnimate_Animation animation)
        {
            var k = e.CurrentTime;

            e.Matrix.Translate(-e.ClientRectangle.Width * k * animation.SlideCoeff.X, -e.ClientRectangle.Height * k * animation.SlideCoeff.Y);
        }
        /// <summary>
        /// Does the mosaic.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <param name="animation">The animation.</param>
        /// <param name="buffer">The buffer.</param>
        /// <param name="pixelsBuffer">The pixels buffer.</param>
        public static void DoMosaic(NonLinearTransfromNeededEventArg e, ZeroitAnimate_Animation animation, ref System.Drawing.Point[] buffer, ref byte[] pixelsBuffer)
        {
            if (animation.MosaicCoeff == PointF.Empty || animation.MosaicSize == 0)
            {
                return;
            }

            var pixels  = e.Pixels;
            var sx      = e.ClientRectangle.Width;
            var sy      = e.ClientRectangle.Height;
            var s       = e.Stride;
            var a       = e.CurrentTime;
            var count   = pixels.Length;
            var opacity = 1 - e.CurrentTime;

            if (opacity < 0f)
            {
                opacity = 0f;
            }
            if (opacity > 1f)
            {
                opacity = 1f;
            }
            var mkx = animation.MosaicCoeff.X;
            var mky = animation.MosaicCoeff.Y;

            if (buffer == null)
            {
                buffer = new System.Drawing.Point[pixels.Length];
                for (int i = 0; i < pixels.Length; i++)
                {
                    buffer[i] = new System.Drawing.Point((int)(mkx * (rnd.NextDouble() - 0.5)), (int)(mky * (rnd.NextDouble() - 0.5)));
                }
            }

            if (pixelsBuffer == null)
            {
                pixelsBuffer = (byte[])pixels.Clone();
            }


            for (int i = 0; i < count; i += bytesPerPixel)
            {
                pixels[i + 0] = 255;
                pixels[i + 1] = 255;
                pixels[i + 2] = 255;
                pixels[i + 3] = 0;
            }

            var ms  = animation.MosaicSize;
            var msx = animation.MosaicShift.X;
            var msy = animation.MosaicShift.Y;

            for (int y = 0; y < sy; y++)
            {
                for (int x = 0; x < sx; x++)
                {
                    int yi = (y / ms);
                    int xi = (x / ms);
                    int i  = y * s + x * bytesPerPixel;
                    int j  = yi * s + xi * bytesPerPixel;

                    var newX = x + (int)(a * (buffer[j].X + xi * msx));
                    var newY = y + (int)(a * (buffer[j].Y + yi * msy));

                    if (newX >= 0 && newX < sx)
                    {
                        if (newY >= 0 && newY < sy)
                        {
                            int newI = newY * s + newX * bytesPerPixel;
                            pixels[newI + 0] = pixelsBuffer[i + 0];
                            pixels[newI + 1] = pixelsBuffer[i + 1];
                            pixels[newI + 2] = pixelsBuffer[i + 2];
                            pixels[newI + 3] = (byte)(pixelsBuffer[i + 3] * opacity);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Adds the contol to animation queue.
        /// </summary>
        /// <param name="control">Target control</param>
        /// <param name="mode">Animation mode</param>
        /// <param name="parallel">Allows to animate it same time as other animations</param>
        /// <param name="animation">Personal animation</param>
        /// <param name="clipRectangle">The clip rectangle.</param>
        public void AddToQueue(Control control, AnimateMode mode, bool parallel = true, ZeroitAnimate_Animation animation = null, Rectangle clipRectangle = default(Rectangle))
        {
            if (animation == null)
            {
                animation = DefaultAnimation;
            }

            if (control is IFakeControl)
            {
                control.Visible = false;
                return;
            }

            var item = new QueueItem()
            {
                animation = animation, control = control, IsActive = parallel, mode = mode, clipRectangle = clipRectangle
            };

            //check visible state
            switch (mode)
            {
            case AnimateMode.Show:
                if (control.Visible)    //already showed
                {
                    OnCompleted(new QueueItem {
                        control = control, mode = mode
                    });
                    return;
                }
                break;

            case AnimateMode.Hide:
                if (!control.Visible)    //already hidden
                {
                    OnCompleted(new QueueItem {
                        control = control, mode = mode
                    });
                    return;
                }
                break;
            }

            //add to queue
            lock (queue)
                queue.Add(item);
            lock (requests)
                requests.Add(item);
        }
 /// <summary>
 /// Hides the control and waits while animation will be completed. As result the control will be hidden with animation.
 /// </summary>
 /// <param name="control">Target control</param>
 /// <param name="parallel">Allows to animate it same time as other animations</param>
 /// <param name="animation">Personal animation</param>
 public void HideSync(Control control, bool parallel = false, ZeroitAnimate_Animation animation = null)
 {
     Hide(control, parallel, animation);
     WaitAnimation(control);
 }
 /// <summary>
 /// Hides the control. As result the control will be hidden with animation.
 /// </summary>
 /// <param name="control">Target control</param>
 /// <param name="parallel">Allows to animate it same time as other animations</param>
 /// <param name="animation">Personal animation</param>
 public void Hide(Control control, bool parallel = false, ZeroitAnimate_Animation animation = null)
 {
     AddToQueue(control, AnimateMode.Hide, parallel, animation);
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="Controller"/> class.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="mode">The mode.</param>
        /// <param name="animation">The animation.</param>
        /// <param name="timeStep">The time step.</param>
        /// <param name="controlClipRect">The control clip rect.</param>
        public Controller(Control control, AnimateMode mode, ZeroitAnimate_Animation animation, float timeStep, Rectangle controlClipRect)
        {
            if (control is System.Windows.Forms.Form)
            {
                DoubleBitmap = new DoubleBitmapForm();
            }
            else
            {
                DoubleBitmap = new DoubleBitmapControl();
            }

            (DoubleBitmap as IFakeControl).FramePainting   += OnFramePainting;
            (DoubleBitmap as IFakeControl).FramePainted    += OnFramePainting;
            (DoubleBitmap as IFakeControl).TransfromNeeded += OnTransfromNeeded;
            DoubleBitmap.MouseDown += OnMouseDown;

            this.animation       = animation;
            this.AnimatedControl = control;
            this.mode            = mode;

            this.CustomClipRect = controlClipRect;

            if (mode == AnimateMode.Show || mode == AnimateMode.BeginUpdate)
            {
                timeStep = -timeStep;
            }

            this.TimeStep = timeStep * (animation.TimeCoeff == 0f ? 1f : animation.TimeCoeff);
            if (this.TimeStep == 0f)
            {
                timeStep = 0.01f;
            }

            try
            {
                switch (mode)
                {
                case AnimateMode.Hide:
                {
                    BgBmp = GetBackground(control);
                    (DoubleBitmap as IFakeControl).InitParent(control, animation.Padding);
                    ctrlBmp = GetForeground(control);
                    DoubleBitmap.Visible = true;
                    control.Visible      = false;
                }
                break;

                case AnimateMode.Show:
                {
                    BgBmp = GetBackground(control);
                    (DoubleBitmap as IFakeControl).InitParent(control, animation.Padding);
                    DoubleBitmap.Visible = true;
                    DoubleBitmap.Refresh();
                    control.Visible = true;
                    ctrlBmp         = GetForeground(control);
                }
                break;

                case AnimateMode.BeginUpdate:
                case AnimateMode.Update:
                {
                    (DoubleBitmap as IFakeControl).InitParent(control, animation.Padding);
                    BgBmp = GetBackground(control, true);
                    DoubleBitmap.Visible = true;
                }
                break;
                }
            }
            catch
            {
                Dispose();
            }
#if debug
            BgBmp.Save("c:\\bgBmp.png");
            if (ctrlBmp != null)
            {
                ctrlBmp.Save("c:\\ctrlBmp.png");
            }
#endif

            CurrentTime = timeStep > 0 ? animation.MinTime : animation.MaxTime;
        }