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