ScrollContentPresenterTests_ILogicalScrollable.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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.Reactive.Linq;
  5. using Avalonia.Controls.Presenters;
  6. using Avalonia.Controls.Primitives;
  7. using Avalonia.Input;
  8. using Xunit;
  9. namespace Avalonia.Controls.UnitTests
  10. {
  11. public class ScrollContentPresenterTests_ILogicalScrollable
  12. {
  13. [Fact]
  14. public void Measure_Should_Pass_Unchanged_Bounds_To_ILogicalScrollable()
  15. {
  16. var scrollable = new TestScrollable();
  17. var target = new ScrollContentPresenter
  18. {
  19. Content = scrollable,
  20. };
  21. target.UpdateChild();
  22. target.Measure(new Size(100, 100));
  23. Assert.Equal(new Size(100, 100), scrollable.AvailableSize);
  24. }
  25. [Fact]
  26. public void Arrange_Should_Not_Offset_ILogicalScrollable_Bounds()
  27. {
  28. var scrollable = new TestScrollable
  29. {
  30. Extent = new Size(100, 100),
  31. Offset = new Vector(50, 50),
  32. Viewport = new Size(25, 25),
  33. };
  34. var target = new ScrollContentPresenter
  35. {
  36. Content = scrollable,
  37. };
  38. target.UpdateChild();
  39. target.Measure(new Size(100, 100));
  40. target.Arrange(new Rect(0, 0, 100, 100));
  41. Assert.Equal(new Rect(0, 0, 100, 100), scrollable.Bounds);
  42. }
  43. [Fact]
  44. public void Arrange_Should_Offset_ILogicalScrollable_Bounds_When_Logical_Scroll_Disabled()
  45. {
  46. var scrollable = new TestScrollable
  47. {
  48. IsLogicalScrollEnabled = false,
  49. };
  50. var target = new ScrollContentPresenter
  51. {
  52. CanHorizontallyScroll = true,
  53. CanVerticallyScroll = true,
  54. Content = scrollable,
  55. Offset = new Vector(25, 25),
  56. };
  57. target.UpdateChild();
  58. target.Measure(new Size(100, 100));
  59. target.Arrange(new Rect(0, 0, 100, 100));
  60. Assert.Equal(new Rect(-25, -25, 150, 150), scrollable.Bounds);
  61. }
  62. [Fact]
  63. public void Arrange_Should_Not_Set_Viewport_And_Extent_With_ILogicalScrollable()
  64. {
  65. var target = new ScrollContentPresenter
  66. {
  67. Content = new TestScrollable()
  68. };
  69. var changed = false;
  70. target.UpdateChild();
  71. target.Measure(new Size(100, 100));
  72. target.GetObservable(ScrollViewer.ViewportProperty).Skip(1).Subscribe(_ => changed = true);
  73. target.GetObservable(ScrollViewer.ExtentProperty).Skip(1).Subscribe(_ => changed = true);
  74. target.Arrange(new Rect(0, 0, 100, 100));
  75. Assert.False(changed);
  76. }
  77. [Fact]
  78. public void InvalidateScroll_Should_Be_Set_When_Set_As_Content()
  79. {
  80. var scrollable = new TestScrollable();
  81. var target = new ScrollContentPresenter
  82. {
  83. Content = scrollable
  84. };
  85. target.UpdateChild();
  86. Assert.NotNull(scrollable.InvalidateScroll);
  87. }
  88. [Fact]
  89. public void InvalidateScroll_Should_Be_Cleared_When_Removed_From_Content()
  90. {
  91. var scrollable = new TestScrollable();
  92. var target = new ScrollContentPresenter
  93. {
  94. Content = scrollable
  95. };
  96. target.UpdateChild();
  97. target.Content = null;
  98. target.UpdateChild();
  99. Assert.Null(scrollable.InvalidateScroll);
  100. }
  101. [Fact]
  102. public void Extent_Offset_And_Viewport_Should_Be_Read_From_ILogicalScrollable()
  103. {
  104. var scrollable = new TestScrollable
  105. {
  106. Extent = new Size(100, 100),
  107. Offset = new Vector(50, 50),
  108. Viewport = new Size(25, 25),
  109. };
  110. var target = new ScrollContentPresenter
  111. {
  112. Content = scrollable
  113. };
  114. target.UpdateChild();
  115. Assert.Equal(scrollable.Extent, target.Extent);
  116. Assert.Equal(scrollable.Offset, target.Offset);
  117. Assert.Equal(scrollable.Viewport, target.Viewport);
  118. scrollable.Extent = new Size(200, 200);
  119. scrollable.Offset = new Vector(100, 100);
  120. scrollable.Viewport = new Size(50, 50);
  121. Assert.Equal(scrollable.Extent, target.Extent);
  122. Assert.Equal(scrollable.Offset, target.Offset);
  123. Assert.Equal(scrollable.Viewport, target.Viewport);
  124. }
  125. [Fact]
  126. public void Offset_Should_Be_Written_To_ILogicalScrollable()
  127. {
  128. var scrollable = new TestScrollable
  129. {
  130. Extent = new Size(100, 100),
  131. Offset = new Vector(50, 50),
  132. };
  133. var target = new ScrollContentPresenter
  134. {
  135. Content = scrollable
  136. };
  137. target.UpdateChild();
  138. target.Offset = new Vector(25, 25);
  139. Assert.Equal(target.Offset, scrollable.Offset);
  140. }
  141. [Fact]
  142. public void Offset_Should_Not_Be_Written_To_ILogicalScrollable_After_Removal()
  143. {
  144. var scrollable = new TestScrollable
  145. {
  146. Extent = new Size(100, 100),
  147. Offset = new Vector(50, 50),
  148. };
  149. var target = new ScrollContentPresenter
  150. {
  151. Content = scrollable
  152. };
  153. target.Content = null;
  154. target.Offset = new Vector(25, 25);
  155. Assert.Equal(new Vector(50, 50), scrollable.Offset);
  156. }
  157. [Fact]
  158. public void Toggling_IsLogicalScrollEnabled_Should_Update_State()
  159. {
  160. var scrollable = new TestScrollable
  161. {
  162. Extent = new Size(100, 100),
  163. Offset = new Vector(50, 50),
  164. Viewport = new Size(25, 25),
  165. };
  166. var target = new ScrollContentPresenter
  167. {
  168. CanHorizontallyScroll = true,
  169. CanVerticallyScroll = true,
  170. Content = scrollable,
  171. };
  172. target.UpdateChild();
  173. target.Measure(new Size(100, 100));
  174. target.Arrange(new Rect(0, 0, 100, 100));
  175. Assert.Equal(scrollable.Extent, target.Extent);
  176. Assert.Equal(scrollable.Offset, target.Offset);
  177. Assert.Equal(scrollable.Viewport, target.Viewport);
  178. Assert.Equal(new Rect(0, 0, 100, 100), scrollable.Bounds);
  179. scrollable.IsLogicalScrollEnabled = false;
  180. scrollable.InvalidateScroll();
  181. target.Measure(new Size(100, 100));
  182. target.Arrange(new Rect(0, 0, 100, 100));
  183. Assert.Equal(new Size(150, 150), target.Extent);
  184. Assert.Equal(new Vector(0, 0), target.Offset);
  185. Assert.Equal(new Size(100, 100), target.Viewport);
  186. Assert.Equal(new Rect(0, 0, 150, 150), scrollable.Bounds);
  187. scrollable.IsLogicalScrollEnabled = true;
  188. scrollable.InvalidateScroll();
  189. target.Measure(new Size(100, 100));
  190. target.Arrange(new Rect(0, 0, 100, 100));
  191. Assert.Equal(scrollable.Extent, target.Extent);
  192. Assert.Equal(scrollable.Offset, target.Offset);
  193. Assert.Equal(scrollable.Viewport, target.Viewport);
  194. Assert.Equal(new Rect(0, 0, 100, 100), scrollable.Bounds);
  195. }
  196. [Fact]
  197. public void Changing_Content_Should_Update_State()
  198. {
  199. var logicalScrollable = new TestScrollable
  200. {
  201. Extent = new Size(100, 100),
  202. Offset = new Vector(50, 50),
  203. Viewport = new Size(25, 25),
  204. };
  205. var nonLogicalScrollable = new TestScrollable
  206. {
  207. IsLogicalScrollEnabled = false,
  208. };
  209. var target = new ScrollContentPresenter
  210. {
  211. CanHorizontallyScroll = true,
  212. CanVerticallyScroll = true,
  213. Content = logicalScrollable,
  214. };
  215. target.UpdateChild();
  216. target.Measure(new Size(100, 100));
  217. target.Arrange(new Rect(0, 0, 100, 100));
  218. Assert.Equal(logicalScrollable.Extent, target.Extent);
  219. Assert.Equal(logicalScrollable.Offset, target.Offset);
  220. Assert.Equal(logicalScrollable.Viewport, target.Viewport);
  221. Assert.Equal(new Rect(0, 0, 100, 100), logicalScrollable.Bounds);
  222. target.Content = nonLogicalScrollable;
  223. target.UpdateChild();
  224. target.Measure(new Size(100, 100));
  225. target.Arrange(new Rect(0, 0, 100, 100));
  226. Assert.Equal(new Size(150, 150), target.Extent);
  227. Assert.Equal(new Vector(0, 0), target.Offset);
  228. Assert.Equal(new Size(100, 100), target.Viewport);
  229. Assert.Equal(new Rect(0, 0, 150, 150), nonLogicalScrollable.Bounds);
  230. target.Content = logicalScrollable;
  231. target.UpdateChild();
  232. target.Measure(new Size(100, 100));
  233. target.Arrange(new Rect(0, 0, 100, 100));
  234. Assert.Equal(logicalScrollable.Extent, target.Extent);
  235. Assert.Equal(logicalScrollable.Offset, target.Offset);
  236. Assert.Equal(logicalScrollable.Viewport, target.Viewport);
  237. Assert.Equal(new Rect(0, 0, 100, 100), logicalScrollable.Bounds);
  238. }
  239. [Fact]
  240. public void Should_Set_ILogicalScrolable_CanHorizontallyScroll()
  241. {
  242. var logicalScrollable = new TestScrollable();
  243. var target = new ScrollContentPresenter { Content = logicalScrollable };
  244. target.UpdateChild();
  245. Assert.False(logicalScrollable.CanHorizontallyScroll);
  246. target.CanHorizontallyScroll = true;
  247. Assert.True(logicalScrollable.CanHorizontallyScroll);
  248. }
  249. [Fact]
  250. public void Should_Set_ILogicalScrolable_CanVerticallyScroll()
  251. {
  252. var logicalScrollable = new TestScrollable();
  253. var target = new ScrollContentPresenter { Content = logicalScrollable };
  254. target.UpdateChild();
  255. Assert.False(logicalScrollable.CanVerticallyScroll);
  256. target.CanVerticallyScroll = true;
  257. Assert.True(logicalScrollable.CanVerticallyScroll);
  258. }
  259. private class TestScrollable : Control, ILogicalScrollable
  260. {
  261. private Size _extent;
  262. private Vector _offset;
  263. private Size _viewport;
  264. public bool CanHorizontallyScroll { get; set; }
  265. public bool CanVerticallyScroll { get; set; }
  266. public bool IsLogicalScrollEnabled { get; set; } = true;
  267. public Size AvailableSize { get; private set; }
  268. public Action InvalidateScroll { get; set; }
  269. public Size Extent
  270. {
  271. get { return _extent; }
  272. set
  273. {
  274. _extent = value;
  275. InvalidateScroll?.Invoke();
  276. }
  277. }
  278. public Vector Offset
  279. {
  280. get { return _offset; }
  281. set
  282. {
  283. _offset = value;
  284. InvalidateScroll?.Invoke();
  285. }
  286. }
  287. public Size Viewport
  288. {
  289. get { return _viewport; }
  290. set
  291. {
  292. _viewport = value;
  293. InvalidateScroll?.Invoke();
  294. }
  295. }
  296. public Size ScrollSize
  297. {
  298. get
  299. {
  300. return new Size(double.PositiveInfinity, 1);
  301. }
  302. }
  303. public Size PageScrollSize
  304. {
  305. get
  306. {
  307. return new Size(double.PositiveInfinity, Viewport.Height);
  308. }
  309. }
  310. public bool BringIntoView(IControl target, Rect targetRect)
  311. {
  312. throw new NotImplementedException();
  313. }
  314. protected override Size MeasureOverride(Size availableSize)
  315. {
  316. AvailableSize = availableSize;
  317. return new Size(150, 150);
  318. }
  319. public IControl GetControlInDirection(NavigationDirection direction, IControl from)
  320. {
  321. throw new NotImplementedException();
  322. }
  323. }
  324. }
  325. }