File: winforms\Managed\System\WinForms\ToolStripMenuItem.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ToolStripMenuItem.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using Microsoft.Win32;
    using System.Drawing.Imaging;
    using System.Threading;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Forms.Layout;   
    using System.Security;
    using System.Security.Permissions;
    using System.Runtime.InteropServices;
    using System.ComponentModel.Design.Serialization;
    using System.Windows.Forms.Design; 
    using System.Globalization;
    using System.Windows.Forms.Internal;    
    using System.Runtime.Versioning;
 
    /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem"]/*' />
    /// <devdoc>
    /// ToolStripMenuItem
    /// </devdoc>
    [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)]
    [DesignerSerializer("System.Windows.Forms.Design.ToolStripMenuItemCodeDomSerializer, " + AssemblyRef.SystemDesign, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + AssemblyRef.SystemDesign)] 
    public class ToolStripMenuItem : ToolStripDropDownItem {
 
        private static MenuTimer menuTimer                             = new MenuTimer();
 
        private static readonly int PropShortcutKeys                   = PropertyStore.CreateKey();
        private static readonly int PropCheckState                     = PropertyStore.CreateKey();
        private static readonly int PropMdiForm                        = PropertyStore.CreateKey();
 
        private bool checkOnClick                                      = false;
        private bool showShortcutKeys                                  = true;
        private ToolStrip lastOwner                                    = null;
 
        // SUPPORT for mapping NATIVE menu commands to ToolStripMenuItems -----
        // corresponds to wID in MENUITEMINFO structure
        private int     nativeMenuCommandID                               = -1;
        private IntPtr  targetWindowHandle                                = IntPtr.Zero;
        private IntPtr  nativeMenuHandle                                  = IntPtr.Zero;
        
        // Keep checked images shared between menu items, but per thread so we dont have locking issues in GDI+
        [ThreadStatic]
        private static Image indeterminateCheckedImage;
        
        [ThreadStatic]
        private static Image checkedImage;
 
        private string shortcutKeyDisplayString;
        private string cachedShortcutText;
        private Size cachedShortcutSize = Size.Empty;
 
        private static readonly Padding defaultPadding = new Padding(4, 0, 4, 0);
        private static readonly Padding defaultDropDownPadding = new Padding(0, 1, 0, 1);
        private static readonly Size checkMarkBitmapSize = new Size(16, 16);
        private Padding scaledDefaultPadding = defaultPadding;
        private Padding scaledDefaultDropDownPadding = defaultDropDownPadding;
        private Size scaledCheckMarkBitmapSize = checkMarkBitmapSize;
 
        private byte openMouseId = 0;
    
        private static readonly object EventCheckedChanged = new object();
        private static readonly object EventCheckStateChanged = new object();
            
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.ToolStripMenuItem"]/*' />
        public ToolStripMenuItem() : base() {
            Initialize(); // all additional work should be done in Initialize
        }
        public ToolStripMenuItem(string text):base(text,null,(EventHandler)null) {
            Initialize();
        }
        public ToolStripMenuItem(Image image):base(null,image,(EventHandler)null) {
            Initialize();
        }
        public ToolStripMenuItem(string text, Image image):base(text,image,(EventHandler)null) {
            Initialize();
        }
        public ToolStripMenuItem(string text, Image image, EventHandler onClick):base(text,image,onClick) {
            Initialize();
        }
        public ToolStripMenuItem(string text, Image image, EventHandler onClick, string name) : base(text,image,onClick, name){
            Initialize();
        }            
        public ToolStripMenuItem(string text, Image image, params ToolStripItem[] dropDownItems):base(text,image,dropDownItems) {
            Initialize();
        }
        public ToolStripMenuItem(string text, Image image, EventHandler onClick, Keys shortcutKeys):base(text,image,onClick) {
            Initialize();
            this.ShortcutKeys = shortcutKeys;
        }
        internal ToolStripMenuItem(Form mdiForm) {
            Initialize();
            Properties.SetObject(PropMdiForm,mdiForm);
        }
 
        /// <devdoc> this constructor is only used when we're trying to
        ///          mimic a native menu like the system menu.  In that case
        ///          we've got to go ahead and collect the command id and the
        ///          target window to send WM_COMMAND/WM_SYSCOMMAND messages to.
        /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        internal ToolStripMenuItem(IntPtr hMenu, int nativeMenuCommandId, IWin32Window targetWindow) {
            Initialize();
            this.Overflow                   = ToolStripItemOverflow.Never;
            this.nativeMenuCommandID        = nativeMenuCommandId;
            this.targetWindowHandle         = Control.GetSafeHandle(targetWindow);
            this.nativeMenuHandle           = hMenu;
 
            // Since fetching the image and the text is an awful lot of work
            // we're going to just cache it and assume the native stuff 
            // doesnt update.
            // we'll only live-update enabled.
            // if this becomes a problem we can override Image and Text properties
            // to live-return the results.
 
            // fetch image
            this.Image = GetNativeMenuItemImage();
            this.ImageScaling = ToolStripItemImageScaling.None;
 
            // fetch text
            string text = GetNativeMenuItemTextAndShortcut();
 
            // the shortcut is tab separated from the item text.
            if (text != null) {
                // separate out the two fields.
                string[] textFields = text.Split('\t');
 
                if (textFields.Length >= 1){
                    this.Text = textFields[0];
                }
 
                if (textFields.Length >= 2) {
                    // VSWhidbey 448242: We dont care about the shortcut here, the OS is going to 
                    // handle it for us by sending a WM_(SYS)COMMAND during TranslateAcellerator
                    // Just display whatever the OS would have.
                    this.ShowShortcutKeys = true;
                    this.ShortcutKeyDisplayString = textFields[1];
                }
            }
        }
 
        internal override void AutoHide(ToolStripItem otherItemBeingSelected) {     
            if (IsOnDropDown) {
                MenuTimer.Transition(this,otherItemBeingSelected as ToolStripMenuItem);
            }
            else {
                base.AutoHide(otherItemBeingSelected);
            }
        }
        private void ClearShortcutCache() {
            cachedShortcutSize = Size.Empty;
            cachedShortcutText = null;
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.CreateDefaultDropDown"]/*' />
        protected override ToolStripDropDown CreateDefaultDropDown() {
            // AutoGenerate a Winbar DropDown - set the property so we hook events
             return new ToolStripDropDownMenu(this, true);
        }
 
        internal override ToolStripItemInternalLayout CreateInternalLayout() {
              return new ToolStripMenuItemInternalLayout(this);
        }
 
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override AccessibleObject CreateAccessibilityInstance() {
            return new ToolStripMenuItemAccessibleObject(this);
        }
 
        private void Initialize() {
            if (DpiHelper.EnableToolStripHighDpiImprovements) {
                scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding);
                scaledDefaultDropDownPadding = DpiHelper.LogicalToDeviceUnits(defaultDropDownPadding);
                scaledCheckMarkBitmapSize = DpiHelper.LogicalToDeviceUnits(checkMarkBitmapSize);
            }
 
            this.Overflow                   = ToolStripItemOverflow.Never;
            this.MouseDownAndUpMustBeInSameItem = false;
            this.SupportsDisabledHotTracking = true;
        }
    
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.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 DpiHelper.EnableToolStripPerMonitorV2HighDpiImprovements ?
                       DpiHelper.LogicalToDeviceUnits(new Size(32, 19), DeviceDpi) :
                       new Size(32, 19);
            }
        }
 
 
        /// <include file='doc\WinBarMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.DefaultMargin"]/*' />
        protected internal override Padding DefaultMargin {
            get {
                 return Padding.Empty;
            }
        }
        /// <include file='doc\WinBarMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.DefaultPadding"]/*' />
        protected override Padding DefaultPadding {
            get {
                if (IsOnDropDown) {
                    return scaledDefaultDropDownPadding;
                }
                else {
                    return scaledDefaultPadding;
                }
            }
        }
 
 
        public override bool Enabled {
           get{
                if (nativeMenuCommandID != -1) {
                    // if we're based off a native menu item,
                    // we need to ask it if it's enabled.
                    if (base.Enabled && nativeMenuHandle != IntPtr.Zero && targetWindowHandle != IntPtr.Zero) {
                        return GetNativeMenuItemEnabled();
                    }
                    return false;
                }
                else {
                    return base.Enabled;
                }
           }
           set {
                base.Enabled = value;
           }
        }
      
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.Checked"]/*' />
        /// <devdoc>
        /// <para>
        /// Gets or sets a value indicating whether the item is checked.
        /// </para>
        /// </devdoc>
        [
        Bindable(true),
        DefaultValue(false),
        SRCategory(SR.CatAppearance),
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.CheckBoxCheckedDescr)
        ]
        public bool Checked {
            get {
                return CheckState != CheckState.Unchecked;
            }
 
            set {
                if (value != Checked) {
                    CheckState = value ? CheckState.Checked : CheckState.Unchecked;
                    InvokePaint();
                }
            }
        }
 
 
        /// <devdoc>
        /// Keeps a shared copy of the checked image between all menu items
        /// Fishes out the appropriate one based on CheckState.
        /// </devdoc>
        internal Image CheckedImage {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                CheckState checkedState = CheckState;
           
                if (checkedState == CheckState.Indeterminate) {
                    if (indeterminateCheckedImage == null) {
                        if (DpiHelper.EnableToolStripHighDpiImprovements) {
                            indeterminateCheckedImage = GetBitmapFromIcon("IndeterminateChecked.ico", scaledCheckMarkBitmapSize);
                        }
                        else {
                            Bitmap indeterminateCheckedBmp = new Bitmap(typeof(ToolStripMenuItem), "IndeterminateChecked.bmp");
                            if (indeterminateCheckedBmp != null) {
                                // 
                                indeterminateCheckedBmp.MakeTransparent(indeterminateCheckedBmp.GetPixel(1, 1));
                                if (DpiHelper.IsScalingRequired) {
                                    DpiHelper.ScaleBitmapLogicalToDevice(ref indeterminateCheckedBmp);
                                }
                                indeterminateCheckedImage = indeterminateCheckedBmp;
                            }
                        }
                    }
                    return indeterminateCheckedImage;
                }
                else if (checkedState == CheckState.Checked)  {
                    if (checkedImage == null) {
                        if (DpiHelper.EnableToolStripHighDpiImprovements) {
                            checkedImage = GetBitmapFromIcon("Checked.ico", scaledCheckMarkBitmapSize);
                        }
                        else {
                            Bitmap checkedBmp = new Bitmap(typeof(ToolStripMenuItem), "Checked.bmp");
                            if (checkedBmp != null) {
                                // 
                                checkedBmp.MakeTransparent(checkedBmp.GetPixel(1, 1));
                                if (DpiHelper.IsScalingRequired) {
                                    DpiHelper.ScaleBitmapLogicalToDevice(ref checkedBmp);
                                }
                                checkedImage = checkedBmp;
                            }
                        }
                    }
                    return checkedImage;
                }
                return null;
                
            }
        }
        
        private static Bitmap GetBitmapFromIcon(string iconName, Size desiredIconSize)
        {
            Bitmap b = null;
 
            Icon icon = new Icon(typeof(ToolStripMenuItem), iconName);
            if (icon != null)
            {
                Icon desiredIcon = new Icon(icon, desiredIconSize);
                if (desiredIcon != null)
                {
                    try
                    {
                        b = desiredIcon.ToBitmap();
 
                        if (b != null)
                        {
                            b.MakeTransparent(b.GetPixel(1, 1));
                            if (DpiHelper.IsScalingRequired && (b.Size.Width != desiredIconSize.Width || b.Size.Height != desiredIconSize.Height))
                            {
                                Bitmap scaledBitmap = DpiHelper.CreateResizedBitmap(b, desiredIconSize);
                                if (scaledBitmap != null)
                                {
                                    b.Dispose();
                                    b = scaledBitmap;
                                }
                            }
                        }
                    }
                    finally
                    {
                        icon.Dispose();
                        desiredIcon.Dispose();
                    }
                }
            }
 
            return b;
        }
 
         /// <include file='doc\WinBarMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.CheckOnClick"]/*' />
         [
         DefaultValue(false),
         SRCategory(SR.CatBehavior),
         SRDescription(SR.ToolStripButtonCheckOnClickDescr)
         ]
         public bool CheckOnClick {
             get {
                 return checkOnClick;
             }
             set {
                 checkOnClick = value;
             }
         }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.CheckState"]/*' />
        /// <devdoc>
        /// <para>Gets
        /// or sets a value indicating whether the check box is checked.</para>
        /// </devdoc>
        [
        Bindable(true),
        SRCategory(SR.CatAppearance),
        DefaultValue(CheckState.Unchecked),
        RefreshProperties(RefreshProperties.All),
        SRDescription(SR.CheckBoxCheckStateDescr)
        ]
        public CheckState CheckState {
            get {
                bool found = false;
                object checkState = Properties.GetInteger(PropCheckState, out found);
                return (found) ? (CheckState)checkState : CheckState.Unchecked;
            }
 
            set {
                //valid values are 0x0 to 0x2
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)CheckState.Unchecked, (int)CheckState.Indeterminate))
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(CheckState));
                }
                  
                if (value != CheckState) {
                    Properties.SetInteger(PropCheckState, (int)value);
                    OnCheckedChanged(EventArgs.Empty);
                    OnCheckStateChanged(EventArgs.Empty);               
                }
            }
        }
        
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.CheckedChanged"]/*' />
        /// <devdoc>
        /// <para>Occurs when the
        /// value of the <see cref='System.Windows.Forms.CheckBox.Checked'/>
        /// property changes.</para>
        /// </devdoc>
        [SRDescription(SR.CheckBoxOnCheckedChangedDescr)]
        public event EventHandler CheckedChanged {
            add {
                Events.AddHandler(EventCheckedChanged, value);
            }
            remove {
                Events.RemoveHandler(EventCheckedChanged, value);
            }
        }   
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.CheckStateChanged"]/*' />
        /// <devdoc>
        /// <para>Occurs when the
        /// value of the <see cref='System.Windows.Forms.CheckBox.CheckState'/>
        /// property changes.</para>
        /// </devdoc>
        [SRDescription(SR.CheckBoxOnCheckStateChangedDescr)]
        public event EventHandler CheckStateChanged {
            add {
                Events.AddHandler(EventCheckStateChanged, value);
            }
            remove {
                Events.RemoveHandler(EventCheckStateChanged, value);
            }
        }
 
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.Overflow"]/*' />
        /// <devdoc>
        /// <para>Specifies whether or not the item is glued to the winbar or overflow or
        /// can float between the two.</para>
        /// </devdoc>
        [
        DefaultValue(ToolStripItemOverflow.Never),
        SRDescription(SR.ToolStripItemOverflowDescr),
        SRCategory(SR.CatLayout)
     	]
        public new ToolStripItemOverflow Overflow {
            get { 
                return base.Overflow;
            }
            set { 
                base.Overflow = value;
            }
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.ShortcutKeys"]/*' />
        /// <devdoc>
        /// <para>
        /// Gets or sets the shortcut keys associated with the menu
        /// item.
        /// </para>
        /// </devdoc>
        [
        Localizable(true),
        DefaultValue(Keys.None),
        SRDescription(SR.MenuItemShortCutDescr)
        ]
        public Keys ShortcutKeys {
            get {
                bool found = false;
                object shortcutKeys = Properties.GetInteger(PropShortcutKeys, out found );
                return (found) ? (Keys)shortcutKeys : Keys.None;
            }
            set {
                if ((value != Keys.None) && !ToolStripManager.IsValidShortcut(value)){
                    // prevent use of alt, ctrl, shift modifiers with no key code.
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(Keys));
                }
                Keys originalShortcut = ShortcutKeys;
                if (originalShortcut != value) {
                    ClearShortcutCache();
                    ToolStrip owner = this.Owner;
                    if (owner != null) {
                        // add to the shortcut caching system.
                        if (originalShortcut != Keys.None) {
                            owner.Shortcuts.Remove(originalShortcut);
                        }
                        if (owner.Shortcuts.Contains(value)) {
                            // last one in wins.
                            owner.Shortcuts[value] = this;
                        }
                        else {
                            owner.Shortcuts.Add(value, this);
                        }
                    }
                    Properties.SetInteger(PropShortcutKeys, (int)value);
                    
                    if (ShowShortcutKeys && IsOnDropDown) { 
                        ToolStripDropDownMenu parent = GetCurrentParentDropDown() as ToolStripDropDownMenu;
                        if (parent != null) {
                            LayoutTransaction.DoLayout(this.ParentInternal, this, "ShortcutKeys");
                            parent.AdjustSize();
                        }
                    }
                }
            }
            
        }
 
        [
        SRDescription(SR.ToolStripMenuItemShortcutKeyDisplayStringDescr),
        SRCategory(SR.CatAppearance),
        DefaultValue(null),
        Localizable(true)
        ]
        public string ShortcutKeyDisplayString {
            get {
                return shortcutKeyDisplayString;
            }
            set {
                if (shortcutKeyDisplayString != value) {
                    shortcutKeyDisplayString = value;
                    ClearShortcutCache();
                    if (ShowShortcutKeys) {
                        ToolStripDropDown parent = this.ParentInternal as ToolStripDropDown;
                        if (parent != null) {
                            LayoutTransaction.DoLayout(parent, this, "ShortcutKeyDisplayString");
                            parent.AdjustSize();
                        }
                    }
                }
            }
        }
                    
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.ShowShortcutKeys"]/*' />
        /// <devdoc>
        /// <para>
        /// Gets or sets a value that indicates whether the shortcut
        /// keys that are assocaited
        /// with the menu item are displayed next to the menu item
        /// caption.
        /// </para>
        /// </devdoc>
        [
        DefaultValue(true),
        Localizable(true),
        SRDescription(SR.MenuItemShowShortCutDescr)
        ]
        public bool ShowShortcutKeys {
            get {
                return showShortcutKeys;
            }
            set {
                if (value != showShortcutKeys) {
                   ClearShortcutCache();
                   showShortcutKeys = value;
                   ToolStripDropDown parent = this.ParentInternal as ToolStripDropDown;
                   if (parent != null) {
                        LayoutTransaction.DoLayout(parent, this, "ShortcutKeys");
                        parent.AdjustSize();
                       
                    }
                }
            }
        }
 
 
        /// <devdoc>
        /// An item is toplevel if it is parented to anything other than a ToolStripDropDownMenu
        /// This implies that a ToolStripMenuItem in an overflow IS a toplevel item
        /// </devdoc>
        internal bool IsTopLevel {
            get {
                return (this.ParentInternal as ToolStripDropDown == null);
            }
        }
 
        [Browsable(false)]
        public bool IsMdiWindowListEntry {
            get{
                return MdiForm != null;
            }
        }
 
        internal static MenuTimer MenuTimer {
            get {
                return menuTimer;
            }
        }
        
 
        /// <devdoc> Tag property for internal use </devdoc>
        internal Form MdiForm {
            get {
                if (Properties.ContainsObject(PropMdiForm)) {
                    return Properties.GetObject(PropMdiForm) as Form;
                }
                return null;
                
            }
        }
 
        internal ToolStripMenuItem Clone() {
 
            // dirt simple clone - just properties, no subitems
            
            ToolStripMenuItem menuItem = new ToolStripMenuItem();
            menuItem.Events.AddHandlers(this.Events);
 
            menuItem.AccessibleName = this.AccessibleName;
            menuItem.AccessibleRole = this.AccessibleRole;
            menuItem.Alignment = this.Alignment;
            menuItem.AllowDrop = this.AllowDrop;
            menuItem.Anchor = this.Anchor;
            menuItem.AutoSize = this.AutoSize;
            menuItem.AutoToolTip = this.AutoToolTip;
            menuItem.BackColor = this.BackColor;
            menuItem.BackgroundImage = this.BackgroundImage;
            menuItem.BackgroundImageLayout = this.BackgroundImageLayout;
            menuItem.Checked = this.Checked;
            menuItem.CheckOnClick = this.CheckOnClick;
            menuItem.CheckState = this.CheckState;
            menuItem.DisplayStyle = this.DisplayStyle;
            menuItem.Dock = this.Dock;
            menuItem.DoubleClickEnabled = this.DoubleClickEnabled;
            menuItem.Enabled = this.Enabled;
            menuItem.Font = this.Font;
            menuItem.ForeColor = this.ForeColor;
            menuItem.Image = this.Image;
            menuItem.ImageAlign = this.ImageAlign;
            menuItem.ImageScaling = this.ImageScaling;
            menuItem.ImageTransparentColor = this.ImageTransparentColor;
            menuItem.Margin = this.Margin;
            menuItem.MergeAction = this.MergeAction;
            menuItem.MergeIndex = this.MergeIndex;
            menuItem.Name = this.Name;
            menuItem.Overflow = this.Overflow;
            menuItem.Padding = this.Padding;
            menuItem.RightToLeft= this.RightToLeft;
 
            // No settings support for cloned items.
            // menuItem.SaveSettings= this.SaveSettings;
            // menuItem.SettingsKey = this.SettingsKey;
 
            menuItem.ShortcutKeys = this.ShortcutKeys;
            menuItem.ShowShortcutKeys = this.ShowShortcutKeys;
            menuItem.Tag = this.Tag;
            menuItem.Text = this.Text;
            menuItem.TextAlign = this.TextAlign;
            menuItem.TextDirection = this.TextDirection;
            menuItem.TextImageRelation = this.TextImageRelation;
            menuItem.ToolTipText = this.ToolTipText;
 
            // cant actually use "Visible" property as that returns whether or not the parent 
            // is visible too.. instead use ParticipatesInLayout as this queries the actual state.
            menuItem.Visible = ((IArrangedElement)this).ParticipatesInLayout;
 
            if (!AutoSize) {
                menuItem.Size = this.Size;
            }
            return menuItem;
       }
 
        internal override int DeviceDpi {
            get {
                return base.DeviceDpi;
            }
 
            // This gets called via ToolStripItem.RescaleConstantsForDpi.
            // It's practically calling Initialize on DpiChanging with the new Dpi value.
            // ToolStripItem.RescaleConstantsForDpi is already behind a quirk.
            set {
                base.DeviceDpi = value;
                scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding, value);
                scaledDefaultDropDownPadding = DpiHelper.LogicalToDeviceUnits(defaultDropDownPadding, value);
                scaledCheckMarkBitmapSize = DpiHelper.LogicalToDeviceUnits(checkMarkBitmapSize, value);
            }
        }
 
        protected override void Dispose(bool disposing) {
            if (disposing) {
                if (lastOwner != null) {
                    Keys shortcut = this.ShortcutKeys;
                    if (shortcut != Keys.None && lastOwner.Shortcuts.ContainsKey(shortcut)) {
                        lastOwner.Shortcuts.Remove(shortcut);
                    }
                    lastOwner = null;
                    if (MdiForm != null) {
                        Properties.SetObject(PropMdiForm,null);
                    }
                        
                }
            }
            base.Dispose(disposing);
        }
 
        private bool GetNativeMenuItemEnabled() {
            if (nativeMenuCommandID == -1 || nativeMenuHandle == IntPtr.Zero) {
                Debug.Fail("why were we called to fetch native menu item info with nothing assigned?");
                return false;
            }
            NativeMethods.MENUITEMINFO_T_RW info = new NativeMethods.MENUITEMINFO_T_RW();
            info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MENUITEMINFO_T_RW));
            info.fMask = NativeMethods.MIIM_STATE;
            info.fType = NativeMethods.MIIM_STATE;
            info.wID = nativeMenuCommandID;
            UnsafeNativeMethods.GetMenuItemInfo(new HandleRef(this, nativeMenuHandle), nativeMenuCommandID, /*fByPosition instead of ID=*/ false, info);
 
            return ((info.fState & NativeMethods.MFS_DISABLED) == 0);
        }
 
        // returns text and shortcut separated by tab.
        private string GetNativeMenuItemTextAndShortcut() {
            
            if (nativeMenuCommandID == -1 || nativeMenuHandle == IntPtr.Zero) {
                Debug.Fail("why were we called to fetch native menu item info with nothing assigned?");
                return null;
            }
            string text = null;
            
            // fetch the string length
            NativeMethods.MENUITEMINFO_T_RW info = new NativeMethods.MENUITEMINFO_T_RW();
            info.fMask = NativeMethods.MIIM_STRING;
            info.fType = NativeMethods.MIIM_STRING;
            info.wID = nativeMenuCommandID;
            info.dwTypeData = IntPtr.Zero;
            UnsafeNativeMethods.GetMenuItemInfo(new HandleRef(this, nativeMenuHandle), nativeMenuCommandID, /*fByPosition instead of ID=*/  false, info);
 
            if (info.cch > 0) {
                // fetch the string
                info.cch += 1;  // according to MSDN we need to increment the count we receive by 1.
                info.wID = nativeMenuCommandID;
                IntPtr allocatedStringBuffer = Marshal.AllocCoTaskMem(info.cch * Marshal.SystemDefaultCharSize);
                info.dwTypeData = allocatedStringBuffer;
                
 
                try {
                    UnsafeNativeMethods.GetMenuItemInfo(new HandleRef(this, nativeMenuHandle), nativeMenuCommandID, /*fByPosition instead of ID=*/  false, info);
 
                    // convert the string into managed data.
                	if (info.dwTypeData != IntPtr.Zero){
                        // we have to use PtrToStringAuto as we can't use Marshal.SizeOf to determine
                        // the size of the struct with a StringBuilder member.
                        text = Marshal.PtrToStringAuto(info.dwTypeData, info.cch);
                    }
                }
                finally {
                   if (allocatedStringBuffer != IntPtr.Zero) {
                        // use our local instead of the info structure member *just* in case windows decides to clobber over it.
                        // we want to be sure to deallocate the memory we know we allocated.
                        Marshal.FreeCoTaskMem(allocatedStringBuffer);
                    }
                }
            }
            return text;
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine | ResourceScope.Process, ResourceScope.Machine | ResourceScope.Process)]
        private Image GetNativeMenuItemImage(){
 
            if (nativeMenuCommandID == -1 || nativeMenuHandle == IntPtr.Zero) {
                Debug.Fail("why were we called to fetch native menu item info with nothing assigned?");
                return null;
            }
            
            NativeMethods.MENUITEMINFO_T_RW info = new NativeMethods.MENUITEMINFO_T_RW();
            info.fMask = NativeMethods.MIIM_BITMAP;
            info.fType = NativeMethods.MIIM_BITMAP;
            info.wID = nativeMenuCommandID;
            UnsafeNativeMethods.GetMenuItemInfo(new HandleRef(this, nativeMenuHandle), nativeMenuCommandID, /*fByPosition instead of ID=*/ false, info);
      
            if (info.hbmpItem != IntPtr.Zero && info.hbmpItem.ToInt32() > NativeMethods.HBMMENU_POPUP_MINIMIZE) {
                return Bitmap.FromHbitmap(info.hbmpItem);
            }
            else {   
                // its a system defined bitmap
                int buttonToUse = -1;
 
                switch (info.hbmpItem.ToInt32()) {
                    case NativeMethods.HBMMENU_MBAR_CLOSE:
                    case NativeMethods.HBMMENU_MBAR_CLOSE_D:
                    case NativeMethods.HBMMENU_POPUP_CLOSE:
                        buttonToUse = (int)CaptionButton.Close;
                        break;
 
                    case NativeMethods.HBMMENU_MBAR_MINIMIZE:
                    case NativeMethods.HBMMENU_MBAR_MINIMIZE_D:
                    case NativeMethods.HBMMENU_POPUP_MINIMIZE:
                        buttonToUse = (int)CaptionButton.Minimize;
                        break;
 
                    case NativeMethods.HBMMENU_MBAR_RESTORE:
                    case NativeMethods.HBMMENU_POPUP_RESTORE:
                        buttonToUse = (int)CaptionButton.Restore;
                        break;
 
                    case NativeMethods.HBMMENU_POPUP_MAXIMIZE:
                        buttonToUse = (int)CaptionButton.Maximize;
                        break;
 
                    case NativeMethods.HBMMENU_SYSTEM:
                        // 
                    case NativeMethods.HBMMENU_CALLBACK:
                        // owner draw not supported
                        default:
                        break;
                }
                if (buttonToUse > -1) {
 
                    // we've mapped to a system defined bitmap we know how to draw
                    Bitmap image = new Bitmap(16, 16);
 
                    using (Graphics g = Graphics.FromImage(image)) {
                        ControlPaint.DrawCaptionButton(g, new Rectangle(Point.Empty, image.Size), (CaptionButton)buttonToUse, ButtonState.Flat);
                        g.DrawRectangle(SystemPens.Control, 0, 0, image.Width - 1, image.Height - 1);
                    }
 
                    image.MakeTransparent(SystemColors.Control);
                    return image;
                }
            }
            return null;
        }
 
        
        internal Size GetShortcutTextSize() {
             if (!ShowShortcutKeys) {
                return Size.Empty;
             }
             string shortcutString = GetShortcutText();
             if (string.IsNullOrEmpty(shortcutString)) {
                return Size.Empty;
             }
             else if (cachedShortcutSize == Size.Empty) {
                cachedShortcutSize = TextRenderer.MeasureText(shortcutString, Font);
             }
             return cachedShortcutSize;
        }
 
        internal string GetShortcutText() {
            if (cachedShortcutText == null) {
                cachedShortcutText = ShortcutToText(this.ShortcutKeys, this.ShortcutKeyDisplayString);                 
            }
            return cachedShortcutText;
        }
        
        internal void HandleAutoExpansion() {
            if (Enabled && ParentInternal != null && ParentInternal.MenuAutoExpand && HasDropDownItems) {
                ShowDropDown();
                if (!AccessibilityImprovements.UseLegacyToolTipDisplay) {
                    KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(this);
                }
                DropDown.SelectNextToolStripItem(null, /*forward=*/true);
            }
        }
 
        /// <include file='doc\WinBarMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnClick"]/*' />
        protected override void OnClick(EventArgs e) {
            if (checkOnClick) {
                this.Checked = !this.Checked;
            }
            base.OnClick(e);
            if (nativeMenuCommandID != -1) {
                // fire off the appropriate native handler by posting a message to the window target.
                if ((nativeMenuCommandID & 0xF000) != 0) {
                    // These are system menu items like Minimize, Maximize, Restore, Resize, Move, Close.
                  
                    // use PostMessage instead of SendMessage so that the DefWndProc can appropriately handle
                    // the system message... if we use SendMessage the dismissal of our window
                    // breaks things like the modal sizing loop.
                    UnsafeNativeMethods.PostMessage( new HandleRef(this, targetWindowHandle), NativeMethods.WM_SYSCOMMAND,nativeMenuCommandID, 0);
                }
                else {
                    // These are user added items like ".Net Window..."
                     
                    // be consistent with sending a WM_SYSCOMMAND, use POST not SEND.
                    UnsafeNativeMethods.PostMessage( new HandleRef(this, targetWindowHandle), NativeMethods.WM_COMMAND, nativeMenuCommandID, 0);
                }
                this.Invalidate();
            }
           
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnCheckedChanged"]/*' />
        /// <devdoc>
        /// <para>Raises the <see cref='System.Windows.Forms.ToolStripMenuItem.CheckedChanged'/>
        /// event.</para>
        /// </devdoc>
        protected virtual void OnCheckedChanged(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventCheckedChanged];
            if (handler != null) handler(this,e);
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnCheckStateChanged"]/*' />
        /// <devdoc>
        /// <para>Raises the <see cref='System.Windows.Forms.ToolStripMenuItem.CheckStateChanged'/> event.</para>
        /// </devdoc>
        protected virtual void OnCheckStateChanged(EventArgs e) {     
            AccessibilityNotifyClients(AccessibleEvents.StateChange);
            EventHandler handler = (EventHandler)Events[EventCheckStateChanged];
            if (handler != null) handler(this,e);
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnDropDownHide"]/*' />
        protected override void OnDropDownHide(EventArgs e) {
        
            Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripMenuItem.OnDropDownHide] MenuTimer.Cancel called");
            MenuTimer.Cancel(this);
            base.OnDropDownHide(e);
        }
 
        protected override void OnDropDownShow(EventArgs e) {
            // if someone has beaten us to the punch by arrowing around
            // cancel the current menu timer.            
            Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripMenuItem.OnDropDownShow] MenuTimer.Cancel called");
            MenuTimer.Cancel(this);
            if (ParentInternal != null) {
                ParentInternal.MenuAutoExpand = true;
            }
            base.OnDropDownShow(e);
        }
 
        protected override void OnFontChanged(EventArgs e) {
            ClearShortcutCache();
            base.OnFontChanged(e);
        }
        /// <devdoc/><internalonly/>
        internal void OnMenuAutoExpand() {
            this.ShowDropDown();
        }
 
        
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnMouseDown"]/*' />
        /// <devdoc/>
        protected override void OnMouseDown(MouseEventArgs e) {
 
            // Opening should happen on mouse down
            // we use a mouse down ID to ensure that the reshow
            
            Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripMenuItem.OnMouseDown] MenuTimer.Cancel called");
            MenuTimer.Cancel(this);
            OnMouseButtonStateChange(e, /*isMouseDown=*/true); 
             
        }
 
        protected override void OnMouseUp(MouseEventArgs e) {
           OnMouseButtonStateChange(e, /*isMouseDown=*/false);
           base.OnMouseUp(e);
        }
 
        private void OnMouseButtonStateChange(MouseEventArgs e, bool isMouseDown) {
            bool showDropDown = true;
            if (IsOnDropDown) {
              ToolStripDropDown dropDown = GetCurrentParentDropDown() as ToolStripDropDown;
 
              // VSWhidbey 260536 - right click support for context menus.
              // used in ToolStripItem to determine whether to fire click OnMouseUp.
              SupportsRightClick = (dropDown.GetFirstDropDown() is ContextMenuStrip);
            }
            else {
              showDropDown = !DropDown.Visible;
              SupportsRightClick = false;
            }
 
            if (e.Button == MouseButtons.Left || 
              (e.Button == MouseButtons.Right && SupportsRightClick)) {
              
                if (isMouseDown && showDropDown) {
                    // opening should happen on mouse down.  
                    Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
                    openMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
                    this.ShowDropDown(/*mousePush =*/true);
 
                }
                else if (!isMouseDown && !showDropDown) {
                    // closing should happen on mouse up.  ensure it's not the mouse
                    // up for the mouse down we opened with.
                    Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
                    byte closeMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
                    int openedMouseID =openMouseId;
                    if (closeMouseId != openedMouseID) {
                        openMouseId = 0;  // reset the mouse id, we should never get this value from toolstrip.
                        ToolStripManager.ModalMenuFilter.CloseActiveDropDown(DropDown, ToolStripDropDownCloseReason.AppClicked);
                        Select();
                    }
 
                }
 
            }
        }
 
            
       
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnMouseEnter"]/*' />
        /// <devdoc/>
        protected override void OnMouseEnter(EventArgs e) {
           
            Debug.Assert(this.ParentInternal != null, "Why is parent null");
                            
            // If we are in a submenu pop down the submenu.		
            if (this.ParentInternal != null && this.ParentInternal.MenuAutoExpand && Selected) {
                Debug.WriteLineIf(ToolStripItem.MouseDebugging.TraceVerbose, "received mouse enter - calling drop down");
 
                Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripMenuItem.OnMouseEnter] MenuTimer.Cancel / MenuTimer.Start called");
                
                MenuTimer.Cancel(this);
                MenuTimer.Start(this);
                
            }
            base.OnMouseEnter(e);
        }
 
       
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnMouseLeave"]/*' />
        /// <devdoc/>
        protected override void OnMouseLeave(EventArgs e) {
              Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[ToolStripMenuItem.OnMouseLeave] MenuTimer.Cancel called");
              MenuTimer.Cancel(this);
              base.OnMouseLeave(e);
        }
 
        protected override void OnOwnerChanged(EventArgs e) {
 
            Keys shortcut = this.ShortcutKeys;
            if (shortcut != Keys.None) {
                if (lastOwner != null) {
                    lastOwner.Shortcuts.Remove(shortcut);
                }
 
                if (Owner != null) {
                   if (Owner.Shortcuts.Contains(shortcut)) {
                        // last one in wins
                        Owner.Shortcuts[shortcut] = this;
                   }
                   else {
                        Owner.Shortcuts.Add(shortcut, this);
                   }
                   lastOwner = Owner;
                }
            }
 
            base.OnOwnerChanged(e);
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.OnPaint"]/*' />
        /// <devdoc/>
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {    
 
            if (this.Owner != null) {
                ToolStripRenderer renderer = this.Renderer;
                Graphics g = e.Graphics;
                renderer.DrawMenuItemBackground(new ToolStripItemRenderEventArgs(g, this));
 
                Color textColor = SystemColors.MenuText;
                if (IsForeColorSet) {
                    textColor =  this.ForeColor;
                }
                else if (!this.IsTopLevel || (ToolStripManager.VisualStylesEnabled)) {
                    if (Selected || Pressed) {
                        textColor = SystemColors.HighlightText;
                    }
                    else {
                        textColor =  SystemColors.MenuText;
                    }
                }
 
                bool rightToLeft = (RightToLeft == RightToLeft.Yes);
                
                ToolStripMenuItemInternalLayout menuItemInternalLayout = this.InternalLayout as ToolStripMenuItemInternalLayout;
                if (menuItemInternalLayout != null && menuItemInternalLayout.UseMenuLayout) {
                    
                    // Support for special DropDownMenu layout
                    #if DEBUG_PAINT
                        g.DrawRectangle(Pens.Green, menuItemInternalLayout.TextRectangle);
                        g.DrawRectangle(Pens.HotPink, menuItemInternalLayout.ImageRectangle);
                        g.DrawRectangle(Pens.Black, menuItemInternalLayout.CheckRectangle);
                        g.DrawRectangle(Pens.Red, menuItemInternalLayout.ArrowRectangle);
                        g.DrawRectangle(Pens.Blue, new Rectangle(Point.Empty, new Size(-1,-1) + this.Size));        
                    #endif
                    if (CheckState != CheckState.Unchecked && menuItemInternalLayout.PaintCheck) {
                        Rectangle checkRectangle = menuItemInternalLayout.CheckRectangle;
                        if (!menuItemInternalLayout.ShowCheckMargin) {
                            checkRectangle =  menuItemInternalLayout.ImageRectangle;
                        }
                        if (checkRectangle.Width != 0) {
                            renderer.DrawItemCheck(new ToolStripItemImageRenderEventArgs(g, this, CheckedImage, checkRectangle));
                        }
                    }
                   
                   
                   if ((DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text) { 
 
                        // render text AND shortcut
                        renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, this.Text, InternalLayout.TextRectangle, textColor, this.Font, (rightToLeft) ? ContentAlignment.MiddleRight : ContentAlignment.MiddleLeft));
                        bool showShortCut = ShowShortcutKeys;
                        if (!DesignMode){
                            showShortCut = showShortCut && !HasDropDownItems;
                        }
                        
                        if (showShortCut) {
                            renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, GetShortcutText(), InternalLayout.TextRectangle, textColor, this.Font, (rightToLeft) ? ContentAlignment.MiddleLeft : ContentAlignment.MiddleRight));
                        }
                   }
 
                    if (HasDropDownItems) {
 
                        ArrowDirection arrowDir = (rightToLeft) ? ArrowDirection.Left : ArrowDirection.Right;
                        Color arrowColor = (Selected ||Pressed) ? SystemColors.HighlightText : SystemColors.MenuText;
                        arrowColor = (Enabled) ? arrowColor : SystemColors.ControlDark;                   
                        renderer.DrawArrow(new ToolStripArrowRenderEventArgs(g, this, menuItemInternalLayout.ArrowRectangle, arrowColor, arrowDir)); 
                    }
 
                    if (menuItemInternalLayout.PaintImage && (DisplayStyle & ToolStripItemDisplayStyle.Image) == ToolStripItemDisplayStyle.Image && Image != null) { 
                       renderer.DrawItemImage(new ToolStripItemImageRenderEventArgs(g, this, InternalLayout.ImageRectangle));
                    }
                    
                }
                else {
                                        
 
                    // Toplevel item support, menu items hosted on a plain winbar dropdown
                    if ((DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text) { 
                        renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, this.Text, InternalLayout.TextRectangle, textColor, this.Font, InternalLayout.TextFormat));
                    }
                    
                    if ((DisplayStyle & ToolStripItemDisplayStyle.Image) == ToolStripItemDisplayStyle.Image && Image != null) { 
                       renderer.DrawItemImage(new ToolStripItemImageRenderEventArgs(g, this, InternalLayout.ImageRectangle));
                    }
                }
 
               
            } 
            
        }
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.ProcessCmdKey"]/*' />
        /// <devdoc>
        /// handle shortcut keys here.
        /// </devdoc>
        [
        SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)
        ]
        protected internal override bool ProcessCmdKey(ref Message m, Keys keyData) {
 
            if (Enabled && ShortcutKeys == keyData && !HasDropDownItems) {
                FireEvent(ToolStripItemEventType.Click);
                return true;
            }
 
            // call base here to get ESC, ALT, etc.. handling.
            return base.ProcessCmdKey(ref m, keyData);            
        }
 
 
        /// <include file='doc\ToolStripMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.ProcessMnemonic"]/*' />
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] // 'charCode' matches control.cs
        protected internal override bool ProcessMnemonic(char charCode) {
             // no need to check IsMnemonic, toolstrip.ProcessMnemonic checks this already.
             if (HasDropDownItems) {
				 Select();
                 ShowDropDown();
 
                 if (!AccessibilityImprovements.UseLegacyToolTipDisplay) {
                    KeyboardToolTipStateMachine.Instance.NotifyAboutLostFocus(this);
                 }
 
                 DropDown.SelectNextToolStripItem(null, /*forward=*/true);
                 return true;
             }
             
             return base.ProcessMnemonic(charCode);
        }
 
        /// <include file='doc\WinBarMenuItem.uex' path='docs/doc[@for="ToolStripMenuItem.SetBounds"]/*' />
        /// <devdoc> overridden here so we scooch over when we're in the ToolStripDropDownMenu</devdoc>
        internal protected override void SetBounds(Rectangle rect) {
 
            ToolStripMenuItemInternalLayout internalLayout = InternalLayout as ToolStripMenuItemInternalLayout;
            if (internalLayout != null && internalLayout.UseMenuLayout) {
               ToolStripDropDownMenu dropDownMenu = Owner as ToolStripDropDownMenu;
 
               // Scooch over by the padding amount.  The padding is added to 
               // the ToolStripDropDownMenu to keep the non-menu item riffraff
               // aligned to the text rectangle. When flow layout comes through to set our position
               // via IArrangedElement DEFY IT!
               if (dropDownMenu != null) {
                    rect.X -= dropDownMenu.Padding.Left;
                    rect.X = Math.Max(rect.X,0);       
               }
            }
            base.SetBounds(rect); 
        }
 
        /// <devdoc> this is to support routing to native menu commands </devdoc>
        internal void SetNativeTargetWindow(IWin32Window window) {
            targetWindowHandle = Control.GetSafeHandle(window);
        }
        
        /// <devdoc> this is to support routing to native menu commands </devdoc>
        internal void SetNativeTargetMenu(IntPtr hMenu) {
            nativeMenuHandle = hMenu;
        }
        internal static string ShortcutToText(Keys shortcutKeys, string shortcutKeyDisplayString) {
            if (!string.IsNullOrEmpty(shortcutKeyDisplayString)) {
                return shortcutKeyDisplayString;
            }
            else if (shortcutKeys == Keys.None) {
                return String.Empty;
            }
            else {
                return TypeDescriptor.GetConverter(typeof(Keys)).ConvertToString(shortcutKeys);
            }
        }
 
        internal override bool IsBeingTabbedTo() {
            if (base.IsBeingTabbedTo()) {
                return true;
            }
 
            if (ToolStripManager.ModalMenuFilter.InMenuMode) {
                return true;
            }
 
            return false;
        }
 
        /// <devdoc>
        /// An implementation of AccessibleChild for use with ToolStripItems        
        /// </devdoc>
        [System.Runtime.InteropServices.ComVisible(true)]        
        internal class ToolStripMenuItemAccessibleObject : ToolStripDropDownItemAccessibleObject {
            private ToolStripMenuItem ownerItem = null;
 
            public ToolStripMenuItemAccessibleObject(ToolStripMenuItem ownerItem) : base(ownerItem) {
              this.ownerItem = ownerItem;
            }
 
 
            public override AccessibleStates State {
                get {
                  if (ownerItem.Enabled ) {
                      AccessibleStates state = base.State;
 
                      if ((state & AccessibleStates.Pressed) == AccessibleStates.Pressed){
                         // for some reason menu items are never "pressed".
                         state &= ~AccessibleStates.Pressed;
                      }
                      
                      if (ownerItem.Checked) {
                         state |= AccessibleStates.Checked;
                      }
                      return state;
                  }
                  return base.State;
                }
            }
                                                
            internal override object GetPropertyValue(int propertyID) {
                if (propertyID == NativeMethods.UIA_ControlTypePropertyId) {
                    return NativeMethods.UIA_MenuItemControlTypeId;
                }
                else if (AccessibilityImprovements.Level2 && propertyID == NativeMethods.UIA_AcceleratorKeyPropertyId) {
                    return ownerItem.GetShortcutText();
                }
                else {
                    return base.GetPropertyValue(propertyID);
                }
            }
        }
    }    
 
 
    internal class MenuTimer {
 
        private System.Windows.Forms.Timer autoMenuExpandTimer                          = new System.Windows.Forms.Timer();
     
        // consider - weak reference?
        private ToolStripMenuItem currentItem = null;
        private ToolStripMenuItem fromItem = null;
        private bool inTransition = false;
        
        private int quickShow = 1;
        
        private int slowShow; 
        
        public MenuTimer() {
            // MenuShowDelay can be set to 0.  In this case, set to something low so it's inperceptable.
            autoMenuExpandTimer.Tick        += new EventHandler(OnTick);
 
            // since MenuShowDelay is registry tweakable we've gotta make sure we've got some sort
            // of interval
            slowShow =  Math.Max(quickShow, SystemInformation.MenuShowDelay);
            
        }
        // the current item to autoexpand.
        private ToolStripMenuItem CurrentItem {
            get {
                return currentItem;
            }
            set{
                Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose && currentItem != value, "[MenuTimer.CurrentItem] changed: " + ((value == null) ? "null" : value.ToString()));
                currentItem = value;                
            }
        }
        public bool InTransition {
            get { return inTransition; }
            set { inTransition = value; }
        }
          
        public void Start(ToolStripMenuItem item) {
            if (InTransition) {
                return;
            }
            StartCore(item);
        }
 
        private void StartCore(ToolStripMenuItem item) {
             if (item != CurrentItem) {
                Cancel(CurrentItem);
            }
            CurrentItem = item;
            if (item != null) {
                CurrentItem = item;
                autoMenuExpandTimer.Interval = item.IsOnDropDown ? slowShow : quickShow;
                autoMenuExpandTimer.Enabled = true;
            }
         }
 
        public void Transition(ToolStripMenuItem fromItem, ToolStripMenuItem toItem) {
            Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[MenuTimer.Transition] transitioning items " + fromItem.ToString() + " " + toItem.ToString());
 
            if (toItem == null && InTransition) {
                Cancel();
                // in this case we're likely to have hit an item that's not a menu item
                // or nothing is selected.
                EndTransition(/*forceClose*/ true);
                return;
            }
        
            if (this.fromItem != fromItem) {
              this.fromItem = fromItem;
              CancelCore();
              StartCore(toItem);
            }
            // set up the current item to be the toItem so it will be auto expanded when complete.
            CurrentItem = toItem;
            InTransition = true;
            
        }
 
 
        public void Cancel() {
            if (InTransition) {
                return;
            }
            CancelCore();
           
        }
        ///<devdoc> cancels if and only if this item was the one that 
        ///         requested the timer
        ///</devdoc>
        public void Cancel(ToolStripMenuItem item) {
            if (InTransition) {
                return;
            }
            if (item == CurrentItem) {
                CancelCore();
           }
        }
 
        private void CancelCore() {
            autoMenuExpandTimer.Enabled = false;
            CurrentItem = null;
        }
        private void EndTransition(bool forceClose) {
            ToolStripMenuItem lastSelected = fromItem;
            fromItem = null; // immediately clear BEFORE we call user code.
            if (InTransition) {                
                InTransition = false;
                
                // we should roolup if the current item has changed and is selected.
                bool rollup = forceClose || (CurrentItem != null && CurrentItem != lastSelected && CurrentItem.Selected);
                if (rollup && lastSelected != null && lastSelected.HasDropDownItems) {
                    lastSelected.HideDropDown();                         
                }
 
            }
 
        }
        internal void HandleToolStripMouseLeave(ToolStrip toolStrip) {
            if (InTransition && toolStrip == fromItem.ParentInternal) {
                // restore the selection back to CurrentItem.
                // we're about to fall off the edge of the toolstrip, something should be selected
                // at all times while we're InTransition mode - otherwise it looks really funny
                // to have an auto expanded item 
                if (CurrentItem != null) {
                    CurrentItem.Select();
                }
            }
            else {
 
                // because we've split up selected/pressed, we need to make sure
                // that onmouseleave we make sure there's a selected menu item.
                if (toolStrip.IsDropDown && toolStrip.ActiveDropDowns.Count > 0) {
                    ToolStripDropDown dropDown = toolStrip.ActiveDropDowns[0] as ToolStripDropDown;
                    
                    ToolStripMenuItem menuItem = (dropDown == null) ? null : dropDown.OwnerItem as ToolStripMenuItem;               
                    if (menuItem != null && menuItem.Pressed) {
                        menuItem.Select();
                    }                       
                }
            }
        }
 
        private void OnTick(object sender, EventArgs e) {
            autoMenuExpandTimer.Enabled = false;
      
            if (CurrentItem == null) {
                return;
            }
            EndTransition(/*forceClose*/false);
            if (CurrentItem != null && !CurrentItem.IsDisposed &&  CurrentItem.Selected && CurrentItem.Enabled && ToolStripManager.ModalMenuFilter.InMenuMode) {
                Debug.WriteLineIf(ToolStrip.MenuAutoExpandDebug.TraceVerbose, "[MenuTimer.OnTick] calling OnMenuAutoExpand");
                CurrentItem.OnMenuAutoExpand();
            }
        }
 
 
    }
 
    internal class ToolStripMenuItemInternalLayout : ToolStripItemInternalLayout {
        private ToolStripMenuItem ownerItem;
        
        public ToolStripMenuItemInternalLayout(ToolStripMenuItem ownerItem) : base(ownerItem) {
            this.ownerItem = ownerItem;    
        }
 
        public bool ShowCheckMargin {
            get{
                ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                if (menu != null) {
                    return menu.ShowCheckMargin;
                }
                return false;
            }
        }
        public bool ShowImageMargin {
            get{
                ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                if (menu != null) {
                    return menu.ShowImageMargin;
                }
                return false;
            }
        }
 
        public bool PaintCheck {
            get {
                return ShowCheckMargin || ShowImageMargin;
            }
        }
        
        public bool PaintImage {
            get {
                return ShowImageMargin;
            }
        }
        public  Rectangle ArrowRectangle {
           get {
               if (UseMenuLayout) {
                   ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                   if (menu != null) {
                        // since menuItem.Padding isnt taken into consideration, we've got to recalc the centering of
                        // the arrow rect per item
                        Rectangle arrowRect = menu.ArrowRectangle;
                        arrowRect.Y = LayoutUtils.VAlign(arrowRect.Size, ownerItem.ClientBounds, ContentAlignment.MiddleCenter).Y;
                        return arrowRect;
                   }
               }
               return Rectangle.Empty;
           }
        }
        public Rectangle CheckRectangle {
            get {
                 if (UseMenuLayout) {
                     ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                     if (menu != null) {
                         Rectangle checkRectangle = menu.CheckRectangle;
                         if (ownerItem.CheckedImage != null) {
                             int imageHeight = ownerItem.CheckedImage.Height;
                             // make sure we're vertically centered
                             checkRectangle.Y += (checkRectangle.Height - imageHeight)/2;
                             checkRectangle.Height = imageHeight;
                             return checkRectangle;
                         }
                     }
                 }
                 return Rectangle.Empty;
            }
        }
        public override Rectangle ImageRectangle {
            get {
                if (UseMenuLayout) {
                    ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                    if (menu != null) {
 
                        // since menuItem.Padding isnt taken into consideration, we've got to recalc the centering of
                        // the image rect per item
                        Rectangle imageRect = menu.ImageRectangle;
                        if (ownerItem.ImageScaling == ToolStripItemImageScaling.SizeToFit) {
                            imageRect.Size = menu.ImageScalingSize;
                        }
                        else {
                            //If we don't have an image, use the CheckedImage
                            Image image = ownerItem.Image ?? ownerItem.CheckedImage;
                            imageRect.Size = image.Size;
                        }
                        imageRect.Y = LayoutUtils.VAlign(imageRect.Size, ownerItem.ClientBounds, ContentAlignment.MiddleCenter).Y;
                        return imageRect;
                    }
                }
                return base.ImageRectangle;
            }
        }
 
        public override Rectangle TextRectangle {
            get {
                if (UseMenuLayout) {
                    ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                    if (menu != null) {
                        return menu.TextRectangle;
                    }
                }
                return base.TextRectangle;
            }
        }
        
        public bool UseMenuLayout {
            get {
                return  ownerItem.Owner is ToolStripDropDownMenu;
            }
        }
 
        public override Size GetPreferredSize(Size constrainingSize) {
            if (UseMenuLayout) {
                ToolStripDropDownMenu menu = ownerItem.Owner as ToolStripDropDownMenu;
                if (menu != null) {
                    return menu.MaxItemSize;
                }
            }
            return base.GetPreferredSize(constrainingSize);
        }
    }
  
 }