GetViewsUnderMouseTests.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. #nullable enable
  2. namespace Terminal.Gui.ViewMouseTests;
  3. [Trait ("Category", "Input")]
  4. public class GetViewsUnderMouseTests
  5. {
  6. [Theory]
  7. [InlineData (0, 0, 0, 0, 0, -1, -1, null)]
  8. [InlineData (0, 0, 0, 0, 0, 0, 0, typeof (Toplevel))]
  9. [InlineData (0, 0, 0, 0, 0, 1, 1, typeof (Toplevel))]
  10. [InlineData (0, 0, 0, 0, 0, 4, 4, typeof (Toplevel))]
  11. [InlineData (0, 0, 0, 0, 0, 9, 9, typeof (Toplevel))]
  12. [InlineData (0, 0, 0, 0, 0, 10, 10, null)]
  13. [InlineData (1, 1, 0, 0, 0, -1, -1, null)]
  14. [InlineData (1, 1, 0, 0, 0, 0, 0, null)]
  15. [InlineData (1, 1, 0, 0, 0, 1, 1, typeof (Toplevel))]
  16. [InlineData (1, 1, 0, 0, 0, 4, 4, typeof (Toplevel))]
  17. [InlineData (1, 1, 0, 0, 0, 9, 9, typeof (Toplevel))]
  18. [InlineData (1, 1, 0, 0, 0, 10, 10, typeof (Toplevel))]
  19. [InlineData (0, 0, 1, 0, 0, -1, -1, null)]
  20. [InlineData (0, 0, 1, 0, 0, 0, 0, typeof (Margin))]
  21. [InlineData (0, 0, 1, 0, 0, 1, 1, typeof (Toplevel))]
  22. [InlineData (0, 0, 1, 0, 0, 4, 4, typeof (Toplevel))]
  23. [InlineData (0, 0, 1, 0, 0, 9, 9, typeof (Margin))]
  24. [InlineData (0, 0, 1, 0, 0, 10, 10, null)]
  25. [InlineData (0, 0, 1, 1, 0, -1, -1, null)]
  26. [InlineData (0, 0, 1, 1, 0, 0, 0, typeof (Margin))]
  27. [InlineData (0, 0, 1, 1, 0, 1, 1, typeof (Border))]
  28. [InlineData (0, 0, 1, 1, 0, 4, 4, typeof (Toplevel))]
  29. [InlineData (0, 0, 1, 1, 0, 9, 9, typeof (Margin))]
  30. [InlineData (0, 0, 1, 1, 0, 10, 10, null)]
  31. [InlineData (0, 0, 1, 1, 1, -1, -1, null)]
  32. [InlineData (0, 0, 1, 1, 1, 0, 0, typeof (Margin))]
  33. [InlineData (0, 0, 1, 1, 1, 1, 1, typeof (Border))]
  34. [InlineData (0, 0, 1, 1, 1, 2, 2, typeof (Padding))]
  35. [InlineData (0, 0, 1, 1, 1, 4, 4, typeof (Toplevel))]
  36. [InlineData (0, 0, 1, 1, 1, 9, 9, typeof (Margin))]
  37. [InlineData (0, 0, 1, 1, 1, 10, 10, null)]
  38. [InlineData (1, 1, 1, 0, 0, -1, -1, null)]
  39. [InlineData (1, 1, 1, 0, 0, 0, 0, null)]
  40. [InlineData (1, 1, 1, 0, 0, 1, 1, typeof (Margin))]
  41. [InlineData (1, 1, 1, 0, 0, 4, 4, typeof (Toplevel))]
  42. [InlineData (1, 1, 1, 0, 0, 9, 9, typeof (Toplevel))]
  43. [InlineData (1, 1, 1, 0, 0, 10, 10, typeof (Margin))]
  44. [InlineData (1, 1, 1, 1, 0, -1, -1, null)]
  45. [InlineData (1, 1, 1, 1, 0, 0, 0, null)]
  46. [InlineData (1, 1, 1, 1, 0, 1, 1, typeof (Margin))]
  47. [InlineData (1, 1, 1, 1, 0, 4, 4, typeof (Toplevel))]
  48. [InlineData (1, 1, 1, 1, 0, 9, 9, typeof (Border))]
  49. [InlineData (1, 1, 1, 1, 0, 10, 10, typeof (Margin))]
  50. [InlineData (1, 1, 1, 1, 1, -1, -1, null)]
  51. [InlineData (1, 1, 1, 1, 1, 0, 0, null)]
  52. [InlineData (1, 1, 1, 1, 1, 1, 1, typeof (Margin))]
  53. [InlineData (1, 1, 1, 1, 1, 2, 2, typeof (Border))]
  54. [InlineData (1, 1, 1, 1, 1, 3, 3, typeof (Padding))]
  55. [InlineData (1, 1, 1, 1, 1, 4, 4, typeof (Toplevel))]
  56. [InlineData (1, 1, 1, 1, 1, 8, 8, typeof (Padding))]
  57. [InlineData (1, 1, 1, 1, 1, 9, 9, typeof (Border))]
  58. [InlineData (1, 1, 1, 1, 1, 10, 10, typeof (Margin))]
  59. public void GetViewsUnderMouse_Top_Adornments_Returns_Correct_View (
  60. int frameX,
  61. int frameY,
  62. int marginThickness,
  63. int borderThickness,
  64. int paddingThickness,
  65. int testX,
  66. int testY,
  67. Type? expectedViewType
  68. )
  69. {
  70. // Arrange
  71. Application.Top = new ()
  72. {
  73. Frame = new (frameX, frameY, 10, 10)
  74. };
  75. Application.Top.Margin.Thickness = new (marginThickness);
  76. Application.Top.Border.Thickness = new (borderThickness);
  77. Application.Top.Padding.Thickness = new (paddingThickness);
  78. var location = new Point (testX, testY);
  79. // Act
  80. List<View?> viewsUnderMouse = View.GetViewsUnderMouse (location);
  81. // Assert
  82. if (expectedViewType == null)
  83. {
  84. Assert.Empty (viewsUnderMouse);
  85. }
  86. else
  87. {
  88. Assert.Contains (viewsUnderMouse, v => v?.GetType () == expectedViewType);
  89. }
  90. Application.Top.Dispose ();
  91. Application.ResetState (true);
  92. }
  93. [Theory]
  94. [InlineData (0, 0)]
  95. [InlineData (1, 1)]
  96. [InlineData (2, 2)]
  97. public void GetViewsUnderMouse_Returns_Top_If_No_SubViews (int testX, int testY)
  98. {
  99. // Arrange
  100. Application.Top = new ()
  101. {
  102. Frame = new (0, 0, 10, 10)
  103. };
  104. var location = new Point (testX, testY);
  105. // Act
  106. List<View?> viewsUnderMouse = View.GetViewsUnderMouse (location);
  107. // Assert
  108. Assert.Contains (viewsUnderMouse, v => v == Application.Top);
  109. Application.Top.Dispose ();
  110. Application.ResetState (true);
  111. }
  112. [Theory]
  113. [InlineData (0, 0)]
  114. [InlineData (2, 1)]
  115. [InlineData (20, 20)]
  116. public void GetViewsUnderMouse_Returns_Null_If_No_SubViews_Coords_Outside (int testX, int testY)
  117. {
  118. // Arrange
  119. var view = new View
  120. {
  121. Frame = new (0, 0, 10, 10)
  122. };
  123. var location = new Point (testX, testY);
  124. // Act
  125. List<View?> viewsUnderMouse = View.GetViewsUnderMouse (location);
  126. // Assert
  127. Assert.Empty (viewsUnderMouse);
  128. }
  129. [Theory]
  130. [InlineData (0, 0)]
  131. [InlineData (2, 1)]
  132. [InlineData (20, 20)]
  133. public void GetViewsUnderMouse_Returns_Null_If_Start_Not_Visible (int testX, int testY)
  134. {
  135. // Arrange
  136. var view = new View
  137. {
  138. Frame = new (0, 0, 10, 10),
  139. Visible = false
  140. };
  141. var location = new Point (testX, testY);
  142. // Act
  143. List<View?> viewsUnderMouse = View.GetViewsUnderMouse (location);
  144. // Assert
  145. Assert.Empty (viewsUnderMouse);
  146. }
  147. [Theory]
  148. [InlineData (0, 0, false)]
  149. [InlineData (1, 1, true)]
  150. [InlineData (9, 9, false)]
  151. [InlineData (10, 10, false)]
  152. [InlineData (6, 7, true)]
  153. [InlineData (1, 2, true)]
  154. [InlineData (5, 6, true)]
  155. public void GetViewsUnderMouse_Returns_Correct_If_SubViews (int testX, int testY, bool expected)
  156. {
  157. // Arrange
  158. Application.Top = new ()
  159. {
  160. Frame = new (0, 0, 10, 10)
  161. };
  162. var subView = new View
  163. {
  164. Frame = new (1, 1, 8, 8)
  165. };
  166. Application.Top.Add (subView);
  167. var location = new Point (testX, testY);
  168. // Act
  169. List<View?> viewsUnderMouse = View.GetViewsUnderMouse (location);
  170. // Assert
  171. if (expected)
  172. {
  173. Assert.Contains (viewsUnderMouse, v => v == subView);
  174. }
  175. else
  176. {
  177. Assert.DoesNotContain (viewsUnderMouse, v => v == subView);
  178. }
  179. Application.Top.Dispose ();
  180. Application.ResetState (true);
  181. }
  182. [Theory]
  183. [InlineData (0, 0, 0, 0, 0, -1, -1, null)]
  184. [InlineData (0, 0, 0, 0, 0, 0, 0, typeof (View))]
  185. [InlineData (0, 0, 0, 0, 0, 1, 1, typeof (View))]
  186. [InlineData (0, 0, 0, 0, 0, 4, 4, typeof (View))]
  187. [InlineData (0, 0, 0, 0, 0, 9, 9, typeof (View))]
  188. [InlineData (0, 0, 0, 0, 0, 10, 10, null)]
  189. [InlineData (1, 1, 0, 0, 0, -1, -1, null)]
  190. [InlineData (1, 1, 0, 0, 0, 0, 0, null)]
  191. [InlineData (1, 1, 0, 0, 0, 1, 1, typeof (View))]
  192. [InlineData (1, 1, 0, 0, 0, 4, 4, typeof (View))]
  193. [InlineData (1, 1, 0, 0, 0, 9, 9, typeof (View))]
  194. [InlineData (1, 1, 0, 0, 0, 10, 10, typeof (View))]
  195. [InlineData (0, 0, 1, 0, 0, -1, -1, null)]
  196. [InlineData (0, 0, 1, 0, 0, 0, 0, typeof (Margin))]
  197. [InlineData (0, 0, 1, 0, 0, 1, 1, typeof (View))]
  198. [InlineData (0, 0, 1, 0, 0, 4, 4, typeof (View))]
  199. [InlineData (0, 0, 1, 0, 0, 9, 9, typeof (Margin))]
  200. [InlineData (0, 0, 1, 0, 0, 10, 10, null)]
  201. [InlineData (0, 0, 1, 1, 0, -1, -1, null)]
  202. [InlineData (0, 0, 1, 1, 0, 0, 0, typeof (Margin))]
  203. [InlineData (0, 0, 1, 1, 0, 1, 1, typeof (Border))]
  204. [InlineData (0, 0, 1, 1, 0, 4, 4, typeof (View))]
  205. [InlineData (0, 0, 1, 1, 0, 9, 9, typeof (Margin))]
  206. [InlineData (0, 0, 1, 1, 0, 10, 10, null)]
  207. [InlineData (0, 0, 1, 1, 1, -1, -1, null)]
  208. [InlineData (0, 0, 1, 1, 1, 0, 0, typeof (Margin))]
  209. [InlineData (0, 0, 1, 1, 1, 1, 1, typeof (Border))]
  210. [InlineData (0, 0, 1, 1, 1, 2, 2, typeof (Padding))]
  211. [InlineData (0, 0, 1, 1, 1, 4, 4, typeof (View))]
  212. [InlineData (0, 0, 1, 1, 1, 9, 9, typeof (Margin))]
  213. [InlineData (0, 0, 1, 1, 1, 10, 10, null)]
  214. [InlineData (1, 1, 1, 0, 0, -1, -1, null)]
  215. [InlineData (1, 1, 1, 0, 0, 0, 0, null)]
  216. [InlineData (1, 1, 1, 0, 0, 1, 1, typeof (Margin))]
  217. [InlineData (1, 1, 1, 0, 0, 4, 4, typeof (View))]
  218. [InlineData (1, 1, 1, 0, 0, 9, 9, typeof (View))]
  219. [InlineData (1, 1, 1, 0, 0, 10, 10, typeof (Margin))]
  220. [InlineData (1, 1, 1, 1, 0, -1, -1, null)]
  221. [InlineData (1, 1, 1, 1, 0, 0, 0, null)]
  222. [InlineData (1, 1, 1, 1, 0, 1, 1, typeof (Margin))]
  223. [InlineData (1, 1, 1, 1, 0, 4, 4, typeof (View))]
  224. [InlineData (1, 1, 1, 1, 0, 9, 9, typeof (Border))]
  225. [InlineData (1, 1, 1, 1, 0, 10, 10, typeof (Margin))]
  226. [InlineData (1, 1, 1, 1, 1, -1, -1, null)]
  227. [InlineData (1, 1, 1, 1, 1, 0, 0, null)]
  228. [InlineData (1, 1, 1, 1, 1, 1, 1, typeof (Margin))]
  229. [InlineData (1, 1, 1, 1, 1, 2, 2, typeof (Border))]
  230. [InlineData (1, 1, 1, 1, 1, 3, 3, typeof (Padding))]
  231. [InlineData (1, 1, 1, 1, 1, 4, 4, typeof (View))]
  232. [InlineData (1, 1, 1, 1, 1, 8, 8, typeof (Padding))]
  233. [InlineData (1, 1, 1, 1, 1, 9, 9, typeof (Border))]
  234. [InlineData (1, 1, 1, 1, 1, 10, 10, typeof (Margin))]
  235. public void Contains (
  236. int frameX,
  237. int frameY,
  238. int marginThickness,
  239. int borderThickness,
  240. int paddingThickness,
  241. int testX,
  242. int testY,
  243. Type? expectedAdornmentType
  244. )
  245. {
  246. var view = new View
  247. {
  248. X = frameX, Y = frameY,
  249. Width = 10, Height = 10
  250. };
  251. view.Margin.Thickness = new (marginThickness);
  252. view.Border.Thickness = new (borderThickness);
  253. view.Padding.Thickness = new (paddingThickness);
  254. Type? containedType = null;
  255. if (view.Contains (new (testX, testY)))
  256. {
  257. containedType = view.GetType ();
  258. }
  259. if (view.Margin.Contains (new (testX, testY)))
  260. {
  261. containedType = view.Margin.GetType ();
  262. }
  263. if (view.Border.Contains (new (testX, testY)))
  264. {
  265. containedType = view.Border.GetType ();
  266. }
  267. if (view.Padding.Contains (new (testX, testY)))
  268. {
  269. containedType = view.Padding.GetType ();
  270. }
  271. Assert.Equal (expectedAdornmentType, containedType);
  272. }
  273. // Test that GetViewsUnderMouse returns the correct view if the start view has no subviews
  274. [Theory]
  275. [InlineData (0, 0)]
  276. [InlineData (1, 1)]
  277. [InlineData (2, 2)]
  278. public void Returns_Start_If_No_SubViews (int testX, int testY)
  279. {
  280. Application.Top = new ()
  281. {
  282. Width = 10, Height = 10
  283. };
  284. Assert.Same (Application.Top, View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ());
  285. Application.Top.Dispose ();
  286. Application.ResetState (true);
  287. }
  288. // Test that GetViewsUnderMouse returns null if the start view has no subviews and coords are outside the view
  289. [Theory]
  290. [InlineData (0, 0)]
  291. [InlineData (2, 1)]
  292. [InlineData (20, 20)]
  293. public void Returns_Null_If_No_SubViews_Coords_Outside (int testX, int testY)
  294. {
  295. Application.Top = new ()
  296. {
  297. X = 1, Y = 2,
  298. Width = 10, Height = 10
  299. };
  300. Assert.Null (View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ());
  301. Application.Top.Dispose ();
  302. Application.ResetState (true);
  303. }
  304. [Theory]
  305. [InlineData (0, 0)]
  306. [InlineData (2, 1)]
  307. [InlineData (20, 20)]
  308. public void Returns_Null_If_Start_Not_Visible (int testX, int testY)
  309. {
  310. Application.Top = new ()
  311. {
  312. X = 1, Y = 2,
  313. Width = 10, Height = 10,
  314. Visible = false
  315. };
  316. Assert.Null (View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ());
  317. Application.Top.Dispose ();
  318. Application.ResetState (true);
  319. }
  320. // Test that GetViewsUnderMouse returns the correct view if the start view has subviews
  321. [Theory]
  322. [InlineData (0, 0, false)]
  323. [InlineData (1, 1, false)]
  324. [InlineData (9, 9, false)]
  325. [InlineData (10, 10, false)]
  326. [InlineData (6, 7, false)]
  327. [InlineData (1, 2, true)]
  328. [InlineData (5, 6, true)]
  329. public void Returns_Correct_If_SubViews (int testX, int testY, bool expectedSubViewFound)
  330. {
  331. Application.Top = new ()
  332. {
  333. Width = 10, Height = 10
  334. };
  335. var subview = new View
  336. {
  337. X = 1, Y = 2,
  338. Width = 5, Height = 5
  339. };
  340. Application.Top.Add (subview);
  341. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  342. Assert.Equal (expectedSubViewFound, found == subview);
  343. Application.Top.Dispose ();
  344. Application.ResetState (true);
  345. }
  346. [Theory]
  347. [InlineData (0, 0, false)]
  348. [InlineData (1, 1, false)]
  349. [InlineData (9, 9, false)]
  350. [InlineData (10, 10, false)]
  351. [InlineData (6, 7, false)]
  352. [InlineData (1, 2, false)]
  353. [InlineData (5, 6, false)]
  354. public void Returns_Null_If_SubView_NotVisible (int testX, int testY, bool expectedSubViewFound)
  355. {
  356. Application.Top = new ()
  357. {
  358. Width = 10, Height = 10
  359. };
  360. var subview = new View
  361. {
  362. X = 1, Y = 2,
  363. Width = 5, Height = 5,
  364. Visible = false
  365. };
  366. Application.Top.Add (subview);
  367. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  368. Assert.Equal (expectedSubViewFound, found == subview);
  369. Application.Top.Dispose ();
  370. Application.ResetState (true);
  371. }
  372. [Theory]
  373. [InlineData (0, 0, false)]
  374. [InlineData (1, 1, false)]
  375. [InlineData (9, 9, false)]
  376. [InlineData (10, 10, false)]
  377. [InlineData (6, 7, false)]
  378. [InlineData (1, 2, false)]
  379. [InlineData (5, 6, false)]
  380. public void Returns_Null_If_Not_Visible_And_SubView_Visible (int testX, int testY, bool expectedSubViewFound)
  381. {
  382. Application.Top = new ()
  383. {
  384. Width = 10, Height = 10,
  385. Visible = false
  386. };
  387. var subview = new View
  388. {
  389. X = 1, Y = 2,
  390. Width = 5, Height = 5
  391. };
  392. Application.Top.Add (subview);
  393. subview.Visible = true;
  394. Assert.True (subview.Visible);
  395. Assert.False (Application.Top.Visible);
  396. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  397. Assert.Equal (expectedSubViewFound, found == subview);
  398. Application.Top.Dispose ();
  399. Application.ResetState (true);
  400. }
  401. // Test that GetViewsUnderMouse works if the start view has positive Adornments
  402. [Theory]
  403. [InlineData (0, 0, false)]
  404. [InlineData (1, 1, false)]
  405. [InlineData (9, 9, false)]
  406. [InlineData (10, 10, false)]
  407. [InlineData (7, 8, false)]
  408. [InlineData (1, 2, false)]
  409. [InlineData (2, 3, true)]
  410. [InlineData (5, 6, true)]
  411. [InlineData (6, 7, true)]
  412. public void Returns_Correct_If_Start_Has_Adornments (int testX, int testY, bool expectedSubViewFound)
  413. {
  414. Application.Top = new ()
  415. {
  416. Width = 10, Height = 10
  417. };
  418. Application.Top.Margin.Thickness = new (1);
  419. var subview = new View
  420. {
  421. X = 1, Y = 2,
  422. Width = 5, Height = 5
  423. };
  424. Application.Top.Add (subview);
  425. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  426. Assert.Equal (expectedSubViewFound, found == subview);
  427. Application.Top.Dispose ();
  428. Application.ResetState (true);
  429. }
  430. // Test that GetViewsUnderMouse works if the start view has offset Viewport location
  431. [Theory]
  432. [InlineData (1, 0, 0, true)]
  433. [InlineData (1, 1, 1, true)]
  434. [InlineData (1, 2, 2, false)]
  435. [InlineData (-1, 3, 3, true)]
  436. [InlineData (-1, 2, 2, true)]
  437. [InlineData (-1, 1, 1, false)]
  438. [InlineData (-1, 0, 0, false)]
  439. public void Returns_Correct_If_Start_Has_Offset_Viewport (int offset, int testX, int testY, bool expectedSubViewFound)
  440. {
  441. Application.Top = new ()
  442. {
  443. Width = 10, Height = 10,
  444. ViewportSettings = ViewportSettings.AllowNegativeLocation
  445. };
  446. Application.Top.Viewport = new (offset, offset, 10, 10);
  447. var subview = new View
  448. {
  449. X = 1, Y = 1,
  450. Width = 2, Height = 2
  451. };
  452. Application.Top.Add (subview);
  453. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  454. Assert.Equal (expectedSubViewFound, found == subview);
  455. Application.Top.Dispose ();
  456. Application.ResetState (true);
  457. }
  458. [Theory]
  459. [InlineData (9, 9, true)]
  460. [InlineData (0, 0, false)]
  461. [InlineData (1, 1, false)]
  462. [InlineData (10, 10, false)]
  463. [InlineData (7, 8, false)]
  464. [InlineData (1, 2, false)]
  465. [InlineData (2, 3, false)]
  466. [InlineData (5, 6, false)]
  467. [InlineData (6, 7, false)]
  468. public void Returns_Correct_If_Start_Has_Adornment_WithSubview (int testX, int testY, bool expectedSubViewFound)
  469. {
  470. Application.Top = new ()
  471. {
  472. Width = 10, Height = 10
  473. };
  474. Application.Top.Padding.Thickness = new (1);
  475. var subview = new View
  476. {
  477. X = Pos.AnchorEnd (1), Y = Pos.AnchorEnd (1),
  478. Width = 1, Height = 1
  479. };
  480. Application.Top.Padding.Add (subview);
  481. Application.Top.BeginInit ();
  482. Application.Top.EndInit ();
  483. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  484. Assert.Equal (expectedSubViewFound, found == subview);
  485. Application.Top.Dispose ();
  486. Application.ResetState (true);
  487. }
  488. [Theory]
  489. [InlineData (0, 0, typeof (Margin))]
  490. [InlineData (9, 9, typeof (Margin))]
  491. [InlineData (1, 1, typeof (Border))]
  492. [InlineData (8, 8, typeof (Border))]
  493. [InlineData (2, 2, typeof (Padding))]
  494. [InlineData (7, 7, typeof (Padding))]
  495. [InlineData (5, 5, typeof (Toplevel))]
  496. public void Returns_Adornment_If_Start_Has_Adornments (int testX, int testY, Type expectedAdornmentType)
  497. {
  498. Application.Top = new ()
  499. {
  500. Width = 10, Height = 10
  501. };
  502. Application.Top.Margin.Thickness = new (1);
  503. Application.Top.Border.Thickness = new (1);
  504. Application.Top.Padding.Thickness = new (1);
  505. var subview = new View
  506. {
  507. X = 1, Y = 1,
  508. Width = 1, Height = 1
  509. };
  510. Application.Top.Add (subview);
  511. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  512. Assert.Equal (expectedAdornmentType, found!.GetType ());
  513. Application.Top.Dispose ();
  514. Application.ResetState (true);
  515. }
  516. // Test that GetViewsUnderMouse works if the subview has positive Adornments
  517. [Theory]
  518. [InlineData (0, 0, false)]
  519. [InlineData (1, 1, false)]
  520. [InlineData (9, 9, false)]
  521. [InlineData (10, 10, false)]
  522. [InlineData (7, 8, false)]
  523. [InlineData (6, 7, false)]
  524. [InlineData (1, 2, false)]
  525. [InlineData (5, 6, false)]
  526. [InlineData (2, 3, true)]
  527. public void Returns_Correct_If_SubView_Has_Adornments (int testX, int testY, bool expectedSubViewFound)
  528. {
  529. Application.Top = new ()
  530. {
  531. Width = 10, Height = 10
  532. };
  533. var subview = new View
  534. {
  535. X = 1, Y = 2,
  536. Width = 5, Height = 5
  537. };
  538. subview.Margin.Thickness = new (1);
  539. Application.Top.Add (subview);
  540. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  541. Assert.Equal (expectedSubViewFound, found == subview);
  542. Application.Top.Dispose ();
  543. Application.ResetState (true);
  544. }
  545. [Theory]
  546. [InlineData (0, 0, false)]
  547. [InlineData (1, 1, false)]
  548. [InlineData (9, 9, false)]
  549. [InlineData (10, 10, false)]
  550. [InlineData (7, 8, false)]
  551. [InlineData (6, 7, false)]
  552. [InlineData (1, 2, false)]
  553. [InlineData (5, 6, false)]
  554. [InlineData (6, 5, false)]
  555. [InlineData (5, 5, true)]
  556. public void Returns_Correct_If_SubView_Has_Adornment_WithSubview (int testX, int testY, bool expectedSubViewFound)
  557. {
  558. Application.Top = new ()
  559. {
  560. Width = 10, Height = 10
  561. };
  562. // A subview with + Padding
  563. var subview = new View
  564. {
  565. X = 1, Y = 1,
  566. Width = 5, Height = 5
  567. };
  568. subview.Padding.Thickness = new (1);
  569. // This subview will be at the bottom-right-corner of subview
  570. // So screen-relative location will be X + Width - 1 = 5
  571. var paddingSubview = new View
  572. {
  573. X = Pos.AnchorEnd (1),
  574. Y = Pos.AnchorEnd (1),
  575. Width = 1,
  576. Height = 1
  577. };
  578. subview.Padding.Add (paddingSubview);
  579. Application.Top.Add (subview);
  580. Application.Top.BeginInit ();
  581. Application.Top.EndInit ();
  582. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  583. Assert.Equal (expectedSubViewFound, found == paddingSubview);
  584. Application.Top.Dispose ();
  585. Application.ResetState (true);
  586. }
  587. [Theory]
  588. [InlineData (0, 0, false)]
  589. [InlineData (1, 1, false)]
  590. [InlineData (9, 9, false)]
  591. [InlineData (10, 10, false)]
  592. [InlineData (7, 8, false)]
  593. [InlineData (6, 7, false)]
  594. [InlineData (1, 2, false)]
  595. [InlineData (5, 6, false)]
  596. [InlineData (6, 5, false)]
  597. [InlineData (5, 5, true)]
  598. public void Returns_Correct_If_SubView_Is_Scrolled_And_Has_Adornment_WithSubview (int testX, int testY, bool expectedSubViewFound)
  599. {
  600. Application.Top = new ()
  601. {
  602. Width = 10, Height = 10
  603. };
  604. // A subview with + Padding
  605. var subview = new View
  606. {
  607. X = 1, Y = 1,
  608. Width = 5, Height = 5
  609. };
  610. subview.Padding.Thickness = new (1);
  611. // Scroll the subview
  612. subview.SetContentSize (new (10, 10));
  613. subview.Viewport = subview.Viewport with { Location = new (1, 1) };
  614. // This subview will be at the bottom-right-corner of subview
  615. // So screen-relative location will be X + Width - 1 = 5
  616. var paddingSubview = new View
  617. {
  618. X = Pos.AnchorEnd (1),
  619. Y = Pos.AnchorEnd (1),
  620. Width = 1,
  621. Height = 1
  622. };
  623. subview.Padding.Add (paddingSubview);
  624. Application.Top.Add (subview);
  625. Application.Top.BeginInit ();
  626. Application.Top.EndInit ();
  627. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  628. Assert.Equal (expectedSubViewFound, found == paddingSubview);
  629. Application.Top.Dispose ();
  630. Application.ResetState (true);
  631. }
  632. // Test that GetViewsUnderMouse works with nested subviews
  633. [Theory]
  634. [InlineData (0, 0, -1)]
  635. [InlineData (9, 9, -1)]
  636. [InlineData (10, 10, -1)]
  637. [InlineData (1, 1, 0)]
  638. [InlineData (1, 2, 0)]
  639. [InlineData (2, 2, 1)]
  640. [InlineData (3, 3, 2)]
  641. [InlineData (5, 5, 2)]
  642. public void Returns_Correct_With_NestedSubViews (int testX, int testY, int expectedSubViewFound)
  643. {
  644. Application.Top = new ()
  645. {
  646. Width = 10, Height = 10
  647. };
  648. var numSubViews = 3;
  649. List<View> subviews = new ();
  650. for (var i = 0; i < numSubViews; i++)
  651. {
  652. var subview = new View
  653. {
  654. X = 1, Y = 1,
  655. Width = 5, Height = 5
  656. };
  657. subviews.Add (subview);
  658. if (i > 0)
  659. {
  660. subviews [i - 1].Add (subview);
  661. }
  662. }
  663. Application.Top.Add (subviews [0]);
  664. View? found = View.GetViewsUnderMouse (new (testX, testY)).LastOrDefault ();
  665. Assert.Equal (expectedSubViewFound, subviews.IndexOf (found!));
  666. Application.Top.Dispose ();
  667. Application.ResetState (true);
  668. }
  669. [Theory]
  670. [InlineData (0, 0, new [] { "top" })]
  671. [InlineData (9, 9, new [] { "top" })]
  672. [InlineData (10, 10, new string [] { })]
  673. [InlineData (1, 1, new [] { "top", "view" })]
  674. [InlineData (1, 2, new [] { "top", "view" })]
  675. [InlineData (2, 1, new [] { "top", "view" })]
  676. [InlineData (2, 2, new [] { "top", "view", "subView" })]
  677. [InlineData (3, 3, new [] { "top" })] // clipped
  678. [InlineData (2, 3, new [] { "top" })] // clipped
  679. public void GetViewsUnderMouse_Tiled_Subviews (int mouseX, int mouseY, string [] viewIdStrings)
  680. {
  681. // Arrange
  682. Application.Top = new ()
  683. {
  684. Frame = new (0, 0, 10, 10),
  685. Id = "top"
  686. };
  687. var view = new View
  688. {
  689. Id = "view",
  690. X = 1,
  691. Y = 1,
  692. Width = 2,
  693. Height = 2,
  694. Arrangement = ViewArrangement.Overlapped
  695. }; // at 1,1 to 3,2 (screen)
  696. var subView = new View
  697. {
  698. Id = "subView",
  699. X = 1,
  700. Y = 1,
  701. Width = 2,
  702. Height = 2,
  703. Arrangement = ViewArrangement.Overlapped
  704. }; // at 2,2 to 4,3 (screen)
  705. view.Add (subView);
  706. Application.Top.Add (view);
  707. List<View?> found = View.GetViewsUnderMouse (new (mouseX, mouseY));
  708. string [] foundIds = found.Select (v => v!.Id).ToArray ();
  709. Assert.Equal (viewIdStrings, foundIds);
  710. Application.Top.Dispose ();
  711. Application.ResetState (true);
  712. }
  713. }