1 // 2 // ToolStripMenuItem.cs 3 // 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: 11 // 12 // The above copyright notice and this permission notice shall be 13 // included in all copies or substantial portions of the Software. 14 // 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. 22 // 23 // Copyright (c) 2006 Jonathan Pobst 24 // 25 // Authors: 26 // Jonathan Pobst (monkey@jpobst.com) 27 // 28 29 using System; 30 using System.Drawing; 31 using System.ComponentModel; 32 using System.Windows.Forms.Design; 33 using System.ComponentModel.Design.Serialization; 34 35 namespace System.Windows.Forms 36 { 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 40 { 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; 48 49 #region Public Constructors ToolStripMenuItem()50 public ToolStripMenuItem () 51 : this (null, null, null, string.Empty) 52 { 53 } 54 ToolStripMenuItem(Image image)55 public ToolStripMenuItem (Image image) 56 : this (null, image, null, string.Empty) 57 { 58 } 59 ToolStripMenuItem(string text)60 public ToolStripMenuItem (string text) 61 : this (text, null, null, string.Empty) 62 { 63 } 64 ToolStripMenuItem(string text, Image image)65 public ToolStripMenuItem (string text, Image image) 66 : this (text, image, null, string.Empty) 67 { 68 } 69 ToolStripMenuItem(string text, Image image, EventHandler onClick)70 public ToolStripMenuItem (string text, Image image, EventHandler onClick) 71 : this (text, image, onClick, string.Empty) 72 { 73 } 74 ToolStripMenuItem(string text, Image image, params ToolStripItem[] dropDownItems)75 public ToolStripMenuItem (string text, Image image, params ToolStripItem[] dropDownItems) 76 : this (text, image, null, string.Empty) 77 { 78 if (dropDownItems != null) 79 foreach (ToolStripItem tsi in dropDownItems) 80 this.DropDownItems.Add (tsi); 81 } 82 ToolStripMenuItem(string text, Image image, EventHandler onClick, Keys shortcutKeys)83 public ToolStripMenuItem (string text, Image image, EventHandler onClick, Keys shortcutKeys) 84 : this (text, image, onClick, string.Empty) 85 { 86 } 87 ToolStripMenuItem(string text, Image image, EventHandler onClick, string name)88 public ToolStripMenuItem (string text, Image image, EventHandler onClick, string name) 89 : base (text, image, onClick, name) 90 { 91 base.Overflow = ToolStripItemOverflow.Never; 92 } 93 #endregion 94 95 #region Public Properties 96 [Bindable (true)] 97 [DefaultValue (false)] 98 [RefreshProperties (RefreshProperties.All)] 99 public bool Checked { 100 get { 101 switch (this.checked_state) { 102 case CheckState.Unchecked: 103 default: 104 return false; 105 case CheckState.Checked: 106 case CheckState.Indeterminate: 107 return true; 108 } 109 } 110 set { 111 CheckState = value ? CheckState.Checked : CheckState.Unchecked; 112 } 113 } 114 115 [DefaultValue (false)] 116 public bool CheckOnClick { 117 get { return this.check_on_click; } 118 set { 119 if (this.check_on_click != value) { 120 this.check_on_click = value; 121 OnUIACheckOnClickChangedEvent (EventArgs.Empty); 122 } 123 } 124 } 125 126 [Bindable (true)] 127 [DefaultValue (CheckState.Unchecked)] 128 [RefreshProperties (RefreshProperties.All)] 129 public CheckState CheckState { 130 get { return this.checked_state; } 131 set 132 { 133 if (!Enum.IsDefined (typeof (CheckState), value)) 134 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for CheckState", value)); 135 136 if (value == checked_state) 137 return; 138 139 this.checked_state = value; 140 this.Invalidate (); 141 this.OnCheckedChanged (EventArgs.Empty); 142 this.OnCheckStateChanged (EventArgs.Empty); 143 } 144 } 145 146 public override bool Enabled { 147 get { return base.Enabled; } 148 set { base.Enabled = value; } 149 } 150 151 [Browsable (false)] 152 public bool IsMdiWindowListEntry { 153 get { return this.mdi_client_form != null; } 154 } 155 156 [DefaultValue (ToolStripItemOverflow.Never)] 157 public new ToolStripItemOverflow Overflow { 158 get { return base.Overflow; } 159 set { base.Overflow = value; } 160 } 161 162 [Localizable (true)] 163 [DefaultValue (true)] 164 public bool ShowShortcutKeys { 165 get { return this.show_shortcut_keys; } 166 set { this.show_shortcut_keys = value; } 167 } 168 169 [Localizable (true)] 170 [DefaultValue (null)] 171 public string ShortcutKeyDisplayString { 172 get { return this.shortcut_display_string; } 173 set { this.shortcut_display_string = value; } 174 } 175 176 [Localizable (true)] 177 [DefaultValue (Keys.None)] 178 public Keys ShortcutKeys { 179 get { return this.shortcut_keys; } 180 set { 181 if (this.shortcut_keys != value) { 182 this.shortcut_keys = value; 183 184 if (this.Parent != null) 185 ToolStripManager.AddToolStripMenuItem (this); 186 } 187 } 188 } 189 #endregion 190 191 #region Protected Properties 192 protected internal override Padding DefaultMargin { 193 get { return new Padding (0); } 194 } 195 196 protected override Padding DefaultPadding { 197 get { return new Padding (4, 0, 4, 0); } 198 } 199 200 protected override Size DefaultSize { 201 get { return new Size (32, 19); } 202 } 203 #endregion 204 205 #region Protected Methods 206 [EditorBrowsable (EditorBrowsableState.Advanced)] CreateAccessibilityInstance()207 protected override AccessibleObject CreateAccessibilityInstance () 208 { 209 return new ToolStripMenuItemAccessibleObject (); 210 } 211 CreateDefaultDropDown()212 protected override ToolStripDropDown CreateDefaultDropDown () 213 { 214 ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu (); 215 tsddm.OwnerItem = this; 216 return tsddm; 217 } 218 Dispose(bool disposing)219 protected override void Dispose (bool disposing) 220 { 221 base.Dispose (disposing); 222 } 223 OnCheckedChanged(EventArgs e)224 protected virtual void OnCheckedChanged (EventArgs e) 225 { 226 EventHandler eh = (EventHandler)Events [CheckedChangedEvent]; 227 if (eh != null) 228 eh (this, e); 229 } 230 OnCheckStateChanged(EventArgs e)231 protected virtual void OnCheckStateChanged (EventArgs e) 232 { 233 EventHandler eh = (EventHandler)Events [CheckStateChangedEvent]; 234 if (eh != null) 235 eh (this, e); 236 } 237 OnClick(EventArgs e)238 protected override void OnClick (EventArgs e) 239 { 240 if (!this.Enabled) 241 return; 242 243 if (this.HasDropDownItems) { 244 base.OnClick (e); 245 return; 246 } 247 248 if (this.OwnerItem is ToolStripDropDownItem) 249 (this.OwnerItem as ToolStripDropDownItem).OnDropDownItemClicked (new ToolStripItemClickedEventArgs (this)); 250 251 if (this.IsOnDropDown) { 252 ToolStrip ts = this.GetTopLevelToolStrip (); 253 254 if (ts != null) 255 ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked); 256 } 257 258 if (this.IsMdiWindowListEntry) { 259 this.mdi_client_form.MdiParent.MdiContainer.ActivateChild (this.mdi_client_form); 260 return; 261 } 262 263 if (this.check_on_click) 264 this.Checked = !this.Checked; 265 266 base.OnClick (e); 267 268 if (!this.IsOnDropDown && !this.HasDropDownItems) { 269 ToolStrip ts = this.GetTopLevelToolStrip (); 270 271 if (ts != null) 272 ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked); 273 } 274 } 275 OnDropDownHide(EventArgs e)276 protected override void OnDropDownHide (EventArgs e) 277 { 278 base.OnDropDownHide (e); 279 } 280 OnDropDownShow(EventArgs e)281 protected override void OnDropDownShow (EventArgs e) 282 { 283 base.OnDropDownShow (e); 284 } 285 OnFontChanged(EventArgs e)286 protected override void OnFontChanged (EventArgs e) 287 { 288 base.OnFontChanged (e); 289 } 290 OnMouseDown(MouseEventArgs e)291 protected override void OnMouseDown (MouseEventArgs e) 292 { 293 if (!this.IsOnDropDown && this.HasDropDownItems && this.DropDown.Visible) 294 this.close_on_mouse_release = true; 295 296 if (Enabled && !this.DropDown.Visible) 297 this.ShowDropDown (); 298 299 base.OnMouseDown (e); 300 } 301 OnMouseEnter(EventArgs e)302 protected override void OnMouseEnter (EventArgs e) 303 { 304 if (this.IsOnDropDown && this.HasDropDownItems && Enabled) 305 this.ShowDropDown (); 306 307 base.OnMouseEnter (e); 308 } 309 OnMouseLeave(EventArgs e)310 protected override void OnMouseLeave (EventArgs e) 311 { 312 base.OnMouseLeave (e); 313 } 314 OnMouseUp(MouseEventArgs e)315 protected override void OnMouseUp (MouseEventArgs e) 316 { 317 if (this.close_on_mouse_release) { 318 this.Parent.Dismiss (ToolStripDropDownCloseReason.ItemClicked); 319 this.Invalidate (); 320 this.close_on_mouse_release = false; 321 } 322 323 if (!this.HasDropDownItems && Enabled) 324 base.OnMouseUp (e); 325 } 326 OnOwnerChanged(EventArgs e)327 protected override void OnOwnerChanged (EventArgs e) 328 { 329 base.OnOwnerChanged (e); 330 } 331 OnPaint(System.Windows.Forms.PaintEventArgs e)332 protected override void OnPaint (System.Windows.Forms.PaintEventArgs e) 333 { 334 base.OnPaint (e); 335 336 // Can't render without an owner 337 if (this.Owner == null) 338 return; 339 340 // If DropDown.ShowImageMargin is false, we don't display the image 341 Image draw_image = this.UseImageMargin ? this.Image : null; 342 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; 346 347 if ((this.Selected || this.Pressed) && this.IsOnDropDown && font_color == SystemColors.MenuText) 348 font_color = SystemColors.HighlightText; 349 350 if (!this.Enabled && this.ForeColor == SystemColors.ControlText) 351 font_color = SystemColors.GrayText; 352 353 // Gray stuff out if we're disabled 354 draw_image = this.Enabled ? draw_image : ToolStripRenderer.CreateDisabledImage (draw_image); 355 356 // Draw our background 357 this.Owner.Renderer.DrawMenuItemBackground (new ToolStripItemRenderEventArgs (e.Graphics, this)); 358 359 // Figure out where our text and image go 360 Rectangle text_layout_rect; 361 Rectangle image_layout_rect; 362 363 this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); 364 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); 369 } else { 370 text_layout_rect = new Rectangle (35, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height); 371 372 if (image_layout_rect != Rectangle.Empty) 373 image_layout_rect = new Rectangle (new Point (4, 3), base.GetImageSize ()); 374 } 375 376 if (this.Checked && this.ShowMargin) 377 this.Owner.Renderer.DrawItemCheck (new ToolStripItemImageRenderEventArgs (e.Graphics, this, new Rectangle (2, 1, 19, 19))); 378 } 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)); 381 382 string key_string = GetShortcutDisplayString (); 383 384 if (!string.IsNullOrEmpty (key_string) && !this.HasDropDownItems) { 385 int offset = 15; 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)); 389 } 390 391 if (image_layout_rect != Rectangle.Empty) 392 this.Owner.Renderer.DrawItemImage (new ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); 393 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)); 396 397 return; 398 } 399 ProcessCmdKey(ref Message m, Keys keyData)400 protected internal override bool ProcessCmdKey (ref Message m, Keys keyData) 401 { 402 Control source = Control.FromHandle (m.HWnd); 403 Form f = source == null ? null : (Form)source.TopLevelControl; 404 405 if (this.Enabled && keyData == this.shortcut_keys && GetTopLevelControl () == f) { 406 this.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click); 407 return true; 408 } 409 410 return base.ProcessCmdKey (ref m, keyData); 411 } 412 GetTopLevelControl()413 Control GetTopLevelControl () 414 { 415 ToolStripItem item = this; 416 while (item.OwnerItem != null) 417 item = item.OwnerItem; 418 419 if (item.Owner == null) 420 return null; 421 422 if (item.Owner is ContextMenuStrip) { 423 Control container = ((ContextMenuStrip)item.Owner).container; 424 return container == null ? null : container.TopLevelControl; 425 } 426 427 // MainMenuStrip 428 return item.Owner.TopLevelControl; 429 } 430 ProcessMnemonic(char charCode)431 protected internal override bool ProcessMnemonic (char charCode) 432 { 433 if (!this.Selected) 434 this.Parent.ChangeSelection (this); 435 436 if (this.HasDropDownItems) { 437 ToolStripManager.SetActiveToolStrip (this.Parent, true); 438 this.ShowDropDown (); 439 this.DropDown.SelectNextToolStripItem (null, true); 440 } else 441 this.PerformClick (); 442 443 return true; 444 } 445 SetBounds(Rectangle rect)446 protected internal override void SetBounds (Rectangle rect) 447 { 448 base.SetBounds (rect); 449 } 450 #endregion 451 452 #region Public Events 453 static object CheckedChangedEvent = new object (); 454 static object CheckStateChangedEvent = new object (); 455 456 public event EventHandler CheckedChanged { 457 add { Events.AddHandler (CheckedChangedEvent, value); } 458 remove {Events.RemoveHandler (CheckedChangedEvent, value); } 459 } 460 461 public event EventHandler CheckStateChanged { 462 add { Events.AddHandler (CheckStateChangedEvent, value); } 463 remove {Events.RemoveHandler (CheckStateChangedEvent, value); } 464 } 465 #endregion 466 467 #region UIA Framework Events 468 static object UIACheckOnClickChangedEvent = new object (); 469 470 internal event EventHandler UIACheckOnClickChanged { 471 add { Events.AddHandler (UIACheckOnClickChangedEvent, value); } 472 remove { Events.RemoveHandler (UIACheckOnClickChangedEvent, value); } 473 } 474 OnUIACheckOnClickChangedEvent(EventArgs args)475 internal void OnUIACheckOnClickChangedEvent (EventArgs args) 476 { 477 EventHandler eh 478 = (EventHandler) Events [UIACheckOnClickChangedEvent]; 479 if (eh != null) 480 eh (this, args); 481 } 482 #endregion 483 484 #region Internal Properties 485 internal Form MdiClientForm { 486 get { return this.mdi_client_form; } 487 set { this.mdi_client_form = value; } 488 } 489 #endregion 490 491 #region Internal Methods CalculatePreferredSize(Size constrainingSize)492 internal override Size CalculatePreferredSize (Size constrainingSize) 493 { 494 Size base_size = base.CalculatePreferredSize (constrainingSize); 495 496 string key_string = GetShortcutDisplayString (); 497 498 if (string.IsNullOrEmpty (key_string)) 499 return base_size; 500 501 Size text_size = TextRenderer.MeasureText (key_string, this.Font); 502 503 return new Size (base_size.Width + text_size.Width - 25, base_size.Height); 504 } 505 GetShortcutDisplayString()506 internal string GetShortcutDisplayString () 507 { 508 if (this.show_shortcut_keys == false) 509 return string.Empty; 510 if (this.Parent == null || !(this.Parent is ToolStripDropDownMenu)) 511 return string.Empty; 512 513 string key_string = string.Empty; 514 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); 520 } 521 522 return key_string; 523 } 524 HandleAutoExpansion()525 internal void HandleAutoExpansion () 526 { 527 if (this.HasDropDownItems) { 528 this.ShowDropDown (); 529 this.DropDown.SelectNextToolStripItem (null, true); 530 } 531 } 532 HandleClick(int mouse_clicks, EventArgs e)533 internal override void HandleClick (int mouse_clicks, EventArgs e) 534 { 535 this.OnClick (e); 536 537 if (Parent != null) 538 Parent.Invalidate (); 539 } 540 #endregion 541 542 #region ToolStripMenuItemAccessibleObject 543 private class ToolStripMenuItemAccessibleObject : AccessibleObject 544 { 545 } 546 #endregion 547 } 548 } 549