1
0

DefaultMenuInteractionHandlerTests.cs 26 KB

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