Scenario.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using NStack;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Terminal.Gui;
  6. namespace UICatalog {
  7. /// <summary>
  8. /// Base class for each demo/scenario. To define a new scenario simply
  9. ///
  10. /// 1) declare a class derived from Scenario,
  11. /// 2) Set Name and Description as appropriate using [ScenarioMetadata] attribute
  12. /// 3) Set one or more categories with the [ScenarioCategory] attribute
  13. /// 4) Implement Setup.
  14. /// 5) Optionally, implement Run.
  15. ///
  16. /// The Main program uses reflection to find all scenarios and adds them to the
  17. /// ListViews. Press ENTER to run the selected scenario. Press CTRL-Q to exit it.
  18. /// </summary>
  19. public class Scenario : IDisposable {
  20. private bool _disposedValue;
  21. /// <summary>
  22. /// The Top level for the Scenario. This should be set to `Application.Top` in most cases.
  23. /// </summary>
  24. public Toplevel Top { get; set; }
  25. /// <summary>
  26. /// The Window for the Scenario. This should be set within the `Application.Top` in most cases.
  27. /// </summary>
  28. public Window Win { get; set; }
  29. /// <summary>
  30. /// Helper that provides the default Window implementation with a frame and
  31. /// label showing the name of the Scenario and logic to exit back to
  32. /// the Scenario picker UI.
  33. /// Override Init to provide any `Toplevel` behavior needed.
  34. /// </summary>
  35. /// <param name="top"></param>
  36. public virtual void Init(Toplevel top)
  37. {
  38. Top = top;
  39. Win = new Window ($"CTRL-Q to Close - Scenario: {GetName ()}") {
  40. X = 0,
  41. Y = 0,
  42. Width = Dim.Fill (),
  43. Height = Dim.Fill ()
  44. };
  45. Top.Add (Win);
  46. }
  47. [System.AttributeUsage (System.AttributeTargets.Class)]
  48. public class ScenarioMetadata : System.Attribute {
  49. /// <summary>
  50. /// Scenario Name
  51. /// </summary>
  52. public string Name { get; set; }
  53. /// <summary>
  54. /// Scenario Description
  55. /// </summary>
  56. public string Description { get; set; }
  57. public ScenarioMetadata (string Name, string Description)
  58. {
  59. this.Name = Name;
  60. this.Description = Description;
  61. }
  62. /// <summary>
  63. /// Static helper function to get the Scenario Name given a Type
  64. /// </summary>
  65. /// <param name="t"></param>
  66. /// <returns></returns>
  67. public static string GetName (Type t) => ((ScenarioMetadata)System.Attribute.GetCustomAttributes (t) [0]).Name;
  68. /// <summary>
  69. /// Static helper function to get the Scenario Description given a Type
  70. /// </summary>
  71. /// <param name="t"></param>
  72. /// <returns></returns>
  73. public static string GetDescription (Type t) => ((ScenarioMetadata)System.Attribute.GetCustomAttributes (t) [0]).Description;
  74. }
  75. /// <summary>
  76. /// Helper to get the Scenario Name
  77. /// </summary>
  78. /// <returns></returns>
  79. public string GetName () => ScenarioMetadata.GetName (this.GetType ());
  80. /// <summary>
  81. /// Helper to get the Scenario Description
  82. /// </summary>
  83. /// <returns></returns>
  84. public string GetDescription () => ScenarioMetadata.GetDescription (this.GetType ());
  85. [System.AttributeUsage (System.AttributeTargets.Class, AllowMultiple = true)]
  86. public class ScenarioCategory : System.Attribute {
  87. /// <summary>
  88. /// Category Name
  89. /// </summary>
  90. public string Name { get; set; }
  91. public ScenarioCategory (string Name) => this.Name = Name;
  92. /// <summary>
  93. /// Static helper function to get the Scenario Name given a Type
  94. /// </summary>
  95. /// <param name="t"></param>
  96. /// <returns></returns>
  97. public static string GetName (Type t) => ((ScenarioCategory)System.Attribute.GetCustomAttributes (t) [0]).Name;
  98. /// <summary>
  99. /// Static helper function to get the Scenario Categories given a Type
  100. /// </summary>
  101. /// <param name="t"></param>
  102. /// <returns></returns>
  103. public static List<string> GetCategories (Type t) => System.Attribute.GetCustomAttributes (t)
  104. .ToList ()
  105. .Where (a => a is ScenarioCategory)
  106. .Select (a => ((ScenarioCategory)a).Name)
  107. .ToList ();
  108. }
  109. /// <summary>
  110. /// Helper function to get the Categories of a Scenario
  111. /// </summary>
  112. /// <returns></returns>
  113. public List<string> GetCategories () => ScenarioCategory.GetCategories (this.GetType ());
  114. public override string ToString () => $"{GetName (),-30}{GetDescription ()}";
  115. /// <summary>
  116. /// Override this to implement the Scenario setup logic (create controls, etc...).
  117. /// </summary>
  118. public virtual void Setup ()
  119. {
  120. }
  121. /// <summary>
  122. /// Runs the scenario. Override to start the scenario using a Top level different than `Top`.
  123. /// </summary>
  124. public virtual void Run ()
  125. {
  126. Application.Run (Top);
  127. }
  128. /// <summary>
  129. /// Stops the scenario. Override to implement shutdown behavior for the Scenario.
  130. /// </summary>
  131. public virtual void RequestStop ()
  132. {
  133. Application.RequestStop ();
  134. }
  135. /// <summary>
  136. /// Returns a list of all Categories set by all of the scenarios defined in the project.
  137. /// </summary>
  138. internal static List<string> GetAllCategories ()
  139. {
  140. List<string> categories = new List<string> () { "All" };
  141. foreach (Type type in typeof (Scenario).Assembly.GetTypes ()
  142. .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (Scenario)))) {
  143. List<System.Attribute> attrs = System.Attribute.GetCustomAttributes (type).ToList ();
  144. categories = categories.Union (attrs.Where (a => a is ScenarioCategory).Select (a => ((ScenarioCategory)a).Name)).ToList ();
  145. }
  146. return categories;
  147. }
  148. /// <summary>
  149. /// Returns an instance of each Scenario defined in the project.
  150. /// https://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class
  151. /// </summary>
  152. internal static List<Type> GetDerivedClassesCollection ()
  153. {
  154. List<Type> objects = new List<Type> ();
  155. foreach (Type type in typeof (Scenario).Assembly.GetTypes ()
  156. .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (Scenario)))) {
  157. objects.Add (type);
  158. }
  159. return objects;
  160. }
  161. protected virtual void Dispose (bool disposing)
  162. {
  163. if (!_disposedValue) {
  164. if (disposing) {
  165. // TODO: dispose managed state (managed objects)
  166. }
  167. // TODO: free unmanaged resources (unmanaged objects) and override finalizer
  168. // TODO: set large fields to null
  169. _disposedValue = true;
  170. }
  171. }
  172. public void Dispose ()
  173. {
  174. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  175. Dispose (disposing: true);
  176. GC.SuppressFinalize (this);
  177. }
  178. }
  179. }