1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc.
23 // Jordi Mas i Hernandez, jordi@ximian.com
29 using System.Collections;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
33 using System.Drawing.Text;
35 namespace System.Windows.Forms
37 [DefaultProperty("Text")]
38 [DefaultEvent("Click")]
39 [DesignTimeVisible(false)]
41 public class MenuItem : Menu
43 internal bool separator;
45 internal bool bar_break;
46 private Shortcut shortcut;
48 private bool checked_;
49 private bool radiocheck;
51 private char mnemonic;
52 private bool showshortcut;
55 private Hashtable mdilist_items;
56 private Hashtable mdilist_forms;
57 private MdiClient mdicontainer;
58 private bool is_window_menu_item;
59 private bool defaut_item;
61 private bool ownerdraw;
63 private int mergeorder;
65 private int menuheight;
67 private MenuMerge mergetype;
68 internal Rectangle bounds;
70 public MenuItem (): base (null)
72 CommonConstructor (string.Empty);
73 shortcut = Shortcut.None;
76 public MenuItem (string text) : base (null)
78 CommonConstructor (text);
79 shortcut = Shortcut.None;
82 public MenuItem (string text, EventHandler onClick) : base (null)
84 CommonConstructor (text);
85 shortcut = Shortcut.None;
89 public MenuItem (string text, MenuItem[] items) : base (items)
91 CommonConstructor (text);
92 shortcut = Shortcut.None;
95 public MenuItem (string text, EventHandler onClick, Shortcut shortcut) : base (null)
97 CommonConstructor (text);
99 this.shortcut = shortcut;
102 public MenuItem (MenuMerge mergeType, int mergeOrder, Shortcut shortcut, string text,
103 EventHandler onClick, EventHandler onPopup, EventHandler onSelect, MenuItem[] items)
106 CommonConstructor (text);
107 this.shortcut = shortcut;
108 mergeorder = mergeOrder;
109 mergetype = mergeType;
116 private void CommonConstructor (string text)
135 mergetype = MenuMerge.Add;
136 Text = text; // Text can change separator status
140 public event EventHandler Click;
141 public event DrawItemEventHandler DrawItem;
142 public event MeasureItemEventHandler MeasureItem;
143 public event EventHandler Popup;
144 public event EventHandler Select;
147 #region Public Properties
150 [DefaultValue(false)]
151 public bool BarBreak {
152 get { return break_; }
153 set { break_ = value; }
157 [DefaultValue(false)]
159 get { return bar_break; }
160 set { bar_break = value; }
163 [DefaultValue(false)]
164 public bool Checked {
165 get { return checked_; }
166 set { checked_ = value; }
169 [DefaultValue(false)]
170 public bool DefaultItem {
171 get { return defaut_item; }
172 set { defaut_item = value; }
177 public bool Enabled {
178 get { return enabled; }
179 set { enabled = value; }
184 get { return index; }
186 if (Parent != null && Parent.MenuItems != null && (value < 0 || value >= Parent.MenuItems.Count))
187 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'");
193 public override bool IsParent {
194 get { return IsPopup; }
197 [DefaultValue(false)]
198 public bool MdiList {
199 get { return mdilist; }
201 if (mdilist == value)
205 if (mdilist || mdilist_items == null)
208 foreach (MenuItem item in mdilist_items.Keys)
209 MenuItems.Remove (item);
210 mdilist_items.Clear ();
211 mdilist_items = null;
216 protected int MenuID {
217 get { return menuid; }
221 public int MergeOrder {
222 get { return mergeorder; }
223 set { mergeorder = value; }
226 [DefaultValue(MenuMerge.Add)]
227 public MenuMerge MergeType {
228 get { return mergetype; }
230 if (!Enum.IsDefined (typeof (MenuMerge), value))
231 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
238 public char Mnemonic {
239 get { return mnemonic; }
242 [DefaultValue(false)]
243 public bool OwnerDraw {
244 get { return ownerdraw; }
245 set { ownerdraw = value; }
250 get { return parent_menu;}
253 [DefaultValue(false)]
254 public bool RadioCheck {
255 get { return radiocheck; }
256 set { radiocheck = value; }
259 [DefaultValue(Shortcut.None)]
261 public Shortcut Shortcut {
262 get { return shortcut;}
264 if (!Enum.IsDefined (typeof (Shortcut), value))
265 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
273 public bool ShowShortcut {
274 get { return showshortcut;}
275 set { showshortcut = value; }
295 public bool Visible {
296 get { return visible;}
298 if (value == visible)
303 if (menu_items != null) {
304 foreach (MenuItem mi in menu_items)
308 if (parent_menu != null)
309 parent_menu.OnMenuChanged (EventArgs.Empty);
313 #endregion Public Properties
315 #region Private Properties
317 internal new int Height {
318 get { return bounds.Height; }
319 set { bounds.Height = value; }
322 internal bool IsPopup {
324 if (menu_items.Count > 0)
331 internal bool MeasureEventDefined {
333 if (ownerdraw == true && MeasureItem != null) {
341 internal bool MenuBar {
342 get { return menubar; }
343 set { menubar = value; }
346 internal int MenuHeight {
347 get { return menuheight; }
348 set { menuheight = value; }
352 internal bool Selected {
353 get { return selected; }
354 set { selected = value; }
357 internal bool Separator {
358 get { return separator; }
359 set { separator = value; }
362 internal DrawItemState Status {
364 DrawItemState status = DrawItemState.None;
365 MenuTracker tracker = Parent.Tracker;
367 status |= (tracker.active || tracker.Navigating ? DrawItemState.Selected : DrawItemState.HotLight);
369 status |= DrawItemState.Grayed | DrawItemState.Disabled;
371 status |= DrawItemState.Checked;
372 if (!tracker.Navigating)
373 status |= DrawItemState.NoAccelerator;
378 internal new int Width {
379 get { return bounds.Width; }
380 set { bounds.Width = value; }
384 get { return bounds.X; }
385 set { bounds.X = value; }
390 set { xtab = value; }
394 get { return bounds.Y; }
395 set { bounds.Y = value; }
398 #endregion Private Properties
400 #region Public Methods
402 public virtual MenuItem CloneMenu ()
404 MenuItem item = new MenuItem ();
405 item.CloneMenu (this);
409 protected void CloneMenu (MenuItem menuitem)
411 base.CloneMenu (menuitem); // Copy subitems
414 MdiList = menuitem.MdiList;
415 is_window_menu_item = menuitem.is_window_menu_item;
416 // Remove items corresponding to window menu items, and add new items
417 // (Otherwise window menu items would show up twice, since the PopulateWindowMenu doesn't
419 bool populated = false;
420 for (int i = MenuItems.Count - 1; i >= 0; i--) {
421 if (MenuItems [i].is_window_menu_item) {
422 MenuItems.RemoveAt (i);
427 PopulateWindowMenu ();
430 BarBreak = menuitem.BarBreak;
431 Break = menuitem.Break;
432 Checked = menuitem.Checked;
433 DefaultItem = menuitem.DefaultItem;
434 Enabled = menuitem.Enabled;
435 MergeOrder = menuitem.MergeOrder;
436 MergeType = menuitem.MergeType;
437 OwnerDraw = menuitem.OwnerDraw;
438 //Parent = menuitem.Parent;
439 RadioCheck = menuitem.RadioCheck;
440 Shortcut = menuitem.Shortcut;
441 ShowShortcut = menuitem.ShowShortcut;
442 Text = menuitem.Text;
443 Visible = menuitem.Visible;
446 Click = menuitem.Click;
447 DrawItem = menuitem.DrawItem;
448 MeasureItem = menuitem.MeasureItem;
449 Popup = menuitem.Popup;
450 Select = menuitem.Select;
453 protected override void Dispose (bool disposing)
455 base.Dispose (disposing);
458 // This really clones the item
459 public virtual MenuItem MergeMenu ()
461 MenuItem item = new MenuItem ();
462 item.CloneMenu (this);
466 public void MergeMenu (MenuItem menuitem)
468 base.MergeMenu (menuitem);
471 protected virtual void OnClick (EventArgs e)
477 protected virtual void OnDrawItem (DrawItemEventArgs e)
480 if (DrawItem != null)
485 ThemeEngine.Current.DrawMenuItem (this, e);
489 protected virtual void OnInitMenuPopup (EventArgs e)
494 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
496 if (OwnerDraw && MeasureItem != null)
497 MeasureItem (this, e);
500 protected virtual void OnPopup (EventArgs e)
506 protected virtual void OnSelect (EventArgs e)
512 public void PerformClick ()
514 OnClick (EventArgs.Empty);
517 public virtual void PerformSelect ()
519 OnSelect (EventArgs.Empty);
522 public override string ToString ()
524 return base.ToString () + ", Items.Count: " + MenuItems.Count + ", Text: " + text;
527 #endregion Public Methods
529 #region Private Methods
531 internal void PerformPopup ()
533 OnPopup (EventArgs.Empty);
536 internal void PerformDrawItem (DrawItemEventArgs e)
538 PopulateWindowMenu ();
542 private void PopulateWindowMenu ()
545 if (mdilist_items == null) {
546 mdilist_items = new Hashtable ();
547 mdilist_forms = new Hashtable ();
551 MainMenu main = GetMainMenu ();
552 if (main == null || main.GetForm () == null)
555 Form form = main.GetForm ();
556 mdicontainer = form.MdiContainer;
557 if (mdicontainer == null)
560 // Remove closed forms
561 foreach (MenuItem item in mdilist_items.Keys) {
562 Form mdichild = (Form) mdilist_items [item];
563 if (!mdicontainer.original_order.Contains (mdichild)) {
564 mdilist_items.Remove (item);
565 mdilist_forms.Remove (mdichild);
566 MenuItems.Remove (item);
570 // Add new forms and update state for existing forms.
571 MenuItem previous = null;
572 for ( int i = 0; i < mdicontainer.original_order.Count; i++) {
573 Form mdichild = (Form) mdicontainer.original_order [i];
575 if (mdilist_forms.Contains (mdichild)) {
576 item = (MenuItem) mdilist_forms [mdichild];
578 item = new MenuItem ();
579 item.is_window_menu_item = true;
580 item.Click += new EventHandler (MdiWindowClickHandler);
581 mdilist_items [item] = mdichild;
582 mdilist_forms [mdichild] = item;
583 MenuItems.AddNoEvents (item);
585 item.Visible = mdichild.Visible;
586 item.Text = "&" + (i + 1).ToString () + " " + mdichild.Text;
587 item.Checked = form.ActiveMdiChild == mdichild;
593 if (mdilist_items != null) {
594 foreach (MenuItem item in mdilist_items.Values) {
595 MenuItems.Remove (item);
598 mdilist_forms.Clear ();
599 mdilist_items.Clear ();
604 internal void PerformMeasureItem (MeasureItemEventArgs e)
609 private void ProcessMnemonic ()
611 if (text == null || text.Length < 2) {
616 bool bPrevAmp = false;
617 for (int i = 0; i < text.Length -1 ; i++) {
618 if (text[i] == '&') {
619 if (bPrevAmp == false && (text[i+1] != '&')) {
620 mnemonic = Char.ToUpper (text[i+1]);
633 private string GetShortCutTextCtrl () { return "Ctrl"; }
634 private string GetShortCutTextAlt () { return "Alt"; }
635 private string GetShortCutTextShift () { return "Shift"; }
637 internal string GetShortCutText ()
639 /* Ctrl+A - Ctrl+Z */
640 if (Shortcut >= Shortcut.CtrlA && Shortcut <= Shortcut.CtrlZ)
641 return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlA));
644 if (Shortcut >= Shortcut.Alt0 && Shortcut <= Shortcut.Alt9)
645 return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Alt0));
647 /* Alt+F1 - Alt+F2 */
648 if (Shortcut >= Shortcut.AltF1 && Shortcut <= Shortcut.AltF9)
649 return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.AltF1));
651 /* Ctrl+0 - Ctrl+9 */
652 if (Shortcut >= Shortcut.Ctrl0 && Shortcut <= Shortcut.Ctrl9)
653 return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Ctrl0));
655 /* Ctrl+F0 - Ctrl+F9 */
656 if (Shortcut >= Shortcut.CtrlF1 && Shortcut <= Shortcut.CtrlF9)
657 return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlF1));
659 /* Ctrl+Shift+0 - Ctrl+Shift+9 */
660 if (Shortcut >= Shortcut.CtrlShift0 && Shortcut <= Shortcut.CtrlShift9)
661 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.CtrlShift0));
663 /* Ctrl+Shift+A - Ctrl+Shift+Z */
664 if (Shortcut >= Shortcut.CtrlShiftA && Shortcut <= Shortcut.CtrlShiftZ)
665 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlShiftA));
667 /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */
668 if (Shortcut >= Shortcut.CtrlShiftF1 && Shortcut <= Shortcut.CtrlShiftF9)
669 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlShiftF1));
672 if (Shortcut >= Shortcut.F1 && Shortcut <= Shortcut.F9)
673 return "F" + (char)((int) '1' + (int)(Shortcut - Shortcut.F1));
675 /* Shift+F1 - Shift+F9 */
676 if (Shortcut >= Shortcut.ShiftF1 && Shortcut <= Shortcut.ShiftF9)
677 return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.ShiftF1));
681 case Shortcut.AltBksp:
683 case Shortcut.AltF10:
684 return GetShortCutTextAlt () + "+F10";
685 case Shortcut.AltF11:
686 return GetShortCutTextAlt () + "+F11";
687 case Shortcut.AltF12:
688 return GetShortCutTextAlt () + "+F12";
689 case Shortcut.CtrlDel:
690 return GetShortCutTextCtrl () + "+Del";
691 case Shortcut.CtrlF10:
692 return GetShortCutTextCtrl () + "+F10";
693 case Shortcut.CtrlF11:
694 return GetShortCutTextCtrl () + "+F11";
695 case Shortcut.CtrlF12:
696 return GetShortCutTextCtrl () + "+F12";
697 case Shortcut.CtrlIns:
698 return GetShortCutTextCtrl () + "+Ins";
699 case Shortcut.CtrlShiftF10:
700 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10";
701 case Shortcut.CtrlShiftF11:
702 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11";
703 case Shortcut.CtrlShiftF12:
704 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12";
717 case Shortcut.ShiftDel:
718 return GetShortCutTextShift () + "+Del";
719 case Shortcut.ShiftF10:
720 return GetShortCutTextShift () + "+F10";
721 case Shortcut.ShiftF11:
722 return GetShortCutTextShift () + "+F11";
723 case Shortcut.ShiftF12:
724 return GetShortCutTextShift () + "+F12";
725 case Shortcut.ShiftIns:
726 return GetShortCutTextShift () + "+Ins";
734 private void MdiWindowClickHandler (object sender, EventArgs e)
736 Form mdichild = (Form) mdilist_items [SelectedItem];
738 // people could add weird items to the Window menu
739 // so we can't assume its just us
740 if (mdichild == null)
743 mdicontainer.ActivateChild (mdichild);
746 #endregion Private Methods