ScrollContentPresenterTests_ILogicalScrollable.cs 13 KB

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