File: winforms\Managed\System\WinForms\ButtonBase.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ButtonBase.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Drawing.Imaging;
    using System;
    using System.Security.Permissions;
    using System.Drawing.Drawing2D;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Windows.Forms.ButtonInternal;
    using System.Windows.Forms.Layout;
    using System.ComponentModel;
    using Microsoft.Win32;
    using System.Globalization;
    using System.Runtime.Versioning;
 
    /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase"]/*' />
    /// <devdoc>
    ///    <para>
    ///       Implements the basic functionality required by a button control.
    ///    </para>
    /// </devdoc>
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    Designer("System.Windows.Forms.Design.ButtonBaseDesigner, " + AssemblyRef.SystemDesign)
    ]
    public abstract class ButtonBase : Control {
 
        private FlatStyle flatStyle                  = System.Windows.Forms.FlatStyle.Standard;
        private ContentAlignment imageAlign          = ContentAlignment.MiddleCenter;
        private ContentAlignment textAlign           = ContentAlignment.MiddleCenter;
        private TextImageRelation textImageRelation  = TextImageRelation.Overlay;
        private ImageList.Indexer imageIndex         = new ImageList.Indexer();
        private FlatButtonAppearance flatAppearance;
        private ImageList imageList;
        private Image image;
        
        private const int FlagMouseOver             = 0x0001;
        private const int FlagMouseDown             = 0x0002;
        private const int FlagMousePressed          = 0x0004;
        private const int FlagInButtonUp            = 0x0008;
        private const int FlagCurrentlyAnimating    = 0x0010;
        private const int FlagAutoEllipsis          = 0x0020;
        private const int FlagIsDefault             = 0x0040;
        private const int FlagUseMnemonic           = 0x0080;
        private const int FlagShowToolTip           = 0x0100;
        private int state                           = 0;
 
        private ToolTip textToolTip;
 
        //this allows the user to disable visual styles for the button so that it inherits its background color
        private bool enableVisualStyleBackground = true;     
 
        private bool isEnableVisualStyleBackgroundSet = false;
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ButtonBase"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.ButtonBase'/> class.
        ///       
        ///    </para>
        /// </devdoc>
        protected ButtonBase() {
            // If Button doesn't want double-clicks, we should introduce a StandardDoubleClick style.
            // Checkboxes probably want double-click's (#26120), and RadioButtons certainly do
            // (useful e.g. on a Wizard).
            SetStyle( ControlStyles.SupportsTransparentBackColor | 
                      ControlStyles.Opaque | 
                      ControlStyles.ResizeRedraw |
                      ControlStyles.OptimizedDoubleBuffer |
                      ControlStyles.CacheText | // We gain about 2% in painting by avoiding extra GetWindowText calls
                      ControlStyles.StandardClick,
                      true);
            // this class overrides GetPreferredSizeCore, let Control automatically cache the result
            SetState2(STATE2_USEPREFERREDSIZECACHE, true);  
 
            SetStyle(ControlStyles.UserMouse |
                     ControlStyles.UserPaint, OwnerDraw);
            SetFlag(FlagUseMnemonic, true);
            SetFlag(FlagShowToolTip, false);
        }
 
        /// <devdoc>
        ///    <para> This property controls the activation handling of bleedover for the text that 
        ///    extends beyond the width of the button. </para>
        /// </devdoc>
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false),
        Browsable(true), 
        EditorBrowsable(EditorBrowsableState.Always),
        SRDescription(SR.ButtonAutoEllipsisDescr)
        ]
        public bool AutoEllipsis {
            get {
                return GetFlag(FlagAutoEllipsis);
            }
 
            set {
                if (AutoEllipsis != value) {
                    SetFlag(FlagAutoEllipsis, value);
                    if (value) {
                        if (textToolTip == null) {
                            textToolTip  = new ToolTip();
                        }
                    }
                    Invalidate();    
                }
            }
        }
 
        /// <devdoc>
        ///     Indicates whether the control is automatically resized to fit its contents
        /// </devdoc>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override bool AutoSize {
            get {
                return base.AutoSize;
            }
            set {
                base.AutoSize = value;
                //don't show ellipsis if the control is autosized
                if (value) {
                    AutoEllipsis = false;
                }
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.AutoSizeChanged"]/*' />
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnAutoSizeChangedDescr)]
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler AutoSizeChanged
        {
            add
            {
                base.AutoSizeChanged += value;
            }
            remove
            {
                base.AutoSizeChanged -= value;
            }
        }
 
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.BackColor"]/*' />
        /// <devdoc>
        ///     The background color of this control. This is an ambient property and
        ///     will always return a non-null value.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.ControlBackColorDescr)
        ]
        public override Color BackColor {
            get {
                return base.BackColor;
            }
            set {
                if (DesignMode) {
                    if (value != Color.Empty) {
                        PropertyDescriptor pd = TypeDescriptor.GetProperties(this)["UseVisualStyleBackColor"];
                        Debug.Assert(pd != null);
                        if (pd != null) {
                            pd.SetValue(this, false);
                        }
                    }
                }
                else {
                    UseVisualStyleBackColor = false;
                }
 
                base.BackColor = value;
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.DefaultSize"]/*' />
        /// <devdoc>
        ///     Deriving classes can override this to configure a default size for their control.
        ///     This is more efficient than setting the size in the control's constructor.
        /// </devdoc>
        protected override Size DefaultSize {
            get {
                return new Size(75, 23);
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.CreateParams"]/*' />
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
                if (!OwnerDraw) {
                    cp.ExStyle &= ~NativeMethods.WS_EX_RIGHT;   // WS_EX_RIGHT overrides the BS_XXXX alignment styles
                    
                    cp.Style |= NativeMethods.BS_MULTILINE;
                    
                    if (IsDefault) {
                        cp.Style |= NativeMethods.BS_DEFPUSHBUTTON;
                    }
 
                    ContentAlignment align = RtlTranslateContent(TextAlign);                              
                              
                    if ((int)(align & WindowsFormsUtils.AnyLeftAlign) != 0) {
                        cp.Style |= NativeMethods.BS_LEFT;
                    }
                    else if ((int)(align & WindowsFormsUtils.AnyRightAlign) != 0) {
                        cp.Style |= NativeMethods.BS_RIGHT;
                    }
                    else {
                        cp.Style |= NativeMethods.BS_CENTER;
                    
                    }
                    if ((int)(align & WindowsFormsUtils.AnyTopAlign) != 0) {
                        cp.Style |= NativeMethods.BS_TOP;
                    }
                    else if ((int)(align & WindowsFormsUtils.AnyBottomAlign) != 0) {
                        cp.Style |= NativeMethods.BS_BOTTOM;
                    }
                    else {
                        cp.Style |= NativeMethods.BS_VCENTER;
                    }
                }
                return cp;
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.DefaultImeMode"]/*' />
        protected override ImeMode DefaultImeMode {
            get {
                return ImeMode.Disable;
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.IsDefault"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected internal bool IsDefault {
            get {
                return GetFlag(FlagIsDefault);
            }
            set {
                if (GetFlag(FlagIsDefault) != value) {
                    SetFlag(FlagIsDefault, value);
                    if (IsHandleCreated) {
                        if (OwnerDraw) {
                            Invalidate();
                        }
                        else {
                            UpdateStyles();
                        }
                    }
                }
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.FlatStyle"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or
        ///       sets
        ///       the flat style appearance of the button control.
        ///    </para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(FlatStyle.Standard),
        Localizable(true),
        SRDescription(SR.ButtonFlatStyleDescr)
        ]
        public FlatStyle FlatStyle {
            get {
                return flatStyle;
            }
            set {
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)FlatStyle.Flat, (int)FlatStyle.System)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(FlatStyle));
                }
                flatStyle = value;
                LayoutTransaction.DoLayoutIf(AutoSize,ParentInternal, this, PropertyNames.FlatStyle);                
                Invalidate();
                UpdateOwnerDraw();
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.FlatAppearance"]/*' />
        /// <devdoc>
        /// </devdoc>
        [
        Browsable(true),
        SRCategory(SR.CatAppearance),
        SRDescription(SR.ButtonFlatAppearance),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        ]
        public FlatButtonAppearance FlatAppearance {
            get {
                if (flatAppearance == null) {
                    flatAppearance = new FlatButtonAppearance(this);
                }
 
                return flatAppearance;
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.Image"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the image
        ///       that is displayed on a button control.
        ///    </para>
        /// </devdoc>
        [
        SRDescription(SR.ButtonImageDescr),
        Localizable(true),
        SRCategory(SR.CatAppearance)
        ]
        public Image Image {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                if (image == null && imageList != null) {
                    int actualIndex = imageIndex.ActualIndex;
 
                    // Pre-whidbey we used to use ImageIndex rather than ImageIndexer.ActualIndex.
                    // ImageIndex clamps to the length of the image list.  We need to replicate
                    // this logic here for backwards compatibility.  (VSWhidbey #95780)
                    // Per Microsoft we do not bake this into ImageIndexer because different controls
                    // treat this scenario differently.
                    if(actualIndex >= imageList.Images.Count) {
                        actualIndex = imageList.Images.Count - 1;
                    }
 
                    if (actualIndex >= 0) {
                        return imageList.Images[actualIndex];
                    }
                    Debug.Assert(image == null, "We expect to be returning null.");
                }
                return image;
            }
            set {
                if (Image != value) {
                    StopAnimate();
 
                    image = value;
                    if (image != null) {
                        ImageIndex = -1;
                        ImageList = null;
                    }
 
                    LayoutTransaction.DoLayoutIf(AutoSize, ParentInternal, this, PropertyNames.Image);
                    Animate();
                    Invalidate();
                }
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImageAlign"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the alignment of the image on the button control.
        ///    </para>
        /// </devdoc>
        [
        DefaultValue(ContentAlignment.MiddleCenter),
        Localizable(true),
        SRDescription(SR.ButtonImageAlignDescr),
        SRCategory(SR.CatAppearance)
        ]
        public ContentAlignment ImageAlign {
            get {
                return imageAlign;
            }
            set {
                if (!WindowsFormsUtils.EnumValidator.IsValidContentAlignment(value)) {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ContentAlignment));
                }
                if(value != imageAlign) {
                    imageAlign = value;
                    LayoutTransaction.DoLayoutIf(AutoSize, ParentInternal, this, PropertyNames.ImageAlign);
                    Invalidate();
                }
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImageIndex"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the image list index value of the image
        ///       displayed on the button control.
        ///    </para>
        /// </devdoc>
        [
        TypeConverterAttribute(typeof(ImageIndexConverter)),
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        Localizable(true),
        DefaultValue(-1),
        RefreshProperties(RefreshProperties.Repaint),
        SRDescription(SR.ButtonImageIndexDescr),
        SRCategory(SR.CatAppearance)
        ]
        public int ImageIndex {
            get {
                if (imageIndex.Index != -1 && imageList != null && imageIndex.Index >= imageList.Images.Count) {
                    return imageList.Images.Count - 1;
                }
                return imageIndex.Index;
            }
            set {
                if (value < -1) {
                    throw new ArgumentOutOfRangeException("ImageIndex", SR.GetString(SR.InvalidLowBoundArgumentEx, "ImageIndex", (value).ToString(CultureInfo.CurrentCulture), (-1).ToString(CultureInfo.CurrentCulture)));
                }
                if (imageIndex.Index != value) {
                    if (value != -1) {
                        // Image.set calls ImageIndex = -1
                        image = null;
                    }
 
                    // If they were previously using keys - this should clear out the image key field.
                    imageIndex.Index = value;
                    Invalidate();
                }
            }
        }
 
         /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImageKey"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the image list index key of the image
        ///       displayed on the button control.  Note - setting this unsets the ImageIndex
        ///    </para>
        /// </devdoc>
        [
        TypeConverterAttribute(typeof(ImageKeyConverter)),
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        Localizable(true),
        DefaultValue(""),
        RefreshProperties(RefreshProperties.Repaint),
        SRDescription(SR.ButtonImageIndexDescr),
        SRCategory(SR.CatAppearance)
        ]
        public string ImageKey {
            get {
                return imageIndex.Key;
            }
            set {
                if (imageIndex.Key != value) {
                    if (value != null) {
                        // Image.set calls ImageIndex = -1
                        image = null;
                    }
 
                    // If they were previously using indexes - this should clear out the image index field.
                    imageIndex.Key = value;
                    Invalidate();
                }
            }
        }
 
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImageList"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the <see cref='System.Windows.Forms.ImageList'/> that contains the <see cref='System.Drawing.Image'/> displayed on a button control.
        ///    </para>
        /// </devdoc>
        [
        DefaultValue(null),
        SRDescription(SR.ButtonImageListDescr),
        RefreshProperties(RefreshProperties.Repaint),        
        SRCategory(SR.CatAppearance)
        ]
        public ImageList ImageList {
            get {
                return imageList;
            }
            set {
                if (imageList != value) {
                    EventHandler recreateHandler = new EventHandler(ImageListRecreateHandle);
                    EventHandler disposedHandler = new EventHandler(DetachImageList);
 
                    // Detach old event handlers
                    //
                    if (imageList != null) {
                        imageList.RecreateHandle -= recreateHandler;
                        imageList.Disposed -= disposedHandler;                        
                    }
 
                    // Make sure we don't have an Image as well as an ImageList
                    //
                    if (value != null) {
                        image = null; // Image.set calls ImageList = null
                    }
 
                    imageList = value;
                    imageIndex.ImageList = value;
 
                    // Wire up new event handlers
                    //
                    if (value != null) {
                        value.RecreateHandle += recreateHandler;
                        value.Disposed += disposedHandler;                                               
                    }                    
 
                    
                    Invalidate();
                }
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImeMode"]/*' />
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public ImeMode ImeMode {
            get {
                return base.ImeMode;
            }
            set {
                base.ImeMode = value;
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ImeModeChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged {
            add {
                base.ImeModeChanged += value;
            }
            remove {
                base.ImeModeChanged -= value;
            }
        }
 
        /// <devdoc>
        ///     Specifies whether the control is willing to process mnemonics when hosted in an container ActiveX (Ax Sourcing).  
        /// </devdoc>
        internal override bool IsMnemonicsListenerAxSourced 
        {
            get{
                return true;
            }
        }
 
        /// <devdoc>
        ///     <para>
        ///         The area of the button encompassing any changes between the button's
        ///     resting appearance and its appearance when the mouse is over it.
        ///     </para>
        ///     <para>
        ///         Consider overriding this property if you override any painting methods,
        ///     or your button may not paint correctly or may have flicker. Returning
        ///     ClientRectangle is safe for correct painting but may still cause flicker.
        ///     </para>
        /// </devdoc>
        internal virtual Rectangle OverChangeRectangle {
            get {
                if (FlatStyle == FlatStyle.Standard) {
                    // this Rectangle will cause no Invalidation
                    // can't use Rectangle.Empty because it will cause Invalidate(ClientRectangle)
                    return new Rectangle(-1, -1, 1, 1);
                }
                else {
                    return ClientRectangle;
                }
            }
        }
        
        internal bool OwnerDraw {
            get {
                return FlatStyle != FlatStyle.System;
            }
        }
 
        /// <devdoc>
        ///     <para>
        ///         The area of the button encompassing any changes between the button's
        ///     appearance when the mouse is over it but not pressed and when it is pressed.
        ///     </para>
        ///     <para>
        ///         Consider overriding this property if you override any painting methods,
        ///     or your button may not paint correctly or may have flicker. Returning
        ///     ClientRectangle is safe for correct painting but may still cause flicker.
        ///     </para>
        /// </devdoc>
        internal virtual Rectangle DownChangeRectangle {
            get {
                return ClientRectangle;
            }
        }
 
        internal bool MouseIsPressed {
            get {
                return GetFlag(FlagMousePressed);
            }
        }
 
        // a "smart" version of mouseDown for Appearance.Button CheckBoxes & RadioButtons
        // for these, instead of being based on the actual mouse state, it's based on the appropriate button state
        internal bool MouseIsDown {
            get {
                return GetFlag(FlagMouseDown);
            }
        }
 
        // a "smart" version of mouseOver for Appearance.Button CheckBoxes & RadioButtons
        // for these, instead of being based on the actual mouse state, it's based on the appropriate button state
        internal bool MouseIsOver {
            get {
                return GetFlag(FlagMouseOver);
            }
        }
 
        
        /// <devdoc>
        ///     Indicates whether the tooltip should be shown
        /// </devdoc>   
        internal bool ShowToolTip {
            get {
                return GetFlag(FlagShowToolTip);
            }
            set {
                SetFlag(FlagShowToolTip, value);
            }
        }
 
        [
        Editor("System.ComponentModel.Design.MultilineStringEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        SettingsBindable(true)
        ]
        public override string Text {
            get {
                return base.Text;
            }
            set {
                base.Text = value;
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.TextAlign"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets the alignment of the text on the button control.
        ///    </para>
        /// </devdoc>
        [
        DefaultValue(ContentAlignment.MiddleCenter),
        Localizable(true),
        SRDescription(SR.ButtonTextAlignDescr),
        SRCategory(SR.CatAppearance)
        ]
        public virtual ContentAlignment TextAlign {
            get {
                return textAlign;
            }
            set {
                if (!WindowsFormsUtils.EnumValidator.IsValidContentAlignment(value)) {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(ContentAlignment));
                }
                if(value != textAlign) {
                    textAlign = value;
                    LayoutTransaction.DoLayoutIf(AutoSize, ParentInternal, this, PropertyNames.TextAlign);
                    if (OwnerDraw) {
                        Invalidate();
                    }
                    else {
                        UpdateStyles();
                    }
                }
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.TextImageRelation"]/*' />
        [DefaultValue(TextImageRelation.Overlay),
        Localizable(true),
        SRDescription(SR.ButtonTextImageRelationDescr),
        SRCategory(SR.CatAppearance)]
        public TextImageRelation TextImageRelation {
            get {
                return textImageRelation;
            }
            set {
                if (!WindowsFormsUtils.EnumValidator.IsValidTextImageRelation(value)) {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(TextImageRelation));
                }
                if(value != TextImageRelation) {
                    textImageRelation = value;
                    LayoutTransaction.DoLayoutIf(AutoSize, ParentInternal, this, PropertyNames.TextImageRelation);
                    Invalidate();
                }                
            }
        }
 
        /// <devdoc>
        ///    <para>Gets or sets a value indicating whether an ampersand (&amp;) included in the text of
        ///       the control.</para>
        /// </devdoc>
        [
        SRDescription(SR.ButtonUseMnemonicDescr),
        DefaultValue(true),
        SRCategory(SR.CatAppearance)
        ]
        public bool UseMnemonic {
            get {
                return GetFlag(FlagUseMnemonic);
            }
        
            set {
                SetFlag(FlagUseMnemonic, value);
                LayoutTransaction.DoLayoutIf(AutoSize, ParentInternal, this, PropertyNames.Text);
                Invalidate();
            }
        }
 
        private void Animate() {
            Animate(!DesignMode && Visible && Enabled && ParentInternal != null);
        }
 
        private void StopAnimate() {
            Animate(false);
        }
 
        private void Animate(bool animate) {
            if (animate != GetFlag(FlagCurrentlyAnimating)) {
                if (animate) {
                    if (this.image != null) {
                        ImageAnimator.Animate(this.image, new EventHandler(this.OnFrameChanged));
                        SetFlag(FlagCurrentlyAnimating, animate);
                    }
                }
                else {
                    if (this.image != null) {
                        ImageAnimator.StopAnimate(this.image, new EventHandler(this.OnFrameChanged));
                        SetFlag(FlagCurrentlyAnimating, animate);
                    }
                }
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.CreateAccessibilityInstance"]/*' />
        protected override AccessibleObject CreateAccessibilityInstance() {
            return new ButtonBaseAccessibleObject(this);
        }
 
        private void DetachImageList(object sender, EventArgs e) {
            ImageList = null;
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.Dispose"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        protected override void Dispose(bool disposing) {
            if (disposing) {
                StopAnimate();
                if (imageList != null) {
                    imageList.Disposed -= new EventHandler(this.DetachImageList);
                }
                //Dipose the tooltip if one present..
                if (textToolTip != null) {
                    textToolTip.Dispose();
                    textToolTip = null;
                }
            }
            base.Dispose(disposing);
        }
 
        private bool GetFlag(int flag) {
            return ((state & flag) == flag);
        }
 
        private void ImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) {
                Invalidate();
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnGotFocus"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnGotFocus'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnGotFocus(EventArgs e) {
            base.OnGotFocus(e);
            Invalidate();
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnLostFocus"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnLostFocus'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnLostFocus(EventArgs e) {
            base.OnLostFocus(e);
 
            // Hitting tab while holding down the space key. See ASURT 38669.
            SetFlag(FlagMouseDown, false);
            CaptureInternal = false;
 
            Invalidate();
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnMouseEnter"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.Control.OnMouseEnter'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnMouseEnter(EventArgs eventargs) {
            Debug.Assert(Enabled, "ButtonBase.OnMouseEnter should not be called if the button is disabled");
            SetFlag(FlagMouseOver, true);
            Invalidate();
            if (!DesignMode && AutoEllipsis && ShowToolTip && textToolTip != null) {
                // SECREVIEW: VSWhidbey 531915 - ToolTip should show in internet zone
                IntSecurity.AllWindows.Assert();
                try { 
                    textToolTip.Show(WindowsFormsUtils.TextWithoutMnemonics(Text), this);
                }
                finally {
                    System.Security.CodeAccessPermission.RevertAssert();
                }
            }
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnMouseEnter(eventargs);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnMouseLeave"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.Control.OnMouseLeave'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnMouseLeave(EventArgs eventargs) {
            SetFlag(FlagMouseOver, false);    
            if (textToolTip != null) {
                // SECREVIEW: VSWhidbey 531915 - ToolTip should show in internet zone
                IntSecurity.AllWindows.Assert();
                try {
                    textToolTip.Hide(this);
                }
                finally {
                    System.Security.CodeAccessPermission.RevertAssert();
                }
            }
            Invalidate();
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnMouseLeave(eventargs);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnMouseMove"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.Control.OnMouseMove'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnMouseMove(MouseEventArgs mevent) {
            Debug.Assert(Enabled, "ButtonBase.OnMouseMove should not be called if the button is disabled");
            if (mevent.Button != MouseButtons.None && GetFlag(FlagMousePressed)) {
                Rectangle r = ClientRectangle;
                if (!r.Contains(mevent.X, mevent.Y)) {
                    if (GetFlag(FlagMouseDown)) {
                        SetFlag(FlagMouseDown, false);
                        Invalidate(DownChangeRectangle);
                    }
                }
                else {
                    if (!GetFlag(FlagMouseDown)) {
                        SetFlag(FlagMouseDown, true);
                        Invalidate(DownChangeRectangle);
                    }
                }
            }
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnMouseMove(mevent);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnMouseDown"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.Control.OnMouseDown'/> event.
        ///    </para>
        /// </devdoc>
        protected override void OnMouseDown(MouseEventArgs mevent) {
            Debug.Assert(Enabled, "ButtonBase.OnMouseDown should not be called if the button is disabled");
            if (mevent.Button == MouseButtons.Left) {
                SetFlag(FlagMouseDown, true);
                SetFlag(FlagMousePressed, true);
                Invalidate(DownChangeRectangle);
            }
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnMouseDown(mevent);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnMouseUp"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnMouseUp'/> event.
        ///       
        ///    </para>
        /// </devdoc>
        protected override void OnMouseUp(MouseEventArgs mevent) {
            base.OnMouseUp(mevent);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.ResetFlagsandPaint"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Used for quick re-painting of the button after the pressed state.
        ///    </para>
        /// </devdoc>
        protected void ResetFlagsandPaint() {
            SetFlag(FlagMousePressed, false);
            SetFlag(FlagMouseDown, false);
            Invalidate(DownChangeRectangle);
            Update();
        }
 
        /// <devdoc>
        ///     Central paint dispatcher to one of the three styles of painting.
        /// </devdoc>
        private void PaintControl(PaintEventArgs pevent) {        
            Debug.Assert(GetStyle(ControlStyles.UserPaint), "Shouldn't be in PaintControl when control is not UserPaint style");
            Adapter.Paint(pevent);
        }
 
        public override Size GetPreferredSize( Size proposedSize ) {
            // TableLayoutPanel passes width = 1 to get the minimum autosize width, since Buttons word-break text
            // that width would be the size of the widest caracter in the text.  We need to make the proposed size
            // unbounded.  
            // This is the same as what Label does.
            if( proposedSize.Width == 1 ) {
                proposedSize.Width = 0;
            }
            if( proposedSize.Height == 1 ) {
                proposedSize.Height = 0;
            }
            return base.GetPreferredSize( proposedSize );
        }
 
        internal override Size GetPreferredSizeCore(Size proposedConstraints) {
            Size prefSize = Adapter.GetPreferredSizeCore(proposedConstraints);
            return LayoutUtils.UnionSizes(prefSize + Padding.Size, MinimumSize);
        }
 
        private ButtonBaseAdapter  _adapter = null;
        private FlatStyle          _cachedAdapterType;
 
        internal ButtonBaseAdapter Adapter {
            get {
                if(_adapter == null || FlatStyle != _cachedAdapterType) {
                    switch (FlatStyle) {
                        case FlatStyle.Standard:
                            _adapter = CreateStandardAdapter();
                            break;
                        case FlatStyle.Popup:
                            _adapter = CreatePopupAdapter();
                            break;
                        case FlatStyle.Flat:
                            _adapter = CreateFlatAdapter();;
                            break;
                        default:
                            Debug.Fail("Unsupported FlatStyle: '" + FlatStyle + '"');
                            break;
                    }
                    _cachedAdapterType = FlatStyle;
                }
                return _adapter;
            }
        }
 
        internal virtual ButtonBaseAdapter CreateFlatAdapter() {
            Debug.Fail("Derived classes need to provide a meaningful implementation.");
            return null;
        }
 
        internal virtual ButtonBaseAdapter CreatePopupAdapter() {
            Debug.Fail("Derived classes need to provide a meaningful implementation.");
            return null;
        }
            
        internal virtual ButtonBaseAdapter CreateStandardAdapter() {
            Debug.Fail("Derived classes need to provide a meaningful implementation.");
            return null;
        }
 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        internal virtual StringFormat CreateStringFormat() {
            if( Adapter == null ) {
                Debug.Fail("Adapter not expected to be null at this point");
                return new StringFormat();
            }
            return Adapter.CreateStringFormat();
        }
 
        internal virtual TextFormatFlags CreateTextFormatFlags() {
            if( Adapter == null ) {
                Debug.Fail( "Adapter not expected to be null at this point" );
                return TextFormatFlags.Default;
            }
            return Adapter.CreateTextFormatFlags();
        }
 
        private void OnFrameChanged(object o, EventArgs e) {
            if (Disposing || IsDisposed) {
                return;
            }
            if (IsHandleCreated && InvokeRequired) {
                BeginInvoke(new EventHandler(this.OnFrameChanged), new object[]{o,e});
                return;
            }
 
            Invalidate();
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnEnabledChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnEnabledChanged(EventArgs e) {
            base.OnEnabledChanged(e);
            Animate();
            if (!Enabled) {
                // disabled button is always "up"
                SetFlag(FlagMouseDown, false);
                SetFlag(FlagMouseOver, false);
                Invalidate();
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnTextChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnTextChanged(EventArgs e) {
            using(LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.Text)) {
                base.OnTextChanged(e);
                Invalidate();
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnKeyDown"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnKeyDown'/> event.
        ///       
        ///    </para>
        /// </devdoc>
        protected override void OnKeyDown(KeyEventArgs kevent) {
            Debug.Assert(Enabled, "ButtonBase.OnKeyDown should not be called if the button is disabled");
            if (kevent.KeyData == Keys.Space) {
                if (!GetFlag(FlagMouseDown)) {
                    SetFlag(FlagMouseDown, true);
                    // It looks like none of the "SPACE" key downs generate the BM_SETSTATE.
                    // This causes to not draw the focus rectangle inside the button and also
                    // not paint the button as "un-depressed".
                    //
                    if(!OwnerDraw) {
                        SendMessage(NativeMethods.BM_SETSTATE, 1, 0);
                    }
                    Invalidate(DownChangeRectangle);
                }
                kevent.Handled = true;
            }
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnKeyDown(kevent);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnKeyUp"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnKeyUp'/> event.
        ///       
        ///    </para>
        /// </devdoc>
        protected override void OnKeyUp(KeyEventArgs kevent) {
            if (GetFlag(FlagMouseDown) && !ValidationCancelled) {
                if (OwnerDraw) {
                    ResetFlagsandPaint();
                }
                else {
                    SetFlag(FlagMousePressed, false);
                    SetFlag(FlagMouseDown, false);
                    SendMessage(NativeMethods.BM_SETSTATE, 0, 0);
                }
                // VSWhidbey 498398: Breaking change: specifically filter out Keys.Enter and Keys.Space as the only
                // two keystrokes to execute OnClick.  
                if (kevent.KeyCode == Keys.Enter || kevent.KeyCode == Keys.Space) {
                    OnClick(EventArgs.Empty);
                }
                kevent.Handled = true;
            }
            // call base last, so if it invokes any listeners that disable the button, we
            // don't have to recheck
            base.OnKeyUp(kevent);
            
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnPaint"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///    <para>
        ///       Raises the <see cref='System.Windows.Forms.ButtonBase.OnPaint'/> event.
        ///       
        ///    </para>
        /// </devdoc>
        protected override void OnPaint(PaintEventArgs pevent) {
            if( AutoEllipsis ){
                Size preferredSize = PreferredSize;
                ShowToolTip = (this.ClientRectangle.Width < preferredSize.Width || this.ClientRectangle.Height < preferredSize.Height);
            }
            else {
                ShowToolTip = false;
            }
 
            if (GetStyle(ControlStyles.UserPaint)) {
                Animate();
                ImageAnimator.UpdateFrames(this.Image);
 
                PaintControl(pevent);
            }
            base.OnPaint(pevent);
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnParentChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnParentChanged(EventArgs e) {
            base.OnParentChanged(e);
            Animate();
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.OnVisibleChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void OnVisibleChanged(EventArgs e) {
            base.OnVisibleChanged(e);
            Animate();
        }
 
        private void ResetImage() {
            Image = null;
        }
 
        private void SetFlag(int flag, bool value) {
            bool oldValue = ((state & flag) != 0);
 
            if (value) {
                state |= flag;
            }
            else {
                state &= ~flag;
            }
 
            if (OwnerDraw && (flag & FlagMouseDown) != 0 && value != oldValue) {
                AccessibilityNotifyClients(AccessibleEvents.StateChange, -1);
            }
        }
        
        private bool ShouldSerializeImage() {
            return image != null;
        }
        
        private void UpdateOwnerDraw() {
            if (OwnerDraw != GetStyle(ControlStyles.UserPaint)) {
                SetStyle(ControlStyles.UserMouse | ControlStyles.UserPaint, OwnerDraw);
                RecreateHandle();
            }
        }
 
        /// <devdoc>
        ///     Determines whether to use compatible text rendering engine (GDI+) or not (GDI).
        /// </devdoc>
        [
        DefaultValue(false),
        SRCategory(SR.CatBehavior),
        SRDescription(SR.UseCompatibleTextRenderingDescr)
        ]
        public bool UseCompatibleTextRendering {
            get{
                return base.UseCompatibleTextRenderingInt;
            }
            set{
                base.UseCompatibleTextRenderingInt = value;
            }
        }
 
        /// <devdoc>
        ///     Determines whether the control supports rendering text using GDI+ and GDI.
        ///     This is provided for container controls to iterate through its children to set UseCompatibleTextRendering to the same
        ///     value if the child control supports it.
        /// </devdoc>
        internal override bool SupportsUseCompatibleTextRendering {
            get {
                return true;
            }
        }
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.UseVisualStyleBackColor"]/*' />
        /// <internalonly/>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.ButtonUseVisualStyleBackColorDescr)
        ]
        public bool UseVisualStyleBackColor {
            get {
                if (isEnableVisualStyleBackgroundSet || ((RawBackColor.IsEmpty) && (BackColor == SystemColors.Control)))
                {
                	return enableVisualStyleBackground;
                }
                else
                {
                	return false;
                }
 
            }            
            set {
                isEnableVisualStyleBackgroundSet = true;                
                enableVisualStyleBackground = value;
                this.Invalidate();
            }
        }
 
        private void ResetUseVisualStyleBackColor() {
            isEnableVisualStyleBackgroundSet = false;
            enableVisualStyleBackground = true;
            this.Invalidate();
        }
 
        private bool ShouldSerializeUseVisualStyleBackColor() {
            return isEnableVisualStyleBackgroundSet;
        }
        
 
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBase.WndProc"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
 
            switch (m.Msg) {
                // NDPWhidbey 28043 -- we don't respect this because the code below eats BM_SETSTATE.
                // so we just invoke the click.
                //
                case NativeMethods.BM_CLICK:
                    if (this is IButtonControl) {
                        ((IButtonControl)this).PerformClick();
                    }
                    else {
                        OnClick(EventArgs.Empty);
                    }
                    return;
            }
 
            if (OwnerDraw) {
                switch (m.Msg) {
                    case NativeMethods.BM_SETSTATE:
                        // Ignore BM_SETSTATE -- Windows gets confused and paints
                        // things, even though we are ownerdraw. See ASURT 38669.
                        break;
 
                    case NativeMethods.WM_KILLFOCUS:
                    case NativeMethods.WM_CANCELMODE:
                    case NativeMethods.WM_CAPTURECHANGED:
                        if (!GetFlag(FlagInButtonUp) && GetFlag(FlagMousePressed)) {
                            SetFlag(FlagMousePressed, false);
 
                            if (GetFlag(FlagMouseDown)) {
                                SetFlag(FlagMouseDown, false);
                                Invalidate(DownChangeRectangle);
                            }
                        }
                        base.WndProc(ref m);
                        break;
 
                    case NativeMethods.WM_LBUTTONUP:
                    case NativeMethods.WM_MBUTTONUP:
                    case NativeMethods.WM_RBUTTONUP:
                        try {
                            SetFlag(FlagInButtonUp, true);
                            base.WndProc(ref m);
                        }
                        finally {
                            SetFlag(FlagInButtonUp, false);
                        }
                        break;
 
                    default:
                        base.WndProc(ref m);
                        break;
                }
            }
            else {
                switch (m.Msg) {
                    case NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND:
                        if (NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.BN_CLICKED && !ValidationCancelled) {
                            OnClick(EventArgs.Empty);
                        }
                        break;
                    default:
                        base.WndProc(ref m);
                        break;
                }
            }
        }
        
        /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBaseAccessibleObject"]/*' />
        /// <internalonly/>
        [System.Runtime.InteropServices.ComVisible(true)]        
        public class ButtonBaseAccessibleObject : ControlAccessibleObject {
            
            /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBaseAccessibleObject.ButtonBaseAccessibleObject"]/*' />
            public ButtonBaseAccessibleObject(Control owner) : base(owner) {
            }
 
            /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBaseAccessibleObject.DoDefaultAction"]/*' />
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public override void DoDefaultAction() {
                ((ButtonBase)Owner).OnClick(EventArgs.Empty);
            }
            
            /// <include file='doc\ButtonBase.uex' path='docs/doc[@for="ButtonBaseAccessibleObject.State"]/*' />
            public override AccessibleStates State {
                get {
                    AccessibleStates state = base.State;
 
                    ButtonBase owner = (ButtonBase) Owner;
                    if (owner.OwnerDraw && owner.MouseIsDown) {
                        state |= AccessibleStates.Pressed;
                    }
 
                    return state;
                }
            }                        
 
        }
    }
}