ScrollContentPresenterTests.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Reactive.Linq;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Primitives;
  8. using Avalonia.Layout;
  9. using Xunit;
  10. namespace Avalonia.Controls.UnitTests.Presenters
  11. {
  12. public class ScrollContentPresenterTests
  13. {
  14. [Theory]
  15. [InlineData(HorizontalAlignment.Stretch, VerticalAlignment.Stretch, 10, 10, 80, 80)]
  16. [InlineData(HorizontalAlignment.Left, VerticalAlignment.Stretch, 10, 10, 16, 80)]
  17. [InlineData(HorizontalAlignment.Right, VerticalAlignment.Stretch, 74, 10, 16, 80)]
  18. [InlineData(HorizontalAlignment.Center, VerticalAlignment.Stretch, 42, 10, 16, 80)]
  19. [InlineData(HorizontalAlignment.Stretch, VerticalAlignment.Top, 10, 10, 80, 16)]
  20. [InlineData(HorizontalAlignment.Stretch, VerticalAlignment.Bottom, 10, 74, 80, 16)]
  21. [InlineData(HorizontalAlignment.Stretch, VerticalAlignment.Center, 10, 42, 80, 16)]
  22. public void Alignment_And_Padding_Are_Applied_To_Child_Bounds(
  23. HorizontalAlignment h,
  24. VerticalAlignment v,
  25. double expectedX,
  26. double expectedY,
  27. double expectedWidth,
  28. double expectedHeight)
  29. {
  30. Border content;
  31. var target = new ScrollContentPresenter
  32. {
  33. Padding = new Thickness(10),
  34. Content = content = new Border
  35. {
  36. MinWidth = 16,
  37. MinHeight = 16,
  38. HorizontalAlignment = h,
  39. VerticalAlignment = v,
  40. },
  41. };
  42. target.UpdateChild();
  43. target.Measure(new Size(100, 100));
  44. target.Arrange(new Rect(0, 0, 100, 100));
  45. Assert.Equal(new Rect(expectedX, expectedY, expectedWidth, expectedHeight), content.Bounds);
  46. }
  47. [Fact]
  48. public void DesiredSize_Is_Content_Size_When_Smaller_Than_AvailableSize()
  49. {
  50. var target = new ScrollContentPresenter
  51. {
  52. Padding = new Thickness(10),
  53. Content = new Border
  54. {
  55. MinWidth = 16,
  56. MinHeight = 16,
  57. },
  58. };
  59. target.UpdateChild();
  60. target.Measure(new Size(100, 100));
  61. target.Arrange(new Rect(0, 0, 100, 100));
  62. Assert.Equal(new Size(16, 16), target.DesiredSize);
  63. }
  64. [Fact]
  65. public void DesiredSize_Is_AvailableSize_When_Content_Larger_Than_AvailableSize()
  66. {
  67. var target = new ScrollContentPresenter
  68. {
  69. Padding = new Thickness(10),
  70. Content = new Border
  71. {
  72. MinWidth = 160,
  73. MinHeight = 160,
  74. },
  75. };
  76. target.UpdateChild();
  77. target.Measure(new Size(100, 100));
  78. target.Arrange(new Rect(0, 0, 100, 100));
  79. Assert.Equal(new Size(100, 100), target.DesiredSize);
  80. }
  81. [Fact]
  82. public void Content_Can_Be_Larger_Than_Viewport()
  83. {
  84. TestControl content;
  85. var target = new ScrollContentPresenter
  86. {
  87. CanHorizontallyScroll = true,
  88. CanVerticallyScroll = true,
  89. Content = content = new TestControl(),
  90. };
  91. target.UpdateChild();
  92. target.Measure(new Size(100, 100));
  93. target.Arrange(new Rect(0, 0, 100, 100));
  94. Assert.Equal(new Rect(0, 0, 150, 150), content.Bounds);
  95. }
  96. [Fact]
  97. public void Content_Can_Be_Offset()
  98. {
  99. Border content;
  100. var target = new ScrollContentPresenter
  101. {
  102. CanHorizontallyScroll = true,
  103. CanVerticallyScroll = true,
  104. Content = content = new Border
  105. {
  106. Width = 150,
  107. Height = 150,
  108. },
  109. Offset = new Vector(25, 25),
  110. };
  111. target.UpdateChild();
  112. target.Measure(new Size(100, 100));
  113. target.Arrange(new Rect(0, 0, 100, 100));
  114. Assert.Equal(new Rect(-25, -25, 150, 150), content.Bounds);
  115. }
  116. [Fact]
  117. public void Measure_Should_Pass_Bounded_X_If_CannotScrollHorizontally()
  118. {
  119. var child = new TestControl();
  120. var target = new ScrollContentPresenter
  121. {
  122. CanVerticallyScroll = true,
  123. Content = child,
  124. };
  125. target.UpdateChild();
  126. target.Measure(new Size(100, 100));
  127. Assert.Equal(new Size(100, double.PositiveInfinity), child.AvailableSize);
  128. }
  129. [Fact]
  130. public void Measure_Should_Pass_Unbounded_X_If_CanScrollHorizontally()
  131. {
  132. var child = new TestControl();
  133. var target = new ScrollContentPresenter
  134. {
  135. CanHorizontallyScroll = true,
  136. CanVerticallyScroll = true,
  137. Content = child,
  138. };
  139. target.UpdateChild();
  140. target.Measure(new Size(100, 100));
  141. Assert.Equal(Size.Infinity, child.AvailableSize);
  142. }
  143. [Fact]
  144. public void Arrange_Should_Set_Viewport_And_Extent_In_That_Order()
  145. {
  146. var target = new ScrollContentPresenter
  147. {
  148. Content = new Border { Width = 40, Height = 50 }
  149. };
  150. var set = new List<string>();
  151. target.UpdateChild();
  152. target.Measure(new Size(100, 100));
  153. target.GetObservable(ScrollViewer.ViewportProperty).Skip(1).Subscribe(_ => set.Add("Viewport"));
  154. target.GetObservable(ScrollViewer.ExtentProperty).Skip(1).Subscribe(_ => set.Add("Extent"));
  155. target.Arrange(new Rect(0, 0, 100, 100));
  156. Assert.Equal(new[] { "Viewport", "Extent" }, set);
  157. }
  158. [Fact]
  159. public void Should_Correctly_Arrange_Child_Larger_Than_Viewport()
  160. {
  161. var child = new Canvas { MinWidth = 150, MinHeight = 150 };
  162. var target = new ScrollContentPresenter { Content = child, };
  163. target.UpdateChild();
  164. target.Measure(Size.Infinity);
  165. target.Arrange(new Rect(0, 0, 100, 100));
  166. Assert.Equal(new Size(150, 150), child.Bounds.Size);
  167. }
  168. [Fact]
  169. public void Arrange_Should_Constrain_Child_Width_When_CanHorizontallyScroll_False()
  170. {
  171. var child = new WrapPanel
  172. {
  173. Children =
  174. {
  175. new Border { Width = 40, Height = 50 },
  176. new Border { Width = 40, Height = 50 },
  177. new Border { Width = 40, Height = 50 },
  178. }
  179. };
  180. var target = new ScrollContentPresenter
  181. {
  182. Content = child,
  183. CanHorizontallyScroll = false,
  184. };
  185. target.UpdateChild();
  186. target.Measure(Size.Infinity);
  187. target.Arrange(new Rect(0, 0, 100, 100));
  188. Assert.Equal(100, child.Bounds.Width);
  189. }
  190. [Fact]
  191. public void Extent_Width_Should_Be_Arrange_Width_When_CanScrollHorizontally_False()
  192. {
  193. var child = new WrapPanel
  194. {
  195. Children =
  196. {
  197. new Border { Width = 40, Height = 50 },
  198. new Border { Width = 40, Height = 50 },
  199. new Border { Width = 40, Height = 50 },
  200. }
  201. };
  202. var target = new ScrollContentPresenter
  203. {
  204. Content = child,
  205. CanHorizontallyScroll = false,
  206. };
  207. target.UpdateChild();
  208. target.Measure(Size.Infinity);
  209. target.Arrange(new Rect(0, 0, 100, 100));
  210. Assert.Equal(new Size(100, 100), target.Extent);
  211. }
  212. [Fact]
  213. public void Setting_Offset_Should_Invalidate_Arrange()
  214. {
  215. var target = new ScrollContentPresenter
  216. {
  217. Content = new Border { Width = 140, Height = 150 }
  218. };
  219. target.UpdateChild();
  220. target.Measure(new Size(100, 100));
  221. target.Arrange(new Rect(0, 0, 100, 100));
  222. target.Offset = new Vector(10, 100);
  223. Assert.True(target.IsMeasureValid);
  224. Assert.False(target.IsArrangeValid);
  225. }
  226. [Fact]
  227. public void BringDescendantIntoView_Should_Update_Offset()
  228. {
  229. var target = new ScrollContentPresenter
  230. {
  231. Width = 100,
  232. Height = 100,
  233. Content = new Border
  234. {
  235. Width = 200,
  236. Height = 200,
  237. }
  238. };
  239. target.UpdateChild();
  240. target.Measure(Size.Infinity);
  241. target.Arrange(new Rect(0, 0, 100, 100));
  242. target.BringDescendantIntoView(target.Child, new Rect(200, 200, 0, 0));
  243. Assert.Equal(new Vector(100, 100), target.Offset);
  244. }
  245. [Fact]
  246. public void BringDescendantIntoView_Should_Handle_Child_Margin()
  247. {
  248. Border border;
  249. var target = new ScrollContentPresenter
  250. {
  251. CanHorizontallyScroll = true,
  252. CanVerticallyScroll = true,
  253. Width = 100,
  254. Height = 100,
  255. Content = new Decorator
  256. {
  257. Margin = new Thickness(50),
  258. Child = border = new Border
  259. {
  260. Width = 200,
  261. Height = 200,
  262. }
  263. }
  264. };
  265. target.UpdateChild();
  266. target.Measure(Size.Infinity);
  267. target.Arrange(new Rect(0, 0, 100, 100));
  268. target.BringDescendantIntoView(border, new Rect(200, 200, 0, 0));
  269. Assert.Equal(new Vector(150, 150), target.Offset);
  270. }
  271. private class TestControl : Control
  272. {
  273. public Size AvailableSize { get; private set; }
  274. protected override Size MeasureOverride(Size availableSize)
  275. {
  276. AvailableSize = availableSize;
  277. return new Size(150, 150);
  278. }
  279. }
  280. }
  281. }