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; }
205 if (enabled
== value)
215 get { return index; }
217 if (Parent
!= null && Parent
.MenuItems
!= null && (value < 0 || value >= Parent
.MenuItems
.Count
))
218 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'");
224 public override bool IsParent
{
225 get { return IsPopup; }
228 [DefaultValue(false)]
229 public bool MdiList
{
230 get { return mdilist; }
232 if (mdilist
== value)
236 if (mdilist
|| mdilist_items
== null)
239 foreach (MenuItem item
in mdilist_items
.Keys
)
240 MenuItems
.Remove (item
);
241 mdilist_items
.Clear ();
242 mdilist_items
= null;
246 protected int MenuID
{
247 get { return menuid; }
251 public int MergeOrder
{
252 get { return mergeorder; }
253 set { mergeorder = value; }
256 [DefaultValue(MenuMerge
.Add
)]
257 public MenuMerge MergeType
{
258 get { return mergetype; }
260 if (!Enum
.IsDefined (typeof (MenuMerge
), value))
261 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
268 public char Mnemonic
{
269 get { return mnemonic; }
272 [DefaultValue(false)]
273 public bool OwnerDraw
{
274 get { return ownerdraw; }
275 set { ownerdraw = value; }
280 get { return parent_menu;}
283 [DefaultValue(false)]
284 public bool RadioCheck
{
285 get { return radiocheck; }
286 set { radiocheck = value; }
289 [DefaultValue(Shortcut
.None
)]
291 public Shortcut Shortcut
{
292 get { return shortcut;}
294 if (!Enum
.IsDefined (typeof (Shortcut
), value))
295 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
303 public bool ShowShortcut
{
304 get { return showshortcut;}
305 set { showshortcut = value; }
326 public bool Visible
{
327 get { return visible;}
329 if (value == visible
)
334 if (menu_items
!= null) {
335 foreach (MenuItem mi
in menu_items
)
339 if (parent_menu
!= null)
340 parent_menu
.OnMenuChanged (EventArgs
.Empty
);
344 #endregion Public Properties
346 #region Private Properties
348 internal new int Height
{
349 get { return bounds.Height; }
350 set { bounds.Height = value; }
353 internal bool IsPopup
{
355 if (menu_items
.Count
> 0)
362 internal bool MeasureEventDefined
{
364 if (ownerdraw
== true && Events
[MeasureItemEvent
] != null) {
372 internal bool MenuBar
{
373 get { return menubar; }
374 set { menubar = value; }
377 internal int MenuHeight
{
378 get { return menuheight; }
379 set { menuheight = value; }
383 internal bool Selected
{
384 get { return selected; }
385 set { selected = value; }
388 internal bool Separator
{
389 get { return separator; }
390 set { separator = value; }
393 internal DrawItemState Status
{
395 DrawItemState status
= DrawItemState
.None
;
396 MenuTracker tracker
= Parent
.Tracker
;
398 status
|= (tracker
.active
|| tracker
.Navigating
? DrawItemState
.Selected
: DrawItemState
.HotLight
);
400 status
|= DrawItemState
.Grayed
| DrawItemState
.Disabled
;
402 status
|= DrawItemState
.Checked
;
403 if (!tracker
.Navigating
)
404 status
|= DrawItemState
.NoAccelerator
;
409 internal bool VisibleItems
{
411 if (menu_items
!= null) {
412 foreach (MenuItem mi
in menu_items
)
420 internal new int Width
{
421 get { return bounds.Width; }
422 set { bounds.Width = value; }
426 get { return bounds.X; }
427 set { bounds.X = value; }
432 set { xtab = value; }
436 get { return bounds.Y; }
437 set { bounds.Y = value; }
440 #endregion Private Properties
442 #region Public Methods
444 public virtual MenuItem
CloneMenu ()
446 MenuItem item
= new MenuItem ();
447 item
.CloneMenu (this);
451 protected void CloneMenu (MenuItem menuitem
)
453 base.CloneMenu (menuitem
); // Copy subitems
456 MdiList
= menuitem
.MdiList
;
457 is_window_menu_item
= menuitem
.is_window_menu_item
;
458 // Remove items corresponding to window menu items, and add new items
459 // (Otherwise window menu items would show up twice, since the PopulateWindowMenu doesn't
461 bool populated
= false;
462 for (int i
= MenuItems
.Count
- 1; i
>= 0; i
--) {
463 if (MenuItems
[i
].is_window_menu_item
) {
464 MenuItems
.RemoveAt (i
);
469 PopulateWindowMenu ();
472 BarBreak
= menuitem
.BarBreak
;
473 Break
= menuitem
.Break
;
474 Checked
= menuitem
.Checked
;
475 DefaultItem
= menuitem
.DefaultItem
;
476 Enabled
= menuitem
.Enabled
;
477 MergeOrder
= menuitem
.MergeOrder
;
478 MergeType
= menuitem
.MergeType
;
479 OwnerDraw
= menuitem
.OwnerDraw
;
480 //Parent = menuitem.Parent;
481 RadioCheck
= menuitem
.RadioCheck
;
482 Shortcut
= menuitem
.Shortcut
;
483 ShowShortcut
= menuitem
.ShowShortcut
;
484 Text
= menuitem
.Text
;
485 Visible
= menuitem
.Visible
;
488 Events
[ClickEvent
] = menuitem
.Events
[ClickEvent
];
489 Events
[DrawItemEvent
] = menuitem
.Events
[DrawItemEvent
];
490 Events
[MeasureItemEvent
] = menuitem
.Events
[MeasureItemEvent
];
491 Events
[PopupEvent
] = menuitem
.Events
[PopupEvent
];
492 Events
[SelectEvent
] = menuitem
.Events
[SelectEvent
];
495 protected override void Dispose (bool disposing
)
497 base.Dispose (disposing
);
500 // This really clones the item
501 public virtual MenuItem
MergeMenu ()
503 MenuItem item
= new MenuItem ();
504 item
.CloneMenu (this);
508 public void MergeMenu (MenuItem menuitem
)
510 base.MergeMenu (menuitem
);
513 protected virtual void OnClick (EventArgs e
)
515 EventHandler eh
= (EventHandler
)(Events
[ClickEvent
]);
520 protected virtual void OnDrawItem (DrawItemEventArgs e
)
523 DrawItemEventHandler eh
= (DrawItemEventHandler
)(Events
[DrawItemEvent
]);
529 ThemeEngine
.Current
.DrawMenuItem (this, e
);
533 protected virtual void OnInitMenuPopup (EventArgs e
)
538 protected virtual void OnMeasureItem (MeasureItemEventArgs e
)
543 MeasureItemEventHandler eh
= (MeasureItemEventHandler
)(Events
[MeasureItemEvent
]);
548 protected virtual void OnPopup (EventArgs e
)
550 EventHandler eh
= (EventHandler
)(Events
[PopupEvent
]);
555 protected virtual void OnSelect (EventArgs e
)
557 EventHandler eh
= (EventHandler
)(Events
[SelectEvent
]);
562 public void PerformClick ()
564 OnClick (EventArgs
.Empty
);
567 public virtual void PerformSelect ()
569 OnSelect (EventArgs
.Empty
);
572 public override string ToString ()
574 return base.ToString () + ", Items.Count: " + MenuItems
.Count
+ ", Text: " + text
;
577 #endregion Public Methods
579 #region Private Methods
581 internal virtual void Invalidate ()
583 if ((Parent
!= null) && (Parent
is MainMenu
) && Parent
.Wnd
!= null)
584 XplatUI
.RequestNCRecalc (Parent
.Wnd
.FindForm ().Handle
);
587 internal void PerformPopup ()
589 OnPopup (EventArgs
.Empty
);
592 internal void PerformDrawItem (DrawItemEventArgs e
)
594 PopulateWindowMenu ();
598 private void PopulateWindowMenu ()
601 if (mdilist_items
== null) {
602 mdilist_items
= new Hashtable ();
603 mdilist_forms
= new Hashtable ();
607 MainMenu main
= GetMainMenu ();
608 if (main
== null || main
.GetForm () == null)
611 Form form
= main
.GetForm ();
612 mdicontainer
= form
.MdiContainer
;
613 if (mdicontainer
== null)
617 // Remove closed forms
618 MenuItem
[] items
= new MenuItem
[mdilist_items
.Count
];
619 mdilist_items
.Keys
.CopyTo (items
, 0);
620 foreach (MenuItem item
in items
) {
621 Form mdichild
= (Form
) mdilist_items
[item
];
622 if (!mdicontainer
.mdi_child_list
.Contains(mdichild
)) {
623 mdilist_items
.Remove (item
);
624 mdilist_forms
.Remove (mdichild
);
625 MenuItems
.Remove (item
);
629 // Add new forms and update state for existing forms.
630 for (int i
= 0; i
< mdicontainer
.mdi_child_list
.Count
; i
++) {
631 Form mdichild
= (Form
)mdicontainer
.mdi_child_list
[i
];
633 if (mdilist_forms
.Contains (mdichild
)) {
634 item
= (MenuItem
) mdilist_forms
[mdichild
];
636 item
= new MenuItem ();
637 item
.is_window_menu_item
= true;
638 item
.Click
+= new EventHandler (MdiWindowClickHandler
);
639 mdilist_items
[item
] = mdichild
;
640 mdilist_forms
[mdichild
] = item
;
641 MenuItems
.AddNoEvents (item
);
643 item
.Visible
= mdichild
.Visible
;
644 item
.Text
= "&" + (i
+ 1).ToString () + " " + mdichild
.Text
;
645 item
.Checked
= form
.ActiveMdiChild
== mdichild
;
650 if (mdilist_items
!= null) {
651 foreach (MenuItem item
in mdilist_items
.Values
) {
652 MenuItems
.Remove (item
);
655 mdilist_forms
.Clear ();
656 mdilist_items
.Clear ();
661 internal void PerformMeasureItem (MeasureItemEventArgs e
)
666 private void ProcessMnemonic ()
668 if (text
== null || text
.Length
< 2) {
673 bool bPrevAmp
= false;
674 for (int i
= 0; i
< text
.Length
-1 ; i
++) {
675 if (text
[i
] == '&') {
676 if (bPrevAmp
== false && (text
[i
+1] != '&')) {
677 mnemonic
= Char
.ToUpper (text
[i
+1]);
690 private string GetShortCutTextCtrl () { return "Ctrl"; }
691 private string GetShortCutTextAlt () { return "Alt"; }
692 private string GetShortCutTextShift () { return "Shift"; }
694 internal string GetShortCutText ()
696 /* Ctrl+A - Ctrl+Z */
697 if (Shortcut
>= Shortcut
.CtrlA
&& Shortcut
<= Shortcut
.CtrlZ
)
698 return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut
- Shortcut
.CtrlA
));
701 if (Shortcut
>= Shortcut
.Alt0
&& Shortcut
<= Shortcut
.Alt9
)
702 return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut
- Shortcut
.Alt0
));
704 /* Alt+F1 - Alt+F2 */
705 if (Shortcut
>= Shortcut
.AltF1
&& Shortcut
<= Shortcut
.AltF9
)
706 return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut
- Shortcut
.AltF1
));
708 /* Ctrl+0 - Ctrl+9 */
709 if (Shortcut
>= Shortcut
.Ctrl0
&& Shortcut
<= Shortcut
.Ctrl9
)
710 return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut
- Shortcut
.Ctrl0
));
712 /* Ctrl+F0 - Ctrl+F9 */
713 if (Shortcut
>= Shortcut
.CtrlF1
&& Shortcut
<= Shortcut
.CtrlF9
)
714 return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut
- Shortcut
.CtrlF1
));
716 /* Ctrl+Shift+0 - Ctrl+Shift+9 */
717 if (Shortcut
>= Shortcut
.CtrlShift0
&& Shortcut
<= Shortcut
.CtrlShift9
)
718 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut
- Shortcut
.CtrlShift0
));
720 /* Ctrl+Shift+A - Ctrl+Shift+Z */
721 if (Shortcut
>= Shortcut
.CtrlShiftA
&& Shortcut
<= Shortcut
.CtrlShiftZ
)
722 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut
- Shortcut
.CtrlShiftA
));
724 /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */
725 if (Shortcut
>= Shortcut
.CtrlShiftF1
&& Shortcut
<= Shortcut
.CtrlShiftF9
)
726 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut
- Shortcut
.CtrlShiftF1
));
729 if (Shortcut
>= Shortcut
.F1
&& Shortcut
<= Shortcut
.F9
)
730 return "F" + (char)((int) '1' + (int)(Shortcut
- Shortcut
.F1
));
732 /* Shift+F1 - Shift+F9 */
733 if (Shortcut
>= Shortcut
.ShiftF1
&& Shortcut
<= Shortcut
.ShiftF9
)
734 return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut
- Shortcut
.ShiftF1
));
738 case Shortcut
.AltBksp
:
740 case Shortcut
.AltF10
:
741 return GetShortCutTextAlt () + "+F10";
742 case Shortcut
.AltF11
:
743 return GetShortCutTextAlt () + "+F11";
744 case Shortcut
.AltF12
:
745 return GetShortCutTextAlt () + "+F12";
746 case Shortcut
.CtrlDel
:
747 return GetShortCutTextCtrl () + "+Del";
748 case Shortcut
.CtrlF10
:
749 return GetShortCutTextCtrl () + "+F10";
750 case Shortcut
.CtrlF11
:
751 return GetShortCutTextCtrl () + "+F11";
752 case Shortcut
.CtrlF12
:
753 return GetShortCutTextCtrl () + "+F12";
754 case Shortcut
.CtrlIns
:
755 return GetShortCutTextCtrl () + "+Ins";
756 case Shortcut
.CtrlShiftF10
:
757 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10";
758 case Shortcut
.CtrlShiftF11
:
759 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11";
760 case Shortcut
.CtrlShiftF12
:
761 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12";
774 case Shortcut
.ShiftDel
:
775 return GetShortCutTextShift () + "+Del";
776 case Shortcut
.ShiftF10
:
777 return GetShortCutTextShift () + "+F10";
778 case Shortcut
.ShiftF11
:
779 return GetShortCutTextShift () + "+F11";
780 case Shortcut
.ShiftF12
:
781 return GetShortCutTextShift () + "+F12";
782 case Shortcut
.ShiftIns
:
783 return GetShortCutTextShift () + "+Ins";
791 private void MdiWindowClickHandler (object sender
, EventArgs e
)
793 Form mdichild
= (Form
) mdilist_items
[sender
];
795 // people could add weird items to the Window menu
796 // so we can't assume its just us
797 if (mdichild
== null)
800 mdicontainer
.ActivateChild (mdichild
);
803 #endregion Private Methods