diff --git a/UnitTests/ScenarioTests.cs b/UnitTests/ScenarioTests.cs index 03b0372c8..8c31c4ba1 100644 --- a/UnitTests/ScenarioTests.cs +++ b/UnitTests/ScenarioTests.cs @@ -1,6 +1,8 @@ +using NStack; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Terminal.Gui; using UICatalog; using Xunit; @@ -157,5 +159,418 @@ namespace Terminal.Gui { Responder.Instances.Clear (); #endif } + + [Fact] + public void Run_All_Views_Tester_Scenario () + { + Window _leftPane; + ListView _classListView; + FrameView _hostPane; + + Dictionary _viewClasses; + View _curView = null; + + // Settings + FrameView _settingsPane; + CheckBox _computedCheckBox; + FrameView _locationFrame; + RadioGroup _xRadioGroup; + TextField _xText; + int _xVal = 0; + RadioGroup _yRadioGroup; + TextField _yText; + int _yVal = 0; + + FrameView _sizeFrame; + RadioGroup _wRadioGroup; + TextField _wText; + int _wVal = 0; + RadioGroup _hRadioGroup; + TextField _hText; + int _hVal = 0; + List posNames = new List { "Factor", "AnchorEnd", "Center", "Absolute" }; + List dimNames = new List { "Factor", "Fill", "Absolute" }; + + + Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))); + + var Top = Application.Top; + + _viewClasses = GetAllViewClassesCollection () + .OrderBy (t => t.Name) + .Select (t => new KeyValuePair (t.Name, t)) + .ToDictionary (t => t.Key, t => t.Value); + + _leftPane = new Window ("Classes") { + X = 0, + Y = 0, + Width = 15, + Height = Dim.Fill (1), // for status bar + CanFocus = false, + ColorScheme = Colors.TopLevel, + }; + + _classListView = new ListView (_viewClasses.Keys.ToList ()) { + X = 0, + Y = 0, + Width = Dim.Fill (0), + Height = Dim.Fill (0), + AllowsMarking = false, + ColorScheme = Colors.TopLevel, + }; + _leftPane.Add (_classListView); + + _settingsPane = new FrameView ("Settings") { + X = Pos.Right (_leftPane), + Y = 0, // for menu + Width = Dim.Fill (), + Height = 10, + CanFocus = false, + ColorScheme = Colors.TopLevel, + }; + _computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 }; + _settingsPane.Add (_computedCheckBox); + + var radioItems = new ustring [] { "Percent(x)", "AnchorEnd(x)", "Center", "At(x)" }; + _locationFrame = new FrameView ("Location (Pos)") { + X = Pos.Left (_computedCheckBox), + Y = Pos.Bottom (_computedCheckBox), + Height = 3 + radioItems.Length, + Width = 36, + }; + _settingsPane.Add (_locationFrame); + + var label = new Label ("x:") { X = 0, Y = 0 }; + _locationFrame.Add (label); + _xRadioGroup = new RadioGroup (radioItems) { + X = 0, + Y = Pos.Bottom (label), + }; + _xText = new TextField ($"{_xVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 }; + _locationFrame.Add (_xText); + + _locationFrame.Add (_xRadioGroup); + + radioItems = new ustring [] { "Percent(y)", "AnchorEnd(y)", "Center", "At(y)" }; + label = new Label ("y:") { X = Pos.Right (_xRadioGroup) + 1, Y = 0 }; + _locationFrame.Add (label); + _yText = new TextField ($"{_yVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 }; + _locationFrame.Add (_yText); + _yRadioGroup = new RadioGroup (radioItems) { + X = Pos.X (label), + Y = Pos.Bottom (label), + }; + _locationFrame.Add (_yRadioGroup); + + _sizeFrame = new FrameView ("Size (Dim)") { + X = Pos.Right (_locationFrame), + Y = Pos.Y (_locationFrame), + Height = 3 + radioItems.Length, + Width = 40, + }; + + radioItems = new ustring [] { "Percent(width)", "Fill(width)", "Sized(width)" }; + label = new Label ("width:") { X = 0, Y = 0 }; + _sizeFrame.Add (label); + _wRadioGroup = new RadioGroup (radioItems) { + X = 0, + Y = Pos.Bottom (label), + }; + _wText = new TextField ($"{_wVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 }; + _sizeFrame.Add (_wText); + _sizeFrame.Add (_wRadioGroup); + + radioItems = new ustring [] { "Percent(height)", "Fill(height)", "Sized(height)" }; + label = new Label ("height:") { X = Pos.Right (_wRadioGroup) + 1, Y = 0 }; + _sizeFrame.Add (label); + _hText = new TextField ($"{_hVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 }; + _sizeFrame.Add (_hText); + + _hRadioGroup = new RadioGroup (radioItems) { + X = Pos.X (label), + Y = Pos.Bottom (label), + }; + _sizeFrame.Add (_hRadioGroup); + + _settingsPane.Add (_sizeFrame); + + _hostPane = new FrameView ("") { + X = Pos.Right (_leftPane), + Y = Pos.Bottom (_settingsPane), + Width = Dim.Fill (), + Height = Dim.Fill (1), // + 1 for status bar + ColorScheme = Colors.Dialog, + }; + + _classListView.OpenSelectedItem += (a) => { + _settingsPane.SetFocus (); + }; + _classListView.SelectedItemChanged += (args) => { + ClearClass (_curView); + _curView = CreateClass (_viewClasses.Values.ToArray () [_classListView.SelectedItem]); + }; + + _computedCheckBox.Toggled += (previousState) => { + if (_curView != null) { + _curView.LayoutStyle = previousState ? LayoutStyle.Absolute : LayoutStyle.Computed; + _hostPane.LayoutSubviews (); + } + }; + + _xRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView); + + _xText.TextChanged += (args) => { + try { + _xVal = int.Parse (_xText.Text.ToString ()); + DimPosChanged (_curView); + } catch { + + } + }; + + _yText.TextChanged += (args) => { + try { + _yVal = int.Parse (_yText.Text.ToString ()); + DimPosChanged (_curView); + } catch { + + } + }; + + _yRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView); + + _wRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView); + + _wText.TextChanged += (args) => { + try { + _wVal = int.Parse (_wText.Text.ToString ()); + DimPosChanged (_curView); + } catch { + + } + }; + + _hText.TextChanged += (args) => { + try { + _hVal = int.Parse (_hText.Text.ToString ()); + DimPosChanged (_curView); + } catch { + + } + }; + + _hRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView); + + Top.Add (_leftPane, _settingsPane, _hostPane); + + // This is not needed because ListView always run the SelectedItemChanged event at first time + //_curView = CreateClass (_viewClasses.First ().Value); + + int iterations = 0; + + Application.Iteration += () => { + iterations++; + + if (iterations < _viewClasses.Count) { + _classListView.MoveDown (); + } else { + Application.RequestStop (); + } + }; + + Application.Run (); + + Assert.Equal (_viewClasses.Count, iterations); + + Application.Shutdown (); + + + void DimPosChanged (View view) + { + if (view == null) { + return; + } + + var layout = view.LayoutStyle; + + try { + view.LayoutStyle = LayoutStyle.Absolute; + + switch (_xRadioGroup.SelectedItem) { + case 0: + view.X = Pos.Percent (_xVal); + break; + case 1: + view.X = Pos.AnchorEnd (_xVal); + break; + case 2: + view.X = Pos.Center (); + break; + case 3: + view.X = Pos.At (_xVal); + break; + } + + switch (_yRadioGroup.SelectedItem) { + case 0: + view.Y = Pos.Percent (_yVal); + break; + case 1: + view.Y = Pos.AnchorEnd (_yVal); + break; + case 2: + view.Y = Pos.Center (); + break; + case 3: + view.Y = Pos.At (_yVal); + break; + } + + switch (_wRadioGroup.SelectedItem) { + case 0: + view.Width = Dim.Percent (_wVal); + break; + case 1: + view.Width = Dim.Fill (_wVal); + break; + case 2: + view.Width = Dim.Sized (_wVal); + break; + } + + switch (_hRadioGroup.SelectedItem) { + case 0: + view.Height = Dim.Percent (_hVal); + break; + case 1: + view.Height = Dim.Fill (_hVal); + break; + case 2: + view.Height = Dim.Sized (_hVal); + break; + } + } catch (Exception e) { + MessageBox.ErrorQuery ("Exception", e.Message, "Ok"); + } finally { + view.LayoutStyle = layout; + } + UpdateTitle (view); + } + + void UpdateSettings (View view) + { + var x = view.X.ToString (); + var y = view.Y.ToString (); + _xRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => x.Contains (s)).First ()); + _yRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => y.Contains (s)).First ()); + _xText.Text = $"{view.Frame.X}"; + _yText.Text = $"{view.Frame.Y}"; + + var w = view.Width.ToString (); + var h = view.Height.ToString (); + _wRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => w.Contains (s)).First ()); + _hRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => h.Contains (s)).First ()); + _wText.Text = $"{view.Frame.Width}"; + _hText.Text = $"{view.Frame.Height}"; + } + + void UpdateTitle (View view) + { + _hostPane.Title = $"{view.GetType ().Name} - {view.X.ToString ()}, {view.Y.ToString ()}, {view.Width.ToString ()}, {view.Height.ToString ()}"; + } + + List GetAllViewClassesCollection () + { + List types = new List (); + foreach (Type type in typeof (View).Assembly.GetTypes () + .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) { + types.Add (type); + } + return types; + } + + void ClearClass (View view) + { + // Remove existing class, if any + if (view != null) { + view.LayoutComplete -= LayoutCompleteHandler; + _hostPane.Remove (view); + view.Dispose (); + _hostPane.Clear (); + } + } + + View CreateClass (Type type) + { + // If we are to create a generic Type + if (type.IsGenericType) { + + // For each of the arguments + List typeArguments = new List (); + + // use + foreach (var arg in type.GetGenericArguments ()) { + typeArguments.Add (typeof (object)); + } + + // And change what type we are instantiating from MyClass to MyClass + type = type.MakeGenericType (typeArguments.ToArray ()); + } + // Instantiate view + var view = (View)Activator.CreateInstance (type); + + //_curView.X = Pos.Center (); + //_curView.Y = Pos.Center (); + view.Width = Dim.Percent (75); + view.Height = Dim.Percent (75); + + // Set the colorscheme to make it stand out if is null by default + if (view.ColorScheme == null) { + view.ColorScheme = Colors.Base; + } + + // If the view supports a Text property, set it so we have something to look at + if (view.GetType ().GetProperty ("Text") != null) { + try { + view.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (view, new [] { ustring.Make ("Test Text") }); + } catch (TargetInvocationException e) { + MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok"); + view = null; + } + } + + // If the view supports a Title property, set it so we have something to look at + if (view != null && view.GetType ().GetProperty ("Title") != null) { + view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { ustring.Make ("Test Title") }); + } + + // If the view supports a Source property, set it so we have something to look at + if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType ().GetProperty ("Source").PropertyType == typeof (Terminal.Gui.IListDataSource)) { + var source = new ListWrapper (new List () { ustring.Make ("Test Text #1"), ustring.Make ("Test Text #2"), ustring.Make ("Test Text #3") }); + view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source }); + } + + // Set Settings + _computedCheckBox.Checked = view.LayoutStyle == LayoutStyle.Computed; + + // Add + _hostPane.Add (view); + //DimPosChanged (); + _hostPane.LayoutSubviews (); + _hostPane.Clear (); + _hostPane.SetNeedsDisplay (); + UpdateSettings (view); + UpdateTitle (view); + + view.LayoutComplete += LayoutCompleteHandler; + + return view; + } + + void LayoutCompleteHandler (View.LayoutEventArgs args) + { + UpdateTitle (_curView); + } + } } }