OutputView.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #nullable enable
  2. using Terminal.Gui.App;
  3. using Terminal.Gui.Configuration;
  4. using Terminal.Gui.Drawing;
  5. using Terminal.Gui.ViewBase;
  6. using Terminal.Gui.Views;
  7. using Attribute = Terminal.Gui.Drawing.Attribute;
  8. // Disable all shadows and highlights
  9. ConfigurationManager.RuntimeConfig = """
  10. {
  11. "Themes": [
  12. {
  13. "Default": {
  14. "Window.DefaultShadow": "None",
  15. "Dialog.DefaultShadow": "None",
  16. "Button.DefaultShadow": "None",
  17. "Menuv2.DefaultBorderStyle": "Single"
  18. }
  19. }
  20. ]
  21. }
  22. """;
  23. ConfigurationManager.Enable (ConfigLocations.Runtime);
  24. // Get the view name and output file from commandline
  25. string? viewName = null;
  26. string? outputFile = null;
  27. string [] commandArgs = Environment.GetCommandLineArgs ();
  28. for (var i = 0; i < commandArgs.Length; i++)
  29. {
  30. if (commandArgs [i].StartsWith ("--view=", StringComparison.OrdinalIgnoreCase))
  31. {
  32. viewName = commandArgs [i] ["--view=".Length..];
  33. }
  34. else if (commandArgs [i] == "--view" && i + 1 < commandArgs.Length)
  35. {
  36. viewName = commandArgs [i + 1];
  37. }
  38. else if (commandArgs [i].StartsWith ("--output=", StringComparison.OrdinalIgnoreCase))
  39. {
  40. outputFile = commandArgs [i] ["--output=".Length..];
  41. }
  42. else if (commandArgs [i] == "--output" && i + 1 < commandArgs.Length)
  43. {
  44. outputFile = commandArgs [i + 1];
  45. }
  46. }
  47. if (string.IsNullOrEmpty (viewName))
  48. {
  49. Console.WriteLine (@"No view name specified. Use --view=ViewName to specify a view.");
  50. return;
  51. }
  52. ViewDemoWindow.ViewName = viewName;
  53. // Force 16 colors and end after first iteration
  54. Application.StopAfterFirstIteration = true;
  55. var demoWindow = Application.Run<ViewDemoWindow> ();
  56. string? output = demoWindow.Output?.Trim ();
  57. demoWindow.Dispose ();
  58. // Before the application exits, reset Terminal.Gui for clean shutdown
  59. Application.Shutdown ();
  60. if (output is null)
  61. {
  62. Console.WriteLine (@"No output was generated.");
  63. return;
  64. }
  65. // Write to file or console
  66. if (!string.IsNullOrEmpty (outputFile))
  67. {
  68. File.WriteAllText (outputFile, output);
  69. }
  70. else
  71. {
  72. Console.WriteLine (output);
  73. }
  74. // Defines a top-level window with border and title
  75. public class ViewDemoWindow : Window
  76. {
  77. public static string? ViewName { get; set; }
  78. public string? Output { get; set; }
  79. public ViewDemoWindow ()
  80. {
  81. // Limit the size of the window to 50x20, which works good for most views
  82. Width = 50;
  83. Height = 20;
  84. // Use only white on black
  85. SetScheme (new (new Attribute (ColorName16.White, ColorName16.Black)));
  86. BorderStyle = LineStyle.None;
  87. // Convert ViewName to type that's in the Terminal.Gui assembly:
  88. var type = Type.GetType ($"Terminal.Gui.Views.{ViewName!}, Terminal.Gui", false, true);
  89. if (type is null)
  90. {
  91. Console.WriteLine (@$"View {ViewName} type is invalid.");
  92. return;
  93. }
  94. // Create the view
  95. View? view = CreateView (type!);
  96. if (view is null)
  97. {
  98. Console.WriteLine (@$"View {ViewName} could not be created.");
  99. return;
  100. }
  101. // Initialize the view
  102. view.Initialized += ViewInitialized;
  103. base.Add (view);
  104. // In normal apps, each iteration would call Application.LayoutAndDraw()
  105. // but since we set Application.EndAfterFirstIteration = true, we need to
  106. // call it manually here and capture the output
  107. Application.Iteration += (sender, args) =>
  108. {
  109. Application.LayoutAndDraw ();
  110. Output = Application.ToString ();
  111. };
  112. }
  113. private static View? CreateView (Type type)
  114. {
  115. // If we are to create a generic Type
  116. if (type.IsGenericType)
  117. {
  118. // For each of the <T> arguments
  119. List<Type> typeArguments = new ();
  120. // use <object> or the original type if applicable
  121. foreach (Type arg in type.GetGenericArguments ())
  122. {
  123. if (arg.IsValueType && Nullable.GetUnderlyingType (arg) == null)
  124. {
  125. typeArguments.Add (arg);
  126. }
  127. else
  128. {
  129. typeArguments.Add (typeof (object));
  130. }
  131. }
  132. // And change what type we are instantiating from MyClass<T> to MyClass<object> or MyClass<T>
  133. type = type.MakeGenericType (typeArguments.ToArray ());
  134. }
  135. // Ensure the type does not contain any generic parameters
  136. if (type.ContainsGenericParameters)
  137. {
  138. Console.WriteLine (@$"Cannot create an instance of {type} because it contains generic parameters.");
  139. return null;
  140. }
  141. // Instantiate view
  142. var view = (View)Activator.CreateInstance (type)!;
  143. if (view is IDesignable designable)
  144. {
  145. var settingsEditorDemoText = "Demo Text";
  146. designable.EnableForDesign (ref settingsEditorDemoText);
  147. }
  148. else
  149. {
  150. view.Text = "Demo Text";
  151. view.Title = "_Demo Title";
  152. }
  153. return view;
  154. }
  155. private static void ViewInitialized (object? sender, EventArgs e)
  156. {
  157. if (sender is not View view)
  158. {
  159. return;
  160. }
  161. if (view.Width == Dim.Absolute (0) || view.Width is null)
  162. {
  163. view.Width = Dim.Fill ();
  164. }
  165. if (view.Height == Dim.Absolute (0) || view.Height is null)
  166. {
  167. view.Height = Dim.Fill ();
  168. }
  169. view.X = 0;
  170. view.Y = 0;
  171. }
  172. }