File: winforms\Managed\System\WinForms\DataGridViewButtonCell.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="DataGridViewButtonCell.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms
{
    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms.Internal;
    using System.Drawing.Drawing2D;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Forms.VisualStyles;
    using System.Security.Permissions;
    using System.Windows.Forms.ButtonInternal;
    using System.Globalization;
 
    /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell"]/*' />
    /// <devdoc>
    ///    <para>Identifies a button cell in the dataGridView.</para>
    /// </devdoc>
    public class DataGridViewButtonCell : DataGridViewCell
    {
        private static readonly int PropButtonCellFlatStyle = PropertyStore.CreateKey();
        private static readonly int PropButtonCellState = PropertyStore.CreateKey();
        private static readonly int PropButtonCellUseColumnTextForButtonValue = PropertyStore.CreateKey();
        private static readonly VisualStyleElement ButtonElement = VisualStyleElement.Button.PushButton.Normal;
 
        private const byte DATAGRIDVIEWBUTTONCELL_themeMargin = 100;  // used to calculate the margins required for XP theming rendering
        private const byte DATAGRIDVIEWBUTTONCELL_horizontalTextMargin = 2;
        private const byte DATAGRIDVIEWBUTTONCELL_verticalTextMargin = 1;
        private const byte DATAGRIDVIEWBUTTONCELL_textPadding = 5;
 
        private static Rectangle rectThemeMargins = new Rectangle(-1, -1, 0, 0);
        private static bool mouseInContentBounds = false;
 
        private static Type defaultFormattedValueType = typeof(System.String);
        private static Type defaultValueType = typeof(System.Object);
        private static Type cellType = typeof(DataGridViewButtonCell);
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.DataGridViewButtonCell"]/*' />
        public DataGridViewButtonCell()
        {
        }
 
        private ButtonState ButtonState
        {
            get
            {
                bool found;
                int buttonState = this.Properties.GetInteger(PropButtonCellState, out found);
                if (found)
                {
                    return (ButtonState)buttonState;
                }
                return ButtonState.Normal;
            }
            set
            {
                // ButtonState.Pushed is used for mouse interaction
                // ButtonState.Checked is used for keyboard interaction
                Debug.Assert((value & ~(ButtonState.Normal | ButtonState.Pushed | ButtonState.Checked)) == 0);
                if (this.ButtonState != value)
                {
                    this.Properties.SetInteger(PropButtonCellState, (int)value);
                }
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.EditType"]/*' />
        public override Type EditType
        {
            get
            {
                // Buttons can't switch to edit mode
                return null;
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.FlatStyle"]/*' />
        [
            DefaultValue(FlatStyle.Standard)
        ]
        public FlatStyle FlatStyle
        {
            get
            {
                bool found;
                int flatStyle = this.Properties.GetInteger(PropButtonCellFlatStyle, out found);
                if (found)
                {
                    return (FlatStyle)flatStyle;
                }
                return FlatStyle.Standard;
            }
            set
            {
               // Sequential enum.  Valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)FlatStyle.Flat, (int)FlatStyle.System))
                {
                     throw new InvalidEnumArgumentException("value", (int)value, typeof(FlatStyle)); 
                }
                if (value != this.FlatStyle)
                {
                    this.Properties.SetInteger(PropButtonCellFlatStyle, (int)value);
                    OnCommonChange();
                }
            }
        }
 
        internal FlatStyle FlatStyleInternal
        {
            set
            {
                Debug.Assert(value >= FlatStyle.Flat && value <= FlatStyle.System);
                if (value != this.FlatStyle)
                {
                    this.Properties.SetInteger(PropButtonCellFlatStyle, (int)value);
                }
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.FormattedValueType"]/*' />
        public override Type FormattedValueType
        {
            get 
            {
                // we return string for the formatted type
                return defaultFormattedValueType;
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.UseColumnTextForButtonValue"]/*' />
        [DefaultValue(false)]
        public bool UseColumnTextForButtonValue
        {
            get
            {
                bool found;
                int useColumnTextForButtonValue = this.Properties.GetInteger(PropButtonCellUseColumnTextForButtonValue, out found);
                if (found)
                {
                    return useColumnTextForButtonValue == 0 ? false : true;
                }
                return false;
            }
            set
            {
                if (value != this.UseColumnTextForButtonValue)
                {
                    this.Properties.SetInteger(PropButtonCellUseColumnTextForButtonValue, value ? 1 : 0);
                    OnCommonChange();
                }
            }
        }
 
        internal bool UseColumnTextForButtonValueInternal
        {
            set
            {
                if (value != this.UseColumnTextForButtonValue)
                {
                    this.Properties.SetInteger(PropButtonCellUseColumnTextForButtonValue, value ? 1 : 0);
                }
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.ValueType"]/*' />
        public override Type ValueType
        {
            get
            {
                Type valueType = base.ValueType;
                if (valueType != null)
                {
                    return valueType;
                }
                return defaultValueType;
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.Clone"]/*' />
        public override object Clone()
        {
            DataGridViewButtonCell dataGridViewCell;
            Type thisType = this.GetType();
 
            if (thisType == cellType) //performance improvement
            {
                dataGridViewCell = new DataGridViewButtonCell();
            }
            else
            {
                // SECREVIEW : Late-binding does not represent a security thread, see bug#411899 for more info..
                //
                dataGridViewCell = (DataGridViewButtonCell)System.Activator.CreateInstance(thisType);
            }
            base.CloneInternal(dataGridViewCell);
            dataGridViewCell.FlatStyleInternal = this.FlatStyle;
            dataGridViewCell.UseColumnTextForButtonValueInternal = this.UseColumnTextForButtonValue;
            return dataGridViewCell;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.CreateAccessibilityInstance"]/*' />
        protected override AccessibleObject CreateAccessibilityInstance()
        {
            return new DataGridViewButtonCellAccessibleObject(this);
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.GetContentBounds"]/*' />
        protected override Rectangle GetContentBounds(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
        {
            if (cellStyle == null)
            {
                throw new ArgumentNullException("cellStyle");
            }
 
            if (this.DataGridView == null || rowIndex < 0 || this.OwningColumn == null)
            {
                return Rectangle.Empty;
            }
 
            DataGridViewAdvancedBorderStyle dgvabsEffective;
            DataGridViewElementStates cellState;
            Rectangle cellBounds;
 
            ComputeBorderStyleCellStateAndCellBounds(rowIndex, out dgvabsEffective, out cellState, out cellBounds);
 
            Rectangle contentBounds = PaintPrivate(graphics,
                cellBounds,
                cellBounds,
                rowIndex,
                cellState,
                null /*formattedValue*/,            // contentBounds is independent of formattedValue
                null /*errorText*/,                 // contentBounds is independent of errorText
                cellStyle,
                dgvabsEffective,
                DataGridViewPaintParts.ContentForeground,
                true  /*computeContentBounds*/,
                false /*computeErrorIconBounds*/,
                false /*paint*/);
 
#if DEBUG
            object value = GetValue(rowIndex);
            Rectangle contentBoundsDebug = PaintPrivate(graphics,
                cellBounds,
                cellBounds,
                rowIndex,
                cellState,
                GetFormattedValue(value, rowIndex, ref cellStyle, null, null, DataGridViewDataErrorContexts.Formatting),
                GetErrorText(rowIndex),
                cellStyle,
                dgvabsEffective,
                DataGridViewPaintParts.ContentForeground,
                true  /*computeContentBounds*/,
                false /*computeErrorIconBounds*/,
                false /*paint*/);
            Debug.Assert(contentBoundsDebug.Equals(contentBounds));
#endif
 
            return contentBounds;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.GetErrorIconBounds"]/*' />
        protected override Rectangle GetErrorIconBounds(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
        {
            if (cellStyle == null)
            {
                throw new ArgumentNullException("cellStyle");
            }
 
            if (this.DataGridView == null ||
                rowIndex < 0 ||
                this.OwningColumn == null ||
                !this.DataGridView.ShowCellErrors ||
                String.IsNullOrEmpty(GetErrorText(rowIndex)))
            {
                return Rectangle.Empty;
            }
 
            DataGridViewAdvancedBorderStyle dgvabsEffective;
            DataGridViewElementStates cellState;
            Rectangle cellBounds;
 
            ComputeBorderStyleCellStateAndCellBounds(rowIndex, out dgvabsEffective, out cellState, out cellBounds);
 
            Rectangle errorIconBounds = PaintPrivate(graphics,
                cellBounds,
                cellBounds,
                rowIndex,
                cellState,
                null /*formattedValue*/,            // errorIconBounds is independent of formattedValue
                GetErrorText(rowIndex),
                cellStyle,
                dgvabsEffective,
                DataGridViewPaintParts.ContentForeground,
                false /*computeContentBounds*/,
                true  /*computeErrorIconBounds*/,
                false /*paint*/);
 
#if DEBUG
            object value = GetValue(rowIndex);
            Rectangle errorIconBoundsDebug = PaintPrivate(graphics,
                cellBounds,
                cellBounds,
                rowIndex,
                cellState,
                GetFormattedValue(value, rowIndex, ref cellStyle, null, null, DataGridViewDataErrorContexts.Formatting),
                GetErrorText(rowIndex),
                cellStyle,
                dgvabsEffective,
                DataGridViewPaintParts.ContentForeground,
                false /*computeContentBounds*/,
                true  /*computeErrorIconBounds*/,
                false /*paint*/);
            Debug.Assert(errorIconBoundsDebug.Equals(errorIconBounds));
#endif
 
            return errorIconBounds;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.GetPreferredSize"]/*' />
        protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize)
        {
            if (this.DataGridView == null)
            {
                return new Size(-1, -1);
            }
 
            if (cellStyle == null)
            {
                throw new ArgumentNullException("cellStyle");
            }
 
            Size preferredSize;
            Rectangle borderWidthsRect = this.StdBorderWidths;
            int borderAndPaddingWidths = borderWidthsRect.Left + borderWidthsRect.Width + cellStyle.Padding.Horizontal;
            int borderAndPaddingHeights = borderWidthsRect.Top + borderWidthsRect.Height + cellStyle.Padding.Vertical;
            DataGridViewFreeDimension freeDimension = DataGridViewCell.GetFreeDimensionFromConstraint(constraintSize);
            int marginWidths, marginHeights;
            string formattedString = GetFormattedValue(rowIndex, ref cellStyle, DataGridViewDataErrorContexts.Formatting | DataGridViewDataErrorContexts.PreferredSize) as string;
            if (string.IsNullOrEmpty(formattedString))
            {
                formattedString = " ";
            }
            TextFormatFlags flags = DataGridViewUtilities.ComputeTextFormatFlagsForCellStyleAlignment(this.DataGridView.RightToLeftInternal, cellStyle.Alignment, cellStyle.WrapMode);
 
            // Adding space for text padding.
            if (this.DataGridView.ApplyVisualStylesToInnerCells)
            {
                Rectangle rectThemeMargins = DataGridViewButtonCell.GetThemeMargins(graphics);
                marginWidths = rectThemeMargins.X + rectThemeMargins.Width;
                marginHeights = rectThemeMargins.Y + rectThemeMargins.Height;
            }
            else
            {
                // Hardcoding 5 for the button borders for now.
                marginWidths = marginHeights = DATAGRIDVIEWBUTTONCELL_textPadding;
            }
 
            switch (freeDimension)
            {
                case DataGridViewFreeDimension.Width:
                {
                    if (cellStyle.WrapMode == DataGridViewTriState.True && formattedString.Length > 1 &&
                        constraintSize.Height - borderAndPaddingHeights - marginHeights - 2 * DATAGRIDVIEWBUTTONCELL_verticalTextMargin > 0)
                    {
                        preferredSize = new Size(DataGridViewCell.MeasureTextWidth(graphics, 
                                                                                   formattedString,
                                                                                   cellStyle.Font,
                                                                                   constraintSize.Height - borderAndPaddingHeights - marginHeights - 2 * DATAGRIDVIEWBUTTONCELL_verticalTextMargin,
                                                                                   flags), 
                                                 0);
                    }
                    else
                    {
                        preferredSize = new Size(DataGridViewCell.MeasureTextSize(graphics, formattedString, cellStyle.Font, flags).Width, 
                                                 0);
                    }
                    break;
                }
                case DataGridViewFreeDimension.Height:
                {
                    if (cellStyle.WrapMode == DataGridViewTriState.True && formattedString.Length > 1 &&
                        constraintSize.Width - borderAndPaddingWidths - marginWidths - 2 * DATAGRIDVIEWBUTTONCELL_horizontalTextMargin > 0)
                    {
                        preferredSize = new Size(0,
                                                 DataGridViewCell.MeasureTextHeight(graphics, 
                                                                                    formattedString,
                                                                                    cellStyle.Font,
                                                                                    constraintSize.Width - borderAndPaddingWidths - marginWidths - 2 * DATAGRIDVIEWBUTTONCELL_horizontalTextMargin,
                                                                                    flags));
                    }
                    else
                    {
                        preferredSize = new Size(0,
                                                 DataGridViewCell.MeasureTextSize(graphics, 
                                                                                  formattedString, 
                                                                                  cellStyle.Font, 
                                                                                  flags).Height);
                    }
                    break;
                }
                default:
                {
                    if (cellStyle.WrapMode == DataGridViewTriState.True && formattedString.Length > 1)
                    {
                        preferredSize = DataGridViewCell.MeasureTextPreferredSize(graphics, formattedString, cellStyle.Font, 5.0F, flags);
                    }
                    else
                    {
                        preferredSize = DataGridViewCell.MeasureTextSize(graphics, formattedString, cellStyle.Font, flags);
                    }
                    break;
                }
            }
 
            if (freeDimension != DataGridViewFreeDimension.Height)
            {
                preferredSize.Width += borderAndPaddingWidths + marginWidths + 2 * DATAGRIDVIEWBUTTONCELL_horizontalTextMargin;
                if (this.DataGridView.ShowCellErrors)
                {
                    // Making sure that there is enough room for the potential error icon
                    preferredSize.Width = Math.Max(preferredSize.Width, borderAndPaddingWidths + DATAGRIDVIEWCELL_iconMarginWidth * 2 + iconsWidth);
                }
            }
            if (freeDimension != DataGridViewFreeDimension.Width)
            {
                preferredSize.Height += borderAndPaddingHeights + marginHeights + 2 * DATAGRIDVIEWBUTTONCELL_verticalTextMargin;
                if (this.DataGridView.ShowCellErrors)
                {
                    // Making sure that there is enough room for the potential error icon
                    preferredSize.Height = Math.Max(preferredSize.Height, borderAndPaddingHeights + DATAGRIDVIEWCELL_iconMarginHeight * 2 + iconsHeight);
                }
            }
            return preferredSize;
        }
 
        private static Rectangle GetThemeMargins(Graphics g)
        {
            if (rectThemeMargins.X == -1)
            {
                Rectangle rectCell = new Rectangle(0, 0, DATAGRIDVIEWBUTTONCELL_themeMargin, DATAGRIDVIEWBUTTONCELL_themeMargin);
                Rectangle rectContent = DataGridViewButtonCellRenderer.DataGridViewButtonRenderer.GetBackgroundContentRectangle(g, rectCell);
                rectThemeMargins.X = rectContent.X;
                rectThemeMargins.Y = rectContent.Y;
                rectThemeMargins.Width = DATAGRIDVIEWBUTTONCELL_themeMargin - rectContent.Right;
                rectThemeMargins.Height = DATAGRIDVIEWBUTTONCELL_themeMargin - rectContent.Bottom;
            }
            return rectThemeMargins;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.GetValue"]/*' />
        protected override object GetValue(int rowIndex)
        {
            if (this.UseColumnTextForButtonValue &&
                this.DataGridView != null && 
                this.DataGridView.NewRowIndex != rowIndex && 
                this.OwningColumn != null && 
                this.OwningColumn is DataGridViewButtonColumn)
            {
                return ((DataGridViewButtonColumn) this.OwningColumn).Text;
            }
            return base.GetValue(rowIndex);
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.KeyDownUnsharesRow"]/*' />
        protected override bool KeyDownUnsharesRow(KeyEventArgs e, int rowIndex)
        {
            return e.KeyCode == Keys.Space && !e.Alt && !e.Control && !e.Shift;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.KeyUpUnsharesRow"]/*' />
        protected override bool KeyUpUnsharesRow(KeyEventArgs e, int rowIndex)
        {
            return e.KeyCode == Keys.Space;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.MouseDownUnsharesRow"]/*' />
        protected override bool MouseDownUnsharesRow(DataGridViewCellMouseEventArgs e)
        {
            return e.Button == MouseButtons.Left;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.MouseEnterUnsharesRow"]/*' />
        protected override bool MouseEnterUnsharesRow(int rowIndex)
        {
            return this.ColumnIndex == this.DataGridView.MouseDownCellAddress.X && rowIndex == this.DataGridView.MouseDownCellAddress.Y;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.MouseLeaveUnsharesRow"]/*' />
        protected override bool MouseLeaveUnsharesRow(int rowIndex)
        {
            return (this.ButtonState & ButtonState.Pushed) != 0;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.MouseUpUnsharesRow"]/*' />
        protected override bool MouseUpUnsharesRow(DataGridViewCellMouseEventArgs e)
        {
            return e.Button == MouseButtons.Left;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnKeyDown"]/*' />
        protected override void OnKeyDown(KeyEventArgs e, int rowIndex)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            if (e.KeyCode == Keys.Space && !e.Alt && !e.Control && !e.Shift)
            {
                UpdateButtonState(this.ButtonState | ButtonState.Checked, rowIndex);
                e.Handled = true;
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnKeyUp"]/*' />
        protected override void OnKeyUp(KeyEventArgs e, int rowIndex)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            if (e.KeyCode == Keys.Space)
            {
                UpdateButtonState(this.ButtonState & ~ButtonState.Checked, rowIndex);
                if (!e.Alt && !e.Control && !e.Shift)
                {
                    RaiseCellClick(new DataGridViewCellEventArgs(this.ColumnIndex, rowIndex));
                    if (this.DataGridView != null &&
                        this.ColumnIndex < this.DataGridView.Columns.Count &&
                        rowIndex < this.DataGridView.Rows.Count)
                    {
                        RaiseCellContentClick(new DataGridViewCellEventArgs(this.ColumnIndex, rowIndex));
                    }
                    e.Handled = true;
                }
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnLeave"]/*' />
        protected override void OnLeave(int rowIndex, bool throughMouseClick)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            if (this.ButtonState != ButtonState.Normal)
            {
                Debug.Assert(this.RowIndex >= 0); // Cell is not in a shared row.
                UpdateButtonState(ButtonState.Normal, rowIndex);
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnMouseDown"]/*' />
        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            if (e.Button == MouseButtons.Left && mouseInContentBounds)
            {
                Debug.Assert(this.DataGridView.CellMouseDownInContentBounds);
                UpdateButtonState(this.ButtonState | ButtonState.Pushed, e.RowIndex);
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnMouseLeave"]/*' />
        protected override void OnMouseLeave(int rowIndex)
        {
            if (this.DataGridView == null)
            {
                return;
            }
 
            if (mouseInContentBounds)
            {
                mouseInContentBounds = false;
                if (this.ColumnIndex >= 0 &&
                    rowIndex >= 0 &&
                    (this.DataGridView.ApplyVisualStylesToInnerCells || this.FlatStyle == FlatStyle.Flat || this.FlatStyle == FlatStyle.Popup))
                {
                    this.DataGridView.InvalidateCell(this.ColumnIndex, rowIndex);
                }
            }
 
            if ((this.ButtonState & ButtonState.Pushed) != 0 &&
                this.ColumnIndex == this.DataGridView.MouseDownCellAddress.X &&
                rowIndex == this.DataGridView.MouseDownCellAddress.Y)
            {
                UpdateButtonState(this.ButtonState & ~ButtonState.Pushed, rowIndex);
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnMouseMove"]/*' />
        protected override void OnMouseMove(DataGridViewCellMouseEventArgs e)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            
            bool oldMouseInContentBounds = mouseInContentBounds;
            mouseInContentBounds = GetContentBounds(e.RowIndex).Contains(e.X, e.Y);
            if (oldMouseInContentBounds != mouseInContentBounds)
            {
                if (this.DataGridView.ApplyVisualStylesToInnerCells || this.FlatStyle == FlatStyle.Flat || this.FlatStyle == FlatStyle.Popup)
                {
                    this.DataGridView.InvalidateCell(this.ColumnIndex, e.RowIndex);
                }
 
                if (e.ColumnIndex == this.DataGridView.MouseDownCellAddress.X &&
                    e.RowIndex == this.DataGridView.MouseDownCellAddress.Y &&
                    Control.MouseButtons == MouseButtons.Left)
                {
                    if ((this.ButtonState & ButtonState.Pushed) == 0 && 
                        mouseInContentBounds &&
                        this.DataGridView.CellMouseDownInContentBounds)
                    {
                        UpdateButtonState(this.ButtonState | ButtonState.Pushed, e.RowIndex);
                    }
                    else if ((this.ButtonState & ButtonState.Pushed) != 0 && !mouseInContentBounds)
                    {
                        UpdateButtonState(this.ButtonState & ~ButtonState.Pushed, e.RowIndex);
                    }
                }
            }
 
            base.OnMouseMove(e);
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.OnMouseUp"]/*' />
        protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
        {
            if (this.DataGridView == null)
            {
                return;
            }
            if (e.Button == MouseButtons.Left)
            {
                UpdateButtonState(this.ButtonState & ~ButtonState.Pushed, e.RowIndex);
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.Paint"]/*' />
        protected override void Paint(Graphics graphics, 
            Rectangle clipBounds,
            Rectangle cellBounds, 
            int rowIndex, 
            DataGridViewElementStates elementState, 
            object value,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts)
        {
            if (cellStyle == null)
            {
                throw new ArgumentNullException("cellStyle");
            }
 
            PaintPrivate(graphics, 
                clipBounds,
                cellBounds, 
                rowIndex, 
                elementState, 
                formattedValue,
                errorText,
                cellStyle,
                advancedBorderStyle,
                paintParts,
                false /*computeContentBounds*/,
                false /*computeErrorIconBounds*/,
                true  /*paint*/);
        }
 
        // PaintPrivate is used in three places that need to duplicate the paint code:
        // 1. DataGridViewCell::Paint method
        // 2. DataGridViewCell::GetContentBounds
        // 3. DataGridViewCell::GetErrorIconBounds
        // 
        // if computeContentBounds is true then PaintPrivate returns the contentBounds
        // else if computeErrorIconBounds is true then PaintPrivate returns the errorIconBounds
        // else it returns Rectangle.Empty;
        private Rectangle PaintPrivate(Graphics g, 
            Rectangle clipBounds,
            Rectangle cellBounds, 
            int rowIndex, 
            DataGridViewElementStates elementState,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts,
            bool computeContentBounds,
            bool computeErrorIconBounds,
            bool paint)
        {
            // Parameter checking.
            // One bit and one bit only should be turned on
            Debug.Assert(paint || computeContentBounds || computeErrorIconBounds);
            Debug.Assert(!paint || !computeContentBounds || !computeErrorIconBounds);
            Debug.Assert(!computeContentBounds || !computeErrorIconBounds || !paint);
            Debug.Assert(!computeErrorIconBounds || !paint || !computeContentBounds);
            Debug.Assert(cellStyle != null);
 
            Point ptCurrentCell = this.DataGridView.CurrentCellAddress;
            bool cellSelected = (elementState & DataGridViewElementStates.Selected) != 0;
            bool cellCurrent = (ptCurrentCell.X == this.ColumnIndex && ptCurrentCell.Y == rowIndex);
 
            Rectangle resultBounds;
            string formattedString = formattedValue as string;
 
            SolidBrush backBrush = this.DataGridView.GetCachedBrush((DataGridViewCell.PaintSelectionBackground(paintParts) && cellSelected) ? cellStyle.SelectionBackColor : cellStyle.BackColor);
            SolidBrush foreBrush = this.DataGridView.GetCachedBrush(cellSelected ? cellStyle.SelectionForeColor : cellStyle.ForeColor);
 
            if (paint && DataGridViewCell.PaintBorder(paintParts))
            {
                PaintBorder(g, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
            }
 
            Rectangle valBounds = cellBounds;
            Rectangle borderWidths = BorderWidths(advancedBorderStyle);
 
            valBounds.Offset(borderWidths.X, borderWidths.Y);
            valBounds.Width -= borderWidths.Right;
            valBounds.Height -= borderWidths.Bottom;
 
            if (valBounds.Height > 0 && valBounds.Width > 0)
            {
                if (paint && DataGridViewCell.PaintBackground(paintParts) && backBrush.Color.A == 255)
                {
                    g.FillRectangle(backBrush, valBounds);
                }
 
                if (cellStyle.Padding != Padding.Empty)
                {
                    if (this.DataGridView.RightToLeftInternal)
                    {
                        valBounds.Offset(cellStyle.Padding.Right, cellStyle.Padding.Top);
                    }
                    else
                    {
                        valBounds.Offset(cellStyle.Padding.Left, cellStyle.Padding.Top);
                    }
                    valBounds.Width -= cellStyle.Padding.Horizontal;
                    valBounds.Height -= cellStyle.Padding.Vertical;
                }
 
                Rectangle errorBounds = valBounds;
 
                if (valBounds.Height > 0 && valBounds.Width > 0 && (paint || computeContentBounds))
                {
                    if (this.FlatStyle == FlatStyle.Standard || this.FlatStyle == FlatStyle.System)
                    {
                        if (this.DataGridView.ApplyVisualStylesToInnerCells)
                        {
                            if (paint && DataGridViewCell.PaintContentBackground(paintParts))
                            {
                                VisualStyles.PushButtonState pbState = VisualStyles.PushButtonState.Normal;
                                if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0)
                                {
                                    pbState = VisualStyles.PushButtonState.Pressed;
                                }
                                else if (this.DataGridView.MouseEnteredCellAddress.Y == rowIndex && 
                                         this.DataGridView.MouseEnteredCellAddress.X == this.ColumnIndex &&
                                         mouseInContentBounds)
                                {
                                    pbState = VisualStyles.PushButtonState.Hot;
                                }
                                if (DataGridViewCell.PaintFocus(paintParts) && 
                                    cellCurrent && 
                                    this.DataGridView.ShowFocusCues && 
                                    this.DataGridView.Focused)
                                {
                                    pbState |= VisualStyles.PushButtonState.Default;
                                }
                                DataGridViewButtonCellRenderer.DrawButton(g, valBounds, (int)pbState);
                            }
                            resultBounds = valBounds;
                            valBounds = DataGridViewButtonCellRenderer.DataGridViewButtonRenderer.GetBackgroundContentRectangle(g, valBounds);
                        }
                        else
                        {
                            if (paint && DataGridViewCell.PaintContentBackground(paintParts))
                            {
                                ControlPaint.DrawBorder(g, valBounds, SystemColors.Control, 
                                                        (this.ButtonState == ButtonState.Normal) ? ButtonBorderStyle.Outset : ButtonBorderStyle.Inset);
                            }
                            resultBounds = valBounds;
                            valBounds.Inflate(-SystemInformation.Border3DSize.Width, -SystemInformation.Border3DSize.Height);
                        }
                    }
                    else if (this.FlatStyle == FlatStyle.Flat)
                    {
                        // ButtonBase::PaintFlatDown and ButtonBase::PaintFlatUp paint the border in the same way
                        valBounds.Inflate(-1, -1);
                        if (paint && DataGridViewCell.PaintContentBackground(paintParts))
                        {
                            ButtonInternal.ButtonBaseAdapter.DrawDefaultBorder(g, valBounds, foreBrush.Color, true /*isDefault == true*/);
 
                            if (backBrush.Color.A == 255)
                            {
                                if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0)
                                {
                                    ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintFlatRender(g,
                                                                                                           cellStyle.ForeColor,
                                                                                                           cellStyle.BackColor,
                                                                                                           this.DataGridView.Enabled).Calculate();
 
                                    IntPtr hdc = g.GetHdc();
                                    try {
                                        using( WindowsGraphics wg = WindowsGraphics.FromHdc(hdc)) {
                                            
                                            System.Windows.Forms.Internal.WindowsBrush windowsBrush;
                                            if (colors.options.highContrast)
                                            {
                                                windowsBrush = new System.Windows.Forms.Internal.WindowsSolidBrush(wg.DeviceContext, colors.buttonShadow);
                                            }
                                            else
                                            {
                                                windowsBrush = new System.Windows.Forms.Internal.WindowsSolidBrush(wg.DeviceContext, colors.lowHighlight);
                                            }
                                            try
                                            {
                                                ButtonInternal.ButtonBaseAdapter.PaintButtonBackground(wg, valBounds, windowsBrush);
                                            }
                                            finally
                                            {
                                                windowsBrush.Dispose();
                                            }
                                        }                                        
                                    }
                                    finally {
                                        g.ReleaseHdc();
                                    }
                                }
                                else if (this.DataGridView.MouseEnteredCellAddress.Y == rowIndex &&
                                         this.DataGridView.MouseEnteredCellAddress.X == this.ColumnIndex &&
                                         mouseInContentBounds)
                                {
                                    IntPtr hdc = g.GetHdc();
                                    try {
                                        using( WindowsGraphics wg = WindowsGraphics.FromHdc(hdc)) {
                                            Color mouseOverBackColor = SystemColors.ControlDark;
                                            using (System.Windows.Forms.Internal.WindowsBrush windowBrush = new System.Windows.Forms.Internal.WindowsSolidBrush(wg.DeviceContext, mouseOverBackColor))
                                            {
                                                ButtonInternal.ButtonBaseAdapter.PaintButtonBackground(wg, valBounds, windowBrush);
                                            }
                                        }
                                    }
                                    finally {
                                        g.ReleaseHdc();
                                    }
                                }
                            }
                        }
                        resultBounds = valBounds;
                    }
                    else
                    {
                        Debug.Assert(this.FlatStyle == FlatStyle.Popup, "FlatStyle.Popup is the last flat style");
                        valBounds.Inflate(-1, -1);
                        if (paint && DataGridViewCell.PaintContentBackground(paintParts))
                        {
                            if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0)
                            {
                                // paint down
                                ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintPopupRender(g,
                                                                                                        cellStyle.ForeColor,
                                                                                                        cellStyle.BackColor,
                                                                                                        this.DataGridView.Enabled).Calculate();
                                ButtonBaseAdapter.DrawDefaultBorder(g,
                                                                    valBounds,
                                                                    colors.options.highContrast ? colors.windowText : colors.windowFrame,
                                                                    true /*isDefault*/);
                                ControlPaint.DrawBorder(g,
                                                        valBounds,
                                                        colors.options.highContrast ? colors.windowText : colors.buttonShadow,
                                                        ButtonBorderStyle.Solid);
                            }
                            else if (this.DataGridView.MouseEnteredCellAddress.Y == rowIndex &&
                                     this.DataGridView.MouseEnteredCellAddress.X == this.ColumnIndex &&
                                     mouseInContentBounds)
                            {
                                // paint over
                                ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintPopupRender(g,
                                                                                                        cellStyle.ForeColor,
                                                                                                        cellStyle.BackColor,
                                                                                                        this.DataGridView.Enabled).Calculate();
                                ButtonBaseAdapter.DrawDefaultBorder(g,
                                                                    valBounds,
                                                                    colors.options.highContrast ? colors.windowText : colors.buttonShadow,
                                                                    false /*isDefault*/);
                                ButtonBaseAdapter.Draw3DLiteBorder(g, valBounds, colors, true);
                            }
                            else
                            {
                                // paint up
                                ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintPopupRender(g,
                                                                                                        cellStyle.ForeColor,
                                                                                                        cellStyle.BackColor,
                                                                                                        this.DataGridView.Enabled).Calculate();
                                ButtonBaseAdapter.DrawDefaultBorder(g, valBounds, colors.options.highContrast ? colors.windowText : colors.buttonShadow, false /*isDefault*/);
                                ButtonBaseAdapter.DrawFlatBorder(g, valBounds, colors.options.highContrast ? colors.windowText : colors.buttonShadow);
                            }
                        }
                        resultBounds = valBounds;
                    }
                }
                else if (computeErrorIconBounds)
                {
                    if (!String.IsNullOrEmpty(errorText))
                    {
                        resultBounds = ComputeErrorIconBounds(errorBounds);
                    }
                    else
                    {
                        resultBounds = Rectangle.Empty;
                    }
                }
                else
                {
                    Debug.Assert(valBounds.Height <= 0 || valBounds.Width <= 0);
                    resultBounds = Rectangle.Empty;
                }
                
                if (paint &&
                    DataGridViewCell.PaintFocus(paintParts) &&
                    cellCurrent &&
                    this.DataGridView.ShowFocusCues && 
                    this.DataGridView.Focused &&
                    valBounds.Width > 2 * SystemInformation.Border3DSize.Width + 1 &&
                    valBounds.Height > 2 * SystemInformation.Border3DSize.Height + 1)
                {
                    // Draw focus rectangle
                    if (this.FlatStyle == FlatStyle.System || this.FlatStyle == FlatStyle.Standard)
                    {
                        ControlPaint.DrawFocusRectangle(g, Rectangle.Inflate(valBounds, -1, -1), Color.Empty, SystemColors.Control);
                    }
                    else if (this.FlatStyle == FlatStyle.Flat)
                    {
                        if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0 ||
                            (this.DataGridView.CurrentCellAddress.Y == rowIndex && this.DataGridView.CurrentCellAddress.X == this.ColumnIndex))
                        {
                            ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintFlatRender(g,
                                                                                                   cellStyle.ForeColor,
                                                                                                   cellStyle.BackColor,
                                                                                                   this.DataGridView.Enabled).Calculate();
                            string text = (formattedString != null) ? formattedString : String.Empty;
 
                            ButtonBaseAdapter.LayoutOptions options = ButtonInternal.ButtonFlatAdapter.PaintFlatLayout(g,
                                                                                                                   true,
                                                                                                                   SystemInformation.HighContrast,
                                                                                                                   1,
                                                                                                                   valBounds,
                                                                                                                   Padding.Empty,
                                                                                                                   false,
                                                                                                                   cellStyle.Font,
                                                                                                                   text,
                                                                                                                   this.DataGridView.Enabled,
                                                                                                                   DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
                                                                                                                   this.DataGridView.RightToLeft);
                            options.everettButtonCompat = false;
                            ButtonBaseAdapter.LayoutData layout = options.Layout();
 
                            ButtonInternal.ButtonBaseAdapter.DrawFlatFocus(g,
                                                                           layout.focus,
                                                                           colors.options.highContrast ? colors.windowText : colors.constrastButtonShadow);
                        }
                    }
                    else
                    {
                        Debug.Assert(this.FlatStyle == FlatStyle.Popup, "FlatStyle.Popup is the last flat style");
                        if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0 || 
                            (this.DataGridView.CurrentCellAddress.Y == rowIndex && this.DataGridView.CurrentCellAddress.X == this.ColumnIndex))
                        {
                            // If we are painting the current cell, then paint the text up.
                            // If we are painting the current cell and the current cell is pressed down, then paint the text down.
                            bool paintUp = (this.ButtonState == ButtonState.Normal);
                            string text = (formattedString != null) ? formattedString : String.Empty;
                            ButtonBaseAdapter.LayoutOptions options = ButtonInternal.ButtonPopupAdapter.PaintPopupLayout(g,
                                                                                                                   paintUp,
                                                                                                                   SystemInformation.HighContrast ? 2 : 1,
                                                                                                                   valBounds,
                                                                                                                   Padding.Empty,
                                                                                                                   false,
                                                                                                                   cellStyle.Font,
                                                                                                                   text,
                                                                                                                   this.DataGridView.Enabled,
                                                                                                                   DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
                                                                                                                   this.DataGridView.RightToLeft);
                            options.everettButtonCompat = false;
                            ButtonBaseAdapter.LayoutData layout = options.Layout();
                         
 
                            ControlPaint.DrawFocusRectangle(g,
                                                            layout.focus,
                                                            cellStyle.ForeColor,
                                                            cellStyle.BackColor);
                        }
                    }
                }
 
                if (formattedString != null && paint && DataGridViewCell.PaintContentForeground(paintParts))
                {
                    // Font independent margins
                    valBounds.Offset(DATAGRIDVIEWBUTTONCELL_horizontalTextMargin, DATAGRIDVIEWBUTTONCELL_verticalTextMargin);
                    valBounds.Width -= 2 * DATAGRIDVIEWBUTTONCELL_horizontalTextMargin;
                    valBounds.Height -= 2 * DATAGRIDVIEWBUTTONCELL_verticalTextMargin;
 
                    if ((this.ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0 &&
                        this.FlatStyle != FlatStyle.Flat && this.FlatStyle != FlatStyle.Popup)
                    {
                        valBounds.Offset(1, 1);
                        valBounds.Width--;
                        valBounds.Height--;
                    }
 
                    if (valBounds.Width > 0 && valBounds.Height > 0)
                    {
                        Color textColor;
                        if (this.DataGridView.ApplyVisualStylesToInnerCells &&
                            (this.FlatStyle == FlatStyle.System || this.FlatStyle == FlatStyle.Standard))
                        {
                            textColor = DataGridViewButtonCellRenderer.DataGridViewButtonRenderer.GetColor(ColorProperty.TextColor);
                        }
                        else
                        {
                            textColor = foreBrush.Color;
                        }
                        TextFormatFlags flags = DataGridViewUtilities.ComputeTextFormatFlagsForCellStyleAlignment(this.DataGridView.RightToLeftInternal, cellStyle.Alignment, cellStyle.WrapMode);
                        TextRenderer.DrawText(g,
                                              formattedString,
                                              cellStyle.Font,
                                              valBounds,
                                              textColor,
                                              flags);
                    }
                }
 
                if (this.DataGridView.ShowCellErrors && paint && DataGridViewCell.PaintErrorIcon(paintParts))
                {
                    PaintErrorIcon(g, cellStyle, rowIndex, cellBounds, errorBounds, errorText);
                }
            }
            else
            {
                resultBounds = Rectangle.Empty;
            }
 
            return resultBounds;
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCell.ToString"]/*' />
        public override string ToString()
        {
            return "DataGridViewButtonCell { ColumnIndex=" + ColumnIndex.ToString(CultureInfo.CurrentCulture) + ", RowIndex=" + RowIndex.ToString(CultureInfo.CurrentCulture) + " }";
        }
 
        private void UpdateButtonState(ButtonState newButtonState, int rowIndex)
        {
            if (this.ButtonState != newButtonState)
            {
                this.ButtonState = newButtonState;
                this.DataGridView.InvalidateCell(this.ColumnIndex, rowIndex);
            }
        }
 
        private class DataGridViewButtonCellRenderer
        {
            private static VisualStyleRenderer visualStyleRenderer;
 
            private DataGridViewButtonCellRenderer()
            {
            }
 
            public static VisualStyleRenderer DataGridViewButtonRenderer
            {
                get
                {
                    if (visualStyleRenderer == null)
                    {
                        visualStyleRenderer = new VisualStyleRenderer(ButtonElement);
                    }
                    return visualStyleRenderer;
                }
            }
 
            public static void DrawButton(Graphics g, Rectangle bounds, int buttonState)
            {
                DataGridViewButtonRenderer.SetParameters(ButtonElement.ClassName, ButtonElement.Part, buttonState);
                DataGridViewButtonRenderer.DrawBackground(g, bounds, Rectangle.Truncate(g.ClipBounds));
            }
        }
 
        /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCellAccessibleObject"]/*' />
        protected class DataGridViewButtonCellAccessibleObject : DataGridViewCellAccessibleObject
        {
            /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCellAccessibleObject.DataGridViewButtonCellAccessibleObject"]/*' />
            public DataGridViewButtonCellAccessibleObject(DataGridViewCell owner) : base (owner)
            {
            }
 
            /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCellAccessibleObject.DefaultAction"]/*' />
            public override string DefaultAction
            {
                get
                {
                    return SR.GetString(SR.DataGridView_AccButtonCellDefaultAction);
                }
            }
 
            /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCellAccessibleObject.DoDefaultAction"]/*' />
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public override void DoDefaultAction()
            {
                DataGridViewButtonCell dataGridViewCell = (DataGridViewButtonCell)this.Owner;
                DataGridView dataGridView = dataGridViewCell.DataGridView;
 
                if (dataGridView != null && dataGridViewCell.RowIndex == -1)
                {
                    throw new InvalidOperationException(SR.GetString(SR.DataGridView_InvalidOperationOnSharedCell));
                }
 
                if (dataGridViewCell.OwningColumn != null && dataGridViewCell.OwningRow != null)
                {
                    dataGridView.OnCellClickInternal(new DataGridViewCellEventArgs(dataGridViewCell.ColumnIndex, dataGridViewCell.RowIndex));
                    dataGridView.OnCellContentClickInternal(new DataGridViewCellEventArgs(dataGridViewCell.ColumnIndex, dataGridViewCell.RowIndex));
                }
            }
 
            /// <include file='doc\DataGridViewButtonCell.uex' path='docs/doc[@for="DataGridViewButtonCellAccessibleObject.GetChildCount"]/*' />
            public override int GetChildCount()
            {
                return 0;
            }
 
            internal override bool IsIAccessibleExSupported()
            {
                if (AccessibilityImprovements.Level2)
                {
                    return true;
                }
 
                return base.IsIAccessibleExSupported();
            }
 
            internal override object GetPropertyValue(int propertyID)
            {
                if (propertyID == NativeMethods.UIA_ControlTypePropertyId)
                {
                    return NativeMethods.UIA_ButtonControlTypeId;
                }
 
                return base.GetPropertyValue(propertyID);
            }
        }
    }
}