/// <summary>
        /// Initializes the animation preview.
        /// </summary>
        private void RunPreview( object sender, System.EventArgs e )
        {
            m_cmdPreview.Enabled = false;

            // Get the animation!
            if( m_frames == null )
            {
                this.Cursor = Cursors.WaitCursor;

                m_frames = m_animation.GetUncachedAnimation(
                    m_options,
                    50
                    );

                this.Cursor = Cursors.Default;
            }
            m_curFrame = 0;

            // Start the animation!
            m_tmrAnimate.Enabled = true;
        }
        /// <summary>
        /// The number of frames to render has changed.
        /// </summary>
        private void FramesToRenderChanged(
            object sender, 
            System.EventArgs e
            )
        {
            if( m_nudFrames.Value != m_animation.FramesToRender )
            {
                m_animation.FramesToRender =
                    (int)m_nudFrames.Value;

                m_animation.ClearAnimation();
                m_frames = null;
            }
        }
        /// <summary>
        /// The layout style changed.
        /// </summary>
        private void LayoutStyleChanged( 
            object sender, 
            System.EventArgs e 
            )
        {
            m_animation.LayoutAnimator = (IFrameLayoutManager)
                (m_cboLayout.SelectedItem as ComboItem).Value;

            m_animation.ClearAnimation();
            m_frames = null;
        }
        /// <summary>
        /// The effect style changed.
        /// </summary>
        private void EffectStyleChanged(
            object sender, 
            System.EventArgs e
            )
        {
            m_animation.FrameImageEffect = (IFrameModifier)
                (m_cboEffect.SelectedItem as ComboItem).Value;

            m_animation.ClearAnimation();
            m_frames = null;
        }
        /// <summary>
        /// Returns a set of frames for this animation.
        /// </summary>
        /// <param name="menuOptions">
        /// The menu options to animate.  Cannot be null.
        /// </param>
        /// <param name="radius">
        /// The radius to apply to the menu layout.
        /// </param>
        /// <param name="cacheResult">
        /// If true, the result of this method will be saved for quick 
        /// reference later.  To clear a cached result, use the 
        /// <see cref="ClearAnimation"/> method.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if the provided collection is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the provided collection does not contain any visible 
        /// options to animate.
        /// </exception>
        public FrameCollection GetAnimation( 
            MenuOptionCollection menuOptions, 
            int radius,
            bool cacheResult 
            )
        {
            if( m_animation != null )
                return m_animation;

            else
            {
                FrameCollection animation =
                    GetUncachedAnimation( menuOptions, radius );

                if( cacheResult ) m_animation = animation;
                return animation;
            }
        }
 /// <summary>
 /// Ensures that the cached set of frames for this animation is 
 /// cleared.
 /// </summary>
 public void ClearAnimation()
 {
     m_animation = null;
 }
 /// <summary>
 /// Creates a new animator.
 /// </summary>
 public Animator( 
     CircularMenuWindow window,
     FrameCollection animation,
     bool closeOnDone
     )
 {
     m_window = window;
     m_animation = animation;
     m_closeOnDone = closeOnDone;
 }
        /// <summary>
        /// Initializes a new circular menu window for the provided menu.
        /// </summary>
        /// <param name="menu">
        /// The menu to animate.  Cannot be null.
        /// </param>
        /// <param name="position">
        /// The screen coordinates of central pixel of the animation.  The
        /// window will position itself around this point while ensuring
        /// that the entire menu can still be shown on the screen.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if the provided menu is a null reference.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the provided menu does not have any visible options, or
        /// if the provided screen coordinate does not exist on any screen.
        /// </exception>
        public CircularMenuWindow( CircularMenuPopup menu, Point position )
        {
            InitializeComponent();
            if( menu == null ) throw new ArgumentNullException();

            // Set up our animation.
            #region ...

            m_menu = menu;
            MenuOptionCollection options = menu.MenuOptions;
            m_animation = menu.OpeningAnimation.GetAnimation( options, menu.Radius );
            m_closeAnimation = menu.ClosingAnimation.GetAnimation( options, menu.Radius );
            m_isReady = false;

            #endregion

            // Position ourselves.
            #region ...

            Screen s = GetScreen( position );
            if( s == null ) throw new ArgumentException(
                                "The provided point does not exist on any screen",
                                "position"
                                );

            Rectangle ourPos = new Rectangle(
                position.X - m_animation.FinalFrame.Bounds.Width / 2,
                position.Y - m_animation.FinalFrame.Bounds.Height / 2,
                m_animation.FinalFrame.Bounds.Width,
                m_animation.FinalFrame.Bounds.Height
                );

            #endregion

            // Adjust our boundaries to allow for specialized tool tip
            // renderers.
            #region ...

            Rectangle extend =
                new Rectangle( 0, 0, ourPos.Width, ourPos.Height );

            Rectangle rawToolTip = extend;

            m_centerX = ourPos.Width / 2;
            m_centerY = ourPos.Height / 2;

            if( m_menu.ActualRenderer is IExtraSpaceToolTipRenderer )
            {
                Bitmap temp =
                    new Bitmap( this.Bounds.Width, this.Bounds.Height );

                using( Graphics tempG = Graphics.FromImage( temp ) )
                {
                    extend = (m_menu.ActualRenderer as IExtraSpaceToolTipRenderer ).GetMaximumRenderArea(
                        tempG,
                        new Point( m_centerX, m_centerY ),
                        ourPos.Size
                        );

                    rawToolTip = extend;
                }
                temp.Dispose();

                // Position "extend" on the screen.
                extend.X += ourPos.Left;
                extend.Y += ourPos.Top;

                // Incorporate "extend" into our region.
                extend = Rectangle.Union( extend, ourPos );
                m_centerX += (ourPos.Left - extend.Left);
                m_centerY += (ourPos.Top - extend.Top);

                ourPos = extend;
            }

            // Make sure we're on the screen.
            if( ourPos.Width > s.WorkingArea.Width )
                ourPos.Width = s.WorkingArea.Width;
            if( ourPos.Height > s.WorkingArea.Height )
                ourPos.Height = s.WorkingArea.Height;

            if( ourPos.Left < s.WorkingArea.Left )
                ourPos.X = s.WorkingArea.Left;
            if( ourPos.Top < s.WorkingArea.Top )
                ourPos.Y = s.WorkingArea.Top;

            if( ourPos.Right > s.WorkingArea.Right )
                ourPos.X = s.WorkingArea.Right - ourPos.Width;
            if( ourPos.Bottom > s.WorkingArea.Bottom )
                ourPos.Y = s.WorkingArea.Bottom - ourPos.Height;

            // We have it.
            m_finalFrameRegion = ourPos;

            // Set the tool tip.
            m_toolTipArea = rawToolTip;
            if( m_toolTipArea.X < 0 ) m_toolTipArea.X += (-m_toolTipArea.X );
            if( m_toolTipArea.Y < 0 ) m_toolTipArea.Y += (-m_toolTipArea.Y );

            #endregion

            // Get our overall boundaries.
            #region ...

            int centerX = ourPos.Left + m_centerX;
            int centerY = ourPos.Top + m_centerY;

            int left = ourPos.Left;
            int top = ourPos.Top;
            int right = ourPos.Right;
            int bottom = ourPos.Bottom;

            foreach( Frame f in m_animation )
            {
                int fleft = f.Bounds.Left + centerX;
                int ftop = f.Bounds.Top + centerY;
                int fright = f.Bounds.Right + centerX;
                int fbottom = f.Bounds.Bottom + centerY;

                if( fleft < left ) left = fleft;
                if( ftop < top ) top = ftop;
                if( fright > right ) right = fright;
                if( fbottom > bottom ) bottom = fbottom;
            }
            foreach( Frame f in m_closeAnimation )
            {
                int fleft = f.Bounds.Left + centerX;
                int ftop = f.Bounds.Top + centerY;
                int fright = f.Bounds.Right + centerX;
                int fbottom = f.Bounds.Bottom + centerY;

                if( fleft < left ) left = fleft;
                if( ftop < top ) top = ftop;
                if( fright > right ) right = fright;
                if( fbottom > bottom ) bottom = fbottom;
            }

            // We have to be at least 100x100.
            if( right - left < 75 )
            {
                left -= 50;
                right += 50;

                m_centerX += 50;
            }
            if( bottom - top < 75 )
            {
                top -= 50;
                bottom += 50;

                m_centerY += 50;
            }

            // Set our region.
            m_menuRegion = Rectangle.FromLTRB( left, top, right, bottom );
            this.Bounds = m_menuRegion;

            #endregion

            // Create a bitmap to use.
            #region ...

            m_controlBackground = new Bitmap( this.Width, this.Height );

            #endregion

            // Start the animation.
            #region ...

            m_animator = new Animator(
                this,
                m_animation,
                false
                );

            new Thread( new ThreadStart( m_animator.Start ) ).Start();

            #endregion
        }