* TextBoxBase.cs: Take HideSelection into account when
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MenuItem.cs
blob9e47912166fe8d47784b208bc210f4749b84e583
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:
8 //
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.
22 // Authors:
23 // Jordi Mas i Hernandez, jordi@ximian.com
27 // NOT COMPLETE
29 using System.Collections;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33 using System.Drawing.Text;
35 namespace System.Windows.Forms
37 [DefaultProperty("Text")]
38 [DefaultEvent("Click")]
39 [DesignTimeVisible(false)]
40 [ToolboxItem(false)]
41 public class MenuItem : Menu
43 internal bool separator;
44 internal bool break_;
45 internal bool bar_break;
46 private Shortcut shortcut;
47 private string text;
48 private bool checked_;
49 private bool radiocheck;
50 private bool enabled;
51 private char mnemonic;
52 private bool showshortcut;
53 private int index;
54 private bool mdilist;
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;
60 private bool visible;
61 private bool ownerdraw;
62 private int menuid;
63 private int mergeorder;
64 private int xtab;
65 private int menuheight;
66 private bool menubar;
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;
86 Click += onClick;
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);
98 Click += onClick;
99 this.shortcut = shortcut;
102 public MenuItem (MenuMerge mergeType, int mergeOrder, Shortcut shortcut, string text,
103 EventHandler onClick, EventHandler onPopup, EventHandler onSelect, MenuItem[] items)
104 : base (items)
106 CommonConstructor (text);
107 this.shortcut = shortcut;
108 mergeorder = mergeOrder;
109 mergetype = mergeType;
111 Click += onClick;
112 Popup += onPopup;
113 Select += onSelect;
116 private void CommonConstructor (string text)
118 defaut_item = false;
119 separator = false;
120 break_ = false;
121 bar_break = false;
122 checked_ = false;
123 radiocheck = false;
124 enabled = true;
125 showshortcut = true;
126 visible = true;
127 ownerdraw = false;
128 menubar = false;
129 menuheight = 0;
130 xtab = 0;
131 index = -1;
132 mnemonic = '\0';
133 menuid = -1;
134 mergeorder = 0;
135 mergetype = MenuMerge.Add;
136 Text = text; // Text can change separator status
139 #region Events
140 static object ClickEvent = new object ();
141 static object DrawItemEvent = new object ();
142 static object MeasureItemEvent = new object ();
143 static object PopupEvent = new object ();
144 static object SelectEvent = new object ();
146 public event EventHandler Click {
147 add { Events.AddHandler (ClickEvent, value); }
148 remove { Events.RemoveHandler (ClickEvent, value); }
151 public event DrawItemEventHandler DrawItem {
152 add { Events.AddHandler (DrawItemEvent, value); }
153 remove { Events.RemoveHandler (DrawItemEvent, value); }
156 public event MeasureItemEventHandler MeasureItem {
157 add { Events.AddHandler (MeasureItemEvent, value); }
158 remove { Events.RemoveHandler (MeasureItemEvent, value); }
161 public event EventHandler Popup {
162 add { Events.AddHandler (PopupEvent, value); }
163 remove { Events.RemoveHandler (PopupEvent, value); }
166 public event EventHandler Select {
167 add { Events.AddHandler (SelectEvent, value); }
168 remove { Events.RemoveHandler (SelectEvent, value); }
170 #endregion // Events
172 #region Public Properties
174 [Browsable(false)]
175 [DefaultValue(false)]
176 public bool BarBreak {
177 get { return break_; }
178 set { break_ = value; }
181 [Browsable(false)]
182 [DefaultValue(false)]
183 public bool Break {
184 get { return bar_break; }
185 set { bar_break = value; }
188 [DefaultValue(false)]
189 public bool Checked {
190 get { return checked_; }
191 set { checked_ = value; }
194 [DefaultValue(false)]
195 public bool DefaultItem {
196 get { return defaut_item; }
197 set { defaut_item = value; }
200 [DefaultValue(true)]
201 [Localizable(true)]
202 public bool Enabled {
203 get { return enabled; }
204 set { enabled = value; }
207 [Browsable(false)]
208 public int Index {
209 get { return index; }
210 set {
211 if (Parent != null && Parent.MenuItems != null && (value < 0 || value >= Parent.MenuItems.Count))
212 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'");
213 index = value;
217 [Browsable(false)]
218 public override bool IsParent {
219 get { return IsPopup; }
222 [DefaultValue(false)]
223 public bool MdiList {
224 get { return mdilist; }
225 set {
226 if (mdilist == value)
227 return;
228 mdilist = value;
230 if (mdilist || mdilist_items == null)
231 return;
233 foreach (MenuItem item in mdilist_items.Keys)
234 MenuItems.Remove (item);
235 mdilist_items.Clear ();
236 mdilist_items = null;
241 protected int MenuID {
242 get { return menuid; }
245 [DefaultValue(0)]
246 public int MergeOrder {
247 get { return mergeorder; }
248 set { mergeorder = value; }
251 [DefaultValue(MenuMerge.Add)]
252 public MenuMerge MergeType {
253 get { return mergetype; }
254 set {
255 if (!Enum.IsDefined (typeof (MenuMerge), value))
256 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
258 mergetype = value;
262 [Browsable(false)]
263 public char Mnemonic {
264 get { return mnemonic; }
267 [DefaultValue(false)]
268 public bool OwnerDraw {
269 get { return ownerdraw; }
270 set { ownerdraw = value; }
273 [Browsable(false)]
274 public Menu Parent {
275 get { return parent_menu;}
278 [DefaultValue(false)]
279 public bool RadioCheck {
280 get { return radiocheck; }
281 set { radiocheck = value; }
284 [DefaultValue(Shortcut.None)]
285 [Localizable(true)]
286 public Shortcut Shortcut {
287 get { return shortcut;}
288 set {
289 if (!Enum.IsDefined (typeof (Shortcut), value))
290 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
292 shortcut = value;
296 [DefaultValue(true)]
297 [Localizable(true)]
298 public bool ShowShortcut {
299 get { return showshortcut;}
300 set { showshortcut = value; }
303 [Localizable(true)]
304 public string Text {
305 get { return text; }
306 set {
307 text = value;
309 if (text == "-")
310 separator = true;
311 else
312 separator = false;
314 ProcessMnemonic ();
315 Invalidate ();
319 [DefaultValue(true)]
320 [Localizable(true)]
321 public bool Visible {
322 get { return visible;}
323 set {
324 if (value == visible)
325 return;
327 visible = value;
329 if (menu_items != null) {
330 foreach (MenuItem mi in menu_items)
331 mi.Visible = value;
334 if (parent_menu != null)
335 parent_menu.OnMenuChanged (EventArgs.Empty);
339 #endregion Public Properties
341 #region Private Properties
343 internal new int Height {
344 get { return bounds.Height; }
345 set { bounds.Height = value; }
348 internal bool IsPopup {
349 get {
350 if (menu_items.Count > 0)
351 return true;
352 else
353 return false;
357 internal bool MeasureEventDefined {
358 get {
359 if (ownerdraw == true && Events [MeasureItemEvent] != null) {
360 return true;
361 } else {
362 return false;
367 internal bool MenuBar {
368 get { return menubar; }
369 set { menubar = value; }
372 internal int MenuHeight {
373 get { return menuheight; }
374 set { menuheight = value; }
377 bool selected;
378 internal bool Selected {
379 get { return selected; }
380 set { selected = value; }
383 internal bool Separator {
384 get { return separator; }
385 set { separator = value; }
388 internal DrawItemState Status {
389 get {
390 DrawItemState status = DrawItemState.None;
391 MenuTracker tracker = Parent.Tracker;
392 if (Selected)
393 status |= (tracker.active || tracker.Navigating ? DrawItemState.Selected : DrawItemState.HotLight);
394 if (!Enabled)
395 status |= DrawItemState.Grayed | DrawItemState.Disabled;
396 if (Checked)
397 status |= DrawItemState.Checked;
398 if (!tracker.Navigating)
399 status |= DrawItemState.NoAccelerator;
400 return status;
404 internal bool VisibleItems {
405 get {
406 if (menu_items != null) {
407 foreach (MenuItem mi in menu_items)
408 if (mi.Visible)
409 return true;
411 return false;
415 internal new int Width {
416 get { return bounds.Width; }
417 set { bounds.Width = value; }
420 internal new int X {
421 get { return bounds.X; }
422 set { bounds.X = value; }
425 internal int XTab {
426 get { return xtab; }
427 set { xtab = value; }
430 internal new int Y {
431 get { return bounds.Y; }
432 set { bounds.Y = value; }
435 #endregion Private Properties
437 #region Public Methods
439 public virtual MenuItem CloneMenu ()
441 MenuItem item = new MenuItem ();
442 item.CloneMenu (this);
443 return item;
446 protected void CloneMenu (MenuItem menuitem)
448 base.CloneMenu (menuitem); // Copy subitems
450 // Window list
451 MdiList = menuitem.MdiList;
452 is_window_menu_item = menuitem.is_window_menu_item;
453 // Remove items corresponding to window menu items, and add new items
454 // (Otherwise window menu items would show up twice, since the PopulateWindowMenu doesn't
455 // now them)
456 bool populated = false;
457 for (int i = MenuItems.Count - 1; i >= 0; i--) {
458 if (MenuItems [i].is_window_menu_item) {
459 MenuItems.RemoveAt (i);
460 populated = true;
463 if (populated)
464 PopulateWindowMenu ();
466 // Properties
467 BarBreak = menuitem.BarBreak;
468 Break = menuitem.Break;
469 Checked = menuitem.Checked;
470 DefaultItem = menuitem.DefaultItem;
471 Enabled = menuitem.Enabled;
472 MergeOrder = menuitem.MergeOrder;
473 MergeType = menuitem.MergeType;
474 OwnerDraw = menuitem.OwnerDraw;
475 //Parent = menuitem.Parent;
476 RadioCheck = menuitem.RadioCheck;
477 Shortcut = menuitem.Shortcut;
478 ShowShortcut = menuitem.ShowShortcut;
479 Text = menuitem.Text;
480 Visible = menuitem.Visible;
482 #if notyet
483 // Events
484 Click = menuitem.Click;
485 DrawItem = menuitem.DrawItem;
486 MeasureItem = menuitem.MeasureItem;
487 Popup = menuitem.Popup;
488 Select = menuitem.Select;
489 #endif
492 protected override void Dispose (bool disposing)
494 base.Dispose (disposing);
497 // This really clones the item
498 public virtual MenuItem MergeMenu ()
500 MenuItem item = new MenuItem ();
501 item.CloneMenu (this);
502 return item;
505 public void MergeMenu (MenuItem menuitem)
507 base.MergeMenu (menuitem);
510 protected virtual void OnClick (EventArgs e)
512 EventHandler eh = (EventHandler)(Events [ClickEvent]);
513 if (eh != null)
514 eh (this, e);
517 protected virtual void OnDrawItem (DrawItemEventArgs e)
519 if (OwnerDraw) {
520 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
521 if (eh != null)
522 eh (this, e);
523 return;
526 ThemeEngine.Current.DrawMenuItem (this, e);
530 protected virtual void OnInitMenuPopup (EventArgs e)
532 OnPopup (e);
535 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
537 if (!OwnerDraw)
538 return;
540 MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
541 if (eh != null)
542 eh (this, e);
545 protected virtual void OnPopup (EventArgs e)
547 EventHandler eh = (EventHandler)(Events [PopupEvent]);
548 if (eh != null)
549 eh (this, e);
552 protected virtual void OnSelect (EventArgs e)
554 EventHandler eh = (EventHandler)(Events [SelectEvent]);
555 if (eh != null)
556 eh (this, e);
559 public void PerformClick ()
561 OnClick (EventArgs.Empty);
564 public virtual void PerformSelect ()
566 OnSelect (EventArgs.Empty);
569 public override string ToString ()
571 return base.ToString () + ", Items.Count: " + MenuItems.Count + ", Text: " + text;
574 #endregion Public Methods
576 #region Private Methods
578 internal virtual void Invalidate ()
580 if ((Parent != null) && (Parent is MainMenu) && Parent.Wnd != null)
581 XplatUI.RequestNCRecalc (Parent.Wnd.FindForm ().Handle);
584 internal void PerformPopup ()
586 OnPopup (EventArgs.Empty);
589 internal void PerformDrawItem (DrawItemEventArgs e)
591 PopulateWindowMenu ();
592 OnDrawItem (e);
595 private void PopulateWindowMenu ()
597 if (mdilist) {
598 if (mdilist_items == null) {
599 mdilist_items = new Hashtable ();
600 mdilist_forms = new Hashtable ();
603 do {
604 MainMenu main = GetMainMenu ();
605 if (main == null || main.GetForm () == null)
606 break;
608 Form form = main.GetForm ();
609 mdicontainer = form.MdiContainer;
610 if (mdicontainer == null)
611 break;
614 // Remove closed forms
615 MenuItem[] items = new MenuItem[mdilist_items.Count];
616 mdilist_items.Keys.CopyTo (items, 0);
617 foreach (MenuItem item in items) {
618 Form mdichild = (Form) mdilist_items [item];
619 if (!mdicontainer.mdi_child_list.Contains(mdichild)) {
620 mdilist_items.Remove (item);
621 mdilist_forms.Remove (mdichild);
622 MenuItems.Remove (item);
626 // Add new forms and update state for existing forms.
627 for (int i = 0; i < mdicontainer.mdi_child_list.Count; i++) {
628 Form mdichild = (Form)mdicontainer.mdi_child_list[i];
629 MenuItem item;
630 if (mdilist_forms.Contains (mdichild)) {
631 item = (MenuItem) mdilist_forms [mdichild];
632 } else {
633 item = new MenuItem ();
634 item.is_window_menu_item = true;
635 item.Click += new EventHandler (MdiWindowClickHandler);
636 mdilist_items [item] = mdichild;
637 mdilist_forms [mdichild] = item;
638 MenuItems.AddNoEvents (item);
640 item.Visible = mdichild.Visible;
641 item.Text = "&" + (i + 1).ToString () + " " + mdichild.Text;
642 item.Checked = form.ActiveMdiChild == mdichild;
644 } while (false);
645 } else {
646 // Remove all forms
647 if (mdilist_items != null) {
648 foreach (MenuItem item in mdilist_items.Values) {
649 MenuItems.Remove (item);
652 mdilist_forms.Clear ();
653 mdilist_items.Clear ();
658 internal void PerformMeasureItem (MeasureItemEventArgs e)
660 OnMeasureItem (e);
663 private void ProcessMnemonic ()
665 if (text == null || text.Length < 2) {
666 mnemonic = '\0';
667 return;
670 bool bPrevAmp = false;
671 for (int i = 0; i < text.Length -1 ; i++) {
672 if (text[i] == '&') {
673 if (bPrevAmp == false && (text[i+1] != '&')) {
674 mnemonic = Char.ToUpper (text[i+1]);
675 return;
678 bPrevAmp = true;
680 else
681 bPrevAmp = false;
684 mnemonic = '\0';
687 private string GetShortCutTextCtrl () { return "Ctrl"; }
688 private string GetShortCutTextAlt () { return "Alt"; }
689 private string GetShortCutTextShift () { return "Shift"; }
691 internal string GetShortCutText ()
693 /* Ctrl+A - Ctrl+Z */
694 if (Shortcut >= Shortcut.CtrlA && Shortcut <= Shortcut.CtrlZ)
695 return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlA));
697 /* Alt+0 - Alt+9 */
698 if (Shortcut >= Shortcut.Alt0 && Shortcut <= Shortcut.Alt9)
699 return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Alt0));
701 /* Alt+F1 - Alt+F2 */
702 if (Shortcut >= Shortcut.AltF1 && Shortcut <= Shortcut.AltF9)
703 return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.AltF1));
705 /* Ctrl+0 - Ctrl+9 */
706 if (Shortcut >= Shortcut.Ctrl0 && Shortcut <= Shortcut.Ctrl9)
707 return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Ctrl0));
709 /* Ctrl+F0 - Ctrl+F9 */
710 if (Shortcut >= Shortcut.CtrlF1 && Shortcut <= Shortcut.CtrlF9)
711 return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlF1));
713 /* Ctrl+Shift+0 - Ctrl+Shift+9 */
714 if (Shortcut >= Shortcut.CtrlShift0 && Shortcut <= Shortcut.CtrlShift9)
715 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.CtrlShift0));
717 /* Ctrl+Shift+A - Ctrl+Shift+Z */
718 if (Shortcut >= Shortcut.CtrlShiftA && Shortcut <= Shortcut.CtrlShiftZ)
719 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlShiftA));
721 /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */
722 if (Shortcut >= Shortcut.CtrlShiftF1 && Shortcut <= Shortcut.CtrlShiftF9)
723 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlShiftF1));
725 /* F1 - F9 */
726 if (Shortcut >= Shortcut.F1 && Shortcut <= Shortcut.F9)
727 return "F" + (char)((int) '1' + (int)(Shortcut - Shortcut.F1));
729 /* Shift+F1 - Shift+F9 */
730 if (Shortcut >= Shortcut.ShiftF1 && Shortcut <= Shortcut.ShiftF9)
731 return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.ShiftF1));
733 /* Special cases */
734 switch (Shortcut) {
735 case Shortcut.AltBksp:
736 return "AltBksp";
737 case Shortcut.AltF10:
738 return GetShortCutTextAlt () + "+F10";
739 case Shortcut.AltF11:
740 return GetShortCutTextAlt () + "+F11";
741 case Shortcut.AltF12:
742 return GetShortCutTextAlt () + "+F12";
743 case Shortcut.CtrlDel:
744 return GetShortCutTextCtrl () + "+Del";
745 case Shortcut.CtrlF10:
746 return GetShortCutTextCtrl () + "+F10";
747 case Shortcut.CtrlF11:
748 return GetShortCutTextCtrl () + "+F11";
749 case Shortcut.CtrlF12:
750 return GetShortCutTextCtrl () + "+F12";
751 case Shortcut.CtrlIns:
752 return GetShortCutTextCtrl () + "+Ins";
753 case Shortcut.CtrlShiftF10:
754 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10";
755 case Shortcut.CtrlShiftF11:
756 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11";
757 case Shortcut.CtrlShiftF12:
758 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12";
759 case Shortcut.Del:
760 return "Del";
761 case Shortcut.F10:
762 return "F10";
763 case Shortcut.F11:
764 return "F11";
765 case Shortcut.F12:
766 return "F12";
767 case Shortcut.Ins:
768 return "Ins";
769 case Shortcut.None:
770 return "None";
771 case Shortcut.ShiftDel:
772 return GetShortCutTextShift () + "+Del";
773 case Shortcut.ShiftF10:
774 return GetShortCutTextShift () + "+F10";
775 case Shortcut.ShiftF11:
776 return GetShortCutTextShift () + "+F11";
777 case Shortcut.ShiftF12:
778 return GetShortCutTextShift () + "+F12";
779 case Shortcut.ShiftIns:
780 return GetShortCutTextShift () + "+Ins";
781 default:
782 break;
785 return "";
788 private void MdiWindowClickHandler (object sender, EventArgs e)
790 Form mdichild = (Form) mdilist_items [SelectedItem];
792 // people could add weird items to the Window menu
793 // so we can't assume its just us
794 if (mdichild == null)
795 return;
797 mdicontainer.ActivateChild (mdichild);
800 #endregion Private Methods