CompositorHitTestingTests.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using System;
  2. using System.Linq;
  3. using Avalonia.Controls;
  4. using Avalonia.Controls.Presenters;
  5. using Avalonia.Controls.Shapes;
  6. using Avalonia.Layout;
  7. using Avalonia.Media;
  8. using Avalonia.Platform;
  9. using Avalonia.Rendering;
  10. using Avalonia.UnitTests;
  11. using Avalonia.VisualTree;
  12. using Moq;
  13. using Xunit;
  14. namespace Avalonia.Base.UnitTests.Rendering;
  15. public class CompositorHitTestingTests : CompositorTestsBase
  16. {
  17. [Fact]
  18. public void HitTest_Should_Find_Controls_At_Point()
  19. {
  20. using (var s = new CompositorServices(new Size(200, 200)))
  21. {
  22. var border = new Border
  23. {
  24. Width = 100,
  25. Height = 100,
  26. Background = Brushes.Red,
  27. HorizontalAlignment = HorizontalAlignment.Center,
  28. VerticalAlignment = VerticalAlignment.Center
  29. };
  30. s.TopLevel.Content = border;
  31. s.AssertHitTest(new Point(100, 100), null, border);
  32. }
  33. }
  34. [Fact]
  35. public void HitTest_Should_Not_Find_Empty_Controls_At_Point()
  36. {
  37. using (var s = new CompositorServices(new Size(200, 200)))
  38. {
  39. var border = new Border
  40. {
  41. Width = 100,
  42. Height = 100,
  43. HorizontalAlignment = HorizontalAlignment.Center,
  44. VerticalAlignment = VerticalAlignment.Center
  45. };
  46. s.TopLevel.Content = border;
  47. s.AssertHitTest(new Point(100, 100), null);
  48. }
  49. }
  50. [Fact]
  51. public void HitTest_Should_Not_Find_Invisible_Controls_At_Point()
  52. {
  53. using (var s = new CompositorServices(new Size(200, 200)))
  54. {
  55. Border visible, border;
  56. s.TopLevel.Content = border = new Border
  57. {
  58. Width = 100,
  59. Height = 100,
  60. Background = Brushes.Red,
  61. HorizontalAlignment = HorizontalAlignment.Center,
  62. VerticalAlignment = VerticalAlignment.Center,
  63. IsVisible = false,
  64. Child = visible = new Border
  65. {
  66. Background = Brushes.Red,
  67. HorizontalAlignment = HorizontalAlignment.Stretch,
  68. VerticalAlignment = VerticalAlignment.Stretch,
  69. }
  70. };
  71. s.AssertHitTest(new Point(100, 100), null);
  72. }
  73. }
  74. [Fact]
  75. public void HitTest_Should_Not_Find_Control_Outside_Point()
  76. {
  77. using (var s = new CompositorServices(new Size(200, 200)))
  78. {
  79. var border = new Border
  80. {
  81. Width = 100,
  82. Height = 100,
  83. Background = Brushes.Red,
  84. HorizontalAlignment = HorizontalAlignment.Center,
  85. VerticalAlignment = VerticalAlignment.Center
  86. };
  87. s.TopLevel.Content = border;
  88. s.AssertHitTest(new Point(10, 10), null);
  89. }
  90. }
  91. [Fact]
  92. public void HitTest_Should_Return_Top_Controls_First()
  93. {
  94. using (var s = new CompositorServices(new Size(200, 200)))
  95. {
  96. Panel container = new Panel
  97. {
  98. Width = 200,
  99. Height = 200,
  100. Children =
  101. {
  102. new Border
  103. {
  104. Width = 100,
  105. Height = 100,
  106. Background = Brushes.Red,
  107. HorizontalAlignment = HorizontalAlignment.Center,
  108. VerticalAlignment = VerticalAlignment.Center
  109. },
  110. new Border
  111. {
  112. Width = 50,
  113. Height = 50,
  114. Background = Brushes.Blue,
  115. HorizontalAlignment = HorizontalAlignment.Center,
  116. VerticalAlignment = VerticalAlignment.Center
  117. }
  118. }
  119. };
  120. s.TopLevel.Content = container;
  121. s.AssertHitTest(new Point(100, 100), null, container.Children[1], container.Children[0]);
  122. }
  123. }
  124. [Fact]
  125. public void HitTest_Should_Return_Top_Controls_First_With_ZIndex()
  126. {
  127. using (var s = new CompositorServices(new Size(200, 200)))
  128. {
  129. Panel container = new Panel
  130. {
  131. Width = 200,
  132. Height = 200,
  133. Children =
  134. {
  135. new Border
  136. {
  137. Width = 100,
  138. Height = 100,
  139. ZIndex = 1,
  140. Background = Brushes.Red,
  141. HorizontalAlignment = HorizontalAlignment.Center,
  142. VerticalAlignment = VerticalAlignment.Center
  143. },
  144. new Border
  145. {
  146. Width = 50,
  147. Height = 50,
  148. Background = Brushes.Red,
  149. HorizontalAlignment = HorizontalAlignment.Center,
  150. VerticalAlignment = VerticalAlignment.Center
  151. },
  152. new Border
  153. {
  154. Width = 75,
  155. Height = 75,
  156. ZIndex = 2,
  157. Background = Brushes.Red,
  158. HorizontalAlignment = HorizontalAlignment.Center,
  159. VerticalAlignment = VerticalAlignment.Center
  160. }
  161. }
  162. };
  163. s.TopLevel.Content = container;
  164. s.AssertHitTest(new Point(100, 100), null, new[] { container.Children[2], container.Children[0], container.Children[1] });
  165. }
  166. }
  167. [Fact]
  168. public void HitTest_Should_Find_Control_Translated_Outside_Parent_Bounds()
  169. {
  170. using (var s = new CompositorServices(new Size(200, 200)))
  171. {
  172. Border target;
  173. Panel container = new Panel
  174. {
  175. Width = 200,
  176. Height = 200,
  177. Background = Brushes.Red,
  178. ClipToBounds = false,
  179. Children =
  180. {
  181. new Border
  182. {
  183. Width = 100,
  184. Height = 100,
  185. ZIndex = 1,
  186. Background = Brushes.Red,
  187. HorizontalAlignment = HorizontalAlignment.Left,
  188. VerticalAlignment = VerticalAlignment.Top,
  189. Child = target = new Border
  190. {
  191. Width = 50,
  192. Height = 50,
  193. Background = Brushes.Red,
  194. HorizontalAlignment = HorizontalAlignment.Left,
  195. VerticalAlignment = VerticalAlignment.Top,
  196. RenderTransform = new TranslateTransform(110, 110),
  197. }
  198. },
  199. }
  200. };
  201. s.TopLevel.Content = container;
  202. s.AssertHitTest(new Point(120, 120), null, target, container);
  203. }
  204. }
  205. [Fact]
  206. public void HitTest_Should_Not_Find_Control_Outside_Parent_Bounds_When_Clipped()
  207. {
  208. using (var s = new CompositorServices(new Size(200, 200)))
  209. {
  210. Border target;
  211. Panel container = new Panel
  212. {
  213. Width = 100,
  214. Height = 200,
  215. Background = Brushes.Red,
  216. Children =
  217. {
  218. new Panel()
  219. {
  220. Width = 100,
  221. Height = 100,
  222. Background = Brushes.Red,
  223. Margin = new Thickness(0, 100, 0, 0),
  224. ClipToBounds = true,
  225. Children =
  226. {
  227. (target = new Border()
  228. {
  229. Width = 100,
  230. Height = 100,
  231. Background = Brushes.Red,
  232. Margin = new Thickness(0, -100, 0, 0)
  233. })
  234. }
  235. }
  236. }
  237. };
  238. s.TopLevel.Content = container;
  239. s.AssertHitTest(new Point(50, 50), null, container);
  240. }
  241. }
  242. [Fact]
  243. public void HitTest_Should_Not_Find_Control_Outside_Scroll_Viewport()
  244. {
  245. using (var s = new CompositorServices(new Size(100, 200)))
  246. {
  247. Border target;
  248. Border item1;
  249. Border item2;
  250. ScrollContentPresenter scroll;
  251. Panel container = new Panel
  252. {
  253. Width = 100,
  254. Height = 200,
  255. Background = Brushes.Red,
  256. Children =
  257. {
  258. (target = new Border()
  259. {
  260. Name = "b1",
  261. Width = 100,
  262. Height = 100,
  263. Background = Brushes.Red,
  264. }),
  265. new Border()
  266. {
  267. Name = "b2",
  268. Width = 100,
  269. Height = 100,
  270. Background = Brushes.Red,
  271. Margin = new Thickness(0, 100, 0, 0),
  272. Child = scroll = new ScrollContentPresenter()
  273. {
  274. CanHorizontallyScroll = true,
  275. CanVerticallyScroll = true,
  276. Content = new StackPanel()
  277. {
  278. Children =
  279. {
  280. (item1 = new Border()
  281. {
  282. Name = "b3",
  283. Width = 100,
  284. Height = 100,
  285. Background = Brushes.Red,
  286. }),
  287. (item2 = new Border()
  288. {
  289. Name = "b4",
  290. Width = 100,
  291. Height = 100,
  292. Background = Brushes.Red,
  293. }),
  294. }
  295. }
  296. }
  297. }
  298. }
  299. };
  300. s.TopLevel.Content = container;
  301. scroll.UpdateChild();
  302. s.AssertHitTestFirst(new Point(50, 150), null, item1);
  303. s.AssertHitTestFirst(new Point(50,50), null, target);
  304. scroll.Offset = new Vector(0, 100);
  305. s.AssertHitTestFirst(new Point(50, 150), null, item2);
  306. s.AssertHitTestFirst(new Point(50,50), null, target);
  307. }
  308. }
  309. [Fact]
  310. public void HitTest_Should_Not_Find_Path_When_Outside_Fill()
  311. {
  312. using (var s = new CompositorServices(new Size(200, 200)))
  313. {
  314. Path path = new Path
  315. {
  316. Width = 200,
  317. Height = 200,
  318. Fill = Brushes.Red,
  319. Data = StreamGeometry.Parse("M100,0 L0,100 100,100")
  320. };
  321. s.TopLevel.Content = path;
  322. s.AssertHitTest(new Point(100, 100), null, path);
  323. s.AssertHitTest(new Point(10, 10), null);
  324. }
  325. }
  326. [Fact]
  327. public void HitTest_Should_Respect_Geometry_Clip()
  328. {
  329. using (var s = new CompositorServices(new Size(400, 400)))
  330. {
  331. Canvas canvas;
  332. Border border = new Border
  333. {
  334. Background = Brushes.Red,
  335. Clip = StreamGeometry.Parse("M100,0 L0,100 100,100"),
  336. Width = 200,
  337. Height = 200,
  338. Child = canvas = new Canvas
  339. {
  340. Background = Brushes.Yellow,
  341. Margin = new Thickness(10),
  342. }
  343. };
  344. s.TopLevel.Content = border;
  345. s.RunJobs();
  346. Assert.Equal(new Rect(100, 100, 200, 200), border.Bounds);
  347. s.AssertHitTest(new Point(200,200), null, canvas, border);
  348. s.AssertHitTest(new Point(110, 110), null);
  349. }
  350. }
  351. [Fact]
  352. public void HitTest_Should_Accommodate_ICustomHitTest()
  353. {
  354. using (var s = new CompositorServices(new Size(300, 200)))
  355. {
  356. Border border = new CustomHitTestBorder
  357. {
  358. ClipToBounds = false,
  359. Width = 100,
  360. Height = 100,
  361. Background = Brushes.Red,
  362. HorizontalAlignment = HorizontalAlignment.Center,
  363. VerticalAlignment = VerticalAlignment.Center
  364. };
  365. s.TopLevel.Content = border;
  366. s.AssertHitTest(75, 100, null, border);
  367. s.AssertHitTest(125, 100, null, border);
  368. s.AssertHitTest(175, 100, null);
  369. }
  370. }
  371. [Fact]
  372. public void HitTest_Should_Not_Hit_Controls_Next_Pixel()
  373. {
  374. using (var s = new CompositorServices(new Size(200, 200)))
  375. {
  376. Border targetRectangle;
  377. var stackPanel = new StackPanel
  378. {
  379. Orientation = Orientation.Vertical,
  380. HorizontalAlignment = HorizontalAlignment.Left,
  381. Children =
  382. {
  383. new Border { Width = 10, Height = 10, Background= Brushes.Red},
  384. { targetRectangle = new Border { Width = 10, Height = 10, Background = Brushes.Green} }
  385. }
  386. };
  387. s.TopLevel.Content = stackPanel;
  388. s.AssertHitTest(new Point(5, 10), null, targetRectangle);
  389. }
  390. }
  391. [Fact]
  392. public void HitTest_Filter_Should_Filter_Out_Children()
  393. {
  394. using (var s = new CompositorServices(new Size(200, 200)))
  395. {
  396. Border child, parent;
  397. s.TopLevel.Content = parent = new Border
  398. {
  399. Width = 100,
  400. Height = 100,
  401. Background = Brushes.Red,
  402. HorizontalAlignment = HorizontalAlignment.Center,
  403. VerticalAlignment = VerticalAlignment.Center,
  404. Child = child = new Border
  405. {
  406. Background = Brushes.Red,
  407. HorizontalAlignment = HorizontalAlignment.Stretch,
  408. VerticalAlignment = VerticalAlignment.Stretch,
  409. }
  410. };
  411. s.AssertHitTest(new Point(100, 100), null, child, parent);
  412. s.AssertHitTest(new Point(100, 100), v => v != parent);
  413. }
  414. }
  415. private IDisposable TestApplication()
  416. {
  417. return UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
  418. }
  419. }