ComputedLayout.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Terminal.Gui;
  6. namespace UICatalog {
  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 using the Computed (Dim and Pos) Layout System")]
  14. [ScenarioCategory ("Layout")]
  15. class ComputedLayout : Scenario {
  16. public override void Setup ()
  17. {
  18. //Top.LayoutStyle = LayoutStyle.Computed;
  19. // Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width
  20. // BUGBUG: Dim.Fill returns too big a value sometimes.
  21. const string rule = "|123456789";
  22. var horizontalRuler = new Label ("") {
  23. X = 0,
  24. Y = 0,
  25. Width = Dim.Fill (1), // BUGBUG: I don't think this should be needed; DimFill() should respect container's frame. X does.
  26. ColorScheme = Colors.Error
  27. };
  28. Win.Add (horizontalRuler);
  29. // Demonstrate using Dim to create a vertical ruler that always measures the parent window's height
  30. // TODO: Either build a custom control for this or implement linewrap in Label #352
  31. const string vrule = "|\n1\n2\n3\n4\n5\n6\n7\n8\n9\n";
  32. var verticalRuler = new Label ("") {
  33. X = 0,
  34. Y = 0,
  35. Width = 1,
  36. Height = Dim.Fill (),
  37. ColorScheme = Colors.Error
  38. };
  39. Application.Resized += (sender, a) => {
  40. horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
  41. verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height*2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height*2)];
  42. };
  43. Win.Add (verticalRuler);
  44. // Demonstrate At - Absolute Layout using Pos
  45. var absoluteButton = new Button ("Absolute At(2,1)") {
  46. X = Pos.At (2),
  47. Y = Pos.At (1)
  48. };
  49. Win.Add (absoluteButton);
  50. // Demonstrate using Dim to create a window that fills the parent with a margin
  51. int margin = 10;
  52. var subWin = new Window ($"Centered Sub Window with {margin} character margin") {
  53. X = Pos.Center(),
  54. Y = 2,
  55. Width = Dim.Fill (margin),
  56. Height = 7
  57. };
  58. Win.Add (subWin);
  59. int i = 1;
  60. string txt = "Resize the terminal to see computed layout in action.";
  61. var labelList = new List<Label> ();
  62. labelList.Add (new Label ($"The lines below show different TextAlignments"));
  63. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  64. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  65. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  66. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  67. subWin.Add (labelList.ToArray ());
  68. // #522 repro?
  69. var frameView = new FrameView ($"Centered FrameView with {margin} character margin") {
  70. X = Pos.Center (),
  71. Y = Pos.Bottom(subWin),
  72. Width = Dim.Fill (margin),
  73. Height = 7
  74. };
  75. Win.Add (frameView);
  76. i = 1;
  77. labelList = new List<Label> ();
  78. labelList.Add (new Label ($"The lines below show different TextAlignments"));
  79. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  80. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  81. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  82. labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
  83. frameView.Add (labelList.ToArray ());
  84. // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide
  85. var textView = new TextView () {
  86. X = Pos.Center (),
  87. Y = Pos.Percent (50),
  88. Width = Dim.Percent (80),
  89. Height = Dim.Percent (30),
  90. ColorScheme = Colors.TopLevel,
  91. };
  92. textView.Text = "This text view should be half-way down the terminal,\n20% of its height, and 80% of its width.";
  93. Win.Add (textView);
  94. // Demonstrate AnchorEnd - Button is anchored to bottom/right
  95. var anchorButton = new Button ("Anchor End") {
  96. Y = Pos.AnchorEnd () - 1,
  97. };
  98. // TODO: Use Pos.Width instead of (Right-Left) when implemented (#502)
  99. anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton));
  100. anchorButton.Clicked = () => {
  101. // Ths demonstrates how to have a dynamically sized button
  102. // Each time the button is clicked the button's text gets longer
  103. // The call to Win.LayoutSubviews causes the Computed layout to
  104. // get updated.
  105. anchorButton.Text += "!";
  106. Win.LayoutSubviews ();
  107. };
  108. Win.Add (anchorButton);
  109. // Centering multiple controls horizontally.
  110. // This is intentionally convoluted to illustrate potential bugs.
  111. var bottomLabel = new Label ("This should be the 2nd to last line (Bug #xxx).") {
  112. TextAlignment = Terminal.Gui.TextAlignment.Centered,
  113. ColorScheme = Colors.Menu,
  114. Width = Dim.Fill (),
  115. X = Pos.Center (),
  116. Y = Pos.Bottom (Win) - 4 // BUGBUG: -2 should be two lines above border; but it has to be -4
  117. };
  118. Win.Add (bottomLabel);
  119. // Show positioning vertically using Pos.Bottom
  120. // BUGBUG: -1 should be just above border; but it has to be -3
  121. var leftButton = new Button ("Left") {
  122. Y = Pos.Bottom (Win) - 3
  123. };
  124. leftButton.Clicked = () => {
  125. // Ths demonstrates how to have a dynamically sized button
  126. // Each time the button is clicked the button's text gets longer
  127. // The call to Win.LayoutSubviews causes the Computed layout to
  128. // get updated.
  129. leftButton.Text += "!";
  130. Win.LayoutSubviews ();
  131. };
  132. // show positioning vertically using Pos.AnchorEnd
  133. var centerButton = new Button ("Center") {
  134. X = Pos.Center (),
  135. Y = Pos.AnchorEnd () - 1
  136. };
  137. centerButton.Clicked = () => {
  138. // Ths demonstrates how to have a dynamically sized button
  139. // Each time the button is clicked the button's text gets longer
  140. // The call to Win.LayoutSubviews causes the Computed layout to
  141. // get updated.
  142. centerButton.Text += "!";
  143. Win.LayoutSubviews ();
  144. };
  145. // show positioning vertically using another window and Pos.Bottom
  146. var rightButton = new Button ("Right") {
  147. Y = Pos.Y (centerButton)
  148. };
  149. rightButton.Clicked = () => {
  150. // Ths demonstrates how to have a dynamically sized button
  151. // Each time the button is clicked the button's text gets longer
  152. // The call to Win.LayoutSubviews causes the Computed layout to
  153. // get updated.
  154. rightButton.Text += "!";
  155. Win.LayoutSubviews ();
  156. };
  157. // Center three buttons with 5 spaces between them
  158. // TODO: Use Pos.Width instead of (Right-Left) when implemented (#502)
  159. leftButton.X = Pos.Left (centerButton) - (Pos.Right(leftButton) - Pos.Left (leftButton)) - 5;
  160. rightButton.X = Pos.Right (centerButton) + 5;
  161. Win.Add (leftButton);
  162. Win.Add (centerButton);
  163. Win.Add (rightButton);
  164. }
  165. public override void Run ()
  166. {
  167. base.Run ();
  168. }
  169. }
  170. internal static class StringExtensions {
  171. public static string Repeat (this string instr, int n)
  172. {
  173. if (n <= 0) {
  174. return null;
  175. }
  176. if (string.IsNullOrEmpty (instr) || n == 1) {
  177. return instr;
  178. }
  179. return new StringBuilder (instr.Length * n)
  180. .Insert (0, instr, n)
  181. .ToString ();
  182. }
  183. }
  184. }