2 // ToolStripMenuItem.cs
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
31 using System.ComponentModel;
32 using System.Windows.Forms.Design;
33 using System.ComponentModel.Design.Serialization;
35 namespace System.Windows.Forms
37 [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)]
38 [DesignerSerializer ("System.Windows.Forms.Design.ToolStripMenuItemCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
39 public class ToolStripMenuItem : ToolStripDropDownItem
41 private CheckState checked_state;
42 private bool check_on_click;
43 private bool close_on_mouse_release;
44 private string shortcut_display_string;
45 private Keys shortcut_keys = Keys.None;
46 private bool show_shortcut_keys = true;
47 private Form mdi_client_form;
49 #region Public Constructors
50 public ToolStripMenuItem ()
51 : this (null, null, null, string.Empty)
55 public ToolStripMenuItem (Image image)
56 : this (null, image, null, string.Empty)
60 public ToolStripMenuItem (string text)
61 : this (text, null, null, string.Empty)
65 public ToolStripMenuItem (string text, Image image)
66 : this (text, image, null, string.Empty)
70 public ToolStripMenuItem (string text, Image image, EventHandler onClick)
71 : this (text, image, onClick, string.Empty)
75 public ToolStripMenuItem (string text, Image image, params ToolStripItem[] dropDownItems)
76 : this (text, image, null, string.Empty)
78 if (dropDownItems != null)
79 foreach (ToolStripItem tsi in dropDownItems)
80 this.DropDownItems.Add (tsi);
83 public ToolStripMenuItem (string text, Image image, EventHandler onClick, Keys shortcutKeys)
84 : this (text, image, onClick, string.Empty)
88 public ToolStripMenuItem (string text, Image image, EventHandler onClick, string name)
89 : base (text, image, onClick, name)
91 base.Overflow = ToolStripItemOverflow.Never;
95 #region Public Properties
97 [DefaultValue (false)]
98 [RefreshProperties (RefreshProperties.All)]
101 switch (this.checked_state) {
102 case CheckState.Unchecked:
105 case CheckState.Checked:
106 case CheckState.Indeterminate:
111 CheckState = value ? CheckState.Checked : CheckState.Unchecked;
115 [DefaultValue (false)]
116 public bool CheckOnClick {
117 get { return this.check_on_click; }
119 if (this.check_on_click != value) {
120 this.check_on_click = value;
121 OnUIACheckOnClickChangedEvent (EventArgs.Empty);
127 [DefaultValue (CheckState.Unchecked)]
128 [RefreshProperties (RefreshProperties.All)]
129 public CheckState CheckState {
130 get { return this.checked_state; }
133 if (!Enum.IsDefined (typeof (CheckState), value))
134 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for CheckState", value));
136 if (value == checked_state)
139 this.checked_state = value;
141 this.OnCheckedChanged (EventArgs.Empty);
142 this.OnCheckStateChanged (EventArgs.Empty);
146 public override bool Enabled {
147 get { return base.Enabled; }
148 set { base.Enabled = value; }
152 public bool IsMdiWindowListEntry {
153 get { return this.mdi_client_form != null; }
156 [DefaultValue (ToolStripItemOverflow.Never)]
157 public new ToolStripItemOverflow Overflow {
158 get { return base.Overflow; }
159 set { base.Overflow = value; }
163 [DefaultValue (true)]
164 public bool ShowShortcutKeys {
165 get { return this.show_shortcut_keys; }
166 set { this.show_shortcut_keys = value; }
170 [DefaultValue (null)]
171 public string ShortcutKeyDisplayString {
172 get { return this.shortcut_display_string; }
173 set { this.shortcut_display_string = value; }
177 [DefaultValue (Keys.None)]
178 public Keys ShortcutKeys {
179 get { return this.shortcut_keys; }
181 if (this.shortcut_keys != value) {
182 this.shortcut_keys = value;
184 if (this.Parent != null)
185 ToolStripManager.AddToolStripMenuItem (this);
191 #region Protected Properties
192 protected internal override Padding DefaultMargin {
193 get { return new Padding (0); }
196 protected override Padding DefaultPadding {
197 get { return new Padding (4, 0, 4, 0); }
200 protected override Size DefaultSize {
201 get { return new Size (32, 19); }
205 #region Protected Methods
206 [EditorBrowsable (EditorBrowsableState.Advanced)]
207 protected override AccessibleObject CreateAccessibilityInstance ()
209 return new ToolStripMenuItemAccessibleObject ();
212 protected override ToolStripDropDown CreateDefaultDropDown ()
214 ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu ();
215 tsddm.OwnerItem = this;
219 protected override void Dispose (bool disposing)
221 base.Dispose (disposing);
224 protected virtual void OnCheckedChanged (EventArgs e)
226 EventHandler eh = (EventHandler)Events [CheckedChangedEvent];
231 protected virtual void OnCheckStateChanged (EventArgs e)
233 EventHandler eh = (EventHandler)Events [CheckStateChangedEvent];
238 protected override void OnClick (EventArgs e)
243 if (this.HasDropDownItems) {
248 if (this.OwnerItem is ToolStripDropDownItem)
249 (this.OwnerItem as ToolStripDropDownItem).OnDropDownItemClicked (new ToolStripItemClickedEventArgs (this));
251 if (this.IsOnDropDown) {
252 ToolStrip ts = this.GetTopLevelToolStrip ();
255 ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked);
258 if (this.IsMdiWindowListEntry) {
259 this.mdi_client_form.MdiParent.MdiContainer.ActivateChild (this.mdi_client_form);
263 if (this.check_on_click)
264 this.Checked = !this.Checked;
268 if (!this.IsOnDropDown && !this.HasDropDownItems) {
269 ToolStrip ts = this.GetTopLevelToolStrip ();
272 ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked);
276 protected override void OnDropDownHide (EventArgs e)
278 base.OnDropDownHide (e);
281 protected override void OnDropDownShow (EventArgs e)
283 base.OnDropDownShow (e);
286 protected override void OnFontChanged (EventArgs e)
288 base.OnFontChanged (e);
291 protected override void OnMouseDown (MouseEventArgs e)
293 if (!this.IsOnDropDown && this.HasDropDownItems && this.DropDown.Visible)
294 this.close_on_mouse_release = true;
296 if (Enabled && !this.DropDown.Visible)
297 this.ShowDropDown ();
299 base.OnMouseDown (e);
302 protected override void OnMouseEnter (EventArgs e)
304 if (this.IsOnDropDown && this.HasDropDownItems && Enabled)
305 this.ShowDropDown ();
307 base.OnMouseEnter (e);
310 protected override void OnMouseLeave (EventArgs e)
312 base.OnMouseLeave (e);
315 protected override void OnMouseUp (MouseEventArgs e)
317 if (this.close_on_mouse_release) {
318 this.Parent.Dismiss (ToolStripDropDownCloseReason.ItemClicked);
320 this.close_on_mouse_release = false;
323 if (!this.HasDropDownItems && Enabled)
327 protected override void OnOwnerChanged (EventArgs e)
329 base.OnOwnerChanged (e);
332 protected override void OnPaint (System.Windows.Forms.PaintEventArgs e)
336 // Can't render without an owner
337 if (this.Owner == null)
340 // If DropDown.ShowImageMargin is false, we don't display the image
341 Image draw_image = this.UseImageMargin ? this.Image : null;
343 // Disable this color detection until we do the color detection for ToolStrip *completely*
344 // Color font_color = this.ForeColor == SystemColors.ControlText ? SystemColors.MenuText : this.ForeColor;
345 Color font_color = ForeColor;
347 if ((this.Selected || this.Pressed) && this.IsOnDropDown && font_color == SystemColors.MenuText)
348 font_color = SystemColors.HighlightText;
350 if (!this.Enabled && this.ForeColor == SystemColors.ControlText)
351 font_color = SystemColors.GrayText;
353 // Gray stuff out if we're disabled
354 draw_image = this.Enabled ? draw_image : ToolStripRenderer.CreateDisabledImage (draw_image);
356 // Draw our background
357 this.Owner.Renderer.DrawMenuItemBackground (new ToolStripItemRenderEventArgs (e.Graphics, this));
359 // Figure out where our text and image go
360 Rectangle text_layout_rect;
361 Rectangle image_layout_rect;
363 this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect);
365 if (this.IsOnDropDown) {
366 if (!this.UseImageMargin) {
367 image_layout_rect = Rectangle.Empty;
368 text_layout_rect = new Rectangle (8, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height);
370 text_layout_rect = new Rectangle (35, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height);
372 if (image_layout_rect != Rectangle.Empty)
373 image_layout_rect = new Rectangle (new Point (4, 3), base.GetImageSize ());
376 if (this.Checked && this.ShowMargin)
377 this.Owner.Renderer.DrawItemCheck (new ToolStripItemImageRenderEventArgs (e.Graphics, this, new Rectangle (2, 1, 19, 19)));
379 if (text_layout_rect != Rectangle.Empty)
380 this.Owner.Renderer.DrawItemText (new ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign));
382 string key_string = GetShortcutDisplayString ();
384 if (!string.IsNullOrEmpty (key_string) && !this.HasDropDownItems) {
386 Size key_string_size = TextRenderer.MeasureText (key_string, this.Font);
387 Rectangle key_string_rect = new Rectangle (this.ContentRectangle.Right - key_string_size.Width - offset, text_layout_rect.Top, key_string_size.Width, text_layout_rect.Height);
388 this.Owner.Renderer.DrawItemText (new ToolStripItemTextRenderEventArgs (e.Graphics, this, key_string, key_string_rect, font_color, this.Font, this.TextAlign));
391 if (image_layout_rect != Rectangle.Empty)
392 this.Owner.Renderer.DrawItemImage (new ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect));
394 if (this.IsOnDropDown && this.HasDropDownItems && this.Parent is ToolStripDropDownMenu)
395 this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Bounds.Width - 17, 2, 10, 20), Color.Black, ArrowDirection.Right));
400 protected internal override bool ProcessCmdKey (ref Message m, Keys keyData)
402 Control source = Control.FromHandle (m.HWnd);
403 Form f = source == null ? null : (Form)source.TopLevelControl;
405 if (this.Enabled && keyData == this.shortcut_keys && GetTopLevelControl () == f) {
406 this.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click);
410 return base.ProcessCmdKey (ref m, keyData);
413 Control GetTopLevelControl ()
415 ToolStripItem item = this;
416 while (item.OwnerItem != null)
417 item = item.OwnerItem;
419 if (item.Owner == null)
422 if (item.Owner is ContextMenuStrip) {
423 Control container = ((ContextMenuStrip)item.Owner).container;
424 return container == null ? null : container.TopLevelControl;
428 return item.Owner.TopLevelControl;
431 protected internal override bool ProcessMnemonic (char charCode)
434 this.Parent.ChangeSelection (this);
436 if (this.HasDropDownItems) {
437 ToolStripManager.SetActiveToolStrip (this.Parent, true);
438 this.ShowDropDown ();
439 this.DropDown.SelectNextToolStripItem (null, true);
441 this.PerformClick ();
446 protected internal override void SetBounds (Rectangle rect)
448 base.SetBounds (rect);
452 #region Public Events
453 static object CheckedChangedEvent = new object ();
454 static object CheckStateChangedEvent = new object ();
456 public event EventHandler CheckedChanged {
457 add { Events.AddHandler (CheckedChangedEvent, value); }
458 remove {Events.RemoveHandler (CheckedChangedEvent, value); }
461 public event EventHandler CheckStateChanged {
462 add { Events.AddHandler (CheckStateChangedEvent, value); }
463 remove {Events.RemoveHandler (CheckStateChangedEvent, value); }
467 #region UIA Framework Events
468 static object UIACheckOnClickChangedEvent = new object ();
470 internal event EventHandler UIACheckOnClickChanged {
471 add { Events.AddHandler (UIACheckOnClickChangedEvent, value); }
472 remove { Events.RemoveHandler (UIACheckOnClickChangedEvent, value); }
475 internal void OnUIACheckOnClickChangedEvent (EventArgs args)
478 = (EventHandler) Events [UIACheckOnClickChangedEvent];
484 #region Internal Properties
485 internal Form MdiClientForm {
486 get { return this.mdi_client_form; }
487 set { this.mdi_client_form = value; }
491 #region Internal Methods
492 internal override Size CalculatePreferredSize (Size constrainingSize)
494 Size base_size = base.CalculatePreferredSize (constrainingSize);
496 string key_string = GetShortcutDisplayString ();
498 if (string.IsNullOrEmpty (key_string))
501 Size text_size = TextRenderer.MeasureText (key_string, this.Font);
503 return new Size (base_size.Width + text_size.Width - 25, base_size.Height);
506 internal string GetShortcutDisplayString ()
508 if (this.show_shortcut_keys == false)
510 if (this.Parent == null || !(this.Parent is ToolStripDropDownMenu))
513 string key_string = string.Empty;
515 if (!string.IsNullOrEmpty (this.shortcut_display_string))
516 key_string = this.shortcut_display_string;
517 else if (this.shortcut_keys != Keys.None) {
518 KeysConverter kc = new KeysConverter ();
519 key_string = kc.ConvertToString (this.shortcut_keys);
525 internal void HandleAutoExpansion ()
527 if (this.HasDropDownItems) {
528 this.ShowDropDown ();
529 this.DropDown.SelectNextToolStripItem (null, true);
533 internal override void HandleClick (int mouse_clicks, EventArgs e)
538 Parent.Invalidate ();
542 #region ToolStripMenuItemAccessibleObject
543 private class ToolStripMenuItemAccessibleObject : AccessibleObject