SceneBuilderTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. using System;
  2. using System.Linq;
  3. using Avalonia.Controls;
  4. using Avalonia.Media;
  5. using Avalonia.Rendering.SceneGraph;
  6. using Avalonia.UnitTests;
  7. using Avalonia.VisualTree;
  8. using Xunit;
  9. using Avalonia.Layout;
  10. namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
  11. {
  12. public class SceneBuilderTests
  13. {
  14. [Fact]
  15. public void Should_Build_Initial_Scene()
  16. {
  17. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  18. {
  19. Border border;
  20. TextBlock textBlock;
  21. var tree = new TestRoot
  22. {
  23. Child = border = new Border
  24. {
  25. Width = 100,
  26. Height = 100,
  27. Background = Brushes.Red,
  28. Child = textBlock = new TextBlock
  29. {
  30. Text = "Hello World",
  31. }
  32. }
  33. };
  34. tree.Measure(Size.Infinity);
  35. tree.Arrange(new Rect(tree.DesiredSize));
  36. var result = new Scene(tree);
  37. SceneBuilder.UpdateAll(result);
  38. Assert.Equal(1, result.Root.Children.Count);
  39. var borderNode = (VisualNode)result.Root.Children[0];
  40. Assert.Same(borderNode, result.FindNode(border));
  41. Assert.Same(border, borderNode.Visual);
  42. Assert.Equal(2, borderNode.Children.Count);
  43. var backgroundNode = (RectangleNode)borderNode.Children[0];
  44. Assert.Equal(Brushes.Red, backgroundNode.Brush);
  45. var textBlockNode = (VisualNode)borderNode.Children[1];
  46. Assert.Same(textBlockNode, result.FindNode(textBlock));
  47. Assert.Same(textBlock, textBlockNode.Visual);
  48. Assert.Equal(1, textBlockNode.Children.Count);
  49. var textNode = (TextNode)textBlockNode.Children[0];
  50. Assert.NotNull(textNode.Text);
  51. }
  52. }
  53. [Fact]
  54. public void Should_Respect_Margin_For_ClipBounds()
  55. {
  56. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  57. {
  58. Canvas canvas;
  59. var tree = new TestRoot
  60. {
  61. Width = 200,
  62. Height = 300,
  63. Child = new Border
  64. {
  65. Margin = new Thickness(10, 20, 30, 40),
  66. Child = canvas = new Canvas(),
  67. }
  68. };
  69. tree.Measure(Size.Infinity);
  70. tree.Arrange(new Rect(tree.DesiredSize));
  71. var result = new Scene(tree);
  72. SceneBuilder.UpdateAll(result);
  73. var canvasNode = result.FindNode(canvas);
  74. Assert.Equal(new Rect(10, 20, 160, 240), canvasNode.ClipBounds);
  75. // Initial ClipBounds are correct, make sure they're still correct after updating canvas.
  76. result = result.Clone();
  77. Assert.True(SceneBuilder.Update(result, canvas));
  78. canvasNode = result.FindNode(canvas);
  79. Assert.Equal(new Rect(10, 20, 160, 240), canvasNode.ClipBounds);
  80. }
  81. }
  82. [Fact]
  83. public void Should_Respect_ZIndex()
  84. {
  85. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  86. {
  87. Border front;
  88. Border back;
  89. var tree = new TestRoot
  90. {
  91. Child = new Panel
  92. {
  93. Children =
  94. {
  95. (front = new Border
  96. {
  97. ZIndex = 1,
  98. }),
  99. (back = new Border
  100. {
  101. ZIndex = 0,
  102. }),
  103. }
  104. }
  105. };
  106. var result = new Scene(tree);
  107. SceneBuilder.UpdateAll(result);
  108. var panelNode = result.FindNode(tree.Child);
  109. var expected = new IVisual[] { back, front };
  110. var actual = panelNode.Children.OfType<IVisualNode>().Select(x => x.Visual).ToArray();
  111. Assert.Equal(expected, actual);
  112. }
  113. }
  114. [Fact]
  115. public void ClipBounds_Should_Be_In_Global_Coordinates()
  116. {
  117. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  118. {
  119. Border target;
  120. var tree = new TestRoot
  121. {
  122. Child = new Decorator
  123. {
  124. Margin = new Thickness(24, 26),
  125. Child = target = new Border
  126. {
  127. Margin = new Thickness(26, 24),
  128. Width = 100,
  129. Height = 100,
  130. }
  131. }
  132. };
  133. tree.Measure(Size.Infinity);
  134. tree.Arrange(new Rect(tree.DesiredSize));
  135. var result = new Scene(tree);
  136. SceneBuilder.UpdateAll(result);
  137. var targetNode = result.FindNode(target);
  138. Assert.Equal(new Rect(50, 50, 100, 100), targetNode.ClipBounds);
  139. }
  140. }
  141. [Fact]
  142. public void Should_Update_Border_Background_Node()
  143. {
  144. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  145. {
  146. Border border;
  147. TextBlock textBlock;
  148. var tree = new TestRoot
  149. {
  150. Child = border = new Border
  151. {
  152. Width = 100,
  153. Height = 100,
  154. Background = Brushes.Red,
  155. Child = textBlock = new TextBlock
  156. {
  157. Foreground = Brushes.Green,
  158. Text = "Hello World",
  159. }
  160. }
  161. };
  162. tree.Measure(Size.Infinity);
  163. tree.Arrange(new Rect(tree.DesiredSize));
  164. var initial = new Scene(tree);
  165. SceneBuilder.UpdateAll(initial);
  166. var initialBackgroundNode = initial.FindNode(border).Children[0];
  167. var initialTextNode = initial.FindNode(textBlock).Children[0];
  168. Assert.NotNull(initialBackgroundNode);
  169. Assert.NotNull(initialTextNode);
  170. border.Background = Brushes.Green;
  171. var result = initial.Clone();
  172. SceneBuilder.Update(result, border);
  173. var borderNode = (VisualNode)result.Root.Children[0];
  174. Assert.Same(border, borderNode.Visual);
  175. var backgroundNode = (RectangleNode)borderNode.Children[0];
  176. Assert.NotSame(initialBackgroundNode, backgroundNode);
  177. Assert.Equal(Brushes.Green, backgroundNode.Brush);
  178. var textBlockNode = (VisualNode)borderNode.Children[1];
  179. Assert.Same(textBlock, textBlockNode.Visual);
  180. var textNode = (TextNode)textBlockNode.Children[0];
  181. Assert.Same(initialTextNode, textNode);
  182. }
  183. }
  184. [Fact]
  185. public void Should_Update_When_Control_Added()
  186. {
  187. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  188. {
  189. Border border;
  190. var tree = new TestRoot
  191. {
  192. Width = 100,
  193. Height = 100,
  194. Child = border = new Border
  195. {
  196. Background = Brushes.Red,
  197. }
  198. };
  199. Canvas canvas;
  200. var decorator = new Decorator
  201. {
  202. Child = canvas = new Canvas(),
  203. };
  204. tree.Measure(Size.Infinity);
  205. tree.Arrange(new Rect(tree.DesiredSize));
  206. var initial = new Scene(tree);
  207. SceneBuilder.UpdateAll(initial);
  208. border.Child = decorator;
  209. var result = initial.Clone();
  210. Assert.True(SceneBuilder.Update(result, decorator));
  211. // Updating canvas should result in no-op as it should have been updated along
  212. // with decorator as part of the add opeation.
  213. Assert.False(SceneBuilder.Update(result, canvas));
  214. var borderNode = (VisualNode)result.Root.Children[0];
  215. Assert.Equal(2, borderNode.Children.Count);
  216. var decoratorNode = (VisualNode)borderNode.Children[1];
  217. Assert.Same(decorator, decoratorNode.Visual);
  218. Assert.Same(decoratorNode, result.FindNode(decorator));
  219. var canvasNode = (VisualNode)decoratorNode.Children[0];
  220. Assert.Same(canvas, canvasNode.Visual);
  221. Assert.Same(canvasNode, result.FindNode(canvas));
  222. }
  223. }
  224. [Fact]
  225. public void Should_Update_When_Control_Removed()
  226. {
  227. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  228. {
  229. Border border;
  230. Decorator decorator;
  231. Canvas canvas;
  232. var tree = new TestRoot
  233. {
  234. Width = 100,
  235. Height = 100,
  236. Child = border = new Border
  237. {
  238. Background = Brushes.Red,
  239. Child = decorator = new Decorator
  240. {
  241. Child = canvas = new Canvas()
  242. }
  243. }
  244. };
  245. tree.Measure(Size.Infinity);
  246. tree.Arrange(new Rect(tree.DesiredSize));
  247. var initial = new Scene(tree);
  248. SceneBuilder.UpdateAll(initial);
  249. border.Child = null;
  250. var result = initial.Clone();
  251. Assert.True(SceneBuilder.Update(result, decorator));
  252. Assert.False(SceneBuilder.Update(result, canvas));
  253. var borderNode = (VisualNode)result.Root.Children[0];
  254. Assert.Equal(1, borderNode.Children.Count);
  255. Assert.Null(result.FindNode(decorator));
  256. }
  257. }
  258. [Fact]
  259. public void Should_Update_When_Control_Made_Invisible()
  260. {
  261. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  262. {
  263. Decorator decorator;
  264. Border border;
  265. Canvas canvas;
  266. var tree = new TestRoot
  267. {
  268. Width = 100,
  269. Height = 100,
  270. Child = decorator = new Decorator
  271. {
  272. Child = border = new Border
  273. {
  274. Background = Brushes.Red,
  275. Child = canvas = new Canvas(),
  276. }
  277. }
  278. };
  279. tree.Measure(Size.Infinity);
  280. tree.Arrange(new Rect(tree.DesiredSize));
  281. var initial = new Scene(tree);
  282. SceneBuilder.UpdateAll(initial);
  283. border.IsVisible = false;
  284. var result = initial.Clone();
  285. Assert.True(SceneBuilder.Update(result, border));
  286. Assert.False(SceneBuilder.Update(result, canvas));
  287. var decoratorNode = (VisualNode)result.Root.Children[0];
  288. Assert.Equal(0, decoratorNode.Children.Count);
  289. Assert.Null(result.FindNode(border));
  290. Assert.Null(result.FindNode(canvas));
  291. }
  292. }
  293. [Fact]
  294. public void Should_Update_Descendent_Tranform_When_Margin_Changed()
  295. {
  296. using (TestApplication())
  297. {
  298. Decorator decorator;
  299. Border border;
  300. Canvas canvas;
  301. var tree = new TestRoot
  302. {
  303. Width = 100,
  304. Height = 100,
  305. Child = decorator = new Decorator
  306. {
  307. Margin = new Thickness(0, 10, 0, 0),
  308. Child = border = new Border
  309. {
  310. Child = canvas = new Canvas(),
  311. }
  312. }
  313. };
  314. var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
  315. layout.ExecuteInitialLayoutPass(tree);
  316. var scene = new Scene(tree);
  317. SceneBuilder.UpdateAll(scene);
  318. var borderNode = scene.FindNode(border);
  319. var canvasNode = scene.FindNode(canvas);
  320. Assert.Equal(Matrix.CreateTranslation(0, 10), borderNode.Transform);
  321. Assert.Equal(Matrix.CreateTranslation(0, 10), canvasNode.Transform);
  322. decorator.Margin = new Thickness(0, 20, 0, 0);
  323. layout.ExecuteLayoutPass();
  324. scene = scene.Clone();
  325. SceneBuilder.Update(scene, decorator);
  326. borderNode = scene.FindNode(border);
  327. canvasNode = scene.FindNode(canvas);
  328. Assert.Equal(Matrix.CreateTranslation(0, 20), borderNode.Transform);
  329. Assert.Equal(Matrix.CreateTranslation(0, 20), canvasNode.Transform);
  330. }
  331. }
  332. private IDisposable TestApplication()
  333. {
  334. return UnitTestApplication.Start(
  335. TestServices.MockPlatformRenderInterface.With(
  336. layoutManager: new LayoutManager()));
  337. }
  338. }
  339. }