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 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); }
172 #region Public Properties
175 [DefaultValue(false)]
176 public bool BarBreak
{
177 get { return break_; }
178 set { break_ = value; }
182 [DefaultValue(false)]
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; }
202 public bool Enabled
{
203 get { return enabled; }
204 set { enabled = value; }
209 get { return index; }
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'");
218 public override bool IsParent
{
219 get { return IsPopup; }
222 [DefaultValue(false)]
223 public bool MdiList
{
224 get { return mdilist; }
226 if (mdilist
== value)
230 if (mdilist
|| mdilist_items
== null)
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; }
246 public int MergeOrder
{
247 get { return mergeorder; }
248 set { mergeorder = value; }
251 [DefaultValue(MenuMerge
.Add
)]
252 public MenuMerge MergeType
{
253 get { return mergetype; }
255 if (!Enum
.IsDefined (typeof (MenuMerge
), value))
256 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
263 public char Mnemonic
{
264 get { return mnemonic; }
267 [DefaultValue(false)]
268 public bool OwnerDraw
{
269 get { return ownerdraw; }
270 set { ownerdraw = value; }
275 get { return parent_menu;}
278 [DefaultValue(false)]
279 public bool RadioCheck
{
280 get { return radiocheck; }
281 set { radiocheck = value; }
284 [DefaultValue(Shortcut
.None
)]
286 public Shortcut Shortcut
{
287 get { return shortcut;}
289 if (!Enum
.IsDefined (typeof (Shortcut
), value))
290 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
298 public bool ShowShortcut
{
299 get { return showshortcut;}
300 set { showshortcut = value; }
321 public bool Visible
{
322 get { return visible;}
324 if (value == visible
)
329 if (menu_items
!= null) {
330 foreach (MenuItem mi
in menu_items
)
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
{
350 if (menu_items
.Count
> 0)
357 internal bool MeasureEventDefined
{
359 if (ownerdraw
== true && Events
[MeasureItemEvent
] != null) {
367 internal bool MenuBar
{
368 get { return menubar; }
369 set { menubar = value; }
372 internal int MenuHeight
{
373 get { return menuheight; }
374 set { menuheight = value; }
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
{
390 DrawItemState status
= DrawItemState
.None
;
391 MenuTracker tracker
= Parent
.Tracker
;
393 status
|= (tracker
.active
|| tracker
.Navigating
? DrawItemState
.Selected
: DrawItemState
.HotLight
);
395 status
|= DrawItemState
.Grayed
| DrawItemState
.Disabled
;
397 status
|= DrawItemState
.Checked
;
398 if (!tracker
.Navigating
)
399 status
|= DrawItemState
.NoAccelerator
;
404 internal bool VisibleItems
{
406 if (menu_items
!= null) {
407 foreach (MenuItem mi
in menu_items
)
415 internal new int Width
{
416 get { return bounds.Width; }
417 set { bounds.Width = value; }
421 get { return bounds.X; }
422 set { bounds.X = value; }
427 set { xtab = value; }
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);
446 protected void CloneMenu (MenuItem menuitem
)
448 base.CloneMenu (menuitem
); // Copy subitems
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
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
);
464 PopulateWindowMenu ();
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
;
484 Click
= menuitem
.Click
;
485 DrawItem
= menuitem
.DrawItem
;
486 MeasureItem
= menuitem
.MeasureItem
;
487 Popup
= menuitem
.Popup
;
488 Select
= menuitem
.Select
;
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);
505 public void MergeMenu (MenuItem menuitem
)
507 base.MergeMenu (menuitem
);
510 protected virtual void OnClick (EventArgs e
)
512 EventHandler eh
= (EventHandler
)(Events
[ClickEvent
]);
517 protected virtual void OnDrawItem (DrawItemEventArgs e
)
520 DrawItemEventHandler eh
= (DrawItemEventHandler
)(Events
[DrawItemEvent
]);
526 ThemeEngine
.Current
.DrawMenuItem (this, e
);
530 protected virtual void OnInitMenuPopup (EventArgs e
)
535 protected virtual void OnMeasureItem (MeasureItemEventArgs e
)
540 MeasureItemEventHandler eh
= (MeasureItemEventHandler
)(Events
[MeasureItemEvent
]);
545 protected virtual void OnPopup (EventArgs e
)
547 EventHandler eh
= (EventHandler
)(Events
[PopupEvent
]);
552 protected virtual void OnSelect (EventArgs e
)
554 EventHandler eh
= (EventHandler
)(Events
[SelectEvent
]);
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 ();
595 private void PopulateWindowMenu ()
598 if (mdilist_items
== null) {
599 mdilist_items
= new Hashtable ();
600 mdilist_forms
= new Hashtable ();
604 MainMenu main
= GetMainMenu ();
605 if (main
== null || main
.GetForm () == null)
608 Form form
= main
.GetForm ();
609 mdicontainer
= form
.MdiContainer
;
610 if (mdicontainer
== null)
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
];
630 if (mdilist_forms
.Contains (mdichild
)) {
631 item
= (MenuItem
) mdilist_forms
[mdichild
];
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
;
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
)
663 private void ProcessMnemonic ()
665 if (text
== null || text
.Length
< 2) {
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]);
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
));
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
));
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
));
735 case Shortcut
.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";
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";
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)
797 mdicontainer
.ActivateChild (mdichild
);
800 #endregion Private Methods