#nullable enable using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace UICatalog.Scenarios; [ScenarioMetadata ("All Views Tester", "Provides a test UI for all classes derived from View.")] [ScenarioCategory ("Layout")] [ScenarioCategory ("Tests")] [ScenarioCategory ("Controls")] [ScenarioCategory ("Adornments")] [ScenarioCategory ("Arrangement")] public class AllViewsTester : Scenario { private Dictionary? _viewClasses; private ListView? _classListView; private AdornmentsEditor? _adornmentsEditor; private ArrangementEditor? _arrangementEditor; private LayoutEditor? _layoutEditor; private ViewportSettingsEditor? _viewportSettingsEditor; private ViewPropertiesEditor? _propertiesEditor; private FrameView? _hostPane; private View? _curView; private EventLog? _eventLog; public override void Main () { // Don't create a sub-win (Scenario.Win); just use Application.Current Application.Init (); var app = new Window { Title = GetQuitKeyAndName (), }; // Set the BorderStyle we use for all subviews, but disable the app border thickness app.Border!.LineStyle = LineStyle.Heavy; app.Border!.Thickness = new (0); _viewClasses = GetAllViewClassesCollection () .OrderBy (t => t.Name) .Select (t => new KeyValuePair (t.Name, t)) .ToDictionary (t => t.Key, t => t.Value); _classListView = new () { Title = "Classes [_1]", X = 0, Y = 0, Width = Dim.Auto (), Height = Dim.Fill (), AllowsMarking = false, SelectedItem = 0, Source = new ListWrapper (new (_viewClasses.Keys.ToList ())), SuperViewRendersLineCanvas = true }; _classListView.Border!.Thickness = new (1); _classListView.SelectedItemChanged += (s, args) => { // Dispose existing current View, if any DisposeCurrentView (); CreateCurrentView (_viewClasses.Values.ToArray () [_classListView.SelectedItem.Value]); // Force ViewToEdit to be the view and not a subview if (_adornmentsEditor is { }) { _adornmentsEditor.AutoSelectSuperView = _curView; _adornmentsEditor.ViewToEdit = _curView; } }; _classListView.Accepting += (sender, args) => { _curView?.SetFocus (); args.Handled = true; }; _adornmentsEditor = new () { Title = "Adornments [_2]", X = Pos.Right (_classListView) - 1, Y = 0, Width = Dim.Auto (), Height = Dim.Auto (), AutoSelectViewToEdit = false, AutoSelectAdornments = false, SuperViewRendersLineCanvas = true, }; _adornmentsEditor.Border!.Thickness = new (1); _adornmentsEditor.ExpanderButton!.Orientation = Orientation.Horizontal; _adornmentsEditor.ExpanderButton.Enabled = false; _arrangementEditor = new () { Title = "Arrangement [_3]", X = Pos.Right (_classListView) - 1, Y = Pos.Bottom (_adornmentsEditor) - Pos.Func (_ => _adornmentsEditor.Frame.Height == 1 ? 0 : 1), Width = Dim.Width (_adornmentsEditor), Height = Dim.Fill (), AutoSelectViewToEdit = false, AutoSelectAdornments = false, SuperViewRendersLineCanvas = true }; _arrangementEditor.ExpanderButton!.Orientation = Orientation.Horizontal; _arrangementEditor.ExpanderButton.CollapsedChanging += (sender, args) => { _adornmentsEditor.ExpanderButton.Collapsed = args.NewValue; }; _arrangementEditor.Border!.Thickness = new (1); _layoutEditor = new () { Title = "Layout [_4]", X = Pos.Right (_arrangementEditor) - 1, Y = 0, //Width = Dim.Fill (), // set below Height = Dim.Auto (), CanFocus = true, AutoSelectViewToEdit = false, AutoSelectAdornments = false, SuperViewRendersLineCanvas = true }; _layoutEditor.Border!.Thickness = new (1, 1, 1, 0); _viewportSettingsEditor = new () { Title = "ViewportSettings [_5]", X = Pos.Right (_arrangementEditor) - 1, Y = Pos.Bottom (_layoutEditor) - Pos.Func (_ => _layoutEditor.Frame.Height == 1 ? 0 : 1), Width = Dim.Width (_layoutEditor), Height = Dim.Auto (), CanFocus = true, AutoSelectViewToEdit = false, AutoSelectAdornments = false, SuperViewRendersLineCanvas = true }; _viewportSettingsEditor.Border!.Thickness = new (1, 1, 1, 1); _propertiesEditor = new () { Title = "View Properties [_6]", X = Pos.Right (_adornmentsEditor) - 1, Y = Pos.Bottom (_viewportSettingsEditor) - Pos.Func (_ => _viewportSettingsEditor.Frame.Height == 1 ? 0 : 1), Width = Dim.Width (_layoutEditor), Height = Dim.Auto (), CanFocus = true, SuperViewRendersLineCanvas = true }; _propertiesEditor.Border!.Thickness = new (1, 1, 1, 0); _eventLog = new () { X = Pos.AnchorEnd () - 1, Y = 0, Width = 30, Height = Dim.Fill (), SuperViewRendersLineCanvas = true }; _eventLog.Border!.Thickness = new (1); _layoutEditor.Width = Dim.Fill ( Dim.Func ( _ => { if (_eventLog.NeedsLayout) { // We have two choices: // 1) Call Layout explicitly // 2) Throw LayoutException so Layout tries again _eventLog.Layout (); //throw new LayoutException ("_eventLog"); } return _eventLog.Frame.Width; })); _hostPane = new () { Id = "_hostPane", X = Pos.Right (_adornmentsEditor), Y = Pos.Bottom (_propertiesEditor), Width = Dim.Width (_layoutEditor) - 2, Height = Dim.Fill (), CanFocus = true, TabStop = TabBehavior.TabStop, Arrangement = ViewArrangement.LeftResizable | ViewArrangement.BottomResizable | ViewArrangement.RightResizable, BorderStyle = LineStyle.Double, SuperViewRendersLineCanvas = true }; _hostPane.Border!.SetScheme (app.GetScheme ()); _hostPane.Padding!.Thickness = new (1); _hostPane.Padding.Diagnostics = ViewDiagnosticFlags.Ruler; _hostPane.Padding.SetScheme (app.GetScheme ()); app.Add (_classListView, _adornmentsEditor, _arrangementEditor, _layoutEditor, _viewportSettingsEditor, _propertiesEditor, _eventLog, _hostPane); app.Initialized += App_Initialized; Application.Run (app); app.Dispose (); Application.Shutdown (); } private void App_Initialized (object? sender, EventArgs e) { _classListView!.SelectedItem = 0; _classListView.SetFocus (); } // TODO: Add Command.HotKey handler (pop a message box?) private void CreateCurrentView (Type type) { Debug.Assert (_curView is null); // If we are to create a generic Type if (type.IsGenericType) { // For each of the arguments List typeArguments = []; // use or the original type if applicable foreach (Type arg in type.GetGenericArguments ()) { if (arg.IsValueType && Nullable.GetUnderlyingType (arg) == null) { typeArguments.Add (arg); } else { typeArguments.Add (typeof (object)); } } // And change what type we are instantiating from MyClass to MyClass or MyClass type = type.MakeGenericType (typeArguments.ToArray ()); } // Ensure the type does not contain any generic parameters if (type.ContainsGenericParameters) { Logging.Warning ($"Cannot create an instance of {type} because it contains generic parameters."); //throw new ArgumentException ($"Cannot create an instance of {type} because it contains generic parameters."); return; } // Instantiate view var view = (View)Activator.CreateInstance (type)!; _eventLog!.ViewToLog = view; if (view is IDesignable designable) { string settingsEditorDemoText = _propertiesEditor!.DemoText; designable.EnableForDesign (ref settingsEditorDemoText); } else { view.Text = _propertiesEditor!.DemoText; view.Title = "_Test Title"; } view.Initialized += CurrentView_Initialized; view.SubViewsLaidOut += CurrentView_LayoutComplete; view.Id = "_curView"; _curView = view; _hostPane!.Add (_curView); _layoutEditor!.ViewToEdit = _curView; _viewportSettingsEditor!.ViewToEdit = _curView; _arrangementEditor!.ViewToEdit = _curView; _propertiesEditor!.ViewToEdit = _curView; _curView.SetNeedsLayout (); } private void DisposeCurrentView () { if (_curView != null) { _curView.Initialized -= CurrentView_Initialized; _curView.SubViewsLaidOut -= CurrentView_LayoutComplete; _hostPane!.Remove (_curView); _layoutEditor!.ViewToEdit = null; _viewportSettingsEditor!.ViewToEdit = null; _arrangementEditor!.ViewToEdit = null; _propertiesEditor!.ViewToEdit = null; _curView.Dispose (); _curView = null; } } private static List GetAllViewClassesCollection () { List types = typeof (View).Assembly.GetTypes () .Where ( myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true } && myType.IsSubclassOf (typeof (View))) .ToList (); types.Add (typeof (View)); return types; } private void CurrentView_LayoutComplete (object? sender, LayoutEventArgs args) { UpdateHostTitle (_curView); } private void UpdateHostTitle (View? view) { _hostPane!.Title = $"{view!.GetType ().Name} [_0]"; } private void CurrentView_Initialized (object? sender, EventArgs e) { if (sender is not View view) { return; } if (view.Width == Dim.Absolute (0) || view.Width is null) { view.Width = Dim.Fill (); } if (view.Height == Dim.Absolute (0) || view.Height is null) { view.Height = Dim.Fill (); } UpdateHostTitle (view); } public override List GetDemoKeyStrokes () { var keys = new List (); for (int i = 0; i < GetAllViewClassesCollection ().Count; i++) { keys.Add (Key.CursorDown); } return keys; } }