2
0

ClipTests.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #nullable enable
  2. using System.Text;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewTests;
  5. [Trait ("Category", "Output")]
  6. public class ClipTests (ITestOutputHelper _output)
  7. {
  8. [Fact]
  9. [SetupFakeDriver]
  10. public void Move_Is_Not_Constrained_To_Viewport ()
  11. {
  12. var view = new View
  13. {
  14. X = 1,
  15. Y = 1,
  16. Width = 3, Height = 3
  17. };
  18. view.Margin!.Thickness = new (1);
  19. view.Move (0, 0);
  20. Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
  21. view.Move (-1, -1);
  22. Assert.Equal (new (1, 1), new Point (Application.Driver!.Col, Application.Driver!.Row));
  23. view.Move (1, 1);
  24. Assert.Equal (new (3, 3), new Point (Application.Driver!.Col, Application.Driver!.Row));
  25. }
  26. [Fact]
  27. [SetupFakeDriver]
  28. public void AddRune_Is_Constrained_To_Viewport ()
  29. {
  30. var view = new View
  31. {
  32. X = 1,
  33. Y = 1,
  34. Width = 3, Height = 3
  35. };
  36. view.Padding!.Thickness = new (1);
  37. view.Padding.Diagnostics = ViewDiagnosticFlags.Thickness;
  38. view.BeginInit ();
  39. view.EndInit ();
  40. view.Draw ();
  41. // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen)
  42. Assert.Equal ((Rune)' ', Application.Driver?.Contents! [2, 2].Rune);
  43. // When we exit Draw, the view is excluded from the clip. So drawing at 0,0, is not valid and is clipped.
  44. view.AddRune (0, 0, Rune.ReplacementChar);
  45. Assert.Equal ((Rune)' ', Application.Driver?.Contents! [2, 2].Rune);
  46. view.AddRune (-1, -1, Rune.ReplacementChar);
  47. Assert.Equal ((Rune)'P', Application.Driver?.Contents! [1, 1].Rune);
  48. view.AddRune (1, 1, Rune.ReplacementChar);
  49. Assert.Equal ((Rune)'P', Application.Driver?.Contents! [3, 3].Rune);
  50. }
  51. [Theory]
  52. [InlineData (0, 0, 1, 1)]
  53. [InlineData (0, 0, 2, 2)]
  54. [InlineData (-1, -1, 2, 2)]
  55. [SetupFakeDriver]
  56. public void FillRect_Fills_HonorsClip (int x, int y, int width, int height)
  57. {
  58. var superView = new View { Width = Dim.Fill (), Height = Dim.Fill () };
  59. var view = new View
  60. {
  61. Text = "X",
  62. X = 1, Y = 1,
  63. Width = 3, Height = 3,
  64. BorderStyle = LineStyle.Single
  65. };
  66. superView.Add (view);
  67. superView.BeginInit ();
  68. superView.EndInit ();
  69. superView.LayoutSubviews ();
  70. superView.Draw ();
  71. TestHelpers.AssertDriverContentsWithFrameAre (
  72. @"
  73. ┌─┐
  74. │X│
  75. └─┘",
  76. _output);
  77. Rectangle toFill = new (x, y, width, height);
  78. View.SetClipToScreen ();
  79. view.FillRect (toFill);
  80. TestHelpers.AssertDriverContentsWithFrameAre (
  81. @"
  82. ┌─┐
  83. │ │
  84. └─┘",
  85. _output);
  86. // Now try to clear beyond Viewport (invalid; clipping should prevent)
  87. superView.SetNeedsDraw ();
  88. superView.Draw ();
  89. TestHelpers.AssertDriverContentsWithFrameAre (
  90. @"
  91. ┌─┐
  92. │X│
  93. └─┘",
  94. _output);
  95. toFill = new (-width, -height, width, height);
  96. view.FillRect (toFill);
  97. TestHelpers.AssertDriverContentsWithFrameAre (
  98. @"
  99. ┌─┐
  100. │X│
  101. └─┘",
  102. _output);
  103. // Now try to clear beyond Viewport (valid)
  104. superView.SetNeedsDraw ();
  105. superView.Draw ();
  106. TestHelpers.AssertDriverContentsWithFrameAre (
  107. @"
  108. ┌─┐
  109. │X│
  110. └─┘",
  111. _output);
  112. toFill = new (-1, -1, width + 1, height + 1);
  113. View.SetClipToScreen ();
  114. view.FillRect (toFill);
  115. TestHelpers.AssertDriverContentsWithFrameAre (
  116. @"
  117. ┌─┐
  118. │ │
  119. └─┘",
  120. _output);
  121. // Now clear too much size
  122. superView.SetNeedsDraw ();
  123. superView.Draw ();
  124. TestHelpers.AssertDriverContentsWithFrameAre (
  125. @"
  126. ┌─┐
  127. │X│
  128. └─┘",
  129. _output);
  130. toFill = new (0, 0, width * 2, height * 2);
  131. View.SetClipToScreen ();
  132. view.FillRect (toFill);
  133. TestHelpers.AssertDriverContentsWithFrameAre (
  134. @"
  135. ┌─┐
  136. │ │
  137. └─┘",
  138. _output);
  139. }
  140. // TODO: Simplify this test to just use AddRune directly
  141. [Fact]
  142. [SetupFakeDriver]
  143. [Trait ("Category", "Unicode")]
  144. public void Clipping_Wide_Runes ()
  145. {
  146. ((FakeDriver)Application.Driver!).SetBufferSize (30, 1);
  147. var top = new View
  148. {
  149. Id = "top",
  150. Width = Dim.Fill (),
  151. Height = Dim.Fill ()
  152. };
  153. var frameView = new View
  154. {
  155. Id = "frameView",
  156. Width = Dim.Fill (),
  157. Height = Dim.Fill (),
  158. Text = """
  159. これは広いルーンラインです。
  160. """
  161. };
  162. frameView.Border!.LineStyle = LineStyle.Single;
  163. frameView.Border.Thickness = new (1, 0, 0, 0);
  164. top.Add (frameView);
  165. View.SetClipToScreen ();
  166. top.Layout ();
  167. top.Draw ();
  168. var expectedOutput = """
  169. │これは広いルーンラインです。
  170. """;
  171. TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  172. var view = new View
  173. {
  174. Text = "0123456789",
  175. //Text = "ワイドルー。",
  176. X = 2,
  177. Height = Dim.Auto (),
  178. Width = Dim.Auto (),
  179. BorderStyle = LineStyle.Single
  180. };
  181. view.Border!.Thickness = new (1, 0, 1, 0);
  182. top.Add (view);
  183. top.Layout ();
  184. View.SetClipToScreen ();
  185. top.Draw ();
  186. // 012345678901234567890123456789012345678
  187. // 012 34 56 78 90 12 34 56 78 90 12 34 56 78
  188. // │こ れ は 広 い ル ー ン ラ イ ン で す 。
  189. // 01 2345678901234 56 78 90 12 34 56
  190. // │� |0123456989│� ン ラ イ ン で す 。
  191. expectedOutput = """
  192. │�│0123456789│�ンラインです。
  193. """;
  194. TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  195. }
  196. // TODO: Add more AddRune tests to cover all the cases where wide runes are clipped
  197. [Fact]
  198. [SetupFakeDriver]
  199. public void SetClip_ClipVisibleContentOnly_VisibleContentIsClipped ()
  200. {
  201. // Screen is 25x25
  202. // View is 25x25
  203. // Viewport is (0, 0, 23, 23)
  204. // ContentSize is (10, 10)
  205. // ViewportToScreen is (1, 1, 23, 23)
  206. // Visible content is (1, 1, 10, 10)
  207. // Expected clip is (1, 1, 10, 10) - same as visible content
  208. Rectangle expectedClip = new (1, 1, 10, 10);
  209. // Arrange
  210. var view = new View
  211. {
  212. Width = Dim.Fill (),
  213. Height = Dim.Fill (),
  214. ViewportSettings = ViewportSettings.ClipContentOnly
  215. };
  216. view.SetContentSize (new Size (10, 10));
  217. view.Border!.Thickness = new (1);
  218. view.BeginInit ();
  219. view.EndInit ();
  220. Assert.Equal (view.Frame, View.GetClip ()!.GetBounds ());
  221. // Act
  222. view.AddViewportToClip ();
  223. // Assert
  224. Assert.Equal (expectedClip, View.GetClip ()!.GetBounds ());
  225. view.Dispose ();
  226. }
  227. [Fact]
  228. [SetupFakeDriver]
  229. public void SetClip_Default_ClipsToViewport ()
  230. {
  231. // Screen is 25x25
  232. // View is 25x25
  233. // Viewport is (0, 0, 23, 23)
  234. // ContentSize is (10, 10)
  235. // ViewportToScreen is (1, 1, 23, 23)
  236. // Visible content is (1, 1, 10, 10)
  237. // Expected clip is (1, 1, 23, 23) - same as Viewport
  238. Rectangle expectedClip = new (1, 1, 23, 23);
  239. // Arrange
  240. var view = new View
  241. {
  242. Width = Dim.Fill (),
  243. Height = Dim.Fill ()
  244. };
  245. view.SetContentSize (new Size (10, 10));
  246. view.Border!.Thickness = new (1);
  247. view.BeginInit ();
  248. view.EndInit ();
  249. Assert.Equal (view.Frame, View.GetClip ()!.GetBounds ());
  250. view.Viewport = view.Viewport with { X = 1, Y = 1 };
  251. // Act
  252. view.AddViewportToClip ();
  253. // Assert
  254. Assert.Equal (expectedClip, View.GetClip ()!.GetBounds ());
  255. view.Dispose ();
  256. }
  257. }