ListContainerTest.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Numerics;
  5. using Content.Client.UserInterface.Controls;
  6. using NUnit.Framework;
  7. using Robust.Client.UserInterface;
  8. using Robust.Client.UserInterface.Controls;
  9. using Robust.Shared.IoC;
  10. using Robust.Shared.Maths;
  11. using Robust.UnitTesting;
  12. namespace Content.Tests.Client.UserInterface.Controls;
  13. [TestFixture]
  14. [TestOf(typeof(ListContainer))]
  15. public sealed class ListContainerTest : RobustUnitTest
  16. {
  17. public override UnitTestProject Project => UnitTestProject.Client;
  18. private record TestListData(int Id) : ListData;
  19. [OneTimeSetUp]
  20. public void Setup()
  21. {
  22. IoCManager.Resolve<IUserInterfaceManager>().InitializeTesting();
  23. }
  24. [Test]
  25. public void TestLayoutBasic()
  26. {
  27. var root = new Control { MinSize = new Vector2(50, 60) };
  28. var listContainer = new ListContainer { SeparationOverride = 3 };
  29. root.AddChild(listContainer);
  30. listContainer.GenerateItem += (_, button) => {
  31. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  32. };
  33. var list = new List<TestListData> {new(0), new(1)};
  34. listContainer.PopulateList(list);
  35. root.Arrange(new UIBox2(0, 0, 50, 60));
  36. Assert.That(listContainer.ChildCount, Is.EqualTo(3));
  37. var children = listContainer.Children.ToList();
  38. Assert.That(children[0].Height, Is.EqualTo(10));
  39. Assert.That(children[1].Height, Is.EqualTo(10));
  40. Assert.That(children[0].Position.Y, Is.EqualTo(0));
  41. Assert.That(children[1].Position.Y, Is.EqualTo(13)); // Item height + separation
  42. }
  43. [Test]
  44. public void TestCreatePopulateAndEmpty()
  45. {
  46. const int x = 50;
  47. const int y = 10;
  48. var root = new Control { MinSize = new Vector2(x, y) };
  49. var listContainer = new ListContainer { SeparationOverride = 3 };
  50. root.AddChild(listContainer);
  51. listContainer.GenerateItem += (_, button) => {
  52. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  53. };
  54. var list = new List<TestListData>();
  55. listContainer.PopulateList(list);
  56. root.Arrange(new UIBox2(0, 0, x, y));
  57. list.Add(new(0));
  58. list.Add(new (1));
  59. listContainer.PopulateList(list);
  60. root.Arrange(new UIBox2(0, 0, x, y));
  61. list.Clear();
  62. listContainer.PopulateList(list);
  63. root.Arrange(new UIBox2(0, 0, x, y));
  64. }
  65. [Test]
  66. public void TestOnlyVisibleItemsAreAdded()
  67. {
  68. /*
  69. * 6 items * 10 height + 5 separation * 3 height = 75
  70. * One item should be off the render
  71. * 0 13 26 39 52 65 | 75 height
  72. */
  73. var root = new Control { MinSize = new Vector2(50, 60) };
  74. var listContainer = new ListContainer { SeparationOverride = 3 };
  75. root.AddChild(listContainer);
  76. listContainer.GenerateItem += (_, button) => {
  77. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  78. };
  79. var list = new List<TestListData> {new(0), new(1), new(2), new(3), new(4), new(5)};
  80. listContainer.PopulateList(list);
  81. root.Arrange(new UIBox2(0, 0, 50, 60));
  82. // 6 ControlData
  83. Assert.That(listContainer.Data.Count, Is.EqualTo(6));
  84. // 5 Buttons, 1 Scrollbar
  85. Assert.That(listContainer.ChildCount, Is.EqualTo(6));
  86. var children = listContainer.Children.ToList();
  87. foreach (var child in children)
  88. {
  89. if (child is not ListContainerButton)
  90. continue;
  91. Assert.That(child.Height, Is.EqualTo(10));
  92. }
  93. Assert.That(children[0].Position.Y, Is.EqualTo(0));
  94. Assert.That(children[1].Position.Y, Is.EqualTo(13));
  95. Assert.That(children[2].Position.Y, Is.EqualTo(26));
  96. Assert.That(children[3].Position.Y, Is.EqualTo(39));
  97. Assert.That(children[4].Position.Y, Is.EqualTo(52));
  98. }
  99. [Test]
  100. public void TestNextItemIsVisibleWhenScrolled()
  101. {
  102. /*
  103. * 6 items * 10 height + 5 separation * 3 height = 75
  104. * One items should be off the render
  105. * 0 13 26 39 52 65 | 75 height
  106. */
  107. var root = new Control { MinSize = new Vector2(50, 60) };
  108. var listContainer = new ListContainer { SeparationOverride = 3 };
  109. root.AddChild(listContainer);
  110. listContainer.GenerateItem += (_, button) => {
  111. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  112. };
  113. var list = new List<TestListData> {new(0), new(1), new(2), new(3), new(4), new(5)};
  114. listContainer.PopulateList(list);
  115. root.Arrange(new UIBox2(0, 0, 50, 60));
  116. var scrollbar = (ScrollBar) listContainer.Children.Last(c => c is ScrollBar);
  117. // Test that 6th button is not visible when scrolled
  118. scrollbar.Value = 5;
  119. listContainer.Arrange(root.SizeBox);
  120. var children = listContainer.Children.ToList();
  121. // 5 Buttons, 1 Scrollbar
  122. Assert.That(listContainer.ChildCount, Is.EqualTo(6));
  123. Assert.That(children[0].Position.Y, Is.EqualTo(-5));
  124. Assert.That(children[1].Position.Y, Is.EqualTo(8));
  125. Assert.That(children[2].Position.Y, Is.EqualTo(21));
  126. Assert.That(children[3].Position.Y, Is.EqualTo(34));
  127. Assert.That(children[4].Position.Y, Is.EqualTo(47));
  128. // Test that 6th button is visible when scrolled
  129. scrollbar.Value = 6;
  130. listContainer.Arrange(root.SizeBox);
  131. children = listContainer.Children.ToList();
  132. // 6 Buttons, 1 Scrollbar
  133. Assert.That(listContainer.ChildCount, Is.EqualTo(7));
  134. Assert.That(Math.Abs(scrollbar.Value - 6), Is.LessThan(0.01f));
  135. Assert.That(children[0].Position.Y, Is.EqualTo(-6));
  136. Assert.That(children[1].Position.Y, Is.EqualTo(7));
  137. Assert.That(children[2].Position.Y, Is.EqualTo(20));
  138. Assert.That(children[3].Position.Y, Is.EqualTo(33));
  139. Assert.That(children[4].Position.Y, Is.EqualTo(46));
  140. Assert.That(children[5].Position.Y, Is.EqualTo(59));
  141. }
  142. [Test]
  143. public void TestPreviousItemIsVisibleWhenScrolled()
  144. {
  145. /*
  146. * 6 items * 10 height + 5 separation * 3 height = 75
  147. * One items should be off the render
  148. * 0 13 26 39 52 65 | 75 height
  149. */
  150. var root = new Control { MinSize = new Vector2(50, 60) };
  151. var listContainer = new ListContainer { SeparationOverride = 3 };
  152. root.AddChild(listContainer);
  153. listContainer.GenerateItem += (_, button) => {
  154. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  155. };
  156. var list = new List<TestListData> {new(0), new(1), new(2), new(3), new(4), new(5)};
  157. listContainer.PopulateList(list);
  158. root.Arrange(new UIBox2(0, 0, 50, 60));
  159. var scrollbar = (ScrollBar) listContainer.Children.Last(c => c is ScrollBar);
  160. var scrollValue = 9;
  161. // Test that 6th button is not visible when scrolled
  162. scrollbar.Value = scrollValue;
  163. listContainer.Arrange(root.SizeBox);
  164. var children = listContainer.Children.ToList();
  165. // 6 Buttons, 1 Scrollbar
  166. Assert.That(listContainer.ChildCount, Is.EqualTo(7));
  167. Assert.That(children[0].Position.Y, Is.EqualTo(-9));
  168. Assert.That(children[1].Position.Y, Is.EqualTo(4));
  169. Assert.That(children[2].Position.Y, Is.EqualTo(17));
  170. Assert.That(children[3].Position.Y, Is.EqualTo(30));
  171. Assert.That(children[4].Position.Y, Is.EqualTo(43));
  172. Assert.That(children[5].Position.Y, Is.EqualTo(56));
  173. // Test that 6th button is visible when scrolled
  174. scrollValue = 10;
  175. scrollbar.Value = scrollValue;
  176. listContainer.Arrange(root.SizeBox);
  177. children = listContainer.Children.ToList();
  178. // 5 Buttons, 1 Scrollbar
  179. Assert.That(listContainer.ChildCount, Is.EqualTo(6));
  180. Assert.That(Math.Abs(scrollbar.Value - scrollValue), Is.LessThan(0.01f));
  181. Assert.That(children[0].Position.Y, Is.EqualTo(3));
  182. Assert.That(children[1].Position.Y, Is.EqualTo(16));
  183. Assert.That(children[2].Position.Y, Is.EqualTo(29));
  184. Assert.That(children[3].Position.Y, Is.EqualTo(42));
  185. Assert.That(children[4].Position.Y, Is.EqualTo(55));
  186. }
  187. /// <summary>
  188. /// Test that the ListContainer doesn't push other Controls
  189. /// </summary>
  190. [Test]
  191. public void TestDoesNotExpandWhenChildrenAreAdded()
  192. {
  193. var height = 60;
  194. var root = new BoxContainer
  195. {
  196. Orientation = BoxContainer.LayoutOrientation.Vertical,
  197. MinSize = new Vector2(50, height)
  198. };
  199. var listContainer = new ListContainer
  200. {
  201. SeparationOverride = 0,
  202. GenerateItem = (_, button) => { button.AddChild(new Control {MinSize = new Vector2(10, 10)}); }
  203. };
  204. root.AddChild(listContainer);
  205. var button = new ContainerButton
  206. {
  207. MinSize = new Vector2(10, 10)
  208. };
  209. root.AddChild(button);
  210. var list = new List<TestListData> {new(0), new(1), new(2), new(3), new(4), new(5)};
  211. listContainer.PopulateList(list);
  212. root.Arrange(new UIBox2(0, 0, 50, height));
  213. var children = listContainer.Children.ToList();
  214. // 6 Buttons, 1 Scrollbar
  215. Assert.That(listContainer.ChildCount, Is.EqualTo(6));
  216. Assert.That(children[0].Position.Y, Is.EqualTo(0));
  217. Assert.That(children[1].Position.Y, Is.EqualTo(10));
  218. Assert.That(children[2].Position.Y, Is.EqualTo(20));
  219. Assert.That(children[3].Position.Y, Is.EqualTo(30));
  220. Assert.That(children[4].Position.Y, Is.EqualTo(40));
  221. Assert.That(button.Position.Y, Is.EqualTo(50));
  222. }
  223. [Test]
  224. public void TestSelectedItemStillSelectedWhenScrolling()
  225. {
  226. var height = 10;
  227. var root = new Control { MinSize = new Vector2(50, height) };
  228. var listContainer = new ListContainer { SeparationOverride = 0, Toggle = true };
  229. root.AddChild(listContainer);
  230. listContainer.GenerateItem += (_, button) => {
  231. button.AddChild(new Control { MinSize = new Vector2(10, 10) });
  232. };
  233. var list = new List<TestListData> {new(0), new(1), new(2), new(3), new(4), new(5)};
  234. listContainer.PopulateList(list);
  235. root.Arrange(new UIBox2(0, 0, 50, height));
  236. var scrollbar = (ScrollBar) listContainer.Children.Last(c => c is ScrollBar);
  237. var children = listContainer.Children.ToList();
  238. if (children[0] is not ListContainerButton oldButton)
  239. throw new Exception("First child of ListContainer is not a button");
  240. listContainer.Select(oldButton.Data);
  241. // Test that the button is selected even when scrolled away and scrolled back.
  242. scrollbar.Value = 11;
  243. listContainer.Arrange(root.SizeBox);
  244. Assert.That(oldButton.Disposed);
  245. scrollbar.Value = 0;
  246. listContainer.Arrange(root.SizeBox);
  247. children = listContainer.Children.ToList();
  248. if (children[0] is not ListContainerButton newButton)
  249. throw new Exception("First child of ListContainer is not a button");
  250. Assert.That(newButton.Pressed);
  251. Assert.That(newButton.Disposed == false);
  252. }
  253. }