using NStack; using System; using System.Collections.Generic; using System.Linq; using Terminal.Gui; namespace UICatalog { /// /// Base class for each demo/scenario. To define a new sceanrio simply /// /// 1) declare a class derived from Scenario, /// 2) Set Name and Description as appropriate using [ScenarioMetadata] attribute /// 3) Set one or more categories with the [ScenarioCategory] attribute /// 4) Implement Setup. /// 5) Optionally, implement Run. /// /// The Main program uses reflection to find all sceanarios and adds them to the /// ListViews. Press ENTER to run the selected sceanrio. Press CTRL-Q to exit it. /// public class Scenario { /// /// The Top level for the Scenario. This should be set to `Application.Top` in most cases. /// public Toplevel Top { get; set; } /// /// public Window Win { get; set; } /// /// Helper that provides the default Window implementation with a frame and /// label showing the name of the Scenario and logic to exit back to /// the Scenario picker UI. /// Override Init to provide any `Toplevel` behavior needed. /// /// public virtual void Init(Toplevel top) { Top = top; Win = new Window ($"CTRL-Q to Close - Scenario: {GetName ()}") { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () }; Top.Add (Win); } [System.AttributeUsage (System.AttributeTargets.Class)] public class ScenarioMetadata : System.Attribute { /// /// Scenario Name /// public string Name { get; set; } /// /// Scenario Description /// public string Description { get; set; } public ScenarioMetadata (string Name, string Description) { this.Name = Name; this.Description = Description; } /// /// Static helper function to get the Scenario Name given a Type /// /// /// public static string GetName (Type t) => ((ScenarioMetadata)System.Attribute.GetCustomAttributes (t) [0]).Name; /// /// Static helper function to get the Scenario Description given a Type /// /// /// public static string GetDescription (Type t) => ((ScenarioMetadata)System.Attribute.GetCustomAttributes (t) [0]).Description; } /// /// Helper to get the Scenario Name /// /// public string GetName () => ScenarioMetadata.GetName (this.GetType ()); /// /// Helper to get the Scenario Descripiton /// /// public string GetDescription () => ScenarioMetadata.GetDescription (this.GetType ()); [System.AttributeUsage (System.AttributeTargets.Class, AllowMultiple = true)] public class ScenarioCategory : System.Attribute { /// /// Category Name /// public string Name { get; set; } public ScenarioCategory (string Name) => this.Name = Name; /// /// Static helper function to get the Scenario Name given a Type /// /// /// public static string GetName (Type t) => ((ScenarioCategory)System.Attribute.GetCustomAttributes (t) [0]).Name; /// /// Static helper function to get the Scenario Categories given a Type /// /// /// public static List GetCategories (Type t) => System.Attribute.GetCustomAttributes (t) .ToList () .Where (a => a is ScenarioCategory) .Select (a => ((ScenarioCategory)a).Name) .ToList (); } /// /// Helper function to get the Categories of a Scenario /// /// public List GetCategories () => ScenarioCategory.GetCategories (this.GetType ()); public override string ToString () => $"{GetName (),-30}{GetDescription ()}"; /// /// Override this to implement the Scenario setup logic (create controls, etc...). /// public virtual void Setup () { } /// /// Runs the scenario. Override to start the scearnio using a Top level different than `Top`. /// public virtual void Run () { Application.Run (Top); } /// /// Stops the scenario. Override to implement shutdown behavior for the Scenario. /// public virtual void RequestStop () { Application.RequestStop (); } /// /// Returns a list of all Categories set by all of the scenarios defined in the project. /// internal static List GetAllCategories () { List categories = new List () { "All" }; foreach (Type type in typeof (Scenario).Assembly.GetTypes () .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (Scenario)))) { List attrs = System.Attribute.GetCustomAttributes (type).ToList (); categories = categories.Union (attrs.Where (a => a is ScenarioCategory).Select (a => ((ScenarioCategory)a).Name)).ToList (); } return categories; } /// /// Returns an instance of each Scenario defined in the project. /// https://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class /// internal static List GetDerivedClassesCollection () { List objects = new List (); foreach (Type type in typeof (Scenario).Assembly.GetTypes () .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf (typeof (Scenario)))) { objects.Add (type); } return objects; } } }