ScrollTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. using Microsoft.VisualStudio.TestPlatform.Utilities;
  2. using Xunit.Abstractions;
  3. namespace Terminal.Gui.ViewsTests;
  4. public class ScrollTests
  5. {
  6. public ScrollTests (ITestOutputHelper output) { _output = output; }
  7. private readonly ITestOutputHelper _output;
  8. [Fact]
  9. public void OnOrientationChanged_Keeps_Size ()
  10. {
  11. var scroll = new Scroll ();
  12. scroll.Layout ();
  13. scroll.Size = 1;
  14. scroll.Orientation = Orientation.Horizontal;
  15. Assert.Equal (1, scroll.Size);
  16. }
  17. [Fact]
  18. public void OnOrientationChanged_Sets_Position_To_0 ()
  19. {
  20. View super = new View ()
  21. {
  22. Id = "super",
  23. Width = 10,
  24. Height = 10
  25. };
  26. var scroll = new Scroll ()
  27. {
  28. };
  29. super.Add (scroll);
  30. scroll.Layout ();
  31. scroll.SliderPosition = 1;
  32. scroll.Orientation = Orientation.Horizontal;
  33. Assert.Equal (0, scroll.SliderPosition);
  34. }
  35. // [Theory]
  36. // [AutoInitShutdown]
  37. // [InlineData (
  38. // 20,
  39. // @"
  40. //█
  41. //█
  42. //█
  43. //█
  44. //█
  45. //░
  46. //░
  47. //░
  48. //░
  49. //░",
  50. // @"
  51. //░
  52. //░
  53. //█
  54. //█
  55. //█
  56. //█
  57. //█
  58. //░
  59. //░
  60. //░",
  61. // @"
  62. //░
  63. //░
  64. //░
  65. //░
  66. //░
  67. //█
  68. //█
  69. //█
  70. //█
  71. //█",
  72. // @"
  73. //░
  74. //░
  75. //█
  76. //█
  77. //█
  78. //░
  79. //░
  80. //░
  81. //░
  82. //░",
  83. // @"
  84. //█████░░░░░",
  85. // @"
  86. //░░█████░░░",
  87. // @"
  88. //░░░░░█████",
  89. // @"
  90. //░░███░░░░░")]
  91. // [InlineData (
  92. // 40,
  93. // @"
  94. //█
  95. //█
  96. //█
  97. //░
  98. //░
  99. //░
  100. //░
  101. //░
  102. //░
  103. //░",
  104. // @"
  105. //░
  106. //█
  107. //█
  108. //█
  109. //░
  110. //░
  111. //░
  112. //░
  113. //░
  114. //░",
  115. // @"
  116. //░
  117. //░
  118. //█
  119. //█
  120. //█
  121. //░
  122. //░
  123. //░
  124. //░
  125. //░",
  126. // @"
  127. //░
  128. //█
  129. //█
  130. //░
  131. //░
  132. //░
  133. //░
  134. //░
  135. //░
  136. //░",
  137. // @"
  138. //███░░░░░░░",
  139. // @"
  140. //░███░░░░░░",
  141. // @"
  142. //░░███░░░░░",
  143. // @"
  144. //░██░░░░░░░")]
  145. // public void Changing_Position_Size_Orientation_Draws_Correctly_KeepContentInAllViewport_True (
  146. // int size,
  147. // string firstVertExpected,
  148. // string middleVertExpected,
  149. // string endVertExpected,
  150. // string sizeVertExpected,
  151. // string firstHoriExpected,
  152. // string middleHoriExpected,
  153. // string endHoriExpected,
  154. // string sizeHoriExpected
  155. // )
  156. // {
  157. // var scroll = new Scroll
  158. // {
  159. // Orientation = Orientation.Vertical,
  160. // Size = size,
  161. // Height = 10,
  162. // KeepContentInAllViewport = true
  163. // };
  164. // var top = new Toplevel ();
  165. // top.Add (scroll);
  166. // RunState rs = Application.Begin (top);
  167. // Application.RunIteration (ref rs);
  168. // _ = TestHelpers.AssertDriverContentsWithFrameAre (firstVertExpected, _output);
  169. // scroll.Position = 4;
  170. // Application.RunIteration (ref rs);
  171. // _ = TestHelpers.AssertDriverContentsWithFrameAre (middleVertExpected, _output);
  172. // scroll.Position = 10;
  173. // Application.RunIteration (ref rs);
  174. // _ = TestHelpers.AssertDriverContentsWithFrameAre (endVertExpected, _output);
  175. // scroll.Size = size * 2;
  176. // Application.RunIteration (ref rs);
  177. // _ = TestHelpers.AssertDriverContentsWithFrameAre (sizeVertExpected, _output);
  178. // scroll.Orientation = Orientation.Horizontal;
  179. // scroll.Width = 10;
  180. // scroll.Height = 1;
  181. // scroll.Position = 0;
  182. // scroll.Size = size;
  183. // Application.RunIteration (ref rs);
  184. // _ = TestHelpers.AssertDriverContentsWithFrameAre (firstHoriExpected, _output);
  185. // scroll.Position = 4;
  186. // Application.RunIteration (ref rs);
  187. // _ = TestHelpers.AssertDriverContentsWithFrameAre (middleHoriExpected, _output);
  188. // scroll.Position = 10;
  189. // Application.RunIteration (ref rs);
  190. // _ = TestHelpers.AssertDriverContentsWithFrameAre (endHoriExpected, _output);
  191. // scroll.Size = size * 2;
  192. // Application.RunIteration (ref rs);
  193. // _ = TestHelpers.AssertDriverContentsWithFrameAre (sizeHoriExpected, _output);
  194. // }
  195. [Fact]
  196. public void Constructor_Defaults ()
  197. {
  198. var scroll = new Scroll ();
  199. Assert.False (scroll.CanFocus);
  200. Assert.Equal (Orientation.Vertical, scroll.Orientation);
  201. Assert.Equal (0, scroll.Size);
  202. Assert.Equal (0, scroll.SliderPosition);
  203. }
  204. //[Fact]
  205. //[AutoInitShutdown]
  206. //public void KeepContentInAllViewport_True_False_KeepContentInAllViewport_True ()
  207. //{
  208. // var view = new View { Width = Dim.Fill (), Height = Dim.Fill () };
  209. // view.Padding.Thickness = new (0, 0, 2, 0);
  210. // view.SetContentSize (new (view.Viewport.Width, 30));
  211. // var scroll = new Scroll { Width = 2, Height = Dim.Fill (), Size = view.GetContentSize ().Height, KeepContentInAllViewport = true };
  212. // scroll.PositionChanged += (_, e) => view.Viewport = view.Viewport with { Y = e.CurrentValue };
  213. // view.Padding.Add (scroll);
  214. // var top = new Toplevel ();
  215. // top.Add (view);
  216. // Application.Begin (top);
  217. // Assert.True (scroll.KeepContentInAllViewport);
  218. // Assert.Equal (80, view.Padding.Viewport.Width);
  219. // Assert.Equal (25, view.Padding.Viewport.Height);
  220. // Assert.Equal (2, scroll.Viewport.Width);
  221. // Assert.Equal (25, scroll.Viewport.Height);
  222. // Assert.Equal (30, scroll.Size);
  223. // scroll.KeepContentInAllViewport = false;
  224. // scroll.Position = 50;
  225. // Assert.Equal (scroll.Position, scroll.Size - 1);
  226. // Assert.Equal (scroll.Position, view.Viewport.Y);
  227. // Assert.Equal (29, scroll.Position);
  228. // Assert.Equal (29, view.Viewport.Y);
  229. // top.Dispose ();
  230. //}
  231. //[Theory]
  232. //[AutoInitShutdown]
  233. //[InlineData (Orientation.Vertical)]
  234. //[InlineData (Orientation.Horizontal)]
  235. //public void Moving_Mouse_Outside_Host_Ensures_Correct_Location_KeepContentInAllViewport_True (Orientation orientation)
  236. //{
  237. // var scroll = new Scroll
  238. // {
  239. // X = 10, Y = 10, Width = orientation == Orientation.Vertical ? 1 : 10, Height = orientation == Orientation.Vertical ? 10 : 1, Size = 20,
  240. // SliderPosition = 5, Orientation = orientation
  241. // };
  242. // var top = new Toplevel ();
  243. // top.Add (scroll);
  244. // RunState rs = Application.Begin (top);
  245. // Rectangle scrollSliderFrame = scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame;
  246. // Assert.Equal (scrollSliderFrame, orientation == Orientation.Vertical ? new (0, 2, 1, 5) : new (2, 0, 5, 1));
  247. // Application.RaiseMouseEvent (new () { ScreenPosition = orientation == Orientation.Vertical ? new (10, 12) : new (12, 10), Flags = MouseFlags.Button1Pressed });
  248. // Application.RunIteration (ref rs);
  249. // Application.RaiseMouseEvent (
  250. // new ()
  251. // {
  252. // ScreenPosition = orientation == Orientation.Vertical ? new (10, 0) : new (0, 10),
  253. // Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  254. // });
  255. // Application.RunIteration (ref rs);
  256. // Assert.Equal (new (0, 0), scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame.Location);
  257. // Application.RaiseMouseEvent (
  258. // new ()
  259. // {
  260. // ScreenPosition = orientation == Orientation.Vertical ? new (0, 25) : new (80, 0),
  261. // Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  262. // });
  263. // Application.RunIteration (ref rs);
  264. // Assert.Equal (
  265. // orientation == Orientation.Vertical ? new (0, 5) : new (5, 0),
  266. // scroll.Subviews.FirstOrDefault (x => x.Id == "scrollSlider")!.Frame.Location);
  267. //}
  268. [Theory]
  269. [CombinatorialData]
  270. [AutoInitShutdown]
  271. public void Mouse_Wheel_Increments_Position ([CombinatorialRange (1, 3, 1)] int increment, Orientation orientation)
  272. {
  273. var top = new Toplevel ()
  274. {
  275. Id = "top",
  276. Width = 10,
  277. Height = 10
  278. };
  279. var scroll = new Scroll
  280. {
  281. Id = "scroll",
  282. Orientation = orientation,
  283. Size = 20,
  284. Increment = increment
  285. };
  286. top.Add (scroll);
  287. RunState rs = Application.Begin (top);
  288. Assert.Equal (0, scroll.SliderPosition);
  289. Assert.Equal (0, scroll.ContentPosition);
  290. Application.RaiseMouseEvent (new ()
  291. {
  292. ScreenPosition = new (0, 0),
  293. Flags = orientation == Orientation.Vertical ? MouseFlags.WheeledDown : MouseFlags.WheeledRight
  294. });
  295. Application.RunIteration (ref rs);
  296. Assert.Equal (increment, scroll.ContentPosition);
  297. Application.RaiseMouseEvent (new ()
  298. {
  299. ScreenPosition = new (0, 0),
  300. Flags = orientation == Orientation.Vertical ? MouseFlags.WheeledDown : MouseFlags.WheeledRight
  301. });
  302. Application.RunIteration (ref rs);
  303. Assert.Equal (increment * 2, scroll.ContentPosition);
  304. Application.RaiseMouseEvent (new ()
  305. {
  306. ScreenPosition = new (0, 0),
  307. Flags = orientation == Orientation.Vertical ? MouseFlags.WheeledUp : MouseFlags.WheeledLeft
  308. });
  309. Application.RunIteration (ref rs);
  310. Assert.Equal (increment, scroll.ContentPosition);
  311. Application.ResetState (true);
  312. }
  313. [Theory]
  314. [CombinatorialData]
  315. [AutoInitShutdown]
  316. public void Mouse_Click_Outside_Slider_Moves (Orientation orientation)
  317. {
  318. var top = new Toplevel ()
  319. {
  320. Id = "top",
  321. Width = 10,
  322. Height = 10
  323. };
  324. var scroll = new Scroll
  325. {
  326. Id = "scroll",
  327. Orientation = orientation,
  328. Size = 20,
  329. };
  330. top.Add (scroll);
  331. RunState rs = Application.Begin (top);
  332. scroll.SliderPosition = 5;
  333. Application.RunIteration (ref rs);
  334. Assert.Equal (5, scroll.SliderPosition);
  335. Assert.Equal (10, scroll.ContentPosition);
  336. Application.RaiseMouseEvent (new ()
  337. {
  338. ScreenPosition = new (0, 0),
  339. Flags = MouseFlags.Button1Clicked
  340. });
  341. Application.RunIteration (ref rs);
  342. Assert.Equal (0, scroll.SliderPosition);
  343. Assert.Equal (0, scroll.ContentPosition);
  344. Application.ResetState (true);
  345. }
  346. [Theory]
  347. [CombinatorialData]
  348. public void Position_Clamps_To_Size (
  349. [CombinatorialRange (1, 6, 1)] int scrollSize,
  350. [CombinatorialRange (-1, 6, 1)] int scrollPosition,
  351. Orientation orientation
  352. )
  353. {
  354. var super = new View
  355. {
  356. Id = "super",
  357. Width = 5,
  358. Height = 5
  359. };
  360. var scroll = new Scroll
  361. {
  362. Orientation = orientation,
  363. Width = Dim.Fill (),
  364. Height = Dim.Fill ()
  365. };
  366. super.Add (scroll);
  367. scroll.Size = scrollSize;
  368. super.Layout ();
  369. scroll.SliderPosition = scrollPosition;
  370. super.Layout ();
  371. Assert.True (scroll.SliderPosition <= scrollSize);
  372. }
  373. [Fact]
  374. public void SliderPosition_Event_Cancelables ()
  375. {
  376. var changingCount = 0;
  377. var changedCount = 0;
  378. var scroll = new Scroll { };
  379. scroll.Layout ();
  380. scroll.Size = scroll.Viewport.Height * 2;
  381. scroll.Layout ();
  382. scroll.SliderPositionChanging += (s, e) =>
  383. {
  384. if (changingCount == 0)
  385. {
  386. e.Cancel = true;
  387. }
  388. changingCount++;
  389. };
  390. scroll.SliderPositionChanged += (s, e) => changedCount++;
  391. scroll.SliderPosition = 1;
  392. Assert.Equal (0, scroll.SliderPosition);
  393. Assert.Equal (1, changingCount);
  394. Assert.Equal (0, changedCount);
  395. scroll.SliderPosition = 1;
  396. Assert.Equal (1, scroll.SliderPosition);
  397. Assert.Equal (2, changingCount);
  398. Assert.Equal (1, changedCount);
  399. }
  400. [Fact]
  401. public void PositionChanging_PositionChanged_Events_Only_Raises_Once_If_Position_Was_Really_Changed ()
  402. {
  403. var changing = 0;
  404. var cancel = false;
  405. var changed = 0;
  406. var scroll = new Scroll { Height = 10, Size = 20 };
  407. scroll.SliderPositionChanging += Scroll_PositionChanging;
  408. scroll.SliderPositionChanged += Scroll_PositionChanged;
  409. Assert.Equal (Orientation.Vertical, scroll.Orientation);
  410. scroll.Layout ();
  411. Assert.Equal (new (0, 0, 1, 10), scroll.Viewport);
  412. Assert.Equal (0, scroll.SliderPosition);
  413. Assert.Equal (0, changing);
  414. Assert.Equal (0, changed);
  415. scroll.SliderPosition = 0;
  416. Assert.Equal (0, scroll.SliderPosition);
  417. Assert.Equal (0, changing);
  418. Assert.Equal (0, changed);
  419. scroll.SliderPosition = 1;
  420. Assert.Equal (1, scroll.SliderPosition);
  421. Assert.Equal (1, changing);
  422. Assert.Equal (1, changed);
  423. Reset ();
  424. cancel = true;
  425. scroll.SliderPosition = 2;
  426. Assert.Equal (1, scroll.SliderPosition);
  427. Assert.Equal (1, changing);
  428. Assert.Equal (0, changed);
  429. Reset ();
  430. scroll.SliderPosition = 10;
  431. Assert.Equal (5, scroll.SliderPosition);
  432. Assert.Equal (1, changing);
  433. Assert.Equal (1, changed);
  434. Reset ();
  435. scroll.SliderPosition = 11;
  436. Assert.Equal (5, scroll.SliderPosition);
  437. Assert.Equal (1, changing);
  438. Assert.Equal (1, changed);
  439. Reset ();
  440. scroll.SliderPosition = 0;
  441. Assert.Equal (0, scroll.SliderPosition);
  442. Assert.Equal (1, changing);
  443. Assert.Equal (1, changed);
  444. scroll.SliderPositionChanging -= Scroll_PositionChanging;
  445. scroll.SliderPositionChanged -= Scroll_PositionChanged;
  446. void Scroll_PositionChanging (object sender, CancelEventArgs<int> e)
  447. {
  448. changing++;
  449. e.Cancel = cancel;
  450. }
  451. void Scroll_PositionChanged (object sender, EventArgs<int> e) { changed++; }
  452. void Reset ()
  453. {
  454. changing = 0;
  455. cancel = false;
  456. changed = 0;
  457. }
  458. }
  459. [Fact]
  460. public void Size_Cannot_Be_Negative ()
  461. {
  462. var scroll = new Scroll { Height = 10, Size = -1 };
  463. Assert.Equal (0, scroll.Size);
  464. scroll.Size = -10;
  465. Assert.Equal (0, scroll.Size);
  466. }
  467. [Fact]
  468. public void SizeChanged_Event ()
  469. {
  470. var count = 0;
  471. var scroll = new Scroll ();
  472. scroll.Layout ();
  473. scroll.SizeChanged += (s, e) => count++;
  474. scroll.Size = 10;
  475. Assert.Equal (10, scroll.Size);
  476. Assert.Equal (1, count);
  477. }
  478. [Theory]
  479. [SetupFakeDriver]
  480. [InlineData (
  481. 10,
  482. 1,
  483. 20,
  484. 0,
  485. Orientation.Horizontal,
  486. @"
  487. ┌──────────┐
  488. │█████░░░░░│
  489. └──────────┘")]
  490. [InlineData (
  491. 10,
  492. 3,
  493. 20,
  494. 1,
  495. Orientation.Horizontal,
  496. @"
  497. ┌──────────┐
  498. │░█████░░░░│
  499. │░█████░░░░│
  500. │░█████░░░░│
  501. └──────────┘")]
  502. [InlineData (
  503. 3,
  504. 10,
  505. 20,
  506. 0,
  507. Orientation.Vertical,
  508. @"
  509. ┌───┐
  510. │███│
  511. │███│
  512. │███│
  513. │███│
  514. │███│
  515. │░░░│
  516. │░░░│
  517. │░░░│
  518. │░░░│
  519. │░░░│
  520. └───┘")]
  521. public void Draws_Correctly (int superViewportWidth, int superViewportHeight, int sliderSize, int sliderPosition, Orientation orientation, string expected)
  522. {
  523. var super = new Window
  524. {
  525. Id = "super",
  526. Width = superViewportWidth + 2,
  527. Height = superViewportHeight + 2
  528. };
  529. var scroll = new Scroll
  530. {
  531. Orientation = orientation,
  532. };
  533. if (orientation == Orientation.Vertical)
  534. {
  535. scroll.Width = Dim.Fill ();
  536. }
  537. else
  538. {
  539. scroll.Height = Dim.Fill ();
  540. }
  541. super.Add (scroll);
  542. scroll.Size = sliderSize;
  543. scroll.Layout ();
  544. scroll.SliderPosition = sliderPosition;
  545. super.BeginInit ();
  546. super.EndInit ();
  547. super.Layout ();
  548. super.Draw ();
  549. _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  550. }
  551. }