diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index 5997f3f41..3d91da879 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -23,6 +23,7 @@ namespace Terminal.Gui { public class Window : Toplevel { View contentView; ustring title; + int padding; /// /// The title to be displayed for this window. @@ -52,7 +53,7 @@ namespace Terminal.Gui { /// Superview-relative rectangle specifying the location and size /// Title /// - /// This constructor intitalizes a Window with a of . Use constructors + /// This constructor initializes a Window with a of . Use constructors /// that do not take Rect parameters to initialize a Window with . /// public Window (Rect frame, ustring title = null) : this (frame, title, padding: 0) @@ -64,7 +65,7 @@ namespace Terminal.Gui { /// /// Title. /// - /// This constructor intitalize a View with a of . + /// This constructor initializes a View with a of . /// Use , , , and properties to dynamically control the size and location of the view. /// public Window (ustring title = null) : this (title, padding: 0) @@ -76,7 +77,6 @@ namespace Terminal.Gui { /// public Window () : this (title: null) { } - int padding; /// /// Initializes a new instance of the using positioning with the specified frame for its location, with the specified frame padding, /// and an optional title. @@ -85,40 +85,48 @@ namespace Terminal.Gui { /// Number of characters to use for padding of the drawn frame. /// Title /// - /// This constructor intitalizes a Window with a of . Use constructors + /// This constructor initializes a Window with a of . Use constructors /// that do not take Rect parameters to initialize a Window with of /// public Window (Rect frame, ustring title = null, int padding = 0) : base (frame) { - this.Title = title; - int wb = 2 * (1 + padding); - this.padding = padding; - var cFrame = new Rect (1 + padding, 1 + padding, frame.Width - wb, frame.Height - wb); - contentView = new ContentView (cFrame); - base.Add (contentView); + Initialize (title, frame, padding); } /// - /// Initializes a new instance of the using positioning with the specified frame for its location, with the specified frame padding, + /// Initializes a new instance of the using positioning, /// and an optional title. /// /// Number of characters to use for padding of the drawn frame. /// Title. /// - /// This constructor intitalize a View with a of . + /// This constructor initializes a View with a of . /// Use , , , and properties to dynamically control the size and location of the view. /// public Window (ustring title = null, int padding = 0) : base () { - this.Title = title; - int wb = 1 + padding; + Initialize (title, Rect.Empty, padding); + } + + void Initialize (ustring title, Rect frame, int padding = 0) + { + ColorScheme = Colors.Base; + Title = title; + int wb; + if (frame == Rect.Empty) { + wb = 1 + padding; + contentView = new ContentView () { + X = wb, + Y = wb, + Width = Dim.Fill (wb), + Height = Dim.Fill (wb) + }; + } else { + wb = 2 * (1 + padding); + var cFrame = new Rect (1 + padding, 1 + padding, frame.Width - wb, frame.Height - wb); + contentView = new ContentView (cFrame); + } this.padding = padding; - contentView = new ContentView () { - X = wb, - Y = wb, - Width = Dim.Fill (wb), - Height = Dim.Fill (wb) - }; base.Add (contentView); } @@ -179,7 +187,7 @@ namespace Terminal.Gui { var savedClip = ClipToBounds (); - // Redraw our contenetView + // Redraw our contentView // TODO: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed contentView.Redraw (contentView.Bounds); Driver.Clip = savedClip; @@ -216,7 +224,8 @@ namespace Terminal.Gui { // a pending mouse event activated. int nx, ny; - if (!dragPosition.HasValue && mouseEvent.Flags == (MouseFlags.Button1Pressed)) { + if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed + || mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))) { // Only start grabbing if the user clicks on the title bar. if (mouseEvent.Y == 0) { start = new Point (mouseEvent.X, mouseEvent.Y); diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index e1be1dc09..be992ba1c 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -9,6 +9,7 @@ // - Does not support IEnumerable // Any udpates done here should probably be done in Window as well; TODO: Merge these classes +using System; using System.Linq; using NStack; @@ -50,7 +51,7 @@ namespace Terminal.Gui { /// Title. public FrameView (Rect frame, ustring title = null) : base (frame) { - var cFrame = new Rect (1, 1, frame.Width - 2, frame.Height - 2); + var cFrame = new Rect (1, 1, Math.Max (frame.Width - 2, 0), Math.Max (frame.Height - 2, 0)); this.title = title; contentView = new ContentView (cFrame); Initialize (); diff --git a/UnitTests/AllViewsTests.cs b/UnitTests/AllViewsTests.cs new file mode 100644 index 000000000..913090e7a --- /dev/null +++ b/UnitTests/AllViewsTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Xunit; +using System.IO; + +namespace Terminal.Gui.Views { + public class AllViewsTests { + [Fact] + public void AllViews_Tests_All_Constructors () + { + Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))); + + foreach (var type in GetAllViewClassesCollection ()) { + Assert.True (Constructors_FullTest (type)); + } + + Application.Shutdown (); + } + + public bool Constructors_FullTest (Type type) + { + foreach (var ctor in type.GetConstructors ()) { + if (type.IsGenericType && type.IsTypeDefinition) { + List gTypes = new List (); + + foreach (var args in type.GetGenericArguments ()) { + gTypes.Add (typeof (object)); + } + type = type.MakeGenericType (gTypes.ToArray ()); + + Assert.IsType (type, (View)Activator.CreateInstance (type)); + + } else { + ParameterInfo [] paramsInfo = ctor.GetParameters (); + Type paramType; + List pTypes = new List (); + + if (type.IsGenericType) { + foreach (var args in type.GetGenericArguments ()) { + paramType = args.GetType (); + if (args.Name == "T") { + pTypes.Add (typeof (object)); + } else { + AddArguments (paramType, pTypes); + } + } + } + + foreach (var p in paramsInfo) { + paramType = p.ParameterType; + if (p.HasDefaultValue) { + pTypes.Add (p.DefaultValue); + } else { + AddArguments (paramType, pTypes); + } + + } + + if (type.IsGenericType && !type.IsTypeDefinition) { + Assert.IsType (type, (View)Activator.CreateInstance (type)); + } else { + Assert.IsType (type, ctor.Invoke (pTypes.ToArray ())); + } + } + } + + return true; + } + + private static void AddArguments (Type paramType, List pTypes) + { + if (paramType == typeof (Rect)) { + pTypes.Add (Rect.Empty); + } else if (paramType == typeof (NStack.ustring)) { + pTypes.Add (NStack.ustring.Empty); + } else if (paramType == typeof (int)) { + pTypes.Add (0); + } else if (paramType == typeof (bool)) { + pTypes.Add (true); + } else if (paramType.Name == "IList") { + pTypes.Add (new List ()); + } else if (paramType.Name == "View") { + var top = new Toplevel (); + var view = new View (); + top.Add (view); + pTypes.Add (view); + } else if (paramType.Name == "View[]") { + pTypes.Add (new View [] { }); + } else if (paramType.Name == "Stream") { + pTypes.Add (new MemoryStream ()); + } else if (paramType.Name == "String") { + pTypes.Add (string.Empty); + } else if (paramType.Name == "TreeView`1[T]") { + pTypes.Add (string.Empty); + } else { + pTypes.Add (null); + } + } + + 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; + } + } +}