2
0

ScrollViewTests.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. using System.Text;
  2. using JetBrains.Annotations;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewsTests;
  5. public class ScrollViewTests (ITestOutputHelper output)
  6. {
  7. [Fact]
  8. public void Adding_Views ()
  9. {
  10. var sv = new ScrollView { Width = 20, Height = 10 };
  11. sv.SetContentSize (new (30, 20));
  12. sv.Add (
  13. new View { Width = 10, Height = 5 },
  14. new View { X = 12, Y = 7, Width = 10, Height = 5 }
  15. );
  16. Assert.Equal (new (30, 20), sv.GetContentSize ());
  17. Assert.Equal (2, sv.Subviews [0].Subviews.Count);
  18. }
  19. [Fact]
  20. [AutoInitShutdown]
  21. public void AutoHideScrollBars_False_ShowHorizontalScrollIndicator_ShowVerticalScrollIndicator ()
  22. {
  23. var sv = new ScrollView { Width = 10, Height = 10, AutoHideScrollBars = false };
  24. sv.ShowHorizontalScrollIndicator = true;
  25. sv.ShowVerticalScrollIndicator = true;
  26. var top = new Toplevel ();
  27. top.Add (sv);
  28. Application.Begin (top);
  29. Assert.Equal (new (0, 0, 10, 10), sv.Viewport);
  30. Assert.False (sv.AutoHideScrollBars);
  31. Assert.True (sv.ShowHorizontalScrollIndicator);
  32. Assert.True (sv.ShowVerticalScrollIndicator);
  33. sv.Draw ();
  34. TestHelpers.AssertDriverContentsAre (
  35. @"
  36. ◄├─────┤►
  37. ",
  38. output
  39. );
  40. sv.ShowHorizontalScrollIndicator = false;
  41. Assert.Equal (new (0, 0, 10, 10), sv.Viewport);
  42. sv.ShowVerticalScrollIndicator = true;
  43. Assert.Equal (new (0, 0, 10, 10), sv.Viewport);
  44. Assert.False (sv.AutoHideScrollBars);
  45. Assert.False (sv.ShowHorizontalScrollIndicator);
  46. Assert.True (sv.ShowVerticalScrollIndicator);
  47. sv.Draw ();
  48. TestHelpers.AssertDriverContentsAre (
  49. @"
  50. ",
  51. output
  52. );
  53. sv.ShowHorizontalScrollIndicator = true;
  54. sv.ShowVerticalScrollIndicator = false;
  55. Assert.False (sv.AutoHideScrollBars);
  56. Assert.True (sv.ShowHorizontalScrollIndicator);
  57. Assert.False (sv.ShowVerticalScrollIndicator);
  58. sv.Draw ();
  59. TestHelpers.AssertDriverContentsAre (
  60. @"
  61. ◄├──────┤►
  62. ",
  63. output
  64. );
  65. sv.ShowHorizontalScrollIndicator = false;
  66. sv.ShowVerticalScrollIndicator = false;
  67. Assert.False (sv.AutoHideScrollBars);
  68. Assert.False (sv.ShowHorizontalScrollIndicator);
  69. Assert.False (sv.ShowVerticalScrollIndicator);
  70. sv.Draw ();
  71. TestHelpers.AssertDriverContentsAre (
  72. @"
  73. ",
  74. output
  75. );
  76. top.Dispose ();
  77. }
  78. [Fact]
  79. [AutoInitShutdown]
  80. public void AutoHideScrollBars_ShowHorizontalScrollIndicator_ShowVerticalScrollIndicator ()
  81. {
  82. var sv = new ScrollView { Width = 10, Height = 10 };
  83. var top = new Toplevel ();
  84. top.Add (sv);
  85. Application.Begin (top);
  86. Assert.True (sv.AutoHideScrollBars);
  87. Assert.False (sv.ShowHorizontalScrollIndicator);
  88. Assert.False (sv.ShowVerticalScrollIndicator);
  89. TestHelpers.AssertDriverContentsWithFrameAre ("", output);
  90. sv.AutoHideScrollBars = false;
  91. sv.ShowHorizontalScrollIndicator = true;
  92. sv.ShowVerticalScrollIndicator = true;
  93. sv.LayoutSubviews ();
  94. sv.Draw ();
  95. TestHelpers.AssertDriverContentsWithFrameAre (
  96. @"
  97. ◄├─────┤►
  98. ",
  99. output
  100. );
  101. top.Dispose ();
  102. }
  103. // There are still issue with the lower right corner of the scroll view
  104. [Fact]
  105. [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)]
  106. public void Clear_Window_Inside_ScrollView ()
  107. {
  108. var topLabel = new Label { X = 15, Text = "At 15,0" };
  109. var sv = new ScrollView
  110. {
  111. X = 3,
  112. Y = 3,
  113. Width = 10,
  114. Height = 10,
  115. KeepContentAlwaysInViewport = false
  116. };
  117. sv.SetContentSize (new (23, 23));
  118. var bottomLabel = new Label { X = 15, Y = 15, Text = "At 15,15" };
  119. var top = new Toplevel ();
  120. top.Add (topLabel, sv, bottomLabel);
  121. Application.Begin (top);
  122. TestHelpers.AssertDriverContentsWithFrameAre (
  123. @"
  124. At 15,0
  125. ◄├┤░░░░░►
  126. At 15,15",
  127. output
  128. );
  129. Attribute [] attributes =
  130. {
  131. Colors.ColorSchemes ["TopLevel"].Normal,
  132. Colors.ColorSchemes ["TopLevel"].Focus,
  133. Colors.ColorSchemes ["Base"].Normal
  134. };
  135. TestHelpers.AssertDriverAttributesAre (
  136. @"
  137. 00000000000000000000000
  138. 00000000000000000000000
  139. 00000000000000000000000
  140. 00000000000010000000000
  141. 00000000000010000000000
  142. 00000000000010000000000
  143. 00000000000010000000000
  144. 00000000000010000000000
  145. 00000000000010000000000
  146. 00000000000010000000000
  147. 00000000000010000000000
  148. 00000000000010000000000
  149. 00011111111110000000000
  150. 00000000000000000000000
  151. 00000000000000000000000
  152. 00000000000000000000000",
  153. output,
  154. null,
  155. attributes
  156. );
  157. sv.Add (new Window { X = 3, Y = 3, Width = 20, Height = 20 });
  158. Application.Refresh ();
  159. TestHelpers.AssertDriverContentsWithFrameAre (
  160. @"
  161. At 15,0
  162. ┌─────░
  163. │ ░
  164. │ ░
  165. │ ░
  166. │ ░
  167. │ ▼
  168. ◄├┤░░░░░►
  169. At 15,15",
  170. output
  171. );
  172. TestHelpers.AssertDriverAttributesAre (
  173. @"
  174. 00000000000000000000000
  175. 00000000000000000000000
  176. 00000000000000000000000
  177. 00000000000010000000000
  178. 00000000000010000000000
  179. 00000000000010000000000
  180. 00000022222210000000000
  181. 00000022222210000000000
  182. 00000022222210000000000
  183. 00000022222210000000000
  184. 00000022222210000000000
  185. 00000022222210000000000
  186. 00011111111110000000000
  187. 00000000000000000000000
  188. 00000000000000000000000
  189. 00000000000000000000000",
  190. output,
  191. null,
  192. attributes
  193. );
  194. sv.ContentOffset = new (20, 20);
  195. Application.Refresh ();
  196. TestHelpers.AssertDriverContentsWithFrameAre (
  197. @"
  198. At 15,0
  199. │ ▲
  200. │ ░
  201. ──┘ ░
  202. ◄░░░░├─┤►
  203. At 15,15",
  204. output
  205. );
  206. TestHelpers.AssertDriverAttributesAre (
  207. @"
  208. 00000000000000000000000
  209. 00000000000000000000000
  210. 00000000000000000000000
  211. 00022200000010000000000
  212. 00022200000010000000000
  213. 00022200000010000000000
  214. 00000000000010000000000
  215. 00000000000010000000000
  216. 00000000000010000000000
  217. 00000000000010000000000
  218. 00000000000010000000000
  219. 00000000000010000000000
  220. 00011111111110000000000
  221. 00000000000000000000000
  222. 00000000000000000000000
  223. 00000000000000000000000",
  224. output,
  225. null,
  226. attributes
  227. );
  228. top.Dispose ();
  229. }
  230. [Fact]
  231. public void Constructors_Defaults ()
  232. {
  233. var sv = new ScrollView ();
  234. Assert.True (sv.CanFocus);
  235. Assert.Equal (new (0, 0, 0, 0), sv.Frame);
  236. Assert.Equal (Rectangle.Empty, sv.Frame);
  237. Assert.Equal (Point.Empty, sv.ContentOffset);
  238. Assert.Equal (Size.Empty, sv.GetContentSize ());
  239. Assert.True (sv.AutoHideScrollBars);
  240. Assert.True (sv.KeepContentAlwaysInViewport);
  241. sv = new () { X = 1, Y = 2, Width = 20, Height = 10 };
  242. Assert.True (sv.CanFocus);
  243. Assert.Equal (new (1, 2, 20, 10), sv.Frame);
  244. Assert.Equal (Point.Empty, sv.ContentOffset);
  245. Assert.Equal (sv.Viewport.Size, sv.GetContentSize ());
  246. Assert.True (sv.AutoHideScrollBars);
  247. Assert.True (sv.KeepContentAlwaysInViewport);
  248. }
  249. [Fact]
  250. [SetupFakeDriver]
  251. public void ContentBottomRightCorner_Draw ()
  252. {
  253. ((FakeDriver)Application.Driver!).SetBufferSize (30, 30);
  254. var top = new View { Width = 30, Height = 30, ColorScheme = new () { Normal = Attribute.Default } };
  255. Size size = new (20, 10);
  256. var sv = new ScrollView
  257. {
  258. X = 1,
  259. Y = 1,
  260. Width = 10,
  261. Height = 5,
  262. ColorScheme = new () { Normal = new (Color.Red, Color.Green) }
  263. };
  264. sv.SetContentSize (size);
  265. string text = null;
  266. for (var i = 0; i < size.Height; i++)
  267. {
  268. text += "*".Repeat (size.Width);
  269. if (i < size.Height)
  270. {
  271. text += '\n';
  272. }
  273. }
  274. var view = new View
  275. {
  276. ColorScheme = new () { Normal = new (Color.Blue, Color.Yellow) },
  277. Width = Dim.Auto (DimAutoStyle.Text),
  278. Height = Dim.Auto (DimAutoStyle.Text),
  279. Text = text
  280. };
  281. sv.Add (view);
  282. top.Add (sv);
  283. top.BeginInit ();
  284. top.EndInit ();
  285. top.LayoutSubviews ();
  286. top.Draw ();
  287. View contentBottomRightCorner = sv.Subviews.First (v => v is ScrollBarView.ContentBottomRightCorner);
  288. Assert.True (contentBottomRightCorner is ScrollBarView.ContentBottomRightCorner);
  289. Assert.True (contentBottomRightCorner.Visible);
  290. TestHelpers.AssertDriverContentsWithFrameAre (
  291. @"
  292. *********▲
  293. *********┬
  294. *********┴
  295. *********▼
  296. ◄├──┤░░░► ",
  297. output
  298. );
  299. Attribute [] attrs = { Attribute.Default, new (Color.Red, Color.Green), new (Color.Blue, Color.Yellow) };
  300. TestHelpers.AssertDriverAttributesAre (
  301. @"
  302. 000000000000
  303. 022222222210
  304. 022222222210
  305. 022222222210
  306. 022222222210
  307. 011111111110
  308. 000000000000",
  309. output,
  310. null,
  311. attrs
  312. );
  313. top.Dispose ();
  314. }
  315. [Fact]
  316. [AutoInitShutdown]
  317. public void
  318. ContentOffset_ContentSize_AutoHideScrollBars_ShowHorizontalScrollIndicator_ShowVerticalScrollIndicator ()
  319. {
  320. var sv = new ScrollView
  321. {
  322. Width = 10, Height = 10
  323. };
  324. sv.SetContentSize (new (50, 50));
  325. sv.ContentOffset = new (25, 25);
  326. var top = new Toplevel ();
  327. top.Add (sv);
  328. Application.Begin (top);
  329. Assert.Equal (new (-25, -25), sv.ContentOffset);
  330. Assert.Equal (new (50, 50), sv.GetContentSize ());
  331. Assert.True (sv.AutoHideScrollBars);
  332. Assert.True (sv.ShowHorizontalScrollIndicator);
  333. Assert.True (sv.ShowVerticalScrollIndicator);
  334. TestHelpers.AssertDriverContentsWithFrameAre (
  335. @"
  336. ◄░░░├─┤░►
  337. ",
  338. output
  339. );
  340. top.Dispose ();
  341. }
  342. [Fact]
  343. [AutoInitShutdown]
  344. public void ContentSize_AutoHideScrollBars_ShowHorizontalScrollIndicator_ShowVerticalScrollIndicator ()
  345. {
  346. var sv = new ScrollView { Width = 10, Height = 10 };
  347. sv.SetContentSize (new (50, 50));
  348. var top = new Toplevel ();
  349. top.Add (sv);
  350. Application.Begin (top);
  351. Assert.Equal (50, sv.GetContentSize ().Width);
  352. Assert.Equal (50, sv.GetContentSize ().Height);
  353. Assert.True (sv.AutoHideScrollBars);
  354. Assert.True (sv.ShowHorizontalScrollIndicator);
  355. Assert.True (sv.ShowVerticalScrollIndicator);
  356. TestHelpers.AssertDriverContentsWithFrameAre (
  357. @"
  358. ◄├┤░░░░░►
  359. ",
  360. output
  361. );
  362. top.Dispose ();
  363. }
  364. [Fact]
  365. [AutoInitShutdown]
  366. public void DrawTextFormatter_Respects_The_Clip_Bounds ()
  367. {
  368. var rule = "0123456789";
  369. Size size = new (40, 40);
  370. var view = new View { Frame = new (Point.Empty, size) };
  371. view.Add (
  372. new Label
  373. {
  374. Width = Dim.Fill (),
  375. Height = 1,
  376. Text = rule.Repeat (size.Width / rule.Length)
  377. }
  378. );
  379. view.Add (
  380. new Label
  381. {
  382. Height = Dim.Fill (),
  383. Width = 1,
  384. Text = rule.Repeat (size.Height / rule.Length),
  385. TextDirection = TextDirection.TopBottom_LeftRight
  386. }
  387. );
  388. view.Add (new Label { X = 1, Y = 1, Text = "[ Press me! ]" });
  389. var scrollView = new ScrollView
  390. {
  391. X = 1,
  392. Y = 1,
  393. Width = 15,
  394. Height = 10,
  395. ShowHorizontalScrollIndicator = true,
  396. ShowVerticalScrollIndicator = true
  397. };
  398. scrollView.SetContentSize (size);
  399. scrollView.Add (view);
  400. var win = new Window { X = 1, Y = 1, Width = 20, Height = 14 };
  401. win.Add (scrollView);
  402. var top = new Toplevel ();
  403. top.Add (win);
  404. Application.Begin (top);
  405. var expected = @"
  406. ┌──────────────────┐
  407. │ │
  408. │ 01234567890123▲ │
  409. │ 1[ Press me! ]┬ │
  410. │ 2 │ │
  411. │ 3 ┴ │
  412. │ 4 ░ │
  413. │ 5 ░ │
  414. │ 6 ░ │
  415. │ 7 ░ │
  416. │ 8 ▼ │
  417. │ ◄├───┤░░░░░░░► │
  418. │ │
  419. └──────────────────┘
  420. "
  421. ;
  422. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  423. Assert.Equal (new (1, 1, 21, 14), pos);
  424. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  425. top.Draw ();
  426. expected = @"
  427. ┌──────────────────┐
  428. │ │
  429. │ 12345678901234▲ │
  430. │ [ Press me! ] ┬ │
  431. │ │ │
  432. │ ┴ │
  433. │ ░ │
  434. │ ░ │
  435. │ ░ │
  436. │ ░ │
  437. │ ▼ │
  438. │ ◄├───┤░░░░░░░► │
  439. │ │
  440. └──────────────────┘
  441. "
  442. ;
  443. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  444. Assert.Equal (new (1, 1, 21, 14), pos);
  445. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  446. top.Draw ();
  447. expected = @"
  448. ┌──────────────────┐
  449. │ │
  450. │ 23456789012345▲ │
  451. │ Press me! ] ┬ │
  452. │ │ │
  453. │ ┴ │
  454. │ ░ │
  455. │ ░ │
  456. │ ░ │
  457. │ ░ │
  458. │ ▼ │
  459. │ ◄├────┤░░░░░░► │
  460. │ │
  461. └──────────────────┘
  462. "
  463. ;
  464. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  465. Assert.Equal (new (1, 1, 21, 14), pos);
  466. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  467. top.Draw ();
  468. expected = @"
  469. ┌──────────────────┐
  470. │ │
  471. │ 34567890123456▲ │
  472. │ Press me! ] ┬ │
  473. │ │ │
  474. │ ┴ │
  475. │ ░ │
  476. │ ░ │
  477. │ ░ │
  478. │ ░ │
  479. │ ▼ │
  480. │ ◄├────┤░░░░░░► │
  481. │ │
  482. └──────────────────┘
  483. "
  484. ;
  485. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  486. Assert.Equal (new (1, 1, 21, 14), pos);
  487. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  488. top.Draw ();
  489. expected = @"
  490. ┌──────────────────┐
  491. │ │
  492. │ 45678901234567▲ │
  493. │ ress me! ] ┬ │
  494. │ │ │
  495. │ ┴ │
  496. │ ░ │
  497. │ ░ │
  498. │ ░ │
  499. │ ░ │
  500. │ ▼ │
  501. │ ◄░├───┤░░░░░░► │
  502. │ │
  503. └──────────────────┘
  504. "
  505. ;
  506. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  507. Assert.Equal (new (1, 1, 21, 14), pos);
  508. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  509. top.Draw ();
  510. expected = @"
  511. ┌──────────────────┐
  512. │ │
  513. │ 56789012345678▲ │
  514. │ ess me! ] ┬ │
  515. │ │ │
  516. │ ┴ │
  517. │ ░ │
  518. │ ░ │
  519. │ ░ │
  520. │ ░ │
  521. │ ▼ │
  522. │ ◄░├────┤░░░░░► │
  523. │ │
  524. └──────────────────┘
  525. "
  526. ;
  527. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  528. Assert.Equal (new (1, 1, 21, 14), pos);
  529. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  530. top.Draw ();
  531. expected = @"
  532. ┌──────────────────┐
  533. │ │
  534. │ 67890123456789▲ │
  535. │ ss me! ] ┬ │
  536. │ │ │
  537. │ ┴ │
  538. │ ░ │
  539. │ ░ │
  540. │ ░ │
  541. │ ░ │
  542. │ ▼ │
  543. │ ◄░├────┤░░░░░► │
  544. │ │
  545. └──────────────────┘
  546. "
  547. ;
  548. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  549. Assert.Equal (new (1, 1, 21, 14), pos);
  550. Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
  551. top.Draw ();
  552. expected = @"
  553. ┌──────────────────┐
  554. │ │
  555. │ 78901234567890▲ │
  556. │ s me! ] ┬ │
  557. │ │ │
  558. │ ┴ │
  559. │ ░ │
  560. │ ░ │
  561. │ ░ │
  562. │ ░ │
  563. │ ▼ │
  564. │ ◄░░├───┤░░░░░► │
  565. │ │
  566. └──────────────────┘
  567. ";
  568. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  569. Assert.Equal (new (1, 1, 21, 14), pos);
  570. Assert.True (scrollView.NewKeyDownEvent (Key.End.WithCtrl));
  571. top.Draw ();
  572. expected = @"
  573. ┌──────────────────┐
  574. │ │
  575. │ 67890123456789▲ │
  576. │ ┬ │
  577. │ │ │
  578. │ ┴ │
  579. │ ░ │
  580. │ ░ │
  581. │ ░ │
  582. │ ░ │
  583. │ ▼ │
  584. │ ◄░░░░░░░├───┤► │
  585. │ │
  586. └──────────────────┘
  587. ";
  588. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  589. Assert.Equal (new (1, 1, 21, 14), pos);
  590. Assert.True (scrollView.NewKeyDownEvent (Key.Home.WithCtrl));
  591. Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
  592. top.Draw ();
  593. expected = @"
  594. ┌──────────────────┐
  595. │ │
  596. │ 1[ Press me! ]▲ │
  597. │ 2 ┬ │
  598. │ 3 │ │
  599. │ 4 ┴ │
  600. │ 5 ░ │
  601. │ 6 ░ │
  602. │ 7 ░ │
  603. │ 8 ░ │
  604. │ 9 ▼ │
  605. │ ◄├───┤░░░░░░░► │
  606. │ │
  607. └──────────────────┘
  608. ";
  609. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  610. Assert.Equal (new (1, 1, 21, 14), pos);
  611. Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
  612. top.Draw ();
  613. expected = @"
  614. ┌──────────────────┐
  615. │ │
  616. │ 2 ▲ │
  617. │ 3 ┬ │
  618. │ 4 │ │
  619. │ 5 ┴ │
  620. │ 6 ░ │
  621. │ 7 ░ │
  622. │ 8 ░ │
  623. │ 9 ░ │
  624. │ 0 ▼ │
  625. │ ◄├───┤░░░░░░░► │
  626. │ │
  627. └──────────────────┘
  628. ";
  629. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  630. Assert.Equal (new (1, 1, 21, 14), pos);
  631. Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
  632. top.Draw ();
  633. expected = @"
  634. ┌──────────────────┐
  635. │ │
  636. │ 3 ▲ │
  637. │ 4 ┬ │
  638. │ 5 │ │
  639. │ 6 ┴ │
  640. │ 7 ░ │
  641. │ 8 ░ │
  642. │ 9 ░ │
  643. │ 0 ░ │
  644. │ 1 ▼ │
  645. │ ◄├───┤░░░░░░░► │
  646. │ │
  647. └──────────────────┘
  648. ";
  649. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  650. Assert.Equal (new (1, 1, 21, 14), pos);
  651. Assert.True (scrollView.NewKeyDownEvent (Key.End));
  652. top.Draw ();
  653. expected = @"
  654. ┌──────────────────┐
  655. │ │
  656. │ 1 ▲ │
  657. │ 2 ░ │
  658. │ 3 ░ │
  659. │ 4 ░ │
  660. │ 5 ░ │
  661. │ 6 ░ │
  662. │ 7 ┬ │
  663. │ 8 ┴ │
  664. │ 9 ▼ │
  665. │ ◄├───┤░░░░░░░► │
  666. │ │
  667. └──────────────────┘
  668. ";
  669. TestHelpers.AssertDriverContentsAre (expected, output);
  670. top.Dispose ();
  671. }
  672. // There still have an issue with lower right corner of the scroll view
  673. [Fact]
  674. [AutoInitShutdown]
  675. public void Frame_And_Labels_Does_Not_Overspill_ScrollView ()
  676. {
  677. var sv = new ScrollView
  678. {
  679. X = 3,
  680. Y = 3,
  681. Width = 10,
  682. Height = 10,
  683. TabStop = TabBehavior.TabStop
  684. };
  685. sv.SetContentSize (new (50, 50));
  686. for (var i = 0; i < 8; i++)
  687. {
  688. sv.Add (new CustomButton ("█", $"Button {i}", 20, 3) { Y = i * 3 });
  689. }
  690. var top = new Toplevel ();
  691. top.Add (sv);
  692. Application.Begin (top);
  693. TestHelpers.AssertDriverContentsWithFrameAre (
  694. @"
  695. █████████▲
  696. ██████But┬
  697. █████████┴
  698. ┌────────░
  699. │ But░
  700. └────────░
  701. ┌────────░
  702. │ But░
  703. └────────▼
  704. ◄├┤░░░░░► ",
  705. output
  706. );
  707. sv.ContentOffset = new (5, 5);
  708. sv.LayoutSubviews ();
  709. Application.Refresh ();
  710. TestHelpers.AssertDriverContentsWithFrameAre (
  711. @"
  712. ─────────▲
  713. ─────────┬
  714. Button 2│
  715. ─────────┴
  716. ─────────░
  717. Button 3░
  718. ─────────░
  719. ─────────░
  720. Button 4▼
  721. ◄├─┤░░░░► ",
  722. output
  723. );
  724. top.Dispose ();
  725. }
  726. [Fact]
  727. public void KeyBindings_Command ()
  728. {
  729. var sv = new ScrollView { Width = 20, Height = 10 };
  730. sv.SetContentSize (new (40, 20));
  731. sv.Add (
  732. new View { Width = 20, Height = 5 },
  733. new View { X = 22, Y = 7, Width = 10, Height = 5 }
  734. );
  735. sv.BeginInit ();
  736. sv.EndInit ();
  737. Assert.True (sv.KeepContentAlwaysInViewport);
  738. Assert.True (sv.AutoHideScrollBars);
  739. Assert.Equal (Point.Empty, sv.ContentOffset);
  740. Assert.False (sv.NewKeyDownEvent (Key.CursorUp));
  741. Assert.Equal (Point.Empty, sv.ContentOffset);
  742. Assert.True (sv.NewKeyDownEvent (Key.CursorDown));
  743. Assert.Equal (new (0, -1), sv.ContentOffset);
  744. Assert.True (sv.NewKeyDownEvent (Key.CursorUp));
  745. Assert.Equal (Point.Empty, sv.ContentOffset);
  746. Assert.False (sv.NewKeyDownEvent (Key.PageUp));
  747. Assert.Equal (Point.Empty, sv.ContentOffset);
  748. Assert.True (sv.NewKeyDownEvent (Key.PageDown));
  749. Point point0xMinus10 = new (0, -10);
  750. Assert.Equal (point0xMinus10, sv.ContentOffset);
  751. Assert.False (sv.NewKeyDownEvent (Key.PageDown));
  752. Assert.Equal (point0xMinus10, sv.ContentOffset);
  753. Assert.False (sv.NewKeyDownEvent (Key.CursorDown));
  754. Assert.Equal (point0xMinus10, sv.ContentOffset);
  755. Assert.True (sv.NewKeyDownEvent (Key.V.WithAlt));
  756. Assert.Equal (Point.Empty, sv.ContentOffset);
  757. Assert.True (sv.NewKeyDownEvent (Key.V.WithCtrl));
  758. Assert.Equal (point0xMinus10, sv.ContentOffset);
  759. Assert.False (sv.NewKeyDownEvent (Key.CursorLeft));
  760. Assert.Equal (point0xMinus10, sv.ContentOffset);
  761. Assert.True (sv.NewKeyDownEvent (Key.CursorRight));
  762. Assert.Equal (new (-1, -10), sv.ContentOffset);
  763. Assert.True (sv.NewKeyDownEvent (Key.CursorLeft));
  764. Assert.Equal (point0xMinus10, sv.ContentOffset);
  765. Assert.False (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
  766. Assert.Equal (point0xMinus10, sv.ContentOffset);
  767. Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
  768. Point pointMinus20xMinus10 = new (-20, -10);
  769. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  770. Assert.False (sv.NewKeyDownEvent (Key.CursorRight));
  771. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  772. Assert.True (sv.NewKeyDownEvent (Key.Home));
  773. Point pointMinus20x0 = new (-20, 0);
  774. Assert.Equal (pointMinus20x0, sv.ContentOffset);
  775. Assert.False (sv.NewKeyDownEvent (Key.Home));
  776. Assert.Equal (pointMinus20x0, sv.ContentOffset);
  777. Assert.True (sv.NewKeyDownEvent (Key.End));
  778. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  779. Assert.False (sv.NewKeyDownEvent (Key.End));
  780. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  781. Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
  782. Assert.Equal (point0xMinus10, sv.ContentOffset);
  783. Assert.False (sv.NewKeyDownEvent (Key.Home.WithCtrl));
  784. Assert.Equal (point0xMinus10, sv.ContentOffset);
  785. Assert.True (sv.NewKeyDownEvent (Key.End.WithCtrl));
  786. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  787. Assert.False (sv.NewKeyDownEvent (Key.End.WithCtrl));
  788. Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
  789. Assert.True (sv.NewKeyDownEvent (Key.Home));
  790. Assert.Equal (pointMinus20x0, sv.ContentOffset);
  791. Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
  792. Assert.Equal (Point.Empty, sv.ContentOffset);
  793. sv.KeepContentAlwaysInViewport = false;
  794. Assert.False (sv.KeepContentAlwaysInViewport);
  795. Assert.True (sv.AutoHideScrollBars);
  796. Assert.Equal (Point.Empty, sv.ContentOffset);
  797. Assert.False (sv.NewKeyDownEvent (Key.CursorUp));
  798. Assert.Equal (Point.Empty, sv.ContentOffset);
  799. Assert.True (sv.NewKeyDownEvent (Key.CursorDown));
  800. Assert.Equal (new (0, -1), sv.ContentOffset);
  801. Assert.True (sv.NewKeyDownEvent (Key.CursorUp));
  802. Assert.Equal (Point.Empty, sv.ContentOffset);
  803. Assert.False (sv.NewKeyDownEvent (Key.PageUp));
  804. Assert.Equal (Point.Empty, sv.ContentOffset);
  805. Assert.True (sv.NewKeyDownEvent (Key.PageDown));
  806. Assert.Equal (point0xMinus10, sv.ContentOffset);
  807. Assert.True (sv.NewKeyDownEvent (Key.PageDown));
  808. Point point0xMinus19 = new (0, -19);
  809. Assert.Equal (point0xMinus19, sv.ContentOffset);
  810. Assert.False (sv.NewKeyDownEvent (Key.PageDown));
  811. Assert.Equal (point0xMinus19, sv.ContentOffset);
  812. Assert.False (sv.NewKeyDownEvent (Key.CursorDown));
  813. Assert.Equal (point0xMinus19, sv.ContentOffset);
  814. Assert.True (sv.NewKeyDownEvent (Key.V.WithAlt));
  815. Assert.Equal (new (0, -9), sv.ContentOffset);
  816. Assert.True (sv.NewKeyDownEvent (Key.V.WithCtrl));
  817. Assert.Equal (point0xMinus19, sv.ContentOffset);
  818. Assert.False (sv.NewKeyDownEvent (Key.CursorLeft));
  819. Assert.Equal (point0xMinus19, sv.ContentOffset);
  820. Assert.True (sv.NewKeyDownEvent (Key.CursorRight));
  821. Assert.Equal (new (-1, -19), sv.ContentOffset);
  822. Assert.True (sv.NewKeyDownEvent (Key.CursorLeft));
  823. Assert.Equal (point0xMinus19, sv.ContentOffset);
  824. Assert.False (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
  825. Assert.Equal (point0xMinus19, sv.ContentOffset);
  826. Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
  827. Assert.Equal (new (-20, -19), sv.ContentOffset);
  828. Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
  829. Point pointMinus39xMinus19 = new (-39, -19);
  830. Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
  831. Assert.False (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
  832. Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
  833. Assert.False (sv.NewKeyDownEvent (Key.CursorRight));
  834. Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
  835. Assert.True (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
  836. var pointMinus19xMinus19 = new Point (-19, -19);
  837. Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
  838. Assert.True (sv.NewKeyDownEvent (Key.Home));
  839. Assert.Equal (new (-19, 0), sv.ContentOffset);
  840. Assert.False (sv.NewKeyDownEvent (Key.Home));
  841. Assert.Equal (new (-19, 0), sv.ContentOffset);
  842. Assert.True (sv.NewKeyDownEvent (Key.End));
  843. Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
  844. Assert.False (sv.NewKeyDownEvent (Key.End));
  845. Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
  846. Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
  847. Assert.Equal (point0xMinus19, sv.ContentOffset);
  848. Assert.False (sv.NewKeyDownEvent (Key.Home.WithCtrl));
  849. Assert.Equal (point0xMinus19, sv.ContentOffset);
  850. Assert.True (sv.NewKeyDownEvent (Key.End.WithCtrl));
  851. Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
  852. Assert.False (sv.NewKeyDownEvent (Key.End.WithCtrl));
  853. Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
  854. }
  855. [Fact]
  856. [AutoInitShutdown]
  857. public void Remove_Added_View_Is_Allowed ()
  858. {
  859. var sv = new ScrollView { Width = 20, Height = 20 };
  860. sv.SetContentSize (new (100, 100));
  861. sv.Add (
  862. new View { Width = Dim.Fill (), Height = Dim.Fill (50), Id = "View1" },
  863. new View { Y = 51, Width = Dim.Fill (), Height = Dim.Fill (), Id = "View2" }
  864. );
  865. var top = new Toplevel ();
  866. top.Add (sv);
  867. Application.Begin (top);
  868. Assert.Equal (4, sv.Subviews.Count);
  869. Assert.Equal (2, sv.Subviews [0].Subviews.Count);
  870. sv.Remove (sv.Subviews [0].Subviews [1]);
  871. Assert.Equal (4, sv.Subviews.Count);
  872. Assert.Single (sv.Subviews [0].Subviews);
  873. Assert.Equal ("View1", sv.Subviews [0].Subviews [0].Id);
  874. top.Dispose ();
  875. }
  876. private class CustomButton : FrameView
  877. {
  878. private readonly Label labelFill;
  879. private readonly Label labelText;
  880. public CustomButton (string fill, string text, int width, int height)
  881. {
  882. Width = width;
  883. Height = height;
  884. labelFill = new () { Width = Dim.Fill (), Height = Dim.Fill (), Visible = false };
  885. labelFill.LayoutComplete += (s, e) =>
  886. {
  887. var fillText = new StringBuilder ();
  888. for (var i = 0; i < labelFill.Viewport.Height; i++)
  889. {
  890. if (i > 0)
  891. {
  892. fillText.AppendLine ("");
  893. }
  894. for (var j = 0; j < labelFill.Viewport.Width; j++)
  895. {
  896. fillText.Append (fill);
  897. }
  898. }
  899. labelFill.Text = fillText.ToString ();
  900. };
  901. labelText = new () { X = Pos.Center (), Y = Pos.Center (), Text = text };
  902. Add (labelFill, labelText);
  903. CanFocus = true;
  904. }
  905. protected override void OnHasFocusChanged (bool newHasFocus, [CanBeNull] View previousFocusedView, [CanBeNull] View focusedVew)
  906. {
  907. if (newHasFocus)
  908. {
  909. Border.LineStyle = LineStyle.None;
  910. Border.Thickness = new (0);
  911. labelFill.Visible = true;
  912. }
  913. else
  914. {
  915. Border.LineStyle = LineStyle.Single;
  916. Border.Thickness = new (1);
  917. labelFill.Visible = false;
  918. }
  919. }
  920. }
  921. }