Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / WinForms / Managed / System / WinForms / ToolStripMenuItem.cs / 1 / ToolStripMenuItem.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- 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; ////// /// ToolStripMenuItem /// [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 byte openMouseId = 0; private static readonly object EventCheckedChanged = new object(); private static readonly object EventCheckStateChanged = new object(); ///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); } /// 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. /// [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; } ///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() { this.Overflow = ToolStripItemOverflow.Never; this.MouseDownAndUpMustBeInSameItem = false; this.SupportsDisabledHotTracking = true; } /// /// /// 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. /// protected override Size DefaultSize { get { return new Size(32, 19); } } ///protected internal override Padding DefaultMargin { get { return Padding.Empty; } } /// protected override Padding DefaultPadding { get { if (IsOnDropDown) { return new Padding(0, 1, 0, 1); } else { return new Padding(4, 0, 4, 0); } } } 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; } } /// /// /// [ 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(); } } } ////// Gets or sets a value indicating whether the item is checked. /// ////// Keeps a shared copy of the checked image between all menu items /// Fishes out the appropriate one based on CheckState. /// internal Image CheckedImage { get { CheckState checkedState = CheckState; if (checkedState == CheckState.Indeterminate) { if (indeterminateCheckedImage == null) { Bitmap indeterminateCheckedBmp = new Bitmap(typeof(ToolStripMenuItem), "IndeterminateChecked.bmp"); if (indeterminateCheckedBmp != null) { // indeterminateCheckedBmp.MakeTransparent(indeterminateCheckedBmp.GetPixel(1,1)); indeterminateCheckedImage = indeterminateCheckedBmp; } } return indeterminateCheckedImage; } else if (checkedState == CheckState.Checked) { if (checkedImage == null) { Bitmap checkedBmp = new Bitmap(typeof(ToolStripMenuItem), "Checked.bmp"); if (checkedBmp != null) { // checkedBmp.MakeTransparent(checkedBmp.GetPixel(1,1)); checkedImage = checkedBmp; } } return checkedImage; } return null; } } ///[ DefaultValue(false), SRCategory(SR.CatBehavior), SRDescription(SR.ToolStripButtonCheckOnClickDescr) ] public bool CheckOnClick { get { return checkOnClick; } set { checkOnClick = value; } } /// /// /// [ 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); } } } ///Gets /// or sets a value indicating whether the check box is checked. ////// /// [SRDescription(SR.CheckBoxOnCheckedChangedDescr)] public event EventHandler CheckedChanged { add { Events.AddHandler(EventCheckedChanged, value); } remove { Events.RemoveHandler(EventCheckedChanged, value); } } ///Occurs when the /// value of the ////// property changes. /// /// [SRDescription(SR.CheckBoxOnCheckStateChangedDescr)] public event EventHandler CheckStateChanged { add { Events.AddHandler(EventCheckStateChanged, value); } remove { Events.RemoveHandler(EventCheckStateChanged, value); } } ///Occurs when the /// value of the ////// property changes. /// /// [ DefaultValue(ToolStripItemOverflow.Never), SRDescription(SR.ToolStripItemOverflowDescr), SRCategory(SR.CatLayout) ] public new ToolStripItemOverflow Overflow { get { return base.Overflow; } set { base.Overflow = value; } } ///Specifies whether or not the item is glued to the winbar or overflow or /// can float between the two. ////// /// [ 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(); } } } } } ////// Gets or sets the shortcut keys associated with the menu /// item. /// ////// /// [ 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(); } } } } ////// 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. /// ////// 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 /// 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; } } ///Tag property for internal use 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; } 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; } 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; } private string GetShortcutText() { if (cachedShortcutText == null) { cachedShortcutText = ShortcutToText(this.ShortcutKeys, this.ShortcutKeyDisplayString); } return cachedShortcutText; } internal void HandleAutoExpansion() { if (Enabled && ParentInternal != null && ParentInternal.MenuAutoExpand && HasDropDownItems) { ShowDropDown(); DropDown.SelectNextToolStripItem(null, /*forward=*/true); } } ///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(); } } /// /// /// protected virtual void OnCheckedChanged(EventArgs e) { EventHandler handler = (EventHandler)Events[EventCheckedChanged]; if (handler != null) handler(this,e); } ///Raises the ////// event. /// /// protected virtual void OnCheckStateChanged(EventArgs e) { AccessibilityNotifyClients(AccessibleEvents.StateChange); EventHandler handler = (EventHandler)Events[EventCheckStateChanged]; if (handler != null) handler(this,e); } ///Raises the ///event. 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); } /// internal void OnMenuAutoExpand() { this.ShowDropDown(); } /// /// 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(); } } } } /// /// 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); } /// /// 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); } /// /// 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)); } } } } /// /// /// handle shortcut keys here. /// [ 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); } ///[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(); DropDown.SelectNextToolStripItem(null, /*forward=*/true); return true; } return base.ProcessMnemonic(charCode); } /// /// overridden here so we scooch over when we're in the ToolStripDropDownMenu 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); } ///this is to support routing to native menu commands internal void SetNativeTargetWindow(IWin32Window window) { targetWindowHandle = Control.GetSafeHandle(window); } ///this is to support routing to native menu commands 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); } } ////// An implementation of AccessibleChild for use with ToolStripItems /// [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 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(); } ///cancels if and only if this item was the one that /// requested the timer /// 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 && 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); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- 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; ////// /// ToolStripMenuItem /// [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 byte openMouseId = 0; private static readonly object EventCheckedChanged = new object(); private static readonly object EventCheckStateChanged = new object(); ///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); } /// 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. /// [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; } ///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() { this.Overflow = ToolStripItemOverflow.Never; this.MouseDownAndUpMustBeInSameItem = false; this.SupportsDisabledHotTracking = true; } /// /// /// 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. /// protected override Size DefaultSize { get { return new Size(32, 19); } } ///protected internal override Padding DefaultMargin { get { return Padding.Empty; } } /// protected override Padding DefaultPadding { get { if (IsOnDropDown) { return new Padding(0, 1, 0, 1); } else { return new Padding(4, 0, 4, 0); } } } 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; } } /// /// /// [ 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(); } } } ////// Gets or sets a value indicating whether the item is checked. /// ////// Keeps a shared copy of the checked image between all menu items /// Fishes out the appropriate one based on CheckState. /// internal Image CheckedImage { get { CheckState checkedState = CheckState; if (checkedState == CheckState.Indeterminate) { if (indeterminateCheckedImage == null) { Bitmap indeterminateCheckedBmp = new Bitmap(typeof(ToolStripMenuItem), "IndeterminateChecked.bmp"); if (indeterminateCheckedBmp != null) { // indeterminateCheckedBmp.MakeTransparent(indeterminateCheckedBmp.GetPixel(1,1)); indeterminateCheckedImage = indeterminateCheckedBmp; } } return indeterminateCheckedImage; } else if (checkedState == CheckState.Checked) { if (checkedImage == null) { Bitmap checkedBmp = new Bitmap(typeof(ToolStripMenuItem), "Checked.bmp"); if (checkedBmp != null) { // checkedBmp.MakeTransparent(checkedBmp.GetPixel(1,1)); checkedImage = checkedBmp; } } return checkedImage; } return null; } } ///[ DefaultValue(false), SRCategory(SR.CatBehavior), SRDescription(SR.ToolStripButtonCheckOnClickDescr) ] public bool CheckOnClick { get { return checkOnClick; } set { checkOnClick = value; } } /// /// /// [ 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); } } } ///Gets /// or sets a value indicating whether the check box is checked. ////// /// [SRDescription(SR.CheckBoxOnCheckedChangedDescr)] public event EventHandler CheckedChanged { add { Events.AddHandler(EventCheckedChanged, value); } remove { Events.RemoveHandler(EventCheckedChanged, value); } } ///Occurs when the /// value of the ////// property changes. /// /// [SRDescription(SR.CheckBoxOnCheckStateChangedDescr)] public event EventHandler CheckStateChanged { add { Events.AddHandler(EventCheckStateChanged, value); } remove { Events.RemoveHandler(EventCheckStateChanged, value); } } ///Occurs when the /// value of the ////// property changes. /// /// [ DefaultValue(ToolStripItemOverflow.Never), SRDescription(SR.ToolStripItemOverflowDescr), SRCategory(SR.CatLayout) ] public new ToolStripItemOverflow Overflow { get { return base.Overflow; } set { base.Overflow = value; } } ///Specifies whether or not the item is glued to the winbar or overflow or /// can float between the two. ////// /// [ 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(); } } } } } ////// Gets or sets the shortcut keys associated with the menu /// item. /// ////// /// [ 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(); } } } } ////// 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. /// ////// 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 /// 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; } } ///Tag property for internal use 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; } 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; } 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; } private string GetShortcutText() { if (cachedShortcutText == null) { cachedShortcutText = ShortcutToText(this.ShortcutKeys, this.ShortcutKeyDisplayString); } return cachedShortcutText; } internal void HandleAutoExpansion() { if (Enabled && ParentInternal != null && ParentInternal.MenuAutoExpand && HasDropDownItems) { ShowDropDown(); DropDown.SelectNextToolStripItem(null, /*forward=*/true); } } ///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(); } } /// /// /// protected virtual void OnCheckedChanged(EventArgs e) { EventHandler handler = (EventHandler)Events[EventCheckedChanged]; if (handler != null) handler(this,e); } ///Raises the ////// event. /// /// protected virtual void OnCheckStateChanged(EventArgs e) { AccessibilityNotifyClients(AccessibleEvents.StateChange); EventHandler handler = (EventHandler)Events[EventCheckStateChanged]; if (handler != null) handler(this,e); } ///Raises the ///event. 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); } /// internal void OnMenuAutoExpand() { this.ShowDropDown(); } /// /// 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(); } } } } /// /// 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); } /// /// 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); } /// /// 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)); } } } } /// /// /// handle shortcut keys here. /// [ 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); } ///[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(); DropDown.SelectNextToolStripItem(null, /*forward=*/true); return true; } return base.ProcessMnemonic(charCode); } /// /// overridden here so we scooch over when we're in the ToolStripDropDownMenu 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); } ///this is to support routing to native menu commands internal void SetNativeTargetWindow(IWin32Window window) { targetWindowHandle = Control.GetSafeHandle(window); } ///this is to support routing to native menu commands 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); } } ////// An implementation of AccessibleChild for use with ToolStripItems /// [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 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(); } ///cancels if and only if this item was the one that /// requested the timer /// 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 && 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); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ActiveDocumentEvent.cs
- DbDataRecord.cs
- FontWeights.cs
- Span.cs
- Visual3DCollection.cs
- WCFServiceClientProxyGenerator.cs
- XmlNotation.cs
- ModelUtilities.cs
- DiagnosticTrace.cs
- SiteMapDataSource.cs
- RegexWorker.cs
- ExternalFile.cs
- DbModificationCommandTree.cs
- XmlSchemaInfo.cs
- InteropAutomationProvider.cs
- ContractMapping.cs
- DataColumnMappingCollection.cs
- AlphabeticalEnumConverter.cs
- DecoratedNameAttribute.cs
- ExpressionBindings.cs
- Margins.cs
- EmissiveMaterial.cs
- BatchServiceHost.cs
- XmlExpressionDumper.cs
- CellLabel.cs
- SamlAction.cs
- mediaeventshelper.cs
- BooleanAnimationBase.cs
- SID.cs
- TextShapeableCharacters.cs
- MobileRedirect.cs
- ExpressionHelper.cs
- ObjectViewQueryResultData.cs
- DuplicateWaitObjectException.cs
- ServerIdentity.cs
- TreeNodeStyleCollection.cs
- Icon.cs
- AutoResizedEvent.cs
- QueryInterceptorAttribute.cs
- ExtensibleSyndicationObject.cs
- GroupJoinQueryOperator.cs
- MailDefinition.cs
- WindowsToolbarAsMenu.cs
- QueueAccessMode.cs
- EditorPartCollection.cs
- _SslSessionsCache.cs
- FastPropertyAccessor.cs
- SplitterPanel.cs
- SchemaCollectionPreprocessor.cs
- GeneralTransform.cs
- MarshalByValueComponent.cs
- LicenseContext.cs
- MetadataArtifactLoaderXmlReaderWrapper.cs
- Bitmap.cs
- CacheOutputQuery.cs
- DiagnosticTraceSource.cs
- SignedInfo.cs
- ConfigXmlSignificantWhitespace.cs
- InfoCardAsymmetricCrypto.cs
- StringConcat.cs
- AssemblyCollection.cs
- CqlIdentifiers.cs
- StorageComplexPropertyMapping.cs
- SqlDataSourceCommandEventArgs.cs
- BitmapPalette.cs
- ThrowOnMultipleAssignment.cs
- XsdBuildProvider.cs
- HttpPostLocalhostServerProtocol.cs
- EdmProperty.cs
- Deflater.cs
- UnsafeNativeMethods.cs
- ThreadPoolTaskScheduler.cs
- NameValueConfigurationElement.cs
- AssemblyName.cs
- SafeMarshalContext.cs
- CapabilitiesAssignment.cs
- FontInfo.cs
- APCustomTypeDescriptor.cs
- Brushes.cs
- InstalledVoice.cs
- mactripleDES.cs
- ReadOnlyAttribute.cs
- CatalogPart.cs
- Bitmap.cs
- StrongNamePublicKeyBlob.cs
- OleDbParameterCollection.cs
- HttpDebugHandler.cs
- BuildProviderCollection.cs
- CodeDefaultValueExpression.cs
- DomainUpDown.cs
- StreamResourceInfo.cs
- XmlSchemaImporter.cs
- BuildTopDownAttribute.cs
- UserValidatedEventArgs.cs
- ConfigurationStrings.cs
- ReadOnlyCollection.cs
- util.cs
- ClientType.cs
- ObjectIDGenerator.cs
- AccessDataSource.cs