2007-04-23 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
35 namespace System.Windows.Forms
36 {
37         [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)]
38         public class ToolStripMenuItem : ToolStripDropDownItem
39         {
40                 private CheckState checked_state;
41                 private bool check_on_click;
42                 private string shortcut_display_string;
43                 private Keys shortcut_keys = Keys.None;
44                 private bool show_shortcut_keys = true;
45                 private Form mdi_client_form;
46
47                 #region Public Constructors
48                 public ToolStripMenuItem ()
49                         : this (null, null, null, string.Empty)
50                 {
51                 }
52
53                 public ToolStripMenuItem (Image image)
54                         : this (null, image, null, string.Empty)
55                 {
56                 }
57
58                 public ToolStripMenuItem (string text)
59                         : this (text, null, null, string.Empty)
60                 {
61                 }
62
63                 public ToolStripMenuItem (string text, Image image)
64                         : this (text, image, null, string.Empty)
65                 {
66                 }
67
68                 public ToolStripMenuItem (string text, Image image, EventHandler onClick)
69                         : this (text, image, onClick, string.Empty)
70                 {
71                 }
72
73                 public ToolStripMenuItem (string text, Image image, params ToolStripItem[] dropDownItems)
74                         : this (text, image, null, string.Empty)
75                 {
76                         if (dropDownItems != null)
77                                 foreach (ToolStripItem tsi in dropDownItems)
78                                         this.DropDownItems.Add (tsi);
79                 }
80
81                 public ToolStripMenuItem (string text, Image image, EventHandler onClick, Keys shortcutKeys)
82                         : this (text, image, onClick, string.Empty)
83                 {
84                 }
85
86                 public ToolStripMenuItem (string text, Image image, EventHandler onClick, string name)
87                         : base (text, image, onClick, name)
88                 {
89                         base.Overflow = ToolStripItemOverflow.Never;
90                 }
91                 #endregion
92
93                 #region Public Properties
94                 [Bindable (true)]
95                 [DefaultValue (false)]
96                 [RefreshProperties (RefreshProperties.All)]
97                 public bool Checked {
98                         get {
99                                 switch (this.checked_state) {
100                                         case CheckState.Unchecked:
101                                         default:
102                                                 return false;
103                                         case CheckState.Checked:
104                                         case CheckState.Indeterminate:
105                                                 return true;
106                                 }
107                         }
108                         set {
109                                 if (this.checked_state != (value ? CheckState.Checked : CheckState.Unchecked)) {
110                                         this.checked_state = value ? CheckState.Checked : CheckState.Unchecked;
111                                         this.Invalidate ();
112                                         this.OnCheckedChanged (EventArgs.Empty);
113                                 }
114                         }
115                 }
116
117                 [DefaultValue (false)]
118                 public bool CheckOnClick {
119                         get { return this.check_on_click; }
120                         set { this.check_on_click = value; }
121                 }
122
123                 [Bindable (true)]
124                 [DefaultValue (CheckState.Unchecked)]
125                 [RefreshProperties (RefreshProperties.All)]
126                 public CheckState CheckState {
127                         get { return this.checked_state; }
128                         set
129                         {
130                                 if (!Enum.IsDefined (typeof (CheckState), value))
131                                         throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for CheckState", value));
132
133                                 this.checked_state = value;
134                                 this.Invalidate ();
135                                 this.OnCheckStateChanged (EventArgs.Empty);
136                         }
137                 }
138
139                 public override bool Enabled {
140                         get { return base.Enabled; }
141                         set { base.Enabled = value; }
142                 }
143
144                 [Browsable (false)]
145                 public bool IsMdiWindowListEntry {
146                         get { return this.mdi_client_form != null; }
147                 }
148                 
149                 [DefaultValue (ToolStripItemOverflow.Never)]
150                 public new ToolStripItemOverflow Overflow {
151                         get { return base.Overflow; }
152                         set { base.Overflow = value; }
153                 }
154                 
155                 [Localizable (true)]
156                 [DefaultValue (true)]
157                 public bool ShowShortcutKeys {
158                         get { return this.show_shortcut_keys; }
159                         set { this.show_shortcut_keys = value; }
160                 }
161                 
162                 [Localizable (true)]
163                 [DefaultValue (null)]
164                 public string ShortcutKeyDisplayString {
165                         get { return this.shortcut_display_string; }
166                         set { this.shortcut_display_string = value; }
167                 }
168                 
169                 [Localizable (true)]
170                 [DefaultValue (Keys.None)]
171                 public Keys ShortcutKeys {
172                         get { return this.shortcut_keys; }
173                         set { 
174                                 if (this.shortcut_keys != value) {
175                                         this.shortcut_keys = value;
176                                         
177                                         if (this.Parent != null)
178                                                 ToolStripManager.AddToolStripMenuItem (this);
179                                 }
180                          }
181                 }
182                 #endregion
183
184                 #region Protected Properties
185                 protected internal override Padding DefaultMargin {
186                         get { return new Padding (0); }
187                 }
188
189                 protected override Padding DefaultPadding {
190                         get { return new Padding (4, 0, 4, 0); }
191                 }
192
193                 protected override Size DefaultSize {
194                         get { return new Size (32, 19); }
195                 }
196                 #endregion
197
198                 #region Protected Methods
199                 protected override ToolStripDropDown CreateDefaultDropDown ()
200                 {
201                         ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu ();
202                         tsddm.OwnerItem = this;
203                         return tsddm;
204                 }
205
206                 protected override void Dispose (bool disposing)
207                 {
208                         base.Dispose (disposing);
209                 }
210
211                 protected virtual void OnCheckedChanged (EventArgs e)
212                 {
213                         EventHandler eh = (EventHandler)Events [CheckedChangedEvent];
214                         if (eh != null)
215                                 eh (this, e);
216                 }
217
218                 protected virtual void OnCheckStateChanged (EventArgs e)
219                 {
220                         EventHandler eh = (EventHandler)Events [CheckStateChangedEvent];
221                         if (eh != null)
222                                 eh (this, e);
223                 }
224
225                 protected override void OnClick (EventArgs e)
226                 {
227                         if (!this.Enabled)
228                                 return;
229                                 
230                         if (this.IsOnDropDown) {
231                                 if (this.HasDropDownItems)
232                                         return;
233
234                                 this.HideDropDown (ToolStripDropDownCloseReason.ItemClicked);
235                                 
236                                 (this.Parent as ToolStripDropDown).Close (ToolStripDropDownCloseReason.ItemClicked);
237                                 ToolStripManager.FireAppFocusChanged (this.Parent);
238
239                                 Object parent = this.Parent;
240
241                                 // Find the top level MenuStrip to inform it to close all open
242                                 // dropdowns because this one was clicked
243                                 while (parent != null) {
244                                         if (parent is MenuStrip)
245                                                 (parent as MenuStrip).HideMenus (true, ToolStripDropDownCloseReason.ItemClicked);
246
247                                         if (parent is ToolStripDropDown)
248                                                 parent = (parent as ToolStripDropDown).OwnerItem;
249                                         else if (parent is ToolStripItem)
250                                                 parent = (parent as ToolStripItem).Parent;
251                                         else
252                                                 break;
253                                 }
254                         }
255
256                         if (this.IsMdiWindowListEntry) {
257                                 this.mdi_client_form.MdiParent.MdiContainer.ActivateChild (this.mdi_client_form);
258                                 return;
259                         }
260                         
261                         if (this.check_on_click)
262                                 this.Checked = !this.Checked;
263
264                         base.OnClick (e);
265                 }
266
267                 protected override void OnDropDownHide (EventArgs e)
268                 {
269                         base.OnDropDownHide (e);
270                 }
271
272                 protected override void OnDropDownShow (EventArgs e)
273                 {
274                         base.OnDropDownShow (e);
275                 }
276
277                 protected override void OnFontChanged (EventArgs e)
278                 {
279                         base.OnFontChanged (e);
280                 }
281
282                 protected override void OnMouseDown (MouseEventArgs e)
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.HasDropDownItems && Enabled)
307                                 base.OnMouseUp (e);
308                 }
309
310                 protected override void OnOwnerChanged (EventArgs e)
311                 {
312                         base.OnOwnerChanged (e);
313                 }
314
315                 protected override void OnPaint (System.Windows.Forms.PaintEventArgs e)
316                 {
317                         base.OnPaint (e);
318
319                         if (this.Owner != null) {
320                                 Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText;
321                                 Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image);
322
323                                 if (this.IsOnDropDown)
324                                         this.Owner.Renderer.DrawMenuItemBackground (new System.Windows.Forms.ToolStripItemRenderEventArgs (e.Graphics, this));
325                                 else
326                                         this.Owner.Renderer.DrawButtonBackground (new System.Windows.Forms.ToolStripItemRenderEventArgs (e.Graphics, this));
327
328                                 Rectangle text_layout_rect;
329                                 Rectangle image_layout_rect;
330
331                                 this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect);
332
333                                 if (this.IsOnDropDown) {
334                                         text_layout_rect = new Rectangle (35, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height);
335                                         if (image_layout_rect != Rectangle.Empty)
336                                                 image_layout_rect = new Rectangle (new Point (4, 3), base.GetImageSize ());
337
338                                         if (this.Checked)
339                                                 this.Owner.Renderer.DrawItemCheck (new ToolStripItemImageRenderEventArgs (e.Graphics, this, new Rectangle (2, 1, 19, 19)));
340                                 }
341                                 if (text_layout_rect != Rectangle.Empty)
342                                         this.Owner.Renderer.DrawItemText (new System.Windows.Forms.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign));
343
344                                 string key_string = GetShortcutDisplayString ();
345                                 
346                                 if (!string.IsNullOrEmpty (key_string) && !this.HasDropDownItems) {
347                                         int offset = 15;
348                                         Size key_string_size = TextRenderer.MeasureText (key_string, this.Font);
349                                         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);
350                                         this.Owner.Renderer.DrawItemText (new System.Windows.Forms.ToolStripItemTextRenderEventArgs (e.Graphics, this, key_string, key_string_rect, font_color, this.Font, this.TextAlign));
351                                 }
352                                         
353                                 if (image_layout_rect != Rectangle.Empty)
354                                         this.Owner.Renderer.DrawItemImage (new System.Windows.Forms.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect));
355
356                                 if (this.IsOnDropDown && this.HasDropDownItems)
357                                         this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Bounds.Width - 17, 2, 10, 20), Color.Black, ArrowDirection.Right));
358                                 return;
359                         }
360                 }
361
362                 protected internal override bool ProcessCmdKey (ref Message m, Keys keyData)
363                 {
364                         if (this.Enabled && keyData == this.shortcut_keys) {
365                                 this.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click);
366                                 return true;
367                         }
368                                 
369                         return base.ProcessCmdKey (ref m, keyData);
370                 }
371                 
372                 protected internal override void SetBounds (Rectangle bounds)
373                 {
374                         base.SetBounds (bounds);
375                 }
376                 #endregion
377
378                 #region Public Events
379                 static object CheckedChangedEvent = new object ();
380                 static object CheckStateChangedEvent = new object ();
381
382                 public event EventHandler CheckedChanged {
383                         add { Events.AddHandler (CheckedChangedEvent, value); }
384                         remove {Events.RemoveHandler (CheckedChangedEvent, value); }
385                 }
386
387                 public event EventHandler CheckStateChanged {
388                         add { Events.AddHandler (CheckStateChangedEvent, value); }
389                         remove {Events.RemoveHandler (CheckStateChangedEvent, value); }
390                 }
391                 #endregion
392
393                 #region Internal Properties
394                 internal Form MdiClientForm {
395                         get { return this.mdi_client_form; }
396                         set { this.mdi_client_form = value; }
397                 }
398                 #endregion
399
400                 #region Internal Methods
401                 internal override Size CalculatePreferredSize (Size constrainingSize)
402                 {
403                         Size base_size = base.CalculatePreferredSize (constrainingSize);
404                         
405                         string key_string = GetShortcutDisplayString ();
406                         
407                         if (string.IsNullOrEmpty (key_string))
408                                 return base_size;
409                         
410                         Size text_size = TextRenderer.MeasureText (key_string, this.Font);
411                         
412                         return new Size (base_size.Width + text_size.Width - 25, base_size.Height);
413                 }
414                 
415                 internal string GetShortcutDisplayString ()
416                 {
417                         if (this.show_shortcut_keys == false)
418                                 return string.Empty;
419
420                         string key_string = string.Empty;
421
422                         if (!string.IsNullOrEmpty (this.shortcut_display_string))
423                                 key_string = this.shortcut_display_string;
424                         else if (this.shortcut_keys != Keys.None) {
425                                 KeysConverter kc = new KeysConverter ();
426                                 key_string = kc.ConvertToString (this.shortcut_keys);
427                         }
428                         
429                         return key_string;
430                 }
431                 #endregion
432         }
433 }
434 #endif