ComputedLayout.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using Terminal.Gui;
  6. namespace UICatalog.Scenarios {
  7. /// <summary>
  8. /// This Scenario demonstrates how to use Termina.gui's Dim and Pos Layout System.
  9. /// [x] - Using Dim.Fill to fill a window
  10. /// [x] - Using Dim.Fill and Dim.Pos to automatically align controls based on an initial control
  11. /// [ ] - ...
  12. /// </summary>
  13. [ScenarioMetadata (Name: "Computed Layout", Description: "Demonstrates the Computed (Dim and Pos) Layout System.")]
  14. [ScenarioCategory ("Layout")]
  15. public class ComputedLayout : Scenario {
  16. public override void Init ()
  17. {
  18. Application.Init ();
  19. ConfigurationManager.Themes.Theme = Theme;
  20. ConfigurationManager.Apply ();
  21. Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
  22. }
  23. public override void Setup ()
  24. {
  25. // Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width
  26. const string rule = "|123456789";
  27. var horizontalRuler = new Label (rule, false) {
  28. AutoSize = false,
  29. X = 0,
  30. Y = 0,
  31. Width = Dim.Fill (),
  32. Height = 1,
  33. ColorScheme = Colors.Error
  34. };
  35. Application.Top.Add (horizontalRuler);
  36. // Demonstrate using Dim to create a vertical ruler that always measures the parent window's height
  37. const string vrule = "|\n1\n2\n3\n4\n5\n6\n7\n8\n9\n";
  38. var verticalRuler = new Label (vrule, false) {
  39. AutoSize = false,
  40. X = 0,
  41. Y = 0,
  42. Width = 1,
  43. Height = Dim.Fill (),
  44. ColorScheme = Colors.Error
  45. };
  46. Application.Top.LayoutComplete += (s, a) => {
  47. horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
  48. verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height * 2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height * 2)];
  49. };
  50. Application.Top.Add (verticalRuler);
  51. // Demonstrate At - Using Pos.At to locate a view in an absolute location
  52. var atButton = new Button ("At(2,1)") {
  53. X = Pos.At (2),
  54. Y = Pos.At (1)
  55. };
  56. Application.Top.Add (atButton);
  57. // Throw in a literal absolute - Should function identically to above
  58. var absoluteButton = new Button ("X = 30, Y = 1") {
  59. X = 30,
  60. Y = 1
  61. };
  62. Application.Top.Add (absoluteButton);
  63. // Demonstrate using Dim to create a window that fills the parent with a margin
  64. int margin = 10;
  65. var subWin = new Window () {
  66. X = Pos.Center (),
  67. Y = 2,
  68. Width = Dim.Fill (margin),
  69. Height = 7
  70. };
  71. subWin.Title = $"{subWin.GetType ().Name} {{X={subWin.X},Y={subWin.Y},Width={subWin.Width},Height={subWin.Height}}}";
  72. Application.Top.Add (subWin);
  73. int i = 1;
  74. string txt = "Resize the terminal to see computed layout in action.";
  75. var labelList = new List<Label> ();
  76. labelList.Add (new Label ($"The lines below show different TextAlignments"));
  77. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  78. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  79. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  80. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  81. subWin.Add (labelList.ToArray ());
  82. var frameView = new FrameView () {
  83. X = 2,
  84. Y = Pos.Bottom (subWin),
  85. Width = 30,
  86. Height = 7
  87. };
  88. frameView.Title = $"{frameView.GetType ().Name} {{X={frameView.X},Y={frameView.Y},Width={frameView.Width},Height={frameView.Height}}}";
  89. i = 1;
  90. labelList = new List<Label> ();
  91. labelList.Add (new Label ($"The lines below show different TextAlignments"));
  92. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  93. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  94. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  95. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  96. frameView.Add (labelList.ToArray ());
  97. Application.Top.Add (frameView);
  98. frameView = new FrameView () {
  99. X = Pos.Right (frameView),
  100. Y = Pos.Top (frameView),
  101. Width = Dim.Fill (),
  102. Height = 7,
  103. };
  104. frameView.Title = $"{frameView.GetType ().Name} {{X={frameView.X},Y={frameView.Y},Width={frameView.Width},Height={frameView.Height}}}";
  105. Application.Top.Add (frameView);
  106. // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide
  107. var textView = new TextView () {
  108. X = Pos.Center (),
  109. Y = Pos.Percent (50),
  110. Width = Dim.Percent (80),
  111. Height = Dim.Percent (10),
  112. ColorScheme = Colors.TopLevel,
  113. };
  114. textView.Text = $"This TextView should horizontally & vertically centered and \n10% of the screeen height, and 80% of its width.";
  115. Application.Top.Add (textView);
  116. var oddballButton = new Button ("These buttons demo convoluted PosCombine scenarios") {
  117. X = Pos.Center (),
  118. Y = Pos.Bottom (textView) + 1
  119. };
  120. Application.Top.Add (oddballButton);
  121. #region Issue2358
  122. // Demonstrate odd-ball Combine scenarios
  123. // Until https://github.com/gui-cs/Terminal.Gui/issues/2358 is fixed these won't work right
  124. oddballButton = new Button ("Center + 0") {
  125. X = Pos.Center () + 0,
  126. Y = Pos.Bottom (oddballButton)
  127. };
  128. Application.Top.Add (oddballButton);
  129. oddballButton = new Button ("Center + 1") {
  130. X = Pos.Center () + 1,
  131. Y = Pos.Bottom (oddballButton)
  132. };
  133. Application.Top.Add (oddballButton);
  134. oddballButton = new Button ("0 + Center") {
  135. X = 0 + Pos.Center (),
  136. Y = Pos.Bottom (oddballButton)
  137. };
  138. Application.Top.Add (oddballButton);
  139. oddballButton = new Button ("1 + Center") {
  140. X = 1 + Pos.Center (),
  141. Y = Pos.Bottom (oddballButton)
  142. };
  143. Application.Top.Add (oddballButton);
  144. // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
  145. // The `- Pos.Percent(5)` is there so at least something is visible
  146. oddballButton = new Button ("Center + Center - Percent(50)") {
  147. X = Pos.Center () + Pos.Center () - Pos.Percent (50),
  148. Y = Pos.Bottom (oddballButton)
  149. };
  150. Application.Top.Add (oddballButton);
  151. // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
  152. // The `- Pos.Percent(5)` is there so at least something is visible
  153. oddballButton = new Button ("Percent(50) + Center - Percent(50)") {
  154. X = Pos.Percent (50) + Pos.Center () - Pos.Percent (50),
  155. Y = Pos.Bottom (oddballButton)
  156. };
  157. Application.Top.Add (oddballButton);
  158. // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
  159. // The `- Pos.Percent(5)` is there so at least something is visible
  160. oddballButton = new Button ("Center + Percent(50) - Percent(50)") {
  161. X = Pos.Center () + Pos.Percent (50) - Pos.Percent (50),
  162. Y = Pos.Bottom (oddballButton)
  163. };
  164. Application.Top.Add (oddballButton);
  165. #endregion
  166. // This demonstrates nonsense: Same as At(0)
  167. oddballButton = new Button ("Center - Center - Percent(50)") {
  168. X = Pos.Center () + Pos.Center () - Pos.Percent (50),
  169. Y = Pos.Bottom (oddballButton)
  170. };
  171. Application.Top.Add (oddballButton);
  172. // This demonstrates combining Percents)
  173. oddballButton = new Button ("Percent(40) + Percent(10)") {
  174. X = Pos.Percent (40) + Pos.Percent (10),
  175. Y = Pos.Bottom (oddballButton)
  176. };
  177. Application.Top.Add (oddballButton);
  178. // Demonstrate AnchorEnd - Button is anchored to bottom/right
  179. var anchorButton = new Button ("Button using AnchorEnd") {
  180. Y = Pos.AnchorEnd () - 1,
  181. };
  182. anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton));
  183. anchorButton.Clicked += (s, e) => {
  184. // This demonstrates how to have a dynamically sized button
  185. // Each time the button is clicked the button's text gets longer
  186. // The call to Application.Top.LayoutSubviews causes the Computed layout to
  187. // get updated.
  188. anchorButton.Text += "!";
  189. Application.Top.LayoutSubviews ();
  190. };
  191. Application.Top.Add (anchorButton);
  192. // Demonstrate AnchorEnd(n)
  193. // This is intentionally convoluted to illustrate potential bugs.
  194. var anchorEndLabel1 = new Label ("This Label should be the 2nd to last line (AnchorEnd (2)).") {
  195. TextAlignment = Terminal.Gui.TextAlignment.Centered,
  196. ColorScheme = Colors.Menu,
  197. Width = Dim.Fill (5),
  198. X = 5,
  199. Y = Pos.AnchorEnd (2)
  200. };
  201. Application.Top.Add (anchorEndLabel1);
  202. // Demonstrate DimCombine (via AnchorEnd(n) - 1)
  203. // This is intentionally convoluted to illustrate potential bugs.
  204. var anchorEndLabel2 = new TextField ("This TextField should be the 3rd to last line (AnchorEnd (2) - 1).") {
  205. TextAlignment = Terminal.Gui.TextAlignment.Left,
  206. ColorScheme = Colors.Menu,
  207. Width = Dim.Fill (5),
  208. X = 5,
  209. Y = Pos.AnchorEnd (2) - 1 // Pos.Combine
  210. };
  211. Application.Top.Add (anchorEndLabel2);
  212. // Show positioning vertically using Pos.AnchorEnd via Pos.Combine
  213. var leftButton = new Button ("Left") {
  214. Y = Pos.AnchorEnd () - 1 // Pos.Combine
  215. };
  216. leftButton.Clicked += (s, e) => {
  217. // This demonstrates how to have a dynamically sized button
  218. // Each time the button is clicked the button's text gets longer
  219. // The call to Application.Top.LayoutSubviews causes the Computed layout to
  220. // get updated.
  221. leftButton.Text += "!";
  222. Application.Top.LayoutSubviews ();
  223. };
  224. // show positioning vertically using Pos.AnchorEnd
  225. var centerButton = new Button ("Center") {
  226. X = Pos.Center (),
  227. Y = Pos.AnchorEnd (1) // Pos.AnchorEnd(1)
  228. };
  229. centerButton.Clicked += (s, e) => {
  230. // This demonstrates how to have a dynamically sized button
  231. // Each time the button is clicked the button's text gets longer
  232. // The call to Application.Top.LayoutSubviews causes the Computed layout to
  233. // get updated.
  234. centerButton.Text += "!";
  235. Application.Top.LayoutSubviews ();
  236. };
  237. // show positioning vertically using another window and Pos.Bottom
  238. var rightButton = new Button ("Right") {
  239. Y = Pos.Y (centerButton)
  240. };
  241. rightButton.Clicked += (s, e) => {
  242. // This demonstrates how to have a dynamically sized button
  243. // Each time the button is clicked the button's text gets longer
  244. // The call to Application.Top.LayoutSubviews causes the Computed layout to
  245. // get updated.
  246. rightButton.Text += "!";
  247. Application.Top.LayoutSubviews ();
  248. };
  249. // Center three buttons with 5 spaces between them
  250. leftButton.X = Pos.Left (centerButton) - (Pos.Right (leftButton) - Pos.Left (leftButton)) - 5;
  251. rightButton.X = Pos.Right (centerButton) + 5;
  252. Application.Top.Add (leftButton);
  253. Application.Top.Add (centerButton);
  254. Application.Top.Add (rightButton);
  255. }
  256. }
  257. }