* TextBoxBase.cs: These seem to be the correct values.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MenuAPI.cs
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.
11 //
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.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Mike Kestner  <mkestner@novell.com>
25 //      Everaldo Canuto  <ecanuto@novell.com>
26 //
27
28 using System.Collections;
29 using System.Drawing;
30 using System.Threading;
31
32 namespace System.Windows.Forms {
33
34         /*
35                 When writing this code the Wine project was of great help to
36                 understand the logic behind some Win32 issues. Thanks to them. Jordi,
37         */
38         internal class MenuTracker {
39
40                 internal bool active;
41                 internal bool popup_active;
42                 internal bool popdown_menu;
43                 internal bool hotkey_active;
44                 public Menu CurrentMenu;
45                 public Menu TopMenu;
46                 Form grab_control;
47
48             public MenuTracker (Menu top_menu)
49                 {
50                         TopMenu = CurrentMenu = top_menu;
51                         foreach (MenuItem item in TopMenu.MenuItems)
52                                 AddShortcuts (item);
53
54                         if (top_menu is ContextMenu) {
55                                 grab_control = (top_menu as ContextMenu).SourceControl.FindForm ();
56                                 grab_control.ActiveTracker = this;
57                         } else
58                                 grab_control = top_menu.Wnd.FindForm ();
59                 }
60
61                 enum KeyNavState {
62                         Idle,
63                         Startup,
64                         NoPopups,
65                         Navigating
66                 }
67
68                 KeyNavState keynav_state = KeyNavState.Idle;
69
70                 public bool Navigating {
71                         get { return keynav_state != KeyNavState.Idle || active; }
72                 }
73
74                 internal static Point ScreenToMenu (Menu menu, Point pnt)               
75                 {
76                         int x = pnt.X;
77                         int y = pnt.Y;
78                         XplatUI.ScreenToMenu (menu.Wnd.window.Handle, ref x, ref y);
79                         return new Point (x, y);
80                 }       
81
82                 private void UpdateCursor ()
83                 {
84                         Control child_control = grab_control.GetRealChildAtPoint (Cursor.Position);
85                         if (child_control != null) {
86                                 if (active)
87                                         XplatUI.SetCursor (child_control.Handle, Cursors.Default.handle);
88                                 else
89                                         XplatUI.SetCursor (child_control.Handle, child_control.Cursor.handle);
90                         }
91                 }
92
93                 void Deactivate ()
94                 {
95                         bool redrawbar = (keynav_state != KeyNavState.Idle) && (TopMenu is MainMenu); 
96
97                         active = false;
98                         popup_active = false;
99                         hotkey_active = false;
100                         grab_control.ActiveTracker = null;
101                         keynav_state = KeyNavState.Idle;
102                         if (TopMenu is ContextMenu) {
103                                 PopUpWindow puw = TopMenu.Wnd as PopUpWindow;
104                                 DeselectItem (TopMenu.SelectedItem);
105                                 puw.HideWindow ();
106                         } else {
107                                 DeselectItem (TopMenu.SelectedItem);
108                         }
109                         CurrentMenu = TopMenu;
110
111                         if (redrawbar)
112                                 (TopMenu as MainMenu).Draw ();                  
113                 }
114
115                 MenuItem FindItemByCoords (Menu menu, Point pt)
116                 {
117                         if (menu is MainMenu)
118                                 pt = ScreenToMenu (menu, pt);
119                         else
120                                 pt = menu.Wnd.PointToClient (pt);
121                         foreach (MenuItem item in menu.MenuItems) {
122                                 Rectangle rect = item.bounds;
123                                 if (rect.Contains (pt))
124                                         return item;
125                         }
126
127                         return null;
128                 }
129
130                 MenuItem GetItemAtXY (int x, int y)
131                 {
132                         Point pnt = new Point (x, y);
133                         MenuItem item = null;
134                         if (TopMenu.SelectedItem != null)
135                                 item = FindSubItemByCoord (TopMenu.SelectedItem, Control.MousePosition);
136                         if (item == null)
137                                 item = FindItemByCoords (TopMenu, pnt);
138                         return item;
139                 }
140
141                 public bool OnMouseDown (MouseEventArgs args)
142                 {
143                         MenuItem item = GetItemAtXY (args.X, args.Y);
144
145                         if (item == null) {
146                                 Deactivate ();
147                                 return false;
148                         }
149
150                         if ((args.Button & MouseButtons.Left) == 0)
151                                 return true;
152
153                         if (!item.Enabled)
154                                 return true;
155                         
156                         popdown_menu = active && item.VisibleItems;
157                         
158                         if (item.IsPopup || (item.Parent is MainMenu)) {
159                                 active = true;
160                                 item.Parent.InvalidateItem (item);
161                         }
162                         
163                         if ((CurrentMenu == TopMenu) && !popdown_menu)
164                                 SelectItem (item.Parent, item, item.IsPopup);
165                         
166                         grab_control.ActiveTracker = this;
167                         return true;
168                 }
169
170                 public void OnMotion (MouseEventArgs args)
171                 {
172                         MenuItem item = GetItemAtXY (args.X, args.Y);
173
174                         UpdateCursor ();
175
176                         if (CurrentMenu.SelectedItem == item)
177                                 return;
178
179                         grab_control.ActiveTracker = (active || item != null) ? this : null;
180
181                         if (item == null) {
182                                 MenuItem old_item = CurrentMenu.SelectedItem;
183                                 
184                                 // Return when is a popup with visible subitems for MainMenu 
185                                 if  ((active && old_item.VisibleItems && old_item.IsPopup && (CurrentMenu is MainMenu)))
186                                         return;
187
188                                 // Also returns when keyboard navigating
189                                 if (keynav_state == KeyNavState.Navigating)
190                                         return;
191                                 
192                                 keynav_state = KeyNavState.Navigating;
193                                 
194                                 // Select parent menu when move outside of menu item
195                                 if (old_item.Parent is MenuItem) {
196                                         MenuItem new_item = (old_item.Parent as MenuItem);
197                                         if (new_item.IsPopup) {
198                                                 SelectItem (new_item.Parent, new_item, false);
199                                                 return;
200                                         }
201                                 }
202                                 if (CurrentMenu != TopMenu)
203                                         CurrentMenu = CurrentMenu.parent_menu;
204                                                                 
205                                 DeselectItem (old_item);
206                         } else {
207                                 keynav_state = KeyNavState.Idle;
208                                 SelectItem (item.Parent, item, active && item.IsPopup && popup_active && (CurrentMenu.SelectedItem != item));
209                         }
210                 }
211
212                 public void OnMouseUp (MouseEventArgs args)
213                 {
214                         if ((args.Button & MouseButtons.Left) == 0)
215                                 return;
216                         
217                         MenuItem item = GetItemAtXY (args.X, args.Y);
218
219                         /* the user released the mouse button outside the menu */
220                         if (item == null) {
221                                 Deactivate ();
222                                 return;
223                         }
224                         
225                         if (!item.Enabled)
226                                 return;
227                         
228                         /* Deactivate the menu when is topmenu and popdown and */
229                         if (((CurrentMenu == TopMenu) && !(CurrentMenu is ContextMenu) && popdown_menu) || !item.IsPopup) {
230                                 Deactivate ();
231                                 UpdateCursor ();
232                         }
233                         
234                         /* Perform click when is not a popup */
235                         if (!item.IsPopup) {
236                                 DeselectItem (item);
237                                 item.PerformClick ();
238                         }
239                 }
240
241                 static public bool TrackPopupMenu (Menu menu, Point pnt)
242                 {
243                         Object  queue_id;
244
245                         if (menu.MenuItems.Count <= 0)  // No submenus to track
246                                 return true;                            
247
248                         MenuTracker tracker = new MenuTracker (menu);
249                         tracker.active = true;
250                         tracker.popup_active = true;
251                         menu.tracker = tracker;
252
253                         menu.Wnd = new PopUpWindow (tracker.grab_control, menu);
254                         menu.Wnd.Location =  menu.Wnd.PointToClient (pnt);
255
256                         ((PopUpWindow)menu.Wnd).ShowWindow ();
257
258                         bool no_quit = true;
259
260                         queue_id = XplatUI.StartLoop(Thread.CurrentThread);
261
262                         while ((menu.Wnd != null) && menu.Wnd.Visible && no_quit) {
263                                 MSG msg = new MSG ();
264                                 no_quit = XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0);
265                                 XplatUI.TranslateMessage(ref msg);
266                                 XplatUI.DispatchMessage(ref msg);                               
267                         }
268
269                         if (!no_quit)
270                                 XplatUI.PostQuitMessage(0);
271
272                         if (menu.Wnd != null) {
273                                 menu.Wnd.Dispose ();
274                                 menu.Wnd = null;
275                         }
276
277                         return true;
278                 }
279         
280                 void DeselectItem (MenuItem item)
281                 {
282                         if (item == null)
283                                 return;                         
284                         
285                         item.Selected = false;
286
287                         /* When popup item then close all sub popups and unselect all sub items */
288                         if (item.IsPopup) {
289                                 HideSubPopups (item, TopMenu);
290                                 
291                                 /* Unselect all selected sub itens */
292                                 foreach (MenuItem subitem in item.MenuItems)
293                                         if (subitem.Selected)
294                                                 DeselectItem (subitem);
295                         }
296
297                         Menu menu = item.Parent;
298                         menu.InvalidateItem (item);
299                 }
300
301                 void SelectItem (Menu menu, MenuItem item, bool execute)
302                 {
303                         MenuItem prev_item = CurrentMenu.SelectedItem;
304                         
305                         if (prev_item != item.Parent) {
306                                 DeselectItem (prev_item);
307                                 if ((CurrentMenu != menu) && (prev_item.Parent != item) && (prev_item.Parent is MenuItem)) {
308                                         DeselectItem (prev_item.Parent as MenuItem);
309                                 }
310                         }
311
312                         if (CurrentMenu != menu)
313                                 CurrentMenu = menu;
314                         
315                         item.Selected = true;
316                         menu.InvalidateItem (item);
317                         
318                         if (((CurrentMenu == TopMenu) && execute) || ((CurrentMenu != TopMenu) && popup_active))
319                                 item.PerformSelect ();
320
321                         if ((execute) && ((prev_item == null) || (item != prev_item.Parent)))
322                                 ExecFocusedItem (menu, item);
323                 }
324
325                 //      Used when the user executes the action of an item (press enter, shortcut)
326                 //      or a sub-popup menu has to be shown
327                 void ExecFocusedItem (Menu menu, MenuItem item)
328                 {
329                         if (item == null)
330                                 return;
331
332                         if (!item.Enabled)
333                                 return;
334                                 
335                         if (item.IsPopup) {
336                                 ShowSubPopup (menu, item);
337                         } else {
338                                 Deactivate ();
339                                 item.PerformClick ();
340                         }
341                 }
342
343                 // Create a popup window and show it or only show it if it is already created
344                 void ShowSubPopup (Menu menu, MenuItem item)
345                 {
346                         if (item.Enabled == false)
347                                 return;
348
349                         if (!popdown_menu || !item.VisibleItems) 
350                                 item.PerformPopup ();
351                         
352                         if (item.VisibleItems == false)
353                                 return;
354
355                         if (item.Wnd != null) {
356                                 item.Wnd.Dispose ();
357                         }
358
359                         popup_active = true;
360                         PopUpWindow puw = new PopUpWindow (grab_control, item);
361                         
362                         Point pnt;
363                         if (menu is MainMenu)
364                                 pnt = new Point (item.X, item.Y + item.Height - 2 - menu.Height);
365                         else
366                                 pnt = new Point (item.X + item.Width - 3, item.Y - 3);
367                         pnt = menu.Wnd.PointToScreen (pnt);
368                         puw.Location = pnt;
369                         item.Wnd = puw;
370
371                         puw.ShowWindow ();
372                 }
373
374                 static public void HideSubPopups (Menu menu, Menu topmenu)
375                 {
376                         foreach (MenuItem item in menu.MenuItems)
377                                 if (item.IsPopup)
378                                         HideSubPopups (item, null);
379
380                         if (menu.Wnd == null)
381                                 return;
382
383                         PopUpWindow puw = menu.Wnd as PopUpWindow;
384                         puw.Hide ();
385                         menu.Wnd = null;
386
387 #if NET_2_0
388                         if ((topmenu != null) && (topmenu is MainMenu))
389                                 ((MainMenu) topmenu).OnCollapse (EventArgs.Empty);
390 #endif
391                 }
392
393                 MenuItem FindSubItemByCoord (Menu menu, Point pnt)
394                 {               
395                         foreach (MenuItem item in menu.MenuItems) {
396
397                                 if (item.IsPopup && item.Wnd != null && item.Wnd.Visible && item == menu.SelectedItem) {
398                                         MenuItem result = FindSubItemByCoord (item, pnt);
399                                         if (result != null)
400                                                 return result;
401                                 }
402                                         
403                                 if (menu.Wnd == null || !menu.Wnd.Visible)
404                                         continue;
405
406                                 Rectangle rect = item.bounds;
407                                 Point pnt_client = menu.Wnd.PointToScreen (new Point (item.X, item.Y));
408                                 rect.X = pnt_client.X;
409                                 rect.Y = pnt_client.Y;
410                                 
411                                 if (rect.Contains (pnt) == true)
412                                         return item;
413                         }                       
414                         
415                         return null;
416                 }
417
418                 static MenuItem FindItemByKey (Menu menu, IntPtr key)
419                 {
420                         char key_char = (char ) (key.ToInt32() & 0xff);
421                         key_char = Char.ToUpper (key_char);
422
423                         foreach (MenuItem item in menu.MenuItems) {
424                                 if (item.Mnemonic == '\0')
425                                         continue;
426
427                                 if (item.Mnemonic == key_char)
428                                         return item;
429                         }
430
431                         return null;
432                 }
433
434                 enum ItemNavigation {
435                         First,
436                         Last,
437                         Next,
438                         Previous,
439                 }
440
441                 static MenuItem GetNextItem (Menu menu, ItemNavigation navigation)
442                 {
443                         int pos = 0;
444                         bool selectable_items = false;
445                         MenuItem item;
446
447                         // Check if there is at least a selectable item
448                         for (int i = 0; i < menu.MenuItems.Count; i++) {
449                                 item = menu.MenuItems [i];
450                                 if (item.Separator == false && item.Visible == true) {
451                                         selectable_items = true;
452                                         break;
453                                 }
454                         }
455
456                         if (selectable_items == false)
457                                 return null;
458
459                         switch (navigation) {
460                         case ItemNavigation.First:
461
462                                 /* First item that is not separator and it is visible*/
463                                 for (pos = 0; pos < menu.MenuItems.Count; pos++) {
464                                         item = menu.MenuItems [pos];
465                                         if (item.Separator == false && item.Visible == true)
466                                                 break;
467                                 }
468
469                                 break;
470
471                         case ItemNavigation.Last: // Not used
472                                 break;
473
474                         case ItemNavigation.Next:
475
476                                 if (menu.SelectedItem != null)
477                                         pos = menu.SelectedItem.Index;
478
479                                 /* Next item that is not separator and it is visible*/
480                                 for (pos++; pos < menu.MenuItems.Count; pos++) {
481                                         item = menu.MenuItems [pos];
482                                         if (item.Separator == false && item.Visible == true)
483                                                 break;
484                                 }
485
486                                 if (pos >= menu.MenuItems.Count) { /* Jump at the start of the menu */
487                                         pos = 0;
488                                         /* Next item that is not separator and it is visible*/
489                                         for (; pos < menu.MenuItems.Count; pos++) {
490                                                 item = menu.MenuItems [pos];
491                                                 if (item.Separator == false && item.Visible == true)
492                                                         break;
493                                         }
494                                 }
495                                 break;
496
497                         case ItemNavigation.Previous:
498
499                                 if (menu.SelectedItem != null)
500                                         pos = menu.SelectedItem.Index;
501
502                                 /* Previous item that is not separator and it is visible*/
503                                 for (pos--; pos >= 0; pos--) {
504                                         item = menu.MenuItems [pos];
505                                         if (item.Separator == false && item.Visible == true)
506                                                 break;
507                                 }
508
509                                 if (pos < 0 ) { /* Jump at the end of the menu*/
510                                         pos = menu.MenuItems.Count - 1;
511                                         /* Previous item that is not separator and it is visible*/
512                                         for (; pos >= 0; pos--) {
513                                                 item = menu.MenuItems [pos];
514                                                 if (item.Separator == false && item.Visible == true)
515                                                         break;
516                                         }
517                                 }
518
519                                 break;
520
521                         default:
522                                 break;
523                         }
524
525                         return menu.MenuItems [pos];
526                 }
527
528                 void ProcessMenuKey (Msg msg_type)
529                 {
530                         if (TopMenu.MenuItems.Count == 0)
531                                 return;
532
533                         MainMenu main_menu = TopMenu as MainMenu;
534
535                         switch (msg_type) {
536                         case Msg.WM_SYSKEYDOWN:
537                                 switch (keynav_state) {
538                                 case KeyNavState.Idle:
539                                         keynav_state = KeyNavState.Startup;
540                                         hotkey_active = true;
541                                         grab_control.ActiveTracker = this;
542                                         CurrentMenu = TopMenu;
543                                         main_menu.Draw ();
544                                         break;
545                                 case KeyNavState.Startup:
546                                         break;
547                                 default:
548                                         Deactivate ();
549                                         main_menu.Draw ();
550                                         break;
551                                 }
552                                 break;
553
554                         case Msg.WM_SYSKEYUP:
555                                 switch (keynav_state) {
556                                 case KeyNavState.Idle:
557                                 case KeyNavState.Navigating:
558                                         break;
559                                 case KeyNavState.Startup:
560                                         keynav_state = KeyNavState.NoPopups;
561                                         SelectItem (TopMenu, TopMenu.MenuItems [0], false);
562                                         break;
563                                 default:
564                                         Deactivate ();
565                                         main_menu.Draw ();
566                                         break;
567                                 }
568                                 break;
569                         }
570                 }
571
572                 bool ProcessMnemonic (Message msg, Keys key_data)
573                 {
574                         keynav_state = KeyNavState.Navigating;
575                         MenuItem item = FindItemByKey (CurrentMenu, msg.WParam);
576                         if (item == null)
577                                 return false;
578
579                         active = true;
580                         grab_control.ActiveTracker = this;
581                         
582                         SelectItem (CurrentMenu, item, true);
583                         if (item.IsPopup) {
584                                 CurrentMenu = item;
585                                 SelectItem (item, item.MenuItems [0], false);
586                         }
587                         return true;
588                 }
589
590                 Hashtable shortcuts = new Hashtable ();
591                 
592                 public void AddShortcuts (MenuItem item)
593                 {
594                         foreach (MenuItem child in item.MenuItems) {
595                                 AddShortcuts (child);
596                                 if (child.Shortcut != Shortcut.None)
597                                         shortcuts [(int)child.Shortcut] = child;
598                         }
599
600                         if (item.Shortcut != Shortcut.None)
601                                 shortcuts [(int)item.Shortcut] = item;
602                 }
603
604                 public void RemoveShortcuts (MenuItem item)
605                 {
606                         foreach (MenuItem child in item.MenuItems) {
607                                 RemoveShortcuts (child);
608                                 if (child.Shortcut != Shortcut.None)
609                                         shortcuts.Remove ((int)child.Shortcut);
610                         }
611
612                         if (item.Shortcut != Shortcut.None)
613                                 shortcuts.Remove ((int)item.Shortcut);
614                 }
615
616                 bool ProcessShortcut (Keys keyData)
617                 {
618                         MenuItem item = shortcuts [(int)keyData] as MenuItem;
619                         if (item == null)
620                                 return false;
621
622                         Deactivate ();
623                         item.PerformClick ();
624                         return true;
625                 }
626
627                 public bool ProcessKeys (ref Message msg, Keys keyData)
628                 {
629                         if ((Msg)msg.Msg != Msg.WM_SYSKEYUP && ProcessShortcut (keyData))
630                                 return true;
631                         else if ((keyData & Keys.KeyCode) == Keys.Menu && TopMenu is MainMenu) {
632                                 ProcessMenuKey ((Msg) msg.Msg);
633                                 return true;
634                         } else if ((keyData & Keys.Alt) == Keys.Alt)
635                                 return ProcessMnemonic (msg, keyData);
636                         else if ((Msg)msg.Msg == Msg.WM_SYSKEYUP)
637                                 return false;
638                         else if (!Navigating)
639                                 return false;
640
641                         MenuItem item;
642                         
643                         switch (keyData) {
644                         case Keys.Up:
645                                 if (CurrentMenu is MainMenu)
646                                         return true;
647                                 else if (CurrentMenu.MenuItems.Count == 1 && CurrentMenu.parent_menu == TopMenu) {
648                                         DeselectItem (CurrentMenu.SelectedItem);
649                                         CurrentMenu = TopMenu;
650                                         return true;
651                                 }
652                                 item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
653                                 if (item != null)
654                                         SelectItem (CurrentMenu, item, false);
655                                 break;
656                         
657                         case Keys.Down:
658                                 if (CurrentMenu is MainMenu) {
659                                         if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
660                                                 keynav_state = KeyNavState.Navigating;
661                                                 item = CurrentMenu.SelectedItem;
662                                                 ShowSubPopup (CurrentMenu, item);
663                                                 SelectItem (item, item.MenuItems [0], false);
664                                                 CurrentMenu = item;
665                                                 active = true;
666                                                 grab_control.ActiveTracker = this;
667                                         }
668                                         return true;
669                                 }
670                                 item = GetNextItem (CurrentMenu, ItemNavigation.Next);
671                                 if (item != null)
672                                         SelectItem (CurrentMenu, item, false);
673                                 break;
674                         
675                         case Keys.Right:
676                                 if (CurrentMenu is MainMenu) {
677                                         item = GetNextItem (CurrentMenu, ItemNavigation.Next);
678                                         bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
679                                         SelectItem (CurrentMenu, item, popup);
680                                         if (popup) {
681                                                 SelectItem (item, item.MenuItems [0], false);
682                                                 CurrentMenu = item;
683                                         }
684                                 } else if (CurrentMenu.SelectedItem.IsPopup) {
685                                         item = CurrentMenu.SelectedItem;
686                                         ShowSubPopup (CurrentMenu, item);
687                                         SelectItem (item, item.MenuItems [0], false);
688                                         CurrentMenu = item;
689                                 } else if (CurrentMenu.parent_menu is MainMenu) {
690                                         item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Next);
691                                         SelectItem (CurrentMenu.parent_menu, item, item.IsPopup);
692                                         if (item.IsPopup) {
693                                                 SelectItem (item, item.MenuItems [0], false);
694                                                 CurrentMenu = item;
695                                         }
696                                 }
697                                 break;
698                         
699                         case Keys.Left:
700                                 if (CurrentMenu is MainMenu) {
701                                         item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
702                                         bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
703                                         SelectItem (CurrentMenu, item, popup);
704                                         if (popup) {
705                                                 SelectItem (item, item.MenuItems [0], false);
706                                                 CurrentMenu = item;
707                                         }
708                                 } else if (CurrentMenu.parent_menu is MainMenu) {
709                                         item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Previous);
710                                         SelectItem (CurrentMenu.parent_menu, item, item.IsPopup);
711                                         if (item.IsPopup) {
712                                                 SelectItem (item, item.MenuItems [0], false);
713                                                 CurrentMenu = item;
714                                         }
715                                 } else {
716                                         HideSubPopups (CurrentMenu, TopMenu);
717                                         CurrentMenu = CurrentMenu.parent_menu;
718                                 }
719                                 break;
720
721                         case Keys.Return:
722                                 if (CurrentMenu is MainMenu) {
723                                         if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
724                                                 keynav_state = KeyNavState.Navigating;
725                                                 item = CurrentMenu.SelectedItem;
726                                                 ShowSubPopup (CurrentMenu, item);
727                                                 SelectItem (item, item.MenuItems [0], false);
728                                                 CurrentMenu = item;
729                                                 active = true;
730                                                 grab_control.ActiveTracker = this;
731                                         }
732                                         return true;
733                                 }
734                         
735                                 ExecFocusedItem (CurrentMenu, CurrentMenu.SelectedItem);
736                                 break;
737                                 
738                         case Keys.Escape:
739                                 Deactivate ();
740                                 break;
741
742                         default:
743                                 ProcessMnemonic (msg, keyData);
744                                 break;
745                         }
746
747                         return false;
748                 }
749         }
750
751         internal class PopUpWindow : Control
752         {
753                 private Menu menu;
754                 private Form form;
755
756                 public PopUpWindow (Form form, Menu menu): base ()
757                 {
758                         this.menu = menu;
759                         this.form = form;
760                         SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
761                         SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
762                         is_visible = false;
763                 }
764
765                 protected override CreateParams CreateParams
766                 {
767                         get {
768                                 CreateParams cp = base.CreateParams;
769                                 cp.Caption = "Menu PopUp";
770                                 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP));
771                                 cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);
772                                 return cp;
773                         }
774                 }
775
776                 public void ShowWindow ()
777                 {
778                         XplatUI.SetCursor(form.Handle, Cursors.Default.handle);
779                         RefreshItems ();
780                         Show ();
781                 }
782                 
783                 internal override void OnPaintInternal (PaintEventArgs args)
784                 {
785                         ThemeEngine.Current.DrawPopupMenu (args.Graphics, menu, args.ClipRectangle, ClientRectangle);
786                 }
787                 
788                 public void HideWindow ()
789                 {
790                         XplatUI.SetCursor (form.Handle, form.Cursor.handle);
791                         MenuTracker.HideSubPopups (menu, null);
792                 Hide ();
793                 }
794
795 #if false
796                 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
797                 {       
798                         return MenuTracker.ProcessKeys (menu, ref msg, keyData, tracker);
799                 }
800 #endif
801
802                 protected override void CreateHandle ()
803                 {
804                         base.CreateHandle ();
805                         RefreshItems ();                        
806                 }               
807                 
808                 // Called when the number of items has changed
809                 internal void RefreshItems ()
810                 {
811                         ThemeEngine.Current.CalcPopupMenuSize (DeviceContext, menu);
812
813                         if ((Location.X + menu.Rect.Width) > SystemInformation.WorkingArea.Width) {
814                                 Location = new Point (Location.X - menu.Rect.Width, Location.Y);
815                         }
816                         if ((Location.Y + menu.Rect.Height) > SystemInformation.WorkingArea.Height) {
817                                 Location = new Point (Location.X, Location.Y - menu.Rect.Height);
818                         }
819
820                         Width = menu.Rect.Width;
821                         Height = menu.Rect.Height;                      
822                 }
823                 
824                 internal override bool ActivateOnShow { get { return false; } }
825         }
826 }
827
828