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
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Reflection;
34 using System.Runtime.InteropServices;
36 namespace System.Windows.Forms
39 [Designer ("Microsoft.VisualStudio.Windows.Forms.MenuDesigner, " + Consts.AssemblyMicrosoft_VisualStudio, "System.ComponentModel.Design.IDesigner")]
41 [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
43 public abstract class Menu : Component
45 internal MenuItemCollection menu_items;
46 internal IntPtr menu_handle = IntPtr.Zero;
47 internal Menu parent_menu = null;
48 System.Drawing.Rectangle rect;
50 internal MenuTracker tracker;
53 private string control_name;
54 private object control_tag;
57 public const int FindHandle = 0;
58 public const int FindShortcut = 1;
60 protected Menu (MenuItem[] items)
62 menu_items = new MenuItemCollection (this);
65 menu_items.AddRange (items);
68 #region Public Properties
70 [BrowsableAttribute(false)]
71 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
72 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
73 public IntPtr Handle {
74 get { return menu_handle; }
77 internal virtual void OnMenuChanged (EventArgs e)
79 EventHandler eh = (EventHandler)(Events [MenuChangedEvent]);
84 [BrowsableAttribute(false)]
85 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
86 public virtual bool IsParent {
88 if (menu_items != null && menu_items.Count > 0)
95 [BrowsableAttribute(false)]
96 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
97 public MenuItem MdiListItem {
99 throw new NotImplementedException ();
103 [BrowsableAttribute(false)]
104 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)]
105 [MergableProperty(false)]
106 public MenuItemCollection MenuItems {
107 get { return menu_items; }
112 [BrowsableAttribute(false)]
113 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
115 get { return control_name; }
116 set { control_name = value; }
121 [TypeConverter(typeof(StringConverter))]
123 [MWFCategory("Data")]
125 get { return control_tag; }
126 set { control_tag = value; }
130 #endregion Public Properties
132 #region Private Properties
134 internal System.Drawing.Rectangle Rect {
138 internal MenuItem SelectedItem {
140 foreach (MenuItem item in MenuItems)
148 internal int Height {
149 get { return rect.Height; }
150 set { rect.Height = value; }
154 get { return rect.Width; }
155 set { rect.Width = value; }
159 get { return rect.X; }
160 set { rect.X = value; }
164 get { return rect.Y; }
165 set { rect.Y = value; }
168 internal MenuTracker Tracker {
171 while (top.parent_menu != null)
172 top = top.parent_menu;
177 #endregion Private Properties
179 #region Public Methods
181 protected void CloneMenu (Menu menuSrc)
185 menu_items = new MenuItemCollection (this);
187 for (int i = 0; i < menuSrc.MenuItems.Count ; i++)
188 menu_items.Add (menuSrc.MenuItems [i].CloneMenu ());
191 protected virtual IntPtr CreateMenuHandle ()
196 protected override void Dispose (bool disposing)
199 if (menu_handle != IntPtr.Zero) {
200 menu_handle = IntPtr.Zero;
205 // From Microsoft documentation is impossible to guess that
206 // this method is supossed to do
208 // update: according to MS documentation, first parameter is on of this
209 // constant values FindHandle or FindShortcut, value depends from what
210 // you what to search, by shortcut or handle. FindHandle and FindShortcut
211 // is a constant fields and was defined for this class.
212 public MenuItem FindMenuItem (int type, IntPtr value)
217 protected int FindMergePosition (int mergeOrder)
219 int cnt = MenuItems.Count, cur, pos;
221 for (pos = 0; pos < cnt; ) {
222 cur = (pos + cnt) /2;
223 if (MenuItems[cur].MergeOrder > mergeOrder) {
233 public ContextMenu GetContextMenu ()
235 for (Menu item = this; item != null; item = item.parent_menu) {
236 if (item is ContextMenu) {
237 return (ContextMenu) item;
244 public MainMenu GetMainMenu ()
246 for (Menu item = this; item != null; item = item.parent_menu) {
247 if (item is MainMenu) {
248 return (MainMenu) item;
255 internal virtual void InvalidateItem (MenuItem item)
258 Wnd.Invalidate (item.bounds);
261 public virtual void MergeMenu (Menu menuSrc)
264 throw new ArgumentException ("The menu cannot be merged with itself");
266 for (int i = 0; i < menuSrc.MenuItems.Count; i++) {
268 MenuItem sourceitem = menuSrc.MenuItems[i];
270 switch (sourceitem.MergeType) {
271 case MenuMerge.Remove: // Item not included
276 int pos = FindMergePosition (sourceitem.MergeOrder);
277 MenuItems.Add (pos, sourceitem.CloneMenu ());
281 case MenuMerge.Replace:
282 case MenuMerge.MergeItems:
284 for (int pos = FindMergePosition (sourceitem.MergeOrder-1); pos <= MenuItems.Count; pos++) {
286 if ((pos >= MenuItems.Count) || (MenuItems[pos].MergeOrder != sourceitem.MergeOrder)) {
287 MenuItems.Add (pos, sourceitem.CloneMenu ());
291 MenuItem mergeitem = MenuItems[pos];
293 if (mergeitem.MergeType != MenuMerge.Add) {
294 if ((sourceitem.MergeType == MenuMerge.MergeItems) && (mergeitem.MergeType == MenuMerge.MergeItems)) {
295 mergeitem.MergeMenu (sourceitem);
297 MenuItems.Remove (sourceitem);
298 MenuItems.Add (pos, sourceitem.CloneMenu ());
313 protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData)
317 return tracker.ProcessKeys (ref msg, keyData);
320 public override string ToString ()
322 return base.ToString () + ", Items.Count: " + MenuItems.Count;
325 #endregion Public Methods
326 static object MenuChangedEvent = new object ();
328 internal event EventHandler MenuChanged {
329 add { Events.AddHandler (MenuChangedEvent, value); }
330 remove { Events.RemoveHandler (MenuChangedEvent, value); }
333 [ListBindable(false)]
334 public class MenuItemCollection : IList, ICollection, IEnumerable
337 private ArrayList items = new ArrayList ();
339 public MenuItemCollection (Menu owner)
344 #region Public Properties
347 get { return items.Count;}
350 public bool IsReadOnly {
351 get { return false; }
354 bool ICollection.IsSynchronized {
358 object ICollection.SyncRoot {
362 bool IList.IsFixedSize {
366 public virtual MenuItem this [int index] {
368 if (index < 0 || index >= Count)
369 throw new ArgumentOutOfRangeException ("Index of out range");
371 return (MenuItem) items[index];
375 object IList.this[int index] {
376 get { return items[index]; }
377 set { throw new NotSupportedException (); }
380 #endregion Public Properties
382 #region Public Methods
384 public virtual int Add (MenuItem mi)
386 if (mi.Parent != null)
387 mi.Parent.MenuItems.Remove (mi);
390 mi.Index = items.Count - 1;
393 owner.OnMenuChanged (EventArgs.Empty);
394 if (owner.parent_menu != null)
395 owner.parent_menu.OnMenuChanged (EventArgs.Empty);
396 return items.Count - 1;
399 internal void AddNoEvents (MenuItem mi)
401 if (mi.Parent != null)
402 mi.Parent.MenuItems.Remove (mi);
405 mi.Index = items.Count - 1;
406 mi.parent_menu = owner;
409 public virtual MenuItem Add (string s)
411 MenuItem item = new MenuItem (s);
416 public virtual int Add (int index, MenuItem mi)
418 if (index < 0 || index > Count)
419 throw new ArgumentOutOfRangeException ("Index of out range");
421 ArrayList new_items = new ArrayList (Count + 1);
423 for (int i = 0; i < index; i++)
424 new_items.Add (items[i]);
428 for (int i = index; i < Count; i++)
429 new_items.Add (items[i]);
432 UpdateItemsIndices ();
438 private void UpdateItem (MenuItem mi)
440 mi.parent_menu = owner;
441 owner.OnMenuChanged (EventArgs.Empty);
442 if (owner.parent_menu != null)
443 owner.parent_menu.OnMenuChanged (EventArgs.Empty);
444 if (owner.Tracker != null)
445 owner.Tracker.AddShortcuts (mi);
448 internal void Insert (int index, MenuItem mi)
450 if (index < 0 || index > Count)
451 throw new ArgumentOutOfRangeException ("Index of out range");
453 items.Insert (index, mi);
455 UpdateItemsIndices ();
459 public virtual MenuItem Add (string s, EventHandler e)
461 MenuItem item = new MenuItem (s, e);
467 public virtual MenuItem Add (string s, MenuItem[] items)
469 MenuItem item = new MenuItem (s, items);
475 public virtual void AddRange (MenuItem[] items)
478 throw new ArgumentNullException ("items");
480 foreach (MenuItem mi in items)
484 public virtual void Clear ()
486 MenuTracker tracker = owner.Tracker;
487 foreach (MenuItem item in items) {
489 tracker.RemoveShortcuts (item);
490 item.parent_menu = null;
493 owner.OnMenuChanged (EventArgs.Empty);
496 public bool Contains (MenuItem value)
498 return items.Contains (value);
501 public void CopyTo (Array dest, int index)
503 items.CopyTo (dest, index);
506 public IEnumerator GetEnumerator ()
508 return items.GetEnumerator ();
511 int IList.Add (object value)
513 return Add ((MenuItem)value);
516 bool IList.Contains (object value)
518 return Contains ((MenuItem)value);
521 int IList.IndexOf (object value)
523 return IndexOf ((MenuItem)value);
526 void IList.Insert (int index, object value)
528 Insert (index, (MenuItem) value);
531 void IList.Remove (object value)
533 Remove ((MenuItem) value);
536 public int IndexOf (MenuItem value)
538 return items.IndexOf (value);
541 public virtual void Remove (MenuItem item)
543 RemoveAt (item.Index);
546 public virtual void RemoveAt (int index)
548 if (index < 0 || index >= Count)
549 throw new ArgumentOutOfRangeException ("Index of out range");
551 MenuItem item = (MenuItem) items [index];
552 MenuTracker tracker = owner.Tracker;
554 tracker.RemoveShortcuts (item);
555 item.parent_menu = null;
557 items.RemoveAt (index);
559 UpdateItemsIndices ();
560 owner.OnMenuChanged (EventArgs.Empty);
563 #endregion Public Methods
565 #region Private Methods
567 private void UpdateItemsIndices ()
569 for (int i = 0; i < Count; i++) // Recalculate indeces
570 ((MenuItem)items[i]).Index = i;
573 #endregion Private Methods