MenuAPI.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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, [email protected]
  24. // Mike Kestner <[email protected]>
  25. //
  26. // NOT COMPLETE
  27. using System.Collections;
  28. using System.Drawing;
  29. namespace System.Windows.Forms {
  30. /*
  31. When writing this code the Wine project was of great help to
  32. understand the logic behind some Win32 issues. Thanks to them. Jordi,
  33. */
  34. internal class MenuTracker {
  35. internal bool active;
  36. public Menu CurrentMenu;
  37. public Menu TopMenu;
  38. Form grab_control;
  39. public MenuTracker (Menu top_menu)
  40. {
  41. TopMenu = CurrentMenu = top_menu;
  42. foreach (MenuItem item in TopMenu.MenuItems)
  43. AddShortcuts (item);
  44. if (top_menu is ContextMenu) {
  45. grab_control = (top_menu as ContextMenu).SourceControl.FindForm ();
  46. grab_control.ActiveTracker = this;
  47. } else
  48. grab_control = top_menu.Wnd.FindForm ();
  49. }
  50. enum KeyNavState {
  51. Idle,
  52. Startup,
  53. NoPopups,
  54. Navigating
  55. }
  56. KeyNavState keynav_state = KeyNavState.Idle;
  57. public bool Navigating {
  58. get { return keynav_state != KeyNavState.Idle; }
  59. }
  60. internal static Point ScreenToMenu (Menu menu, Point pnt)
  61. {
  62. int x = pnt.X;
  63. int y = pnt.Y;
  64. XplatUI.ScreenToMenu (menu.Wnd.window.Handle, ref x, ref y);
  65. return new Point (x, y);
  66. }
  67. void Deactivate ()
  68. {
  69. active = false;
  70. grab_control.ActiveTracker = null;
  71. keynav_state = KeyNavState.Idle;
  72. if (TopMenu is ContextMenu) {
  73. PopUpWindow puw = TopMenu.Wnd as PopUpWindow;
  74. puw.HideWindow ();
  75. } else {
  76. DeselectItem (TopMenu.SelectedItem);
  77. (TopMenu as MainMenu).Draw ();
  78. }
  79. CurrentMenu = TopMenu;
  80. }
  81. MenuItem FindItemByCoords (Menu menu, Point pt)
  82. {
  83. if (menu is MainMenu)
  84. pt = ScreenToMenu (menu, pt);
  85. else
  86. pt = menu.Wnd.PointToClient (pt);
  87. foreach (MenuItem item in menu.MenuItems) {
  88. Rectangle rect = item.bounds;
  89. if (rect.Contains (pt))
  90. return item;
  91. }
  92. return null;
  93. }
  94. MenuItem GetItemAtXY (int x, int y)
  95. {
  96. Point pnt = new Point (x, y);
  97. MenuItem item = FindItemByCoords (TopMenu, pnt);
  98. if (item == null && TopMenu.SelectedItem != null)
  99. item = FindSubItemByCoord (TopMenu.SelectedItem, Control.MousePosition);
  100. return item;
  101. }
  102. public void OnClick (MouseEventArgs args)
  103. {
  104. MenuItem item = GetItemAtXY (args.X, args.Y);
  105. if (item == null) {
  106. Deactivate ();
  107. return;
  108. }
  109. SelectItem (item.Parent, item, item.IsPopup);
  110. if (item.IsPopup) {
  111. active = true;
  112. grab_control.ActiveTracker = this;
  113. } else if (item.Parent is MainMenu)
  114. active = false;
  115. else
  116. Deactivate ();
  117. item.PerformClick ();
  118. }
  119. public void OnMotion (MouseEventArgs args)
  120. {
  121. MenuItem item = GetItemAtXY (args.X, args.Y);
  122. if (CurrentMenu.SelectedItem == item)
  123. return;
  124. grab_control.ActiveTracker = (active || item != null) ? this : null;
  125. Rectangle top_bounds = new Rectangle(0, 0, TopMenu.Rect.Width, TopMenu.Rect.Height);
  126. if (item == null && (!active || top_bounds.Contains (ScreenToMenu (TopMenu, new Point (args.X, args.Y)))))
  127. DeselectItem (TopMenu.SelectedItem);
  128. else
  129. MoveSelection (item);
  130. }
  131. void MoveSelection (MenuItem item)
  132. {
  133. if (item == null) {
  134. if (CurrentMenu.SelectedItem.IsPopup)
  135. return;
  136. MenuItem old_item = CurrentMenu.SelectedItem;
  137. if (CurrentMenu != TopMenu)
  138. CurrentMenu = CurrentMenu.parent_menu;
  139. DeselectItem (old_item);
  140. } else {
  141. if (item.Parent != CurrentMenu.SelectedItem)
  142. DeselectItem (CurrentMenu.SelectedItem);
  143. CurrentMenu = item.Parent;
  144. SelectItem (CurrentMenu, item, active && item.IsPopup);
  145. }
  146. }
  147. static public bool TrackPopupMenu (Menu menu, Point pnt)
  148. {
  149. if (menu.MenuItems.Count <= 0) // No submenus to track
  150. return true;
  151. menu.Wnd = new PopUpWindow (menu);
  152. MenuTracker tracker = new MenuTracker (menu);
  153. tracker.active = true;
  154. menu.Wnd.Location = menu.Wnd.PointToClient (pnt);
  155. ((PopUpWindow)menu.Wnd).ShowWindow ();
  156. bool no_quit = true;
  157. while ((menu.Wnd != null) && menu.Wnd.Visible && no_quit) {
  158. MSG msg = new MSG ();
  159. no_quit = XplatUI.GetMessage(ref msg, IntPtr.Zero, 0, 0);
  160. XplatUI.TranslateMessage(ref msg);
  161. XplatUI.DispatchMessage(ref msg);
  162. }
  163. if (!no_quit)
  164. XplatUI.PostQuitMessage(0);
  165. if (menu.Wnd != null) {
  166. menu.Wnd.Dispose ();
  167. menu.Wnd = null;
  168. }
  169. return true;
  170. }
  171. void DeselectItem (MenuItem item)
  172. {
  173. if (item == null)
  174. return;
  175. item.Status = item.Status &~ DrawItemState.Selected;
  176. if (item.IsPopup)
  177. HideSubPopups (item);
  178. Menu menu = item.Parent;
  179. if (menu is MainMenu)
  180. (menu as MainMenu).Draw ();
  181. else if (menu.Wnd != null)
  182. menu.Wnd.Invalidate (item.bounds);
  183. }
  184. void SelectItem (Menu menu, MenuItem item, bool execute)
  185. {
  186. MenuItem prev_item = menu.SelectedItem;
  187. if (prev_item != item) {
  188. DeselectItem (prev_item);
  189. if (CurrentMenu != menu)
  190. CurrentMenu = menu;
  191. item.Status |= DrawItemState.Selected;
  192. if (menu is MainMenu)
  193. (menu as MainMenu).Draw ();
  194. else
  195. menu.Wnd.Invalidate (item.bounds);
  196. item.PerformSelect ();
  197. }
  198. if (execute)
  199. ExecFocusedItem (menu, item);
  200. }
  201. // Used when the user executes the action of an item (press enter, shortcut)
  202. // or a sub-popup menu has to be shown
  203. void ExecFocusedItem (Menu menu, MenuItem item)
  204. {
  205. if (!item.Enabled)
  206. return;
  207. if (item.IsPopup) {
  208. ShowSubPopup (menu, item);
  209. } else {
  210. Deactivate ();
  211. item.PerformClick ();
  212. }
  213. }
  214. // Create a popup window and show it or only show it if it is already created
  215. void ShowSubPopup (Menu menu, MenuItem item)
  216. {
  217. if (item.Enabled == false)
  218. return;
  219. if (item.Wnd != null)
  220. item.Wnd.Dispose ();
  221. item.PerformPopup ();
  222. PopUpWindow puw = new PopUpWindow (item);
  223. Point pnt;
  224. if (menu is MainMenu)
  225. pnt = new Point (item.X, 0);
  226. else
  227. pnt = new Point (item.X + item.Width, item.Y + 1);
  228. pnt = menu.Wnd.PointToScreen (pnt);
  229. puw.Location = pnt;
  230. item.Wnd = puw;
  231. puw.ShowWindow ();
  232. }
  233. static public void HideSubPopups (Menu menu)
  234. {
  235. foreach (MenuItem item in menu.MenuItems)
  236. if (item.IsPopup)
  237. HideSubPopups (item);
  238. if (menu.Wnd == null)
  239. return;
  240. PopUpWindow puw = menu.Wnd as PopUpWindow;
  241. puw.Hide ();
  242. }
  243. MenuItem FindSubItemByCoord (Menu menu, Point pnt)
  244. {
  245. foreach (MenuItem item in menu.MenuItems) {
  246. if (item.IsPopup && item.Wnd != null && item.Wnd.Visible && item == menu.SelectedItem) {
  247. MenuItem result = FindSubItemByCoord (item, pnt);
  248. if (result != null)
  249. return result;
  250. }
  251. if (menu.Wnd == null)
  252. continue;
  253. Rectangle rect = item.bounds;
  254. Point pnt_client = menu.Wnd.PointToScreen (new Point (item.X, item.Y));
  255. rect.X = pnt_client.X;
  256. rect.Y = pnt_client.Y;
  257. if (rect.Contains (pnt) == true)
  258. return item;
  259. }
  260. return null;
  261. }
  262. static MenuItem FindItemByKey (Menu menu, IntPtr key)
  263. {
  264. char key_char = (char ) (key.ToInt32() & 0xff);
  265. key_char = Char.ToUpper (key_char);
  266. foreach (MenuItem item in menu.MenuItems) {
  267. if (item.Mnemonic == '\0')
  268. continue;
  269. if (item.Mnemonic == key_char)
  270. return item;
  271. }
  272. return null;
  273. }
  274. enum ItemNavigation {
  275. First,
  276. Last,
  277. Next,
  278. Previous,
  279. }
  280. static MenuItem GetNextItem (Menu menu, ItemNavigation navigation)
  281. {
  282. int pos = 0;
  283. bool selectable_items = false;
  284. MenuItem item;
  285. // Check if there is at least a selectable item
  286. for (int i = 0; i < menu.MenuItems.Count; i++) {
  287. item = menu.MenuItems [i];
  288. if (item.Separator == false && item.Visible == true) {
  289. selectable_items = true;
  290. break;
  291. }
  292. }
  293. if (selectable_items == false)
  294. return null;
  295. switch (navigation) {
  296. case ItemNavigation.First:
  297. /* First item that is not separator and it is visible*/
  298. for (pos = 0; pos < menu.MenuItems.Count; pos++) {
  299. item = menu.MenuItems [pos];
  300. if (item.Separator == false && item.Visible == true)
  301. break;
  302. }
  303. break;
  304. case ItemNavigation.Last: // Not used
  305. break;
  306. case ItemNavigation.Next:
  307. if (menu.SelectedItem != null)
  308. pos = menu.SelectedItem.Index;
  309. /* Next item that is not separator and it is visible*/
  310. for (pos++; pos < menu.MenuItems.Count; pos++) {
  311. item = menu.MenuItems [pos];
  312. if (item.Separator == false && item.Visible == true)
  313. break;
  314. }
  315. if (pos >= menu.MenuItems.Count) { /* Jump at the start of the menu */
  316. pos = 0;
  317. /* Next item that is not separator and it is visible*/
  318. for (; pos < menu.MenuItems.Count; pos++) {
  319. item = menu.MenuItems [pos];
  320. if (item.Separator == false && item.Visible == true)
  321. break;
  322. }
  323. }
  324. break;
  325. case ItemNavigation.Previous:
  326. if (menu.SelectedItem != null)
  327. pos = menu.SelectedItem.Index;
  328. /* Previous item that is not separator and it is visible*/
  329. for (pos--; pos >= 0; pos--) {
  330. item = menu.MenuItems [pos];
  331. if (item.Separator == false && item.Visible == true)
  332. break;
  333. }
  334. if (pos < 0 ) { /* Jump at the end of the menu*/
  335. pos = menu.MenuItems.Count - 1;
  336. /* Previous item that is not separator and it is visible*/
  337. for (; pos >= 0; pos--) {
  338. item = menu.MenuItems [pos];
  339. if (item.Separator == false && item.Visible == true)
  340. break;
  341. }
  342. }
  343. break;
  344. default:
  345. break;
  346. }
  347. return menu.MenuItems [pos];
  348. }
  349. void ProcessMenuKey (Msg msg_type)
  350. {
  351. if (TopMenu.MenuItems.Count == 0)
  352. return;
  353. MainMenu main_menu = TopMenu as MainMenu;
  354. switch (msg_type) {
  355. case Msg.WM_SYSKEYDOWN:
  356. switch (keynav_state) {
  357. case KeyNavState.Idle:
  358. keynav_state = KeyNavState.Startup;
  359. CurrentMenu = TopMenu;
  360. main_menu.Draw ();
  361. break;
  362. case KeyNavState.Startup:
  363. break;
  364. default:
  365. keynav_state = KeyNavState.Idle;
  366. Deactivate ();
  367. main_menu.Draw ();
  368. break;
  369. }
  370. break;
  371. case Msg.WM_SYSKEYUP:
  372. switch (keynav_state) {
  373. case KeyNavState.Idle:
  374. case KeyNavState.Navigating:
  375. break;
  376. case KeyNavState.Startup:
  377. keynav_state = KeyNavState.NoPopups;
  378. SelectItem (TopMenu, TopMenu.MenuItems [0], false);
  379. break;
  380. default:
  381. keynav_state = KeyNavState.Idle;
  382. Deactivate ();
  383. main_menu.Draw ();
  384. break;
  385. }
  386. break;
  387. default:
  388. throw new ArgumentException ("Invalid msg_type " + msg_type);
  389. }
  390. }
  391. bool ProcessMnemonic (Message msg, Keys key_data)
  392. {
  393. keynav_state = KeyNavState.Navigating;
  394. MenuItem item = FindItemByKey (CurrentMenu, msg.WParam);
  395. if (item == null)
  396. return false;
  397. SelectItem (CurrentMenu, item, true);
  398. if (item.IsPopup) {
  399. SelectItem (item, item.MenuItems [0], false);
  400. CurrentMenu = item;
  401. }
  402. return true;
  403. }
  404. void ProcessArrowKey (Keys keyData)
  405. {
  406. MenuItem item;
  407. switch (keyData) {
  408. case Keys.Up:
  409. if (CurrentMenu is MainMenu)
  410. return;
  411. else if (CurrentMenu.MenuItems.Count == 1 && CurrentMenu.parent_menu == TopMenu) {
  412. DeselectItem (CurrentMenu.SelectedItem);
  413. CurrentMenu = TopMenu;
  414. return;
  415. }
  416. item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
  417. if (item != null)
  418. SelectItem (CurrentMenu, item, false);
  419. break;
  420. case Keys.Down:
  421. if (CurrentMenu is MainMenu) {
  422. if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
  423. keynav_state = KeyNavState.Navigating;
  424. item = CurrentMenu.SelectedItem;
  425. ShowSubPopup (CurrentMenu, item);
  426. SelectItem (item, item.MenuItems [0], false);
  427. CurrentMenu = item;
  428. }
  429. return;
  430. }
  431. item = GetNextItem (CurrentMenu, ItemNavigation.Next);
  432. if (item != null)
  433. SelectItem (CurrentMenu, item, false);
  434. break;
  435. case Keys.Right:
  436. if (CurrentMenu is MainMenu) {
  437. item = GetNextItem (CurrentMenu, ItemNavigation.Next);
  438. bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
  439. SelectItem (CurrentMenu, item, popup);
  440. if (popup) {
  441. SelectItem (item, item.MenuItems [0], false);
  442. CurrentMenu = item;
  443. }
  444. } else if (CurrentMenu.SelectedItem.IsPopup) {
  445. item = CurrentMenu.SelectedItem;
  446. ShowSubPopup (CurrentMenu, item);
  447. SelectItem (item, item.MenuItems [0], false);
  448. CurrentMenu = item;
  449. } else if (CurrentMenu.parent_menu is MainMenu) {
  450. item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Next);
  451. SelectItem (CurrentMenu.parent_menu, item, item.IsPopup);
  452. if (item.IsPopup) {
  453. SelectItem (item, item.MenuItems [0], false);
  454. CurrentMenu = item;
  455. }
  456. }
  457. break;
  458. case Keys.Left:
  459. if (CurrentMenu is MainMenu) {
  460. item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
  461. bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
  462. SelectItem (CurrentMenu, item, popup);
  463. if (popup) {
  464. SelectItem (item, item.MenuItems [0], false);
  465. CurrentMenu = item;
  466. }
  467. } else if (CurrentMenu.parent_menu is MainMenu) {
  468. item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Previous);
  469. SelectItem (CurrentMenu.parent_menu, item, item.IsPopup);
  470. if (item.IsPopup) {
  471. SelectItem (item, item.MenuItems [0], false);
  472. CurrentMenu = item;
  473. }
  474. } else {
  475. HideSubPopups (CurrentMenu);
  476. CurrentMenu = CurrentMenu.parent_menu;
  477. }
  478. break;
  479. default:
  480. throw new ArgumentException ("Invalid keyData: " + keyData);
  481. }
  482. }
  483. Hashtable shortcuts = new Hashtable ();
  484. public void AddShortcuts (MenuItem item)
  485. {
  486. foreach (MenuItem child in item.MenuItems) {
  487. AddShortcuts (child);
  488. if (child.Shortcut != Shortcut.None)
  489. shortcuts [(int)child.Shortcut] = child;
  490. }
  491. if (item.Shortcut != Shortcut.None)
  492. shortcuts [(int)item.Shortcut] = item;
  493. }
  494. public void RemoveShortcuts (MenuItem item)
  495. {
  496. foreach (MenuItem child in item.MenuItems) {
  497. RemoveShortcuts (child);
  498. if (child.Shortcut != Shortcut.None)
  499. shortcuts.Remove ((int)child.Shortcut);
  500. }
  501. if (item.Shortcut != Shortcut.None)
  502. shortcuts.Remove ((int)item.Shortcut);
  503. }
  504. bool ProcessShortcut (Keys keyData)
  505. {
  506. MenuItem item = shortcuts [(int)keyData] as MenuItem;
  507. if (item == null)
  508. return false;
  509. Deactivate ();
  510. item.PerformClick ();
  511. return true;
  512. }
  513. public bool ProcessKeys (ref Message msg, Keys keyData)
  514. {
  515. if ((Msg)msg.Msg != Msg.WM_SYSKEYUP && ProcessShortcut (keyData))
  516. return true;
  517. else if ((keyData & Keys.KeyCode) == Keys.Menu && TopMenu is MainMenu) {
  518. ProcessMenuKey ((Msg) msg.Msg);
  519. return true;
  520. } else if ((keyData & Keys.Alt) == Keys.Alt)
  521. return ProcessMnemonic (msg, keyData);
  522. else if ((Msg)msg.Msg == Msg.WM_SYSKEYUP || keynav_state == KeyNavState.Idle)
  523. return false;
  524. switch (keyData) {
  525. case Keys.Up:
  526. case Keys.Down:
  527. case Keys.Right:
  528. case Keys.Left:
  529. ProcessArrowKey (keyData);
  530. break;
  531. case Keys.Escape:
  532. Deactivate ();
  533. break;
  534. case Keys.Return:
  535. ExecFocusedItem (CurrentMenu, CurrentMenu.SelectedItem);
  536. break;
  537. default:
  538. ProcessMnemonic (msg, keyData);
  539. break;
  540. }
  541. return true;
  542. }
  543. }
  544. internal class PopUpWindow : Control
  545. {
  546. private Menu menu;
  547. public PopUpWindow (Menu menu): base ()
  548. {
  549. this.menu = menu;
  550. Paint += new PaintEventHandler (OnPaintPUW);
  551. SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  552. SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
  553. is_visible = false;
  554. }
  555. protected override CreateParams CreateParams
  556. {
  557. get {
  558. CreateParams cp = base.CreateParams;
  559. cp.Caption = "Menu PopUp";
  560. cp.Style = unchecked ((int)(WindowStyles.WS_POPUP));
  561. cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);
  562. return cp;
  563. }
  564. }
  565. public void ShowWindow ()
  566. {
  567. Show ();
  568. RefreshItems ();
  569. Refresh ();
  570. }
  571. private void OnPaintPUW (Object o, PaintEventArgs args)
  572. {
  573. ThemeEngine.Current.DrawPopupMenu (args.Graphics, menu, args.ClipRectangle, ClientRectangle);
  574. }
  575. public void HideWindow ()
  576. {
  577. MenuTracker.HideSubPopups (menu);
  578. Hide ();
  579. }
  580. #if false
  581. protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
  582. {
  583. return MenuTracker.ProcessKeys (menu, ref msg, keyData, tracker);
  584. }
  585. #endif
  586. protected override void CreateHandle ()
  587. {
  588. base.CreateHandle ();
  589. RefreshItems ();
  590. }
  591. // Called when the number of items has changed
  592. internal void RefreshItems ()
  593. {
  594. ThemeEngine.Current.CalcPopupMenuSize (DeviceContext, menu);
  595. if ((Location.X + menu.Rect.Width) > SystemInformation.WorkingArea.Width) {
  596. Location = new Point (Location.X - menu.Rect.Width, Location.Y);
  597. }
  598. if ((Location.Y + menu.Rect.Height) > SystemInformation.WorkingArea.Height) {
  599. Location = new Point (Location.X, Location.Y - menu.Rect.Height);
  600. }
  601. Width = menu.Rect.Width;
  602. Height = menu.Rect.Height;
  603. }
  604. }
  605. }