DefaultMenuInteractionHandlerTests.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. using System;
  2. using Avalonia.Controls.Platform;
  3. using Avalonia.Controls.Primitives;
  4. using Avalonia.Input;
  5. using Avalonia.Input.GestureRecognizers;
  6. using Avalonia.Interactivity;
  7. using Avalonia.VisualTree;
  8. using Moq;
  9. using Xunit;
  10. namespace Avalonia.Controls.UnitTests.Platform
  11. {
  12. public class DefaultMenuInteractionHandlerTests
  13. {
  14. static PointerPressedEventArgs CreatePressed(object source) => new PointerPressedEventArgs(source,
  15. new FakePointer(), (Visual)source, default,0, new PointerPointProperties (RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
  16. default);
  17. static PointerReleasedEventArgs CreateReleased(object source) => new PointerReleasedEventArgs(source,
  18. new FakePointer(), (Visual)source, default,0,
  19. new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonReleased),
  20. default, MouseButton.Left);
  21. public class TopLevel
  22. {
  23. [Fact]
  24. public void Up_Opens_MenuItem_With_SubMenu()
  25. {
  26. var target = new DefaultMenuInteractionHandler(false);
  27. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  28. var e = new KeyEventArgs { Key = Key.Up, Source = item.Object };
  29. target.KeyDown(item, e);
  30. item.Verify(x => x.Open());
  31. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  32. Assert.True(e.Handled);
  33. }
  34. [Fact]
  35. public void Down_Opens_MenuItem_With_SubMenu()
  36. {
  37. var target = new DefaultMenuInteractionHandler(false);
  38. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  39. var e = new KeyEventArgs { Key = Key.Down, Source = item.Object };
  40. target.KeyDown(item.Object, e);
  41. item.Verify(x => x.Open());
  42. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  43. Assert.True(e.Handled);
  44. }
  45. [Fact]
  46. public void Down_Selects_First_Item_Of_Already_Opened_Submenu()
  47. {
  48. var target = new DefaultMenuInteractionHandler(false);
  49. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, isSubMenuOpen: true);
  50. var e = new KeyEventArgs { Key = Key.Down, Source = item.Object };
  51. target.KeyDown(item, e);
  52. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  53. Assert.True(e.Handled);
  54. }
  55. [Fact]
  56. public void Right_Selects_Next_MenuItem()
  57. {
  58. var target = new DefaultMenuInteractionHandler(false);
  59. var menu = Mock.Of<IMenu>(x => x.MoveSelection(NavigationDirection.Right, true) == true);
  60. var item = CreateMockMenuItem(isTopLevel: true, parent: menu);
  61. var e = new KeyEventArgs { Key = Key.Right, Source = item.Object };
  62. target.KeyDown(item, e);
  63. Mock.Get(menu).Verify(x => x.MoveSelection(NavigationDirection.Right, true));
  64. Assert.True(e.Handled);
  65. }
  66. [Fact]
  67. public void Left_Selects_Previous_MenuItem()
  68. {
  69. var target = new DefaultMenuInteractionHandler(false);
  70. var menu = Mock.Of<IMenu>(x => x.MoveSelection(NavigationDirection.Left, true) == true);
  71. var item = CreateMockMenuItem(isTopLevel: true, parent: menu);
  72. var e = new KeyEventArgs { Key = Key.Left, Source = item.Object };
  73. target.KeyDown(item, e);
  74. Mock.Get(menu).Verify(x => x.MoveSelection(NavigationDirection.Left, true));
  75. Assert.True(e.Handled);
  76. }
  77. [Fact]
  78. public void Enter_On_Item_With_No_SubMenu_Causes_Click()
  79. {
  80. var target = new DefaultMenuInteractionHandler(false);
  81. var menu = Mock.Of<IMenu>();
  82. var item = CreateMockMenuItem(isTopLevel: true, parent: menu);
  83. var e = new KeyEventArgs { Key = Key.Enter, Source = item.Object };
  84. target.KeyDown(item, e);
  85. item.Verify(x => x.RaiseClick());
  86. Mock.Get(menu).Verify(x => x.Close());
  87. Assert.True(e.Handled);
  88. }
  89. [Fact]
  90. public void Enter_On_Item_With_SubMenu_Opens_SubMenu()
  91. {
  92. var target = new DefaultMenuInteractionHandler(false);
  93. var menu = Mock.Of<IMenu>();
  94. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  95. var e = new KeyEventArgs { Key = Key.Enter, Source = item.Object };
  96. target.KeyDown(item, e);
  97. item.Verify(x => x.Open());
  98. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  99. Assert.True(e.Handled);
  100. }
  101. [Fact]
  102. public void Escape_Closes_Parent_Menu()
  103. {
  104. var target = new DefaultMenuInteractionHandler(false);
  105. var menu = Mock.Of<IMenu>();
  106. var item = CreateMockMenuItem(isTopLevel: true, parent: menu);
  107. var e = new KeyEventArgs { Key = Key.Escape, Source = item.Object };
  108. target.KeyDown(item, e);
  109. Mock.Get(menu).Verify(x => x.Close());
  110. Assert.True(e.Handled);
  111. }
  112. [Fact]
  113. public void Click_On_TopLevel_Calls_MainMenu_Open()
  114. {
  115. var target = new DefaultMenuInteractionHandler(false);
  116. var menu = CreateMockMainMenu();
  117. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: (IMenuElement)menu.Object);
  118. var e = CreatePressed(item.Object);
  119. target.PointerPressed(item.Object, e);
  120. menu.Verify(x => x.Open());
  121. }
  122. [Fact]
  123. public void Click_On_Open_TopLevel_Menu_Closes_Menu()
  124. {
  125. var target = new DefaultMenuInteractionHandler(false);
  126. var menu = Mock.Of<IMenu>();
  127. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, isSubMenuOpen: true, parent: menu);
  128. var e = CreatePressed(item.Object);
  129. target.PointerPressed(item.Object, e);
  130. Mock.Get(menu).Verify(x => x.Close());
  131. }
  132. [Fact]
  133. public void PointerEntered_Opens_Item_When_Old_Item_Is_Open()
  134. {
  135. var target = new DefaultMenuInteractionHandler(false);
  136. var menu = new Mock<IMenu>();
  137. var item = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, isSubMenuOpen: true, parent: menu.Object);
  138. var nextItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu.Object);
  139. var e = new RoutedEventArgs(MenuItem.PointerEnteredItemEvent, nextItem.Object);
  140. menu.SetupGet(x => x.SelectedItem).Returns(item.Object);
  141. target.PointerEntered(nextItem, e);
  142. item.Verify(x => x.Close());
  143. menu.VerifySet(x => x.SelectedItem = nextItem.Object);
  144. nextItem.Verify(x => x.Open());
  145. nextItem.Verify(x => x.MoveSelection(NavigationDirection.First, true), Times.Never);
  146. Assert.False(e.Handled);
  147. }
  148. [Fact]
  149. public void PointerExited_Deselects_Item_When_Menu_Not_Open()
  150. {
  151. var target = new DefaultMenuInteractionHandler(false);
  152. var menu = new Mock<IMenu>();
  153. var item = CreateMockMenuItem(isTopLevel: true, parent: menu.Object);
  154. var e = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  155. menu.SetupGet(x => x.SelectedItem).Returns(item.Object);
  156. target.PointerExited(item, e);
  157. menu.VerifySet(x => x.SelectedItem = null);
  158. Assert.False(e.Handled);
  159. }
  160. [Fact]
  161. public void PointerExited_Doesnt_Deselect_Item_When_Menu_Open()
  162. {
  163. var target = new DefaultMenuInteractionHandler(false);
  164. var menu = new Mock<IMenu>();
  165. var item = CreateMockMenuItem(isTopLevel: true, parent: menu.Object);
  166. var e = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  167. menu.SetupGet(x => x.IsOpen).Returns(true);
  168. menu.SetupGet(x => x.SelectedItem).Returns(item.Object);
  169. target.PointerExited(item, e);
  170. menu.VerifySet(x => x.SelectedItem = null, Times.Never);
  171. Assert.False(e.Handled);
  172. }
  173. [Fact]
  174. public void Doesnt_Throw_On_Menu_Keypress()
  175. {
  176. // Issue #3459
  177. var target = new DefaultMenuInteractionHandler(false);
  178. var menu = Mock.Of<IMenu>();
  179. var item = CreateMockMenuItem(isTopLevel: true, parent: menu);
  180. var e = new KeyEventArgs { Key = Key.Tab, Source = menu };
  181. target.KeyDown(menu, e);
  182. }
  183. }
  184. public class NonTopLevel
  185. {
  186. [Fact]
  187. public void Up_Selects_Previous_MenuItem()
  188. {
  189. var target = new DefaultMenuInteractionHandler(false);
  190. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  191. var item = CreateMockMenuItem(parent: parentItem.Object);
  192. var e = new KeyEventArgs { Key = Key.Up, Source = item.Object };
  193. target.KeyDown(item.Object, e);
  194. parentItem.Verify(x => x.MoveSelection(NavigationDirection.Up, true));
  195. Assert.True(e.Handled);
  196. }
  197. [Fact]
  198. public void Down_Selects_Next_MenuItem()
  199. {
  200. var target = new DefaultMenuInteractionHandler(false);
  201. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  202. var item = CreateMockMenuItem(parent: parentItem.Object);
  203. var e = new KeyEventArgs { Key = Key.Down, Source = item.Object };
  204. target.KeyDown(item.Object, e);
  205. parentItem.Verify(x => x.MoveSelection(NavigationDirection.Down, true));
  206. Assert.True(e.Handled);
  207. }
  208. [Fact]
  209. public void Left_Closes_Parent_SubMenu()
  210. {
  211. var target = new DefaultMenuInteractionHandler(false);
  212. var parentItem = CreateMockMenuItem(hasSubMenu: true, isSubMenuOpen: true);
  213. var item = CreateMockMenuItem(parent: parentItem.Object);
  214. var e = new KeyEventArgs { Key = Key.Left, Source = item.Object };
  215. target.KeyDown(item.Object, e);
  216. parentItem.Verify(x => x.Close());
  217. parentItem.Verify(x => x.Focus(It.IsAny<NavigationMethod>(), It.IsAny<KeyModifiers>()));
  218. Assert.True(e.Handled);
  219. }
  220. [Fact]
  221. public void Right_With_SubMenu_Items_Opens_SubMenu()
  222. {
  223. var target = new DefaultMenuInteractionHandler(false);
  224. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  225. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  226. var e = new KeyEventArgs { Key = Key.Right, Source = item.Object };
  227. target.KeyDown(item.Object, e);
  228. item.Verify(x => x.Open());
  229. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  230. Assert.True(e.Handled);
  231. }
  232. [Fact]
  233. public void Right_On_TopLevel_Child_Navigates_TopLevel_Selection()
  234. {
  235. var target = new DefaultMenuInteractionHandler(false);
  236. var menu = new Mock<IMenu>();
  237. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, isSubMenuOpen: true, parent: menu.Object);
  238. var nextItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu.Object);
  239. var item = CreateMockMenuItem(parent: parentItem.Object);
  240. var e = new KeyEventArgs { Key = Key.Right, Source = item.Object };
  241. menu.Setup(x => x.MoveSelection(NavigationDirection.Right, true))
  242. .Callback(() => menu.SetupGet(x => x.SelectedItem).Returns(nextItem.Object))
  243. .Returns(true);
  244. target.KeyDown(item.Object, e);
  245. menu.Verify(x => x.MoveSelection(NavigationDirection.Right, true));
  246. parentItem.Verify(x => x.Close());
  247. nextItem.Verify(x => x.Open());
  248. nextItem.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  249. Assert.True(e.Handled);
  250. }
  251. [Fact]
  252. public void Enter_On_Item_With_No_SubMenu_Causes_Click()
  253. {
  254. var target = new DefaultMenuInteractionHandler(false);
  255. var menu = Mock.Of<IMenu>();
  256. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  257. var item = CreateMockMenuItem(parent: parentItem.Object);
  258. var e = new KeyEventArgs { Key = Key.Enter, Source = item.Object };
  259. target.KeyDown(item.Object, e);
  260. item.Verify(x => x.RaiseClick());
  261. Mock.Get(menu).Verify(x => x.Close());
  262. Assert.True(e.Handled);
  263. }
  264. [Fact]
  265. public void Enter_On_Item_With_SubMenu_Opens_SubMenu()
  266. {
  267. var target = new DefaultMenuInteractionHandler(false);
  268. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  269. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  270. var e = new KeyEventArgs { Key = Key.Enter, Source = item.Object };
  271. target.KeyDown(item.Object, e);
  272. item.Verify(x => x.Open());
  273. item.Verify(x => x.MoveSelection(NavigationDirection.First, true));
  274. Assert.True(e.Handled);
  275. }
  276. [Fact]
  277. public void Escape_Closes_Parent_MenuItem()
  278. {
  279. var target = new DefaultMenuInteractionHandler(false);
  280. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true);
  281. var item = CreateMockMenuItem(parent: parentItem.Object);
  282. var e = new KeyEventArgs { Key = Key.Escape, Source = item.Object };
  283. target.KeyDown(item.Object, e);
  284. parentItem.Verify(x => x.Close());
  285. parentItem.Verify(x => x.Focus(It.IsAny<NavigationMethod>(), It.IsAny<KeyModifiers>()));
  286. Assert.True(e.Handled);
  287. }
  288. [Fact]
  289. public void PointerEntered_Selects_Item()
  290. {
  291. var target = new DefaultMenuInteractionHandler(false);
  292. var menu = Mock.Of<IMenu>();
  293. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  294. var item = CreateMockMenuItem(parent: parentItem.Object);
  295. var e = new RoutedEventArgs(MenuItem.PointerEnteredItemEvent, item.Object);
  296. target.PointerEntered(item.Object, e);
  297. parentItem.VerifySet(x => x.SelectedItem = item.Object);
  298. Assert.False(e.Handled);
  299. }
  300. [Fact]
  301. public void PointerEntered_Opens_Submenu_After_Delay()
  302. {
  303. var timer = new TestTimer();
  304. var target = new DefaultMenuInteractionHandler(false, null, timer.RunOnce);
  305. var menu = Mock.Of<IMenu>();
  306. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  307. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  308. var e = new RoutedEventArgs(MenuItem.PointerEnteredItemEvent, item.Object);
  309. target.PointerEntered(item.Object, e);
  310. item.Verify(x => x.Open(), Times.Never);
  311. timer.Pulse();
  312. item.Verify(x => x.Open());
  313. Assert.False(e.Handled);
  314. }
  315. [Fact]
  316. public void PointerEntered_Closes_Sibling_Submenu_After_Delay()
  317. {
  318. var timer = new TestTimer();
  319. var target = new DefaultMenuInteractionHandler(false, null, timer.RunOnce);
  320. var menu = Mock.Of<IMenu>();
  321. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  322. var item = CreateMockMenuItem(parent: parentItem.Object);
  323. var sibling = CreateMockMenuItem(hasSubMenu: true, isSubMenuOpen: true, parent: parentItem.Object);
  324. var e = new RoutedEventArgs(MenuItem.PointerEnteredItemEvent, item.Object);
  325. parentItem.SetupGet(x => x.SubItems).Returns(new[] { item.Object, sibling.Object });
  326. target.PointerEntered(item, e);
  327. sibling.Verify(x => x.Close(), Times.Never);
  328. timer.Pulse();
  329. sibling.Verify(x => x.Close());
  330. Assert.False(e.Handled);
  331. }
  332. [Fact]
  333. public void PointerExited_Deselects_Item()
  334. {
  335. var target = new DefaultMenuInteractionHandler(false);
  336. var menu = Mock.Of<IMenu>();
  337. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  338. var item = CreateMockMenuItem(parent: parentItem.Object);
  339. var e = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  340. parentItem.SetupGet(x => x.SelectedItem).Returns(item.Object);
  341. target.PointerExited(item, e);
  342. parentItem.VerifySet(x => x.SelectedItem = null);
  343. Assert.False(e.Handled);
  344. }
  345. [Fact]
  346. public void PointerExited_Doesnt_Deselect_Sibling()
  347. {
  348. var target = new DefaultMenuInteractionHandler(false);
  349. var menu = Mock.Of<IMenu>();
  350. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  351. var item = CreateMockMenuItem(parent: parentItem.Object);
  352. var sibling = CreateMockMenuItem(parent: parentItem.Object);
  353. var e = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  354. parentItem.SetupGet(x => x.SelectedItem).Returns(sibling.Object);
  355. target.PointerExited(item, e);
  356. parentItem.VerifySet(x => x.SelectedItem = null, Times.Never);
  357. Assert.False(e.Handled);
  358. }
  359. [Fact]
  360. public void PointerExited_Doesnt_Deselect_Item_If_Pointer_Over_Submenu()
  361. {
  362. var target = new DefaultMenuInteractionHandler(false);
  363. var menu = Mock.Of<IMenu>();
  364. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  365. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  366. var e = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  367. item.Setup(x => x.IsPointerOverSubMenu).Returns(true);
  368. target.PointerExited(item, e);
  369. parentItem.VerifySet(x => x.SelectedItem = null, Times.Never);
  370. Assert.False(e.Handled);
  371. }
  372. [Fact]
  373. public void PointerReleased_On_Item_With_No_SubMenu_Causes_Click()
  374. {
  375. var target = new DefaultMenuInteractionHandler(false);
  376. var menu = Mock.Of<IMenu>();
  377. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  378. var item = CreateMockMenuItem(parent: parentItem.Object);
  379. var e = CreateReleased(item.Object);
  380. target.PointerReleased(item, e);
  381. item.Verify(x => x.RaiseClick());
  382. Mock.Get(menu).Verify(x => x.Close());
  383. Assert.True(e.Handled);
  384. }
  385. [Fact]
  386. public void Selection_Is_Correct_When_Pointer_Temporarily_Exits_Item_To_Select_SubItem()
  387. {
  388. var timer = new TestTimer();
  389. var target = new DefaultMenuInteractionHandler(false, null, timer.RunOnce);
  390. var menu = Mock.Of<IMenu>();
  391. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  392. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  393. var childItem = CreateMockMenuItem(parent: item.Object);
  394. var enter = new RoutedEventArgs(MenuItem.PointerEnteredItemEvent, item.Object);
  395. var leave = new RoutedEventArgs(MenuItem.PointerExitedItemEvent, item.Object);
  396. // Pointer enters item; item is selected.
  397. target.PointerEntered(item, enter);
  398. Assert.True(timer.ActionIsQueued);
  399. parentItem.VerifySet(x => x.SelectedItem = item.Object);
  400. parentItem.Invocations.Clear();
  401. // SubMenu shown after a delay.
  402. timer.Pulse();
  403. item.Verify(x => x.Open());
  404. item.SetupGet(x => x.IsSubMenuOpen).Returns(true);
  405. item.Invocations.Clear();
  406. // Pointer briefly exits item, but submenu remains open.
  407. target.PointerExited(item, leave);
  408. item.Verify(x => x.Close(), Times.Never);
  409. item.Invocations.Clear();
  410. // Pointer enters child item; is selected.
  411. enter.Source = childItem.Object;
  412. target.PointerEntered(childItem, enter);
  413. item.VerifySet(x => x.SelectedItem = childItem.Object);
  414. parentItem.VerifySet(x => x.SelectedItem = item.Object);
  415. }
  416. [Fact]
  417. public void PointerPressed_On_Item_With_SubMenu_Causes_Opens_Submenu()
  418. {
  419. var target = new DefaultMenuInteractionHandler(false);
  420. var menu = Mock.Of<IMenu>();
  421. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, parent: menu);
  422. var item = CreateMockMenuItem(hasSubMenu: true, parent: parentItem.Object);
  423. var e = CreatePressed(item.Object);
  424. target.PointerPressed(item.Object, e);
  425. item.Verify(x => x.Open());
  426. item.Verify(x => x.MoveSelection(NavigationDirection.First, true), Times.Never);
  427. Assert.True(e.Handled);
  428. }
  429. [Fact]
  430. public void PointerPressed_On_Disabled_Item_Doesnt_Close_SubMenu()
  431. {
  432. var target = new DefaultMenuInteractionHandler(false);
  433. var menu = Mock.Of<IMenu>();
  434. var parentItem = CreateMockMenuItem(isTopLevel: true, hasSubMenu: true, isSubMenuOpen: true, parent: menu);
  435. var popup = new Popup();
  436. var e = CreatePressed(popup);
  437. ((ISetLogicalParent)popup).SetParent(parentItem.Object);
  438. target.PointerPressed(parentItem.Object, e);
  439. parentItem.Verify(x => x.Close(), Times.Never);
  440. Assert.True(e.Handled);
  441. }
  442. }
  443. public class ContextMenu
  444. {
  445. [Fact]
  446. public void Down_Selects_Selects_First_MenuItem_When_No_Selection()
  447. {
  448. var target = new DefaultMenuInteractionHandler(true);
  449. var contextMenu = Mock.Of<IMenu>(x => x.MoveSelection(NavigationDirection.Down, true) == true);
  450. var e = new KeyEventArgs { Key = Key.Down, Source = contextMenu };
  451. target.AttachCore(contextMenu);
  452. target.KeyDown(contextMenu, e);
  453. Mock.Get(contextMenu).Verify(x => x.MoveSelection(NavigationDirection.Down, true));
  454. Assert.True(e.Handled);
  455. }
  456. }
  457. private static Mock<IMainMenu> CreateMockMainMenu()
  458. {
  459. var mock = new Mock<Control>();
  460. mock.As<IMenuElement>();
  461. return mock.As<IMainMenu>();
  462. }
  463. private static Mock<IMenuItem> CreateMockMenuItem(
  464. bool isTopLevel = false,
  465. bool hasSubMenu = false,
  466. bool isSubMenuOpen = false,
  467. IMenuElement parent = null)
  468. {
  469. var mock = new Mock<Control>();
  470. var item = mock.As<IMenuItem>();
  471. item.Setup(x => x.IsTopLevel).Returns(isTopLevel);
  472. item.Setup(x => x.HasSubMenu).Returns(hasSubMenu);
  473. item.Setup(x => x.IsSubMenuOpen).Returns(isSubMenuOpen);
  474. item.Setup(x => x.Parent).Returns(parent);
  475. item.SetupProperty(x => x.SelectedItem);
  476. return item;
  477. }
  478. private class TestTimer
  479. {
  480. private Action _action;
  481. public bool ActionIsQueued => _action != null;
  482. public void Pulse()
  483. {
  484. _action();
  485. _action = null;
  486. }
  487. public void RunOnce(Action action, TimeSpan timeSpan)
  488. {
  489. if (_action != null)
  490. {
  491. throw new NotSupportedException("Action already set.");
  492. }
  493. _action = action;
  494. }
  495. }
  496. class FakePointer : IPointer
  497. {
  498. public int Id { get; } = Pointer.GetNextFreeId();
  499. public void Capture(IInputElement control)
  500. {
  501. Captured = control;
  502. }
  503. public IInputElement Captured { get; set; }
  504. public PointerType Type { get; }
  505. public bool IsPrimary { get; } = true;
  506. }
  507. }
  508. }