Tigger Kindel 2 سال پیش
والد
کامیت
d62bcb4b90

+ 22 - 1054
Terminal.Gui/Core/Border.cs

@@ -1,10 +1,10 @@
 using NStack;
 using NStack;
 using System;
 using System;
-using System.Collections.Generic;
 using Terminal.Gui.Graphs;
 using Terminal.Gui.Graphs;
 using System.Text.Json.Serialization;
 using System.Text.Json.Serialization;
 using System.Data;
 using System.Data;
 using System.Text;
 using System.Text;
+using System.Collections.Generic;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
@@ -28,533 +28,34 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		Rounded,
 		Rounded,
 		// TODO: Support Ruler
 		// TODO: Support Ruler
-		///// <summary>
+		///// <summary> 
 		///// The border is drawn as a diagnostic ruler ("|123456789...").
 		///// The border is drawn as a diagnostic ruler ("|123456789...").
 		///// </summary>
 		///// </summary>
 		//Ruler
 		//Ruler
 	}
 	}
 
 
 	/// <summary>
 	/// <summary>
-	/// Describes the thickness of a frame around a rectangle. Four <see cref="int"/> values describe
-	///  the <see cref="Left"/>, <see cref="Top"/>, <see cref="Right"/>, and <see cref="Bottom"/> sides
-	///  of the rectangle, respectively.
-	/// </summary>
-	public class Thickness : IEquatable<Thickness> {
-		private int validate (int width)
-		{
-			if (width < 0) {
-				throw new ArgumentException ("Thickness widths cannot be negative.");
-			}
-			return width;
-		}
-		/// <summary>
-		/// Gets or sets the width of the left side of the rectangle.
-		/// </summary>
-		[JsonInclude]
-		public int Left;
-		/// <summary>
-		/// Gets or sets the width of the upper side of the rectangle.
-		/// </summary>
-		[JsonInclude]
-		public int Top;
-		/// <summary>
-		/// Gets or sets the width of the right side of the rectangle.
-		/// </summary>
-		[JsonInclude]
-		public int Right;
-		/// <summary>
-		/// Gets or sets the width of the lower side of the rectangle.
-		/// </summary>
-		[JsonInclude]
-		public int Bottom;
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="Thickness"/> class with all widths
-		/// set to 0.
-		/// </summary>
-		public Thickness () { }
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="Thickness"/> class with a uniform width to each side.
-		/// </summary>
-		/// <param name="width"></param>
-		public Thickness (int width) : this (width, width, width, width) { }
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="Thickness"/> class that has specific
-		///  widths applied to each side of the rectangle.
-		/// </summary>
-		/// <param name="left"></param>
-		/// <param name="top"></param>
-		/// <param name="right"></param>
-		/// <param name="bottom"></param>
-		public Thickness (int left, int top, int right, int bottom)
-		{
-			Left = left;
-			Top = top;
-			Right = right;
-			Bottom = bottom;
-		}
-
-		/// <summary>
-		/// Returns a rectangle describing the location and size of the inner area of <paramref name="rect"/>
-		/// with the thickness widths subracted. The height and width of the retunred rect may be zero.
-		/// </summary>
-		/// <param name="rect">The source rectangle</param>
-		/// <returns></returns>
-		public Rect GetInnerRect (Rect rect)
-		{
-			var width = rect.Size.Width - (Left + Right);
-			var height = rect.Size.Height - (Top + Bottom);
-			var size = new Size (Math.Max (0, width), Math.Max (0, height));
-			return new Rect (new Point (rect.X + Left, rect.Y + Top), size);
-		}
-
-		private void FillRect (Rect rect, System.Rune rune = default)
-		{
-			for (var r = rect.Y; r < rect.Y + rect.Height; r++) {
-				for (var c = rect.X; c < rect.X + rect.Width; c++) {
-					Application.Driver.Move (c, r);
-					Application.Driver.AddRune (rune == default ? ' ' : rune);
-				}
-			}
-		}
-
-		/// <summary>
-		/// Draws the <see cref="Thickness"/> rectangle with an optional diagnostics label.
-		/// </summary>
-		/// <remarks>
-		/// If <see cref="ConsoleDriver.DiagnosticFlags"/> is set to <see cref="ConsoleDriver.DiagnosticFlags.FramePadding"/> then
-		/// 'T', 'L', 'R', and 'B' glyphs will be used instead of space. If <see cref="ConsoleDriver.DiagnosticFlags"/>
-		/// is set to <see cref="ConsoleDriver.DiagnosticFlags.FrameRuler"/> then a ruler will be drawn on the outer edge of the
-		/// Thickness.
-		/// </remarks>
-		/// <param name="rect">The location and size of the rectangle that bounds the thickness rectangle, in 
-		/// screen coordinates.</param>
-		/// <param name="label">The diagnostics label to draw on the bottom of the <see cref="Bottom"/>.</param>
-		/// <returns>The inner rectangle remaining to be drawn.</returns>
-		public Rect Draw (Rect rect, string label = null)
-		{
-			System.Rune clearChar = ' ';
-			System.Rune leftChar = clearChar;
-			System.Rune rightChar = clearChar;
-			System.Rune topChar = clearChar;
-			System.Rune bottomChar = clearChar;
-
-			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding) {
-				leftChar = 'L';
-				rightChar = 'R';
-				topChar = 'T';
-				bottomChar = 'B';
-			}
-
-			ustring hrule = ustring.Empty;
-			ustring vrule = ustring.Empty;
-			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
-
-				string h = "0123456789";
-				hrule = h.Repeat ((int)Math.Ceiling ((double)(rect.Width) / (double)h.Length)) [0..(rect.Width)];
-				string v = "0123456789";
-				vrule = v.Repeat ((int)Math.Ceiling ((double)(rect.Height * 2) / (double)v.Length)) [0..(rect.Height * 2)];
-			};
-
-			// Draw the Top side
-			FillRect (new Rect (rect.X, rect.Y, rect.Width, Math.Min (rect.Height, Top)), topChar);
-
-			// Draw the Left side
-			FillRect (new Rect (rect.X, rect.Y, Math.Min (rect.Width, Left), rect.Height), leftChar);
-
-			// Draw the Right side			
-			FillRect (new Rect (Math.Max (0, rect.X + rect.Width - Right), rect.Y, Math.Min (rect.Width, Right), rect.Height), rightChar);
-
-			// Draw the Bottom side
-			FillRect (new Rect (rect.X, rect.Y + Math.Max (0, rect.Height - Bottom), rect.Width, Bottom), bottomChar);
-
-			// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
-			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
-				// Top
-				Application.Driver.Move (rect.X, rect.Y);
-				Application.Driver.AddStr (hrule);
-				//Left
-				for (var r = rect.Y; r < rect.Y + rect.Height; r++) {
-					Application.Driver.Move (rect.X, r);
-					Application.Driver.AddRune (vrule [r - rect.Y]);
-				}
-				// Bottom
-				Application.Driver.Move (rect.X, rect.Y + rect.Height - Bottom + 1);
-				Application.Driver.AddStr (hrule);
-				// Right
-				for (var r = rect.Y + 1; r < rect.Y + rect.Height; r++) {
-					Application.Driver.Move (rect.X + rect.Width - Right + 1, r);
-					Application.Driver.AddRune (vrule [r - rect.Y]);
-				}
-			}
-
-			// Draw the diagnostics label on the bottom
-			var tf = new TextFormatter () {
-				Text = label == null ? string.Empty : $"{label} {this}",
-				Alignment = TextAlignment.Centered,
-				VerticalAlignment = VerticalTextAlignment.Bottom
-			};
-			tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect, false);
-
-			return GetInnerRect (rect);
-
-		}
-		// TODO: add operator overloads
-		/// <summary>
-		/// Gets an empty thickness.
-		/// </summary>
-		public static Thickness Empty => new Thickness (0);
-
-		/// <inheritdoc/>
-		public override bool Equals (object obj)
-		{
-			//Check for null and compare run-time types.
-			if ((obj == null) || !this.GetType ().Equals (obj.GetType ())) {
-				return false;
-			} else {
-				return Equals ((Thickness)obj);
-			}
-		}
-
-		/// <summary>Returns the thickness widths of the Thickness formatted as a string.</summary>
-		/// <returns>The thickness widths as a string.</returns>
-		public override string ToString ()
-		{
-			return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})";
-		}
-
-		// IEquitable
-		/// <inheritdoc/>
-		public bool Equals (Thickness other)
-		{
-			return other is not null &&
-			       Left == other.Left &&
-			       Right == other.Right &&
-			       Top == other.Top &&
-			       Bottom == other.Bottom;
-		}
-		
-		/// <inheritdoc/>
-		public override int GetHashCode ()
-		{
-			int hashCode = 1380952125;
-			hashCode = hashCode * -1521134295 + Left.GetHashCode ();
-			hashCode = hashCode * -1521134295 + Right.GetHashCode ();
-			hashCode = hashCode * -1521134295 + Top.GetHashCode ();
-			hashCode = hashCode * -1521134295 + Bottom.GetHashCode ();
-			return hashCode;
-		}
-
-		/// <inheritdoc/>
-		public static bool operator == (Thickness left, Thickness right)
-		{
-			return EqualityComparer<Thickness>.Default.Equals (left, right);
-		}
-
-		/// <inheritdoc/>
-		public static bool operator != (Thickness left, Thickness right)
-		{
-			return !(left == right);
-		}
-
-	}
-
-	internal static class StringExtensions {
-		public static string Repeat (this string instr, int n)
-		{
-			if (n <= 0) {
-				return null;
-			}
-
-			if (string.IsNullOrEmpty (instr) || n == 1) {
-				return instr;
-			}
-
-			return new StringBuilder (instr.Length * n)
-				.Insert (0, instr, n)
-				.ToString ();
-		}
-	}
-
-	/// <summary>
-	/// Draws a border, background, or both around another element.
+	/// Defines the visual border for a <see cref="Frame"/>. Also provides helper APIS for rendering the border.
 	/// </summary>
 	/// </summary>
 	public class Border {
 	public class Border {
-		private int marginFrame => DrawMarginFrame ? 1 : 0;
-
-		///// <summary>
-		///// A sealed <see cref="Toplevel"/> derived class to implement <see cref="Border"/> feature.
-		///// This is only a wrapper to get borders on a toplevel and is recommended using another
-		///// derived, like <see cref="Window"/> where is possible to have borders with or without
-		///// border line or spacing around.
-		///// </summary>
-		//public sealed class ToplevelContainer : Toplevel {
-		//	/// <inheritdoc/>
-		//	public override Border Border {
-		//		get => base.Border;
-		//		set {
-		//			if (base.Border != null && base.Border.Child != null && value.Child == null) {
-		//				value.Child = base.Border.Child;
-		//			}
-		//			base.Border = value;
-		//			if (value == null) {
-		//				return;
-		//			}
-		//			Rect frame;
-		//			if (Border.Child != null && (Border.Child.Width is Dim || Border.Child.Height is Dim)) {
-		//				frame = Rect.Empty;
-		//			} else {
-		//				frame = Frame;
-		//			}
-		//			AdjustContentView (frame);
-
-		//			Border.BorderChanged += Border_BorderChanged;
-		//		}
-		//	}
-
-		//	void Border_BorderChanged (Border border)
-		//	{
-		//		Rect frame;
-		//		if (Border.Child != null && (Border.Child.Width is Dim || Border.Child.Height is Dim)) {
-		//			frame = Rect.Empty;
-		//		} else {
-		//			frame = Frame;
-		//		}
-		//		AdjustContentView (frame);
-		//	}
-
-		//	/// <summary>
-		//	/// Initializes with default null values.
-		//	/// </summary>
-		//	public ToplevelContainer () : this (null, string.Empty) { }
-
-		//	/// <summary>
-		//	/// Initializes a <see cref="ToplevelContainer"/> with a <see cref="LayoutStyle.Computed"/>
-		//	/// </summary>
-		//	/// <param name="border">The border.</param>
-		//	/// <param name="title">The title.</param>
-		//	public ToplevelContainer (Border border, string title = null)
-		//	{
-		//		Initialize (Rect.Empty, border, title ?? string.Empty);
-		//	}
-
-		//	/// <summary>
-		//	/// Initializes a <see cref="ToplevelContainer"/> with a <see cref="LayoutStyle.Absolute"/>
-		//	/// </summary>
-		//	/// <param name="frame">The frame.</param>
-		//	/// <param name="border">The border.</param>
-		//	/// <param name="title">The title.</param>
-		//	public ToplevelContainer (Rect frame, Border border, string title = null) : base (frame)
-		//	{
-		//		Initialize (frame, border, title ?? string.Empty);
-		//	}
-
-		//	private void Initialize (Rect frame, Border border, string title)
-		//	{
-		//		ColorScheme = Colors.TopLevel;
-		//		if (border == null) {
-		//			Border = new Border () {
-		//				BorderStyle = BorderStyle.Single,
-		//				BorderBrush = ColorScheme.Normal.Background,
-		//				Title = (ustring)title
-		//			};
-		//		} else {
-		//			Border = border;
-		//		}
-		//		AdjustContentView (frame);
-		//	}
-
-		//	void AdjustContentView (Rect frame)
-		//	{
-		//		var borderLength = Border.DrawMarginFrame ? 1 : 0;
-		//		var sumPadding = Border.GetSumThickness ();
-		//		var wp = new Point ();
-		//		var wb = new Size ();
-		//		if (frame == Rect.Empty) {
-		//			wp.X = borderLength + sumPadding.Left;
-		//			wp.Y = borderLength + sumPadding.Top;
-		//			wb.Width = borderLength + sumPadding.Right;
-		//			wb.Height = borderLength + sumPadding.Bottom;
-		//			if (Border.Child == null) {
-		//				Border.Child = new ChildContentView (this) {
-		//					X = wp.X,
-		//					Y = wp.Y,
-		//					Width = Dim.Fill (wb.Width),
-		//					Height = Dim.Fill (wb.Height)
-		//				};
-		//			} else {
-		//				Border.Child.X = wp.X;
-		//				Border.Child.Y = wp.Y;
-		//				Border.Child.Width = Dim.Fill (wb.Width);
-		//				Border.Child.Height = Dim.Fill (wb.Height);
-		//			}
-		//		} else {
-		//			wb.Width = (2 * borderLength) + sumPadding.Right + sumPadding.Left;
-		//			wb.Height = (2 * borderLength) + sumPadding.Bottom + sumPadding.Top;
-		//			var cFrame = new Rect (borderLength + sumPadding.Left, borderLength + sumPadding.Top, frame.Width - wb.Width, frame.Height - wb.Height);
-		//			if (Border.Child == null) {
-		//				Border.Child = new ChildContentView (cFrame, this);
-		//			} else {
-		//				Border.Child.Frame = cFrame;
-		//			}
-		//		}
-		//		if (Subviews?.Count == 0)
-		//			base.Add (Border.Child);
-		//		Border.ChildContainer = this;
-		//	}
-
-		//	/// <inheritdoc/>
-		//	public override void Add (View view)
-		//	{
-		//		Border.Child.Add (view);
-		//		if (view.CanFocus) {
-		//			CanFocus = true;
-		//		}
-		//		AddMenuStatusBar (view);
-		//	}
-
-		//	/// <inheritdoc/>
-		//	public override void Remove (View view)
-		//	{
-		//		if (view == null) {
-		//			return;
-		//		}
-
-		//		SetNeedsDisplay ();
-		//		var touched = view.Frame;
-		//		Border.Child.Remove (view);
-
-		//		if (Border.Child.InternalSubviews.Count < 1) {
-		//			CanFocus = false;
-		//		}
-		//		RemoveMenuStatusBar (view);
-		//	}
-
-		//	/// <inheritdoc/>
-		//	public override void RemoveAll ()
-		//	{
-		//		Border.Child.RemoveAll ();
-		//	}
-
-		//	/// <inheritdoc/>
-		//	public override void Redraw (Rect bounds)
-		//	{
-		//		if (!NeedDisplay.IsEmpty) {
-		//			Driver.SetAttribute (GetNormalColor ());
-		//			Clear ();
-		//		}
-		//		var savedClip = Border.Child.ClipToBounds ();
-		//		Border.Child.Redraw (Border.Child.Bounds);
-		//		Driver.Clip = savedClip;
-
-		//		ClearLayoutNeeded ();
-		//		ClearNeedsDisplay ();
-
-		//		Driver.SetAttribute (GetNormalColor ());
-		//		Border.DrawContent (this, false);
-		//		if (HasFocus)
-		//			Driver.SetAttribute (ColorScheme.HotNormal);
-		//		if (Border.DrawMarginFrame) {
-		//			if (!ustring.IsNullOrEmpty (Border.Title))
-		//				Border.DrawTitle (this);
-		//			else
-		//				Border.DrawTitle (this, Frame);
-		//		}
-		//		Driver.SetAttribute (GetNormalColor ());
-
-		//		// Checks if there are any SuperView view which intersect with this window.
-		//		if (SuperView != null) {
-		//			SuperView.SetNeedsLayout ();
-		//			SuperView.SetNeedsDisplay ();
-		//		}
-		//	}
-
-		//	/// <inheritdoc/>
-		//	public override void OnCanFocusChanged ()
-		//	{
-		//		if (Border.Child != null) {
-		//			Border.Child.CanFocus = CanFocus;
-		//		}
-		//		base.OnCanFocusChanged ();
-		//	}
-		//}
-
-		//private class ChildContentView : View {
-		//	View instance;
-
-		//	public ChildContentView (Rect frame, View instance) : base (frame)
-		//	{
-		//		this.instance = instance;
-		//	}
-		//	public ChildContentView (View instance)
-		//	{
-		//		this.instance = instance;
-		//	}
-
-		//	public override bool MouseEvent (MouseEvent mouseEvent)
-		//	{
-		//		return instance.MouseEvent (mouseEvent);
-		//	}
-		//}
 
 
 		/// <summary>
 		/// <summary>
+		/// Raised if any of the properties that define the border are changed.
 		/// </summary>
 		/// </summary>
 		public event Action<Border> BorderChanged;
 		public event Action<Border> BorderChanged;
 
 
-		private BorderStyle borderStyle;
-		private bool drawMarginFrame;
-		private Thickness borderThickness = new Thickness (0);
-		private Color borderBrush;
-		private Color background;
-		private Thickness padding = new Thickness (0);
-		private bool effect3D;
-		private Point effect3DOffset = new Point (1, 1);
-		private Attribute? effect3DBrush;
-		private ustring title = ustring.Empty;
-		//private View child;
+		private BorderStyle _style;
+		private Color _forgroundColor;
+		private Color _backgroundColor;
 
 
 		/// <summary>
 		/// <summary>
 		/// Specifies the <see cref="Gui.BorderStyle"/> for a view.
 		/// Specifies the <see cref="Gui.BorderStyle"/> for a view.
 		/// </summary>
 		/// </summary>
 		[JsonInclude, JsonConverter (typeof (JsonStringEnumConverter))]
 		[JsonInclude, JsonConverter (typeof (JsonStringEnumConverter))]
 		public BorderStyle BorderStyle {
 		public BorderStyle BorderStyle {
-			get => borderStyle;
-			set {
-				if (value != BorderStyle.None && !drawMarginFrame) {
-					// Ensures drawn the border lines.
-					drawMarginFrame = true;
-				}
-				borderStyle = value;
-				OnBorderChanged ();
-			}
-		}
-
-		/// <summary>
-		/// </summary>
-		[JsonInclude]
-		public bool DrawMarginFrame {
-			get => drawMarginFrame;
+			get => _style;
 			set {
 			set {
-				if (borderStyle != BorderStyle.None
-					&& (!value || !drawMarginFrame)) {
-					// Ensures drawn the border lines.
-					drawMarginFrame = true;
-				} else {
-					drawMarginFrame = value;
-				}
-				OnBorderChanged ();
-			}
-		}
-
-		/// <summary>
-		/// </summary>
-		[JsonInclude]
-		public Thickness BorderThickness {
-			get => borderThickness;
-			set {
-				borderThickness = value;
+				_style = value;
 				OnBorderChanged ();
 				OnBorderChanged ();
 			}
 			}
 		}
 		}
@@ -563,10 +64,10 @@ namespace Terminal.Gui {
 		/// Gets or sets the <see cref="Color"/> that draws the outer border color.
 		/// Gets or sets the <see cref="Color"/> that draws the outer border color.
 		/// </summary>
 		/// </summary>
 		[JsonInclude, JsonConverter (typeof (Configuration.ColorJsonConverter))]
 		[JsonInclude, JsonConverter (typeof (Configuration.ColorJsonConverter))]
-		public Color BorderBrush {
-			get => borderBrush;
+		public Color ForgroundColor {
+			get => _forgroundColor;
 			set {
 			set {
-				borderBrush = value;
+				_forgroundColor = value;
 				OnBorderChanged ();
 				OnBorderChanged ();
 			}
 			}
 		}
 		}
@@ -575,554 +76,21 @@ namespace Terminal.Gui {
 		/// Gets or sets the <see cref="Color"/> that fills the area between the bounds of a <see cref="Border"/>.
 		/// Gets or sets the <see cref="Color"/> that fills the area between the bounds of a <see cref="Border"/>.
 		/// </summary>
 		/// </summary>
 		[JsonInclude, JsonConverter (typeof (Configuration.ColorJsonConverter))]
 		[JsonInclude, JsonConverter (typeof (Configuration.ColorJsonConverter))]
-		public Color Background {
-			get => background;
+		public Color BackgroundColor {
+			get => _backgroundColor;
 			set {
 			set {
-				background = value;
+				_backgroundColor = value;
 				OnBorderChanged ();
 				OnBorderChanged ();
 			}
 			}
 		}
 		}
 
 
-		/// <summary>
-		/// Gets or sets a <see cref="Thickness"/> value that describes the amount of space between a
-		///  <see cref="Border"/> and its child element.
-		/// </summary>
-		[JsonInclude]
-		public Thickness Padding {
-			get => padding;
-			set {
-				padding = value;
-				OnBorderChanged ();
-			}
-		}
-
-		///// <summary>
-		///// Gets the rendered width of this element.
-		///// </summary>
-		//[JsonIgnore]
-		//public int ActualWidth {
-		//	get {
-		//		var driver = Application.Driver;
-		//		if (Parent?.Border == null) {
-		//			return Math.Min (Child?.Frame.Width + (2 * marginFrame) + Padding.Right
-		//				+ BorderThickness.Right + Padding.Left + BorderThickness.Left ?? 0, driver.Cols);
-		//		}
-		//		return Math.Min (Parent.Frame.Width, driver.Cols);
-		//	}
-		//}
-		///// <summary>
-		///// Gets the rendered height of this element.
-		///// </summary>
-		//[JsonIgnore]
-		//public int ActualHeight {
-		//	get {
-		//		var driver = Application.Driver;
-		//		if (Parent?.Border == null) {
-		//			return Math.Min (Child?.Frame.Height + (2 * marginFrame) + Padding.Bottom
-		//				+ BorderThickness.Bottom + Padding.Top + BorderThickness.Top ?? 0, driver.Rows);
-		//		}
-		//		return Math.Min (Parent.Frame.Height, driver.Rows);
-		//	}
-		//}
-
-		///// <summary>
-		///// Gets or sets the single child element of a <see cref="View"/>.
-		///// </summary>
-		//[JsonIgnore]
-		//public View Child {
-		//	get => child;
-		//	set {
-		//		child = value;
-		//		if (child != null && Parent != null) {
-		//			Parent.Initialized += Parent_Initialized;
-		//			Parent.Removed += Parent_Removed;
-		//		}
-		//	}
-		//}
-
-		//private void Parent_Removed (View obj)
-		//{
-		//	BorderBrush = default;
-		//	Background = default;
-		//	child.Removed -= Parent_Removed;
-		//}
-
-		//private void Parent_Initialized (object s, EventArgs e)
-		//{
-		//	SetMarginFrameTitleBrush ();
-		//	child.Initialized -= Parent_Initialized;
-		//}
-
-		//private void SetMarginFrameTitleBrush ()
-		//{
-		//	if (child != null) {
-		//		var view = Parent?.Border != null ? Parent : child;
-		//		if (view.ColorScheme != null) {
-		//			if (borderBrush == default) {
-		//				BorderBrush = view.GetNormalColor ().Foreground;
-		//			}
-		//			if (background == default) {
-		//				Background = view.GetNormalColor ().Background;
-		//			}
-		//			return;
-		//		}
-		//	}
-		//	BorderBrush = default;
-		//	Background = default;
-		//}
-
-		///// <summary>
-		///// Gets the parent <see cref="Child"/> parent if any.
-		///// </summary>
-		//[JsonIgnore]
-		//public View Parent { get => Child?.SuperView; }
-
-		///// <summary>
-		///// Gets or private sets by the <see cref="ToplevelContainer"/>
-		///// </summary>
-		//[JsonIgnore]
-		//public ToplevelContainer ChildContainer { get; private set; }
-
-		/// <summary>
-		/// Gets or sets the 3D effect around the <see cref="Border"/>.
-		/// </summary>
-		[JsonInclude]
-		public bool Effect3D {
-			get => effect3D;
-			set {
-				effect3D = value;
-				OnBorderChanged ();
-			}
-		}
-
-		/// <summary>
-		/// Get or sets the offset start position for the <see cref="Effect3D"/>
-		/// </summary>
-		[JsonInclude]
-		public Point Effect3DOffset {
-			get => effect3DOffset;
-			set {
-				effect3DOffset = value;
-				OnBorderChanged ();
-			}
-		}
-		/// <summary>
-		/// Gets or sets the color for the <see cref="Border"/>
-		/// </summary>
-		[JsonInclude, JsonConverter (typeof (Configuration.AttributeJsonConverter))]
-		public Attribute? Effect3DBrush {
-			get {
-				if (effect3DBrush == null && effect3D) {
-					return effect3DBrush = new Attribute (Color.Gray, Color.DarkGray);
-				} else {
-					return effect3DBrush;
-				}
-			}
-
-			set {
-				effect3DBrush = value;
-				OnBorderChanged ();
-			}
-		}
-
-		///// <summary>
-		///// The title to be displayed for this view.
-		///// </summary>
-		//[JsonIgnore]
-		//public ustring Title {
-		//	get => title;
-		//	set {
-		//		title = value;
-		//		OnBorderChanged ();
-		//	}
-		//}
-
-		///// <summary>
-		///// Calculate the sum of the <see cref="Padding"/> and the <see cref="BorderThickness"/>
-		///// </summary>
-		///// <returns>The total of the <see cref="Border"/> <see cref="Thickness"/></returns>
-		//public Thickness GetSumThickness ()
-		//{
-		//	return new Thickness () {
-		//		Left = Padding.Left + BorderThickness.Left,
-		//		Top = Padding.Top + BorderThickness.Top,
-		//		Right = Padding.Right + BorderThickness.Right,
-		//		Bottom = Padding.Bottom + BorderThickness.Bottom
-		//	};
-		//}
-
-		///// <summary>
-		///// Drawn the <see cref="BorderThickness"/> more the <see cref="Padding"/>
-		/////  more the <see cref="Border.BorderStyle"/> and the <see cref="Effect3D"/>.
-		///// </summary>
-		///// <param name="view">The view to draw.</param>
-		///// <param name="fill">If it will clear or not the content area.</param>
-		//public void DrawContent (View view = null, bool fill = true)
-		//{
-		//	if (Child == null) {
-		//		Child = view;
-		//	}
-		//	if (Parent?.Border != null) {
-		//		DrawParentBorder (Parent.ViewToScreen (Parent.Bounds), fill);
-		//	} else {
-		//		DrawChildBorder (Child.ViewToScreen (Child.Bounds), fill);
-		//	}
-		//}
-
-		///// <summary>
-		///// Same as <see cref="DrawContent"/> but drawing full frames for all borders.
-		///// </summary>
-		//public void DrawFullContent ()
-		//{
-		//	var borderThickness = BorderThickness;
-		//	var padding = Padding;
-		//	var marginFrame = DrawMarginFrame ? 1 : 0;
-		//	var driver = Application.Driver;
-		//	Rect scrRect;
-		//	if (Parent?.Border != null) {
-		//		scrRect = Parent.ViewToScreen (Parent.Bounds);
-		//	} else {
-		//		scrRect = Child.ViewToScreen (Child.Bounds);
-		//	}
-		//	Rect borderRect;
-		//	if (Parent?.Border != null) {
-		//		borderRect = scrRect;
-		//	} else {
-		//		borderRect = new Rect () {
-		//			X = scrRect.X - marginFrame - padding.Left - borderThickness.Left,
-		//			Y = scrRect.Y - marginFrame - padding.Top - borderThickness.Top,
-		//			Width = ActualWidth,
-		//			Height = ActualHeight
-		//		};
-		//	}
-		//	var savedAttribute = driver.GetAttribute ();
-
-		//	// Draw 3D effects
-		//	if (Effect3D) {
-		//		driver.SetAttribute ((Attribute)Effect3DBrush);
-
-		//		var effectBorder = new Rect () {
-		//			X = borderRect.X + Effect3DOffset.X,
-		//			Y = borderRect.Y + Effect3DOffset.Y,
-		//			Width = ActualWidth,
-		//			Height = ActualHeight
-		//		};
-		//		//Child.Clear (effectBorder);
-		//		for (int r = effectBorder.Y; r < Math.Min (effectBorder.Bottom, driver.Rows); r++) {
-		//			for (int c = effectBorder.X; c < Math.Min (effectBorder.Right, driver.Cols); c++) {
-
-		//				AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
-		//			}
-		//		}
-		//	}
-
-		//	// Draw border thickness
-		//	driver.SetAttribute (new Attribute (BorderBrush));
-		//	Child.Clear (borderRect);
-
-		//	borderRect = new Rect () {
-		//		X = borderRect.X + borderThickness.Left,
-		//		Y = borderRect.Y + borderThickness.Top,
-		//		Width = Math.Max (borderRect.Width - borderThickness.Right - borderThickness.Left, 0),
-		//		Height = Math.Max (borderRect.Height - borderThickness.Bottom - borderThickness.Top, 0)
-		//	};
-		//	if (borderRect != scrRect) {
-		//		// Draw padding
-		//		driver.SetAttribute (new Attribute (Background));
-		//		Child.Clear (borderRect);
-		//	}
-
-		//	driver.SetAttribute (new Attribute (BorderBrush, Background));
-
-		//	// Draw margin frame
-		//	if (DrawMarginFrame) {
-		//		if (Parent?.Border != null) {
-		//			var sumPadding = GetSumThickness ();
-		//			borderRect = new Rect () {
-		//				X = scrRect.X + sumPadding.Left,
-		//				Y = scrRect.Y + sumPadding.Top,
-		//				Width = Math.Max (scrRect.Width - sumPadding.Right - sumPadding.Left, 0),
-		//				Height = Math.Max (scrRect.Height - sumPadding.Bottom - sumPadding.Top, 0)
-		//			};
-		//		} else {
-		//			borderRect = new Rect () {
-		//				X = borderRect.X + padding.Left,
-		//				Y = borderRect.Y + padding.Top,
-		//				Width = Math.Max (borderRect.Width - padding.Right - padding.Left, 0),
-		//				Height = Math.Max (borderRect.Height - padding.Bottom - padding.Top, 0)
-		//			};
-		//		}
-		//		if (borderRect.Width > 0 && borderRect.Height > 0) {
-		//			driver.DrawWindowFrame (borderRect, 1, 1, 1, 1, BorderStyle != BorderStyle.None, fill: true, this);
-		//		}
-		//	}
-		//	driver.SetAttribute (savedAttribute);
-		//}
-
-		//private void DrawChildBorder (Rect frame, bool fill = true)
-		//{
-		//	var drawMarginFrame = DrawMarginFrame ? 1 : 0;
-		//	var sumThickness = GetSumThickness ();
-		//	var padding = Padding;
-		//	var effect3DOffset = Effect3DOffset;
-		//	var driver = Application.Driver;
-
-		//	var savedAttribute = driver.GetAttribute ();
-
-		//	driver.SetAttribute (new Attribute (BorderBrush));
-
-			// Draw the upper BorderThickness
-		//	for (int r = frame.Y - drawMarginFrame - sumThickness.Top;
-		//		r < frame.Y - drawMarginFrame - padding.Top; r++) {
-
-		//		if (r < 0) {
-		//			continue;
-		//		}
-		//		for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-		//			c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the left BorderThickness
-		//	for (int r = frame.Y - drawMarginFrame - padding.Top;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
-
-		//		if (r < 0) {
-		//			continue;
-		//		}
-		//		for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-		//			c < frame.X - drawMarginFrame - padding.Left; c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the right BorderThickness
-		//	for (int r = frame.Y - drawMarginFrame - padding.Top;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
-
-		//		if (r < 0) {
-		//			continue;
-		//		}
-		//		for (int c = frame.Right + drawMarginFrame + padding.Right;
-		//			c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the lower BorderThickness
-		//	for (int r = frame.Bottom + drawMarginFrame + padding.Bottom;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
-		//		for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-		//			c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		////	driver.SetAttribute (new Attribute (Background));
-
-		//	// Draw the upper Padding
-		//	for (int r = frame.Y - drawMarginFrame - padding.Top;
-		//		r < frame.Y - drawMarginFrame; r++) {
-
-		//		if (r < 0) {
-		//			continue;
-		//		}
-		//		for (int c = frame.X - drawMarginFrame - padding.Left;
-		//			c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the left Padding
-		//	for (int r = frame.Y - drawMarginFrame;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
-		//		for (int c = frame.X - drawMarginFrame - padding.Left;
-		//			c < frame.X - drawMarginFrame; c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the right Padding
-		//	for (int r = frame.Y - drawMarginFrame;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
-		//		for (int c = frame.Right + drawMarginFrame;
-		//			c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	// Draw the lower Padding
-		//	for (int r = frame.Bottom + drawMarginFrame;
-		//		r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
-		//		for (int c = frame.X - drawMarginFrame - padding.Left;
-		//			c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
-
-		////			AddRuneAt (driver, c, r, ' ');
-		////		}
-		////	}
-
-		//	driver.SetAttribute (new Attribute (BorderBrush, Background));
-
-		//	// Draw the MarginFrame
-		//	if (DrawMarginFrame) {
-
-		//		var rect = new Rect () {
-		//			X = frame.X - drawMarginFrame,
-		//			Y = frame.Y - drawMarginFrame,
-		//			Width = frame.Width + (2 * drawMarginFrame),
-		//			Height = frame.Height + (2 * drawMarginFrame)
-		//		};
-		//		if (rect.Width > 0 && rect.Height > 0) {
-		//			driver.DrawWindowFrame (rect, 1, 1, 1, 1, BorderStyle != BorderStyle.None, fill, this);
-		//			DrawTitle (Child);
-		//		}
-
-		//		//var rect = Child.ViewToScreen (new Rect (-1, -1, Child.Frame.Width + 2, Child.Frame.Height + 2));
-		//		//if (rect.Width > 0 && rect.Height > 0) {
-
-		//		//	var lc = new LineCanvas ();
-
-		//		//	lc.AddLine (rect.Location, rect.Width-1, Orientation.Horizontal, BorderStyle);
-		//		//	lc.AddLine (rect.Location, rect.Height-1, Orientation.Vertical, BorderStyle);
-
-		//		//	lc.AddLine (new Point (rect.X, rect.Y + rect.Height-1), rect.Width, Orientation.Horizontal, BorderStyle);
-		//		//	lc.AddLine (new Point (rect.X + rect.Width-1, rect.Y), rect.Height, Orientation.Vertical, BorderStyle);
-
-		//		//	//driver.SetAttribute (new Attribute(Color.Red, Color.BrightYellow));
-		//		//	foreach (var p in lc.GenerateImage (rect)) {
-		//		//		AddRuneAt (driver, p.Key.X, p.Key.Y, p.Value);
-		//		//	}
-		//		//	DrawTitle (Child);
-		//		//}
-		//	}
-
-		//	if (Effect3D) {
-		//		driver.SetAttribute ((Attribute)Effect3DBrush);
-
-		//		// Draw the upper Effect3D
-		//		for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-		//			r >= 0 && r < frame.Y - drawMarginFrame - sumThickness.Top; r++) {
-		//			for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-		//				c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
-
-		//				AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
-		//			}
-		//		}
-
-		//		// Draw the left Effect3D
-		//		for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-		//			r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
-		//			for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-		//				c >= 0 && c < frame.X - drawMarginFrame - sumThickness.Left; c++) {
-
-		//				AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
-		//			}
-		//		}
-
-		//		// Draw the right Effect3D
-		//		for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-		//			r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
-		//			for (int c = frame.Right + drawMarginFrame + sumThickness.Right;
-		//				c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
-
-		//				AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
-		//			}
-		//		}
-
-		//		// Draw the lower Effect3D
-		//		for (int r = frame.Bottom + drawMarginFrame + sumThickness.Bottom;
-		//			r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
-		//			for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-		//				c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
-
-		//				AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
-		//			}
-		//		}
-		//	}
-		//	driver.SetAttribute (savedAttribute);
-		//}
-
-		//private void DrawParentBorder (Rect frame, bool fill = true)
-		//{
-		//	var sumThickness = GetSumThickness ();
-		//	var borderThickness = BorderThickness;
-		//	var effect3DOffset = Effect3DOffset;
-		//	var driver = Application.Driver;
-
-		//	var savedAttribute = driver.GetAttribute ();
-
-		//	driver.SetAttribute (new Attribute (BorderBrush));
-
-			// Draw the upper BorderThickness
-		//}
-
-		//private void AddRuneAt (ConsoleDriver driver, int col, int row, Rune ch)
-		//{
-		//	if (col < driver.Cols && row < driver.Rows && col > 0 && driver.Contents [row, col, 2] == 0
-		//		&& Rune.ColumnWidth ((char)driver.Contents [row, col - 1, 0]) > 1) {
-
-		//		driver.Contents [row, col, 1] = driver.GetAttribute ();
-		//		return;
-		//	}
-		//	driver.Move (col, row);
-		//	driver.AddRune (ch);
-		//}
-
-		///// <summary>
-		///// Draws the view <see cref="Title"/> to the screen.
-		///// </summary>
-		///// <param name="view">The view.</param>
-		//public void DrawTitle (View view)
-		//{
-		//	var driver = Application.Driver;
-		//	if (DrawMarginFrame) {
-		//		driver.SetAttribute (new Attribute (BorderBrush, Background));
-		//		if (view.HasFocus) {
-		//			driver.SetAttribute (new Attribute (Child.ColorScheme.HotNormal.Foreground, Background));
-		//		}
-		//		var padding = view.Border.GetSumThickness ();
-		//		Rect scrRect;
-		//		if (view == Child) {
-		//			scrRect = view.ViewToScreen (new Rect (0, 0, view.Frame.Width + 2, view.Frame.Height + 2));
-		//			scrRect = new Rect (scrRect.X - 1, scrRect.Y - 1, scrRect.Width, scrRect.Height);
-		//			driver.DrawWindowTitle (scrRect, Title, 0, 0, 0, 0);
-		//		} else {
-		//			scrRect = view.ViewToScreen (new Rect (0, 0, view.Frame.Width, view.Frame.Height));
-		//			driver.DrawWindowTitle (scrRect, Parent.Border.Title,
-		//				padding.Left, padding.Top, padding.Right, padding.Bottom);
-		//		}
-		//	}
-		//	driver.SetAttribute (Child.GetNormalColor ());
-		//}
-
-		///// <summary>
-		///// Draws the <see cref="View.Text"/> to the screen.
-		///// </summary>
-		///// <param name="view">The view.</param>
-		///// <param name="rect">The frame.</param>
-		//public void DrawTitle (View view, Rect rect)
-		//{
-		//	var driver = Application.Driver;
-		//	if (DrawMarginFrame) {
-		//		driver.SetAttribute (new Attribute (BorderBrush, Background));
-		//		if (view.HasFocus) {
-		//			driver.SetAttribute (new Attribute (view.ColorScheme.HotNormal.Foreground, Background));
-		//		}
-		//		var padding = Parent.Border.GetSumThickness ();
-		//		var scrRect = Parent.ViewToScreen (new Rect (0, 0, rect.Width, rect.Height));
-		//		driver.DrawWindowTitle (scrRect, view.Text,
-		//			padding.Left, padding.Top, padding.Right, padding.Bottom);
-		//	}
-		//	driver.SetAttribute (view.GetNormalColor ());
-		//}
+		// TODO: These are all temporary to keep code compiling
+		public bool DrawMarginFrame { get; set; }
+		public Point Effect3DOffset { get; set; }
+		public bool Effect3D { get; set; }
+		public Thickness BorderThickness { get; set; }
+		public object Effect3DBrush { get; set; }
+		public Thickness Padding { get; set; }
 
 
 		/// <summary>
 		/// <summary>
 		/// Invoke the <see cref="BorderChanged"/> event.
 		/// Invoke the <see cref="BorderChanged"/> event.

+ 27 - 0
Terminal.Gui/Core/Canvas.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Terminal.Gui.Core {
+	/// <summary>
+	/// The <see cref="Canvas"/> is a <see cref="Responder"/> that can be used to draw on the screen. 
+	/// It is the base class of <see cref="View"/> and <see cref="Frame"/>.
+	/// </summary>
+	public class Canvas : Responder {
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Canvas"/> class.
+		/// </summary>
+		public Canvas () : this (Rect.Empty) {}
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Canvas"/> class.
+		/// </summary>
+		/// <param name="frame">The <see cref="Rect"/> that defines the position and size of the <see cref="Canvas"/> on the screen.</param>
+		/// relative coordinates.</param>
+		public Canvas (Rect frame) 
+		{
+		}
+	}
+}

+ 6 - 43
Terminal.Gui/Core/Container.cs → Terminal.Gui/Core/Frame.cs

@@ -9,21 +9,20 @@ namespace Terminal.Gui {
 
 
 	/// <summary>
 	/// <summary>
 	/// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
 	/// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
-	/// eanbling borders, menus, etc... 
+	/// enabling borders, menus, etc... 
 	/// </summary>
 	/// </summary>
 	public class Frame : View {
 	public class Frame : View {
 
 
 		/// <summary>
 		/// <summary>
 		/// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
 		/// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
-		/// eanbling borders, menus, etc... 
+		/// enabling borders, menus, etc... 
 		/// </summary>
 		/// </summary>
 		public Frame ()
 		public Frame ()
 		{
 		{
-			IgnoreBorderPropertyOnRedraw = true;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// The Parent of this Frame (Adornment). 
+		/// The Parent of this Frame. 
 		/// </summary>
 		/// </summary>
 		public View Parent { get; set; }
 		public View Parent { get; set; }
 
 
@@ -132,8 +131,8 @@ namespace Terminal.Gui {
 					Driver.AddRune (p.Value);
 					Driver.AddRune (p.Value);
 				}
 				}
 
 
-				if (!ustring.IsNullOrEmpty (Title)) {
-					Driver.DrawWindowTitle (screenBounds, Title, 0, 0, 0, 0);
+				if (!ustring.IsNullOrEmpty (Parent?.Title)) {
+					Driver.DrawWindowTitle (screenBounds, Parent?.Title, 0, 0, 0, 0);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -148,7 +147,7 @@ namespace Terminal.Gui {
 		public BorderStyle BorderStyle { get; set; } = BorderStyle.None;
 		public BorderStyle BorderStyle { get; set; } = BorderStyle.None;
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Defines the rectangle that the <see cref="Frame"/> will use to draw its content. 
 		/// </summary>
 		/// </summary>
 		public Thickness Thickness { get; set; }
 		public Thickness Thickness { get; set; }
 
 
@@ -170,41 +169,5 @@ namespace Terminal.Gui {
 				throw new InvalidOperationException ("It makes no sense to explicitly set Bounds.");
 				throw new InvalidOperationException ("It makes no sense to explicitly set Bounds.");
 			}
 			}
 		}
 		}
-
-		//public override void OnDrawContent (Rect viewport)
-		//{
-		//	// do nothing
-		//}
-
-		//public override void Redraw (Rect bounds)
-		//{
-
-		//	if (ColorScheme != null) {
-		//		Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
-		//	}
-
-		//	//if (Text != null) {
-		//	//	Thickness?.Draw (Frame, $"{Text} {DiagnosticsLabel?.Text}");
-		//	//}
-		//	if (BorderStyle != BorderStyle.None) {
-		//		var lc = new LineCanvas ();
-		//		lc.AddLine (Frame.Location, Frame.Width - 1, Orientation.Horizontal, BorderStyle);
-		//		lc.AddLine (Frame.Location, Frame.Height - 1, Orientation.Vertical, BorderStyle);
-
-		//		lc.AddLine (new Point (Frame.X, Frame.Y + Frame.Height - 1), Frame.Width - 1, Orientation.Horizontal, BorderStyle);
-		//		lc.AddLine (new Point (Frame.X + Frame.Width - 1, Frame.Y), Frame.Height - 1, Orientation.Vertical, BorderStyle);
-		//		foreach (var p in lc.GenerateImage (Frame)) {
-		//			Driver.Move (p.Key.X, p.Key.Y);
-		//			Driver.AddRune (p.Value);
-		//		}
-
-		//		if (!ustring.IsNullOrEmpty (Title)) {
-		//			Driver.DrawWindowTitle (Frame, Title, 0, 0, 0, 0);
-		//		}
-		//	}
-
-		//	base.Redraw (bounds);
-		//}
 	}
 	}
-
 }
 }

+ 254 - 0
Terminal.Gui/Core/Thickness.cs

@@ -0,0 +1,254 @@
+using NStack;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json.Serialization;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Describes the thickness of a frame around a rectangle. Four <see cref="int"/> values describe
+	///  the <see cref="Left"/>, <see cref="Top"/>, <see cref="Right"/>, and <see cref="Bottom"/> sides
+	///  of the rectangle, respectively. Provides a helper API (<see cref="Draw(Rect, string)"/> for
+	///  drawing a frame with the specified thickness.
+	/// </summary>
+	public class Thickness : IEquatable<Thickness> {
+		private int validate (int width)
+		{
+			if (width < 0) {
+				throw new ArgumentException ("Thickness widths cannot be negative.");
+			}
+			return width;
+		}
+		/// <summary>
+		/// Gets or sets the width of the left side of the rectangle.
+		/// </summary>
+		[JsonInclude]
+		public int Left;
+		
+		/// <summary>
+		/// Gets or sets the width of the upper side of the rectangle.
+		/// </summary>
+		[JsonInclude]
+		public int Top;
+		
+		/// <summary>
+		/// Gets or sets the width of the right side of the rectangle.
+		/// </summary>
+		[JsonInclude]
+		public int Right;
+		
+		/// <summary>
+		/// Gets or sets the width of the lower side of the rectangle.
+		/// </summary>
+		[JsonInclude]
+		public int Bottom;
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Thickness"/> class with all widths
+		/// set to 0.
+		/// </summary>
+		public Thickness () { }
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Thickness"/> class with a uniform width to each side.
+		/// </summary>
+		/// <param name="width"></param>
+		public Thickness (int width) : this (width, width, width, width) { }
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Thickness"/> class that has specific
+		///  widths applied to each side of the rectangle.
+		/// </summary>
+		/// <param name="left"></param>
+		/// <param name="top"></param>
+		/// <param name="right"></param>
+		/// <param name="bottom"></param>
+		public Thickness (int left, int top, int right, int bottom)
+		{
+			Left = left;
+			Top = top;
+			Right = right;
+			Bottom = bottom;
+		}
+
+		/// <summary>
+		/// Returns a rectangle describing the location and size of the inner area of <paramref name="rect"/>
+		/// with the thickness widths subracted. The height and width of the retunred rect may be zero.
+		/// </summary>
+		/// <param name="rect">The source rectangle</param>
+		/// <returns></returns>
+		public Rect GetInnerRect (Rect rect)
+		{
+			var width = rect.Size.Width - (Left + Right);
+			var height = rect.Size.Height - (Top + Bottom);
+			var size = new Size (Math.Max (0, width), Math.Max (0, height));
+			return new Rect (new Point (rect.X + Left, rect.Y + Top), size);
+		}
+
+		private void FillRect (Rect rect, System.Rune rune = default)
+		{
+			for (var r = rect.Y; r < rect.Y + rect.Height; r++) {
+				for (var c = rect.X; c < rect.X + rect.Width; c++) {
+					Application.Driver.Move (c, r);
+					Application.Driver.AddRune (rune == default ? ' ' : rune);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Draws the <see cref="Thickness"/> rectangle with an optional diagnostics label.
+		/// </summary>
+		/// <remarks>
+		/// If <see cref="ConsoleDriver.DiagnosticFlags"/> is set to <see cref="ConsoleDriver.DiagnosticFlags.FramePadding"/> then
+		/// 'T', 'L', 'R', and 'B' glyphs will be used instead of space. If <see cref="ConsoleDriver.DiagnosticFlags"/>
+		/// is set to <see cref="ConsoleDriver.DiagnosticFlags.FrameRuler"/> then a ruler will be drawn on the outer edge of the
+		/// Thickness.
+		/// </remarks>
+		/// <param name="rect">The location and size of the rectangle that bounds the thickness rectangle, in 
+		/// screen coordinates.</param>
+		/// <param name="label">The diagnostics label to draw on the bottom of the <see cref="Bottom"/>.</param>
+		/// <returns>The inner rectangle remaining to be drawn.</returns>
+		public Rect Draw (Rect rect, string label = null)
+		{
+			System.Rune clearChar = ' ';
+			System.Rune leftChar = clearChar;
+			System.Rune rightChar = clearChar;
+			System.Rune topChar = clearChar;
+			System.Rune bottomChar = clearChar;
+
+			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding) {
+				leftChar = 'L';
+				rightChar = 'R';
+				topChar = 'T';
+				bottomChar = 'B';
+			}
+
+			ustring hrule = ustring.Empty;
+			ustring vrule = ustring.Empty;
+			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
+
+				string h = "0123456789";
+				hrule = h.Repeat ((int)Math.Ceiling ((double)(rect.Width) / (double)h.Length)) [0..(rect.Width)];
+				string v = "0123456789";
+				vrule = v.Repeat ((int)Math.Ceiling ((double)(rect.Height * 2) / (double)v.Length)) [0..(rect.Height * 2)];
+			};
+
+			// Draw the Top side
+			FillRect (new Rect (rect.X, rect.Y, rect.Width, Math.Min (rect.Height, Top)), topChar);
+
+			// Draw the Left side
+			FillRect (new Rect (rect.X, rect.Y, Math.Min (rect.Width, Left), rect.Height), leftChar);
+
+			// Draw the Right side			
+			FillRect (new Rect (Math.Max (0, rect.X + rect.Width - Right), rect.Y, Math.Min (rect.Width, Right), rect.Height), rightChar);
+
+			// Draw the Bottom side
+			FillRect (new Rect (rect.X, rect.Y + Math.Max (0, rect.Height - Bottom), rect.Width, Bottom), bottomChar);
+
+			// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
+			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
+				// Top
+				Application.Driver.Move (rect.X, rect.Y);
+				Application.Driver.AddStr (hrule);
+				//Left
+				for (var r = rect.Y; r < rect.Y + rect.Height; r++) {
+					Application.Driver.Move (rect.X, r);
+					Application.Driver.AddRune (vrule [r - rect.Y]);
+				}
+				// Bottom
+				Application.Driver.Move (rect.X, rect.Y + rect.Height - Bottom + 1);
+				Application.Driver.AddStr (hrule);
+				// Right
+				for (var r = rect.Y + 1; r < rect.Y + rect.Height; r++) {
+					Application.Driver.Move (rect.X + rect.Width - Right + 1, r);
+					Application.Driver.AddRune (vrule [r - rect.Y]);
+				}
+			}
+
+			// Draw the diagnostics label on the bottom
+			var tf = new TextFormatter () {
+				Text = label == null ? string.Empty : $"{label} {this}",
+				Alignment = TextAlignment.Centered,
+				VerticalAlignment = VerticalTextAlignment.Bottom
+			};
+			tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect, false);
+
+			return GetInnerRect (rect);
+
+		}
+		// TODO: add operator overloads
+		/// <summary>
+		/// Gets an empty thickness.
+		/// </summary>
+		public static Thickness Empty => new Thickness (0);
+
+		/// <inheritdoc/>
+		public override bool Equals (object obj)
+		{
+			//Check for null and compare run-time types.
+			if ((obj == null) || !this.GetType ().Equals (obj.GetType ())) {
+				return false;
+			} else {
+				return Equals ((Thickness)obj);
+			}
+		}
+
+		/// <summary>Returns the thickness widths of the Thickness formatted as a string.</summary>
+		/// <returns>The thickness widths as a string.</returns>
+		public override string ToString ()
+		{
+			return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})";
+		}
+
+		// IEquitable
+		/// <inheritdoc/>
+		public bool Equals (Thickness other)
+		{
+			return other is not null &&
+			       Left == other.Left &&
+			       Right == other.Right &&
+			       Top == other.Top &&
+			       Bottom == other.Bottom;
+		}
+		
+		/// <inheritdoc/>
+		public override int GetHashCode ()
+		{
+			int hashCode = 1380952125;
+			hashCode = hashCode * -1521134295 + Left.GetHashCode ();
+			hashCode = hashCode * -1521134295 + Right.GetHashCode ();
+			hashCode = hashCode * -1521134295 + Top.GetHashCode ();
+			hashCode = hashCode * -1521134295 + Bottom.GetHashCode ();
+			return hashCode;
+		}
+
+		/// <inheritdoc/>
+		public static bool operator == (Thickness left, Thickness right)
+		{
+			return EqualityComparer<Thickness>.Default.Equals (left, right);
+		}
+
+		/// <inheritdoc/>
+		public static bool operator != (Thickness left, Thickness right)
+		{
+			return !(left == right);
+		}
+	}
+	
+	internal static class StringExtensions {
+		public static string Repeat (this string instr, int n)
+		{
+			if (n <= 0) {
+				return null;
+			}
+
+			if (string.IsNullOrEmpty (instr) || n == 1) {
+				return instr;
+			}
+
+			return new StringBuilder (instr.Length * n)
+				.Insert (0, instr, n)
+				.ToString ();
+		}
+	}
+}

+ 148 - 64
Terminal.Gui/Core/View.cs

@@ -27,7 +27,7 @@ namespace Terminal.Gui {
 
 
 	/// <summary>
 	/// <summary>
 	/// View is the base class for all views on the screen and represents a visible element that can render itself and 
 	/// View is the base class for all views on the screen and represents a visible element that can render itself and 
-	/// contains zero or more nested views.
+	/// contains zero or more nested views, called SubViews.
 	/// </summary>
 	/// </summary>
 	/// <remarks>
 	/// <remarks>
 	/// <para>
 	/// <para>
@@ -109,7 +109,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		// container == SuperView
 		// container == SuperView
-		View container = null;
+		View _superView = null;
 		View focused = null;
 		View focused = null;
 		Direction focusDirection;
 		Direction focusDirection;
 		bool autoSize;
 		bool autoSize;
@@ -458,15 +458,16 @@ namespace Terminal.Gui {
 		/// The Thickness that separates a View from other SubViews of the same SuperView. 
 		/// The Thickness that separates a View from other SubViews of the same SuperView. 
 		/// The Margin is not part of the View's content and is not clipped by the View's Clip Area. 
 		/// The Margin is not part of the View's content and is not clipped by the View's Clip Area. 
 		/// </summary>
 		/// </summary>
-		public Frame Margin { get; set; }
+		public Frame Margin { get; internal set; }
 
 
+		// TODO: Rename BorderFrame to Border
 		/// <summary>
 		/// <summary>
 		///  Thickness where a visual border (drawn using line-drawing glyphs) and the Title are drawn. 
 		///  Thickness where a visual border (drawn using line-drawing glyphs) and the Title are drawn. 
 		///  The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and 
 		///  The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and 
 		///  title will take up the first row and the second row will be filled with spaces. 
 		///  title will take up the first row and the second row will be filled with spaces. 
 		///  The Border is not part of the View's content and is not clipped by the View's `ClipArea`.
 		///  The Border is not part of the View's content and is not clipped by the View's `ClipArea`.
 		/// </summary>
 		/// </summary>
-		public Frame BorderFrame { get; set; }
+		public Frame BorderFrame { get; internal set; }
 
 
 		/// <summary>
 		/// <summary>
 		/// Means the Thickness inside of an element that offsets the `Content` from the Border. 
 		/// Means the Thickness inside of an element that offsets the `Content` from the Border. 
@@ -475,45 +476,75 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// <remarks>
 		/// (NOTE: in v1 `Padding` is OUTSIDE of the `Border`). 
 		/// (NOTE: in v1 `Padding` is OUTSIDE of the `Border`). 
 		/// </remarks>
 		/// </remarks>
-		public Frame Padding { get; set; }
+		public Frame Padding { get; internal set; }
+
+		/// <summary>
+		/// Gets the rectangle that describes the location and size of the area within the View where
+		/// content and subviews are rendered. This is Bounds offset by all of the top/left thicknesses.
+		/// </summary>
+		public Rect ContentArea {
+			get {
+				// BUGBUG: 
+				if (Padding == null || BorderFrame == null || Margin == null) {
+					return Bounds;
+				}
+
+				return Padding.Thickness.GetInnerRect (BorderFrame.Thickness.GetInnerRect (Margin.Thickness.GetInnerRect (new Rect (default, Frame.Size))));
+			}
+		}
 
 
 		/// <summary>
 		/// <summary>
 		/// Temporary API to support the new v2 API
 		/// Temporary API to support the new v2 API
 		/// </summary>
 		/// </summary>
-		public void EnableFrames ()
+		public void InitializeFrames ()
 		{
 		{
-			IgnoreBorderPropertyOnRedraw = true;
 			Margin?.Dispose ();
 			Margin?.Dispose ();
-			Margin = new Frame () {
-				X = 0,
-				Y = 0,
-				Thickness = new Thickness (0),
-				ColorScheme = SuperView?.ColorScheme ?? ColorScheme,
-				// TODO: Create View.AddAdornment
-				Parent = this
-			};
+			Margin = new Frame () { Id = "Margin", Thickness = new Thickness (0) };
+			Margin.Parent = this;
 			//Margin.DiagnosticsLabel.Text = "Margin";
 			//Margin.DiagnosticsLabel.Text = "Margin";
 
 
 			BorderFrame?.Dispose ();
 			BorderFrame?.Dispose ();
-			BorderFrame = new Frame () {
-				X = 0,
-				Y = 0,
-				BorderStyle = BorderStyle.Single,
-				Thickness = new Thickness (0),
-				ColorScheme = ColorScheme,
-				// TODO: Create View.AddAdornment
-				Parent = this
-			};
+			// TODO: create default for borderstyle
+			BorderFrame = new Frame () { Id = "BorderFrame", Thickness = new Thickness (0), BorderStyle = BorderStyle.Single };
+			BorderFrame.Parent = this;
+			// TODO: Create View.AddAdornment
 
 
 			Padding?.Dispose ();
 			Padding?.Dispose ();
-			Padding = new Frame () {
-				X = 0,
-				Y = 0,
-				Thickness = new Thickness (0),
-				ColorScheme = ColorScheme,
-				// TODO: Create View.AddAdornment
-				Parent = this
-			};
+			Padding = new Frame () { Id = "Padding", Thickness = new Thickness (0) };
+			Padding.Parent = this;
+		}
+
+		public void LayoutFrames ()
+		{
+			if (Margin != null) {
+				Margin.X = 0;
+				Margin.Y = 0;
+				Margin.Width = Frame.Size.Width;
+				Margin.Height = Frame.Size.Height;
+				Margin.SetNeedsLayout ();
+				Margin.LayoutSubviews ();
+				Margin.SetNeedsDisplay ();
+			}
+			if (BorderFrame != null) {
+				var border = Margin?.Thickness.GetInnerRect (Margin.Frame) ?? Frame;
+				BorderFrame.X = border.Location.X;
+				BorderFrame.Y = border.Location.Y;
+				BorderFrame.Width = border.Size.Width;
+				BorderFrame.Height = border.Size.Height;
+				BorderFrame.SetNeedsLayout ();
+				BorderFrame.LayoutSubviews ();
+				BorderFrame.SetNeedsDisplay ();
+			}
+			if (Padding != null) {
+				var padding = BorderFrame?.Thickness.GetInnerRect (BorderFrame?.Frame ?? (Margin?.Thickness.GetInnerRect (Margin.Frame) ?? Frame)) ?? Margin?.Thickness.GetInnerRect (Margin.Frame) ?? Frame;
+				Padding.X = padding.Location.X;
+				Padding.Y = padding.Location.Y;
+				Padding.Width = padding.Size.Width;
+				Padding.Height = padding.Size.Height;
+				Padding.SetNeedsLayout ();
+				Padding.LayoutSubviews ();
+				Padding.SetNeedsDisplay ();
+			}
 		}
 		}
 
 
 		ustring title;
 		ustring title;
@@ -565,8 +596,21 @@ namespace Terminal.Gui {
 		/// </para>
 		/// </para>
 		/// </remarks>
 		/// </remarks>
 		public virtual Rect Bounds {
 		public virtual Rect Bounds {
-			get => new Rect (Point.Empty, Frame.Size);
-			set => Frame = new Rect (frame.Location, value.Size);
+			get {
+				// BUGBUG: 
+				if (Padding == null || BorderFrame == null || Margin == null) {
+					return new Rect (default, Frame.Size);
+				}
+				var frameRelativeBounds = new Rect (default, Padding.Bounds.Size);
+				return frameRelativeBounds;
+			}
+			set {
+				throw new InvalidOperationException ("It makes no sense to explicitly set Bounds.");
+				Frame = new Rect (Frame.Location, value.Size
+					+ new Size (Margin.Thickness.Right, Margin.Thickness.Bottom)
+					+ new Size (BorderFrame.Thickness.Right, BorderFrame.Thickness.Bottom)
+					+ new Size (Padding.Thickness.Right, Padding.Thickness.Bottom));
+			}
 		}
 		}
 
 
 		Pos x, y;
 		Pos x, y;
@@ -738,7 +782,7 @@ namespace Terminal.Gui {
 		/// <value>The super view.</value>
 		/// <value>The super view.</value>
 		public virtual View SuperView {
 		public virtual View SuperView {
 			get {
 			get {
-				return container;
+				return _superView;
 			}
 			}
 			set {
 			set {
 				throw new NotImplementedException ();
 				throw new NotImplementedException ();
@@ -947,7 +991,7 @@ namespace Terminal.Gui {
 				var h = Math.Max (NeedDisplay.Height, region.Height);
 				var h = Math.Max (NeedDisplay.Height, region.Height);
 				NeedDisplay = new Rect (x, y, w, h);
 				NeedDisplay = new Rect (x, y, w, h);
 			}
 			}
-			container?.SetChildNeedsDisplay ();
+			_superView?.SetChildNeedsDisplay ();
 
 
 			if (subviews == null)
 			if (subviews == null)
 				return;
 				return;
@@ -969,8 +1013,8 @@ namespace Terminal.Gui {
 		public void SetChildNeedsDisplay ()
 		public void SetChildNeedsDisplay ()
 		{
 		{
 			ChildNeedsDisplay = true;
 			ChildNeedsDisplay = true;
-			if (container != null)
-				container.SetChildNeedsDisplay ();
+			if (_superView != null)
+				_superView.SetChildNeedsDisplay ();
 		}
 		}
 
 
 		internal bool addingView;
 		internal bool addingView;
@@ -994,7 +1038,7 @@ namespace Terminal.Gui {
 			}
 			}
 			subviews.Add (view);
 			subviews.Add (view);
 			tabIndexes.Add (view);
 			tabIndexes.Add (view);
-			view.container = this;
+			view._superView = this;
 			if (view.CanFocus) {
 			if (view.CanFocus) {
 				addingView = true;
 				addingView = true;
 				if (SuperView?.CanFocus == false) {
 				if (SuperView?.CanFocus == false) {
@@ -1061,7 +1105,7 @@ namespace Terminal.Gui {
 			var touched = view.Frame;
 			var touched = view.Frame;
 			subviews.Remove (view);
 			subviews.Remove (view);
 			tabIndexes.Remove (view);
 			tabIndexes.Remove (view);
-			view.container = null;
+			view._superView = null;
 			view.tabIndex = -1;
 			view.tabIndex = -1;
 			SetNeedsLayout ();
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
@@ -1201,14 +1245,29 @@ namespace Terminal.Gui {
 		public virtual void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
 		public virtual void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
 		{
 		{
 			// Computes the real row, col relative to the screen.
 			// Computes the real row, col relative to the screen.
-			rrow = row + Frame.Y;
-			rcol = col + Frame.X;
+			if (Padding == null || BorderFrame == null || Margin == null) {
+				rrow = row + Frame.Y;
+				rcol = col + Frame.X;
+			} else {
+				var inner = Padding.Thickness.GetInnerRect (BorderFrame.Thickness.GetInnerRect (Margin.Thickness.GetInnerRect (Frame)));
+				rrow = row + inner.Y;
+				rcol = col + inner.X;
+			}
+
+			var super = SuperView;
+			while (super != null) {
+				if (!(super.Padding == null || super.BorderFrame == null || super.Margin == null)) {
+					var inner = super.Padding.Thickness.GetInnerRect (super.BorderFrame.Thickness.GetInnerRect (super.Margin.Thickness.GetInnerRect (super.Frame)));
 
 
-			var curContainer = container;
-			while (curContainer != null) {
-				rrow += curContainer.Frame.Y;
-				rcol += curContainer.Frame.X;
-				curContainer = curContainer.container;
+					//rrow += inner.Y - curContainer.frame.Y;
+					//rcol += inner.X - curContainer.frame.X;
+					rrow += super.frame.Y;
+					rcol += super.frame.X;
+				} else {
+					rrow += super.frame.Y;
+					rcol += super.frame.X;
+				}
+				super = super.SuperView;
 			}
 			}
 
 
 			// The following ensures that the cursor is always in the screen boundaries.
 			// The following ensures that the cursor is always in the screen boundaries.
@@ -1539,6 +1598,33 @@ namespace Terminal.Gui {
 			ChildNeedsDisplay = false;
 			ChildNeedsDisplay = false;
 		}
 		}
 
 
+		// TODO: Make this cancelable
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public virtual bool OnDrawFrames (Rect bounds)
+		{
+			Margin?.Redraw (Frame);
+			BorderFrame?.Redraw (Frame);
+			Padding?.Redraw (Frame);
+
+			//var margin = Margin.Thickness.GetInnerRect (frame);
+			//var padding = BorderFrame.Thickness.GetInnerRect (margin);
+			//var content = Padding.Thickness.GetInnerRect (padding);
+
+			//// Draw the diagnostics label on the bottom of the content
+			//var tf = new TextFormatter () {
+			//	Text = $"Content {Bounds}",
+			//	Alignment = TextAlignment.Centered,
+			//	VerticalAlignment = VerticalTextAlignment.Bottom
+			//};
+			//tf.Draw (Padding.Thickness.GetInnerRect(Padding.Bounds), ColorScheme.Normal, ColorScheme.Normal);
+
+
+			return true;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Redraws this view and its subviews; only redraws the views that have been flagged for a re-display.
 		/// Redraws this view and its subviews; only redraws the views that have been flagged for a re-display.
 		/// </summary>
 		/// </summary>
@@ -1568,17 +1654,7 @@ namespace Terminal.Gui {
 				Driver.SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
 				Driver.SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
 			}
 			}
 
 
-			var boundsAdjustedForBorder = Bounds;
-			//if (!IgnoreBorderPropertyOnRedraw && Border != null) {
-			//	throw new InvalidOperationException("Don't use border!");
-			//} else 
-			if (ustring.IsNullOrEmpty (TextFormatter.Text) &&
-				(GetType ().IsNestedPublic && !IsOverridden (this, "Redraw") || GetType ().Name == "View") &&
-				(!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded)) {
-
-				Clear ();
-				SetChildNeedsDisplay ();
-			}
+			OnDrawFrames (Frame);
 
 
 			if (!ustring.IsNullOrEmpty (TextFormatter.Text)) {
 			if (!ustring.IsNullOrEmpty (TextFormatter.Text)) {
 				Rect containerBounds = GetContainerBounds ();
 				Rect containerBounds = GetContainerBounds ();
@@ -1596,7 +1672,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Invoke DrawContentEvent
 			// Invoke DrawContentEvent
-			OnDrawContent (boundsAdjustedForBorder);
+			OnDrawContent (bounds);
 
 
 			if (subviews != null) {
 			if (subviews != null) {
 				foreach (var view in subviews) {
 				foreach (var view in subviews) {
@@ -1615,14 +1691,13 @@ namespace Terminal.Gui {
 								view.OnDrawContentComplete (rect);
 								view.OnDrawContentComplete (rect);
 							}
 							}
 						}
 						}
-						view.NeedDisplay = Rect.Empty;
-						view.ChildNeedsDisplay = false;
+						view.ClearNeedsDisplay ();
 					}
 					}
 				}
 				}
 			}
 			}
 
 
 			// Invoke DrawContentCompleteEvent
 			// Invoke DrawContentCompleteEvent
-			OnDrawContentComplete (boundsAdjustedForBorder);
+			OnDrawContentComplete (bounds);
 
 
 			ClearLayoutNeeded ();
 			ClearLayoutNeeded ();
 			ClearNeedsDisplay ();
 			ClearNeedsDisplay ();
@@ -1726,7 +1801,7 @@ namespace Terminal.Gui {
 
 
 			// Make sure that this view is a subview
 			// Make sure that this view is a subview
 			View c;
 			View c;
-			for (c = view.container; c != null; c = c.container)
+			for (c = view._superView; c != null; c = c._superView)
 				if (c == this)
 				if (c == this)
 					break;
 					break;
 			if (c == null)
 			if (c == null)
@@ -2512,6 +2587,8 @@ namespace Terminal.Gui {
 				return;
 				return;
 			}
 			}
 
 
+			LayoutFrames ();
+
 			var oldBounds = Bounds;
 			var oldBounds = Bounds;
 			OnLayoutStarted (new LayoutEventArgs () { OldBounds = oldBounds });
 			OnLayoutStarted (new LayoutEventArgs () { OldBounds = oldBounds });
 
 
@@ -2523,7 +2600,7 @@ namespace Terminal.Gui {
 			CollectAll (this, ref nodes, ref edges);
 			CollectAll (this, ref nodes, ref edges);
 			var ordered = View.TopologicalSort (SuperView, nodes, edges);
 			var ordered = View.TopologicalSort (SuperView, nodes, edges);
 			foreach (var v in ordered) {
 			foreach (var v in ordered) {
-				LayoutSubview (v, Frame);
+				LayoutSubview (v, ContentArea);
 			}
 			}
 
 
 			// If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
 			// If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
@@ -3020,6 +3097,13 @@ namespace Terminal.Gui {
 		/// <inheritdoc/>
 		/// <inheritdoc/>
 		protected override void Dispose (bool disposing)
 		protected override void Dispose (bool disposing)
 		{
 		{
+			Margin?.Dispose ();
+			Margin = null;
+			BorderFrame?.Dispose ();
+			Border = null;
+			Padding?.Dispose ();
+			Padding = null;
+
 			for (var i = InternalSubviews.Count - 1; i >= 0; i--) {
 			for (var i = InternalSubviews.Count - 1; i >= 0; i--) {
 				var subview = InternalSubviews [i];
 				var subview = InternalSubviews [i];
 				Remove (subview);
 				Remove (subview);

+ 4 - 4
Terminal.Gui/Windows/Wizard.cs

@@ -849,8 +849,8 @@ namespace Terminal.Gui {
 				if (base.Modal) {
 				if (base.Modal) {
 					ColorScheme = Colors.Dialog;
 					ColorScheme = Colors.Dialog;
 					Border.BorderStyle = BorderStyle.Rounded;
 					Border.BorderStyle = BorderStyle.Rounded;
-					Border.Effect3D = true;
-					Border.DrawMarginFrame = true;
+//					Border.Effect3D = true;
+//					Border.DrawMarginFrame = true;
 				} else {
 				} else {
 					if (SuperView != null) {
 					if (SuperView != null) {
 						ColorScheme = SuperView.ColorScheme;
 						ColorScheme = SuperView.ColorScheme;
@@ -858,9 +858,9 @@ namespace Terminal.Gui {
 						ColorScheme = Colors.Base;
 						ColorScheme = Colors.Base;
 					}
 					}
 					CanFocus = true;
 					CanFocus = true;
-					Border.Effect3D = false;
+//					Border.Effect3D = false;
 					Border.BorderStyle = BorderStyle.None;
 					Border.BorderStyle = BorderStyle.None;
-					Border.DrawMarginFrame = false;
+//					Border.DrawMarginFrame = false;
 				}
 				}
 			}
 			}
 		}
 		}

+ 8 - 7
UICatalog/Scenarios/BordersComparisons.cs

@@ -23,11 +23,12 @@ namespace UICatalog.Scenarios {
 					BorderStyle = borderStyle,
 					BorderStyle = borderStyle,
 					DrawMarginFrame = drawMarginFrame,
 					DrawMarginFrame = drawMarginFrame,
 					BorderThickness = borderThickness,
 					BorderThickness = borderThickness,
-					BorderBrush = borderBrush,
+					ForgroundColor = borderBrush,
 					Padding = padding,
 					Padding = padding,
-					Background = background,
+					BackgroundColor = background,
 					Effect3D = effect3D
 					Effect3D = effect3D
-				});
+				}) {
+			};
 
 
 			var tf1 = new TextField ("1234567890") { Width = 10 };
 			var tf1 = new TextField ("1234567890") { Width = 10 };
 
 
@@ -59,9 +60,9 @@ namespace UICatalog.Scenarios {
 					BorderStyle = borderStyle,
 					BorderStyle = borderStyle,
 					DrawMarginFrame = drawMarginFrame,
 					DrawMarginFrame = drawMarginFrame,
 					BorderThickness = borderThickness,
 					BorderThickness = borderThickness,
-					BorderBrush = borderBrush,
+					ForgroundColor = borderBrush,
 					Padding = padding,
 					Padding = padding,
-					Background = background,
+					BackgroundColor = background,
 					Effect3D = effect3D,
 					Effect3D = effect3D,
 					//Title = "Test2"
 					//Title = "Test2"
 				}) {
 				}) {
@@ -98,9 +99,9 @@ namespace UICatalog.Scenarios {
 					BorderStyle = borderStyle,
 					BorderStyle = borderStyle,
 					DrawMarginFrame = drawMarginFrame,
 					DrawMarginFrame = drawMarginFrame,
 					BorderThickness = borderThickness,
 					BorderThickness = borderThickness,
-					BorderBrush = borderBrush,
+					ForgroundColor = borderBrush,
 					Padding = padding,
 					Padding = padding,
-					Background = background,
+					BackgroundColor = background,
 					Effect3D = effect3D
 					Effect3D = effect3D
 				}) { ColorScheme = Colors.Base };
 				}) { ColorScheme = Colors.Base };
 
 

+ 6 - 6
UICatalog/Scenarios/BordersOnContainers.cs

@@ -23,9 +23,9 @@ namespace UICatalog.Scenarios {
 				BorderStyle = borderStyle,
 				BorderStyle = borderStyle,
 				DrawMarginFrame = drawMarginFrame,
 				DrawMarginFrame = drawMarginFrame,
 				BorderThickness = borderThickness,
 				BorderThickness = borderThickness,
-				BorderBrush = borderBrush,
+				ForgroundColor = borderBrush,
 				Padding = padding,
 				Padding = padding,
-				Background = background,
+				BackgroundColor = background,
 				Effect3D = effect3D,
 				Effect3D = effect3D,
 				//Title = typeName
 				//Title = typeName
 			};
 			};
@@ -354,10 +354,10 @@ namespace UICatalog.Scenarios {
 
 
 				X = 2,
 				X = 2,
 				Y = 6,
 				Y = 6,
-				SelectedItem = (int)smartView.Border.Background
+				SelectedItem = (int)smartView.Border.BackgroundColor
 			};
 			};
 			rbBackground.SelectedItemChanged += (e) => {
 			rbBackground.SelectedItemChanged += (e) => {
-				smartView.Border.Background = (Color)e.SelectedItem;
+				smartView.Border.BackgroundColor = (Color)e.SelectedItem;
 			};
 			};
 			Add (rbBackground);
 			Add (rbBackground);
 
 
@@ -371,10 +371,10 @@ namespace UICatalog.Scenarios {
 
 
 				X = Pos.AnchorEnd (18),
 				X = Pos.AnchorEnd (18),
 				Y = 6,
 				Y = 6,
-				SelectedItem = (int)smartView.Border.BorderBrush
+				SelectedItem = (int)smartView.Border.ForgroundColor
 			};
 			};
 			rbBorderBrush.SelectedItemChanged += (e) => {
 			rbBorderBrush.SelectedItemChanged += (e) => {
-				smartView.Border.BorderBrush = (Color)e.SelectedItem;
+				smartView.Border.ForgroundColor = (Color)e.SelectedItem;
 			};
 			};
 			Add (rbBorderBrush);
 			Add (rbBorderBrush);
 
 

+ 4 - 4
UICatalog/Scenarios/TileViewExperiment.cs

@@ -65,10 +65,10 @@ namespace UICatalog.Scenarios {
 				ColorScheme = Colors.ColorSchemes ["Dialog"],
 				ColorScheme = Colors.ColorSchemes ["Dialog"],
 				Border = new Border () {
 				Border = new Border () {
 					BorderStyle = BorderStyle.Single,
 					BorderStyle = BorderStyle.Single,
-					//BorderThickness = new Thickness (1), 
-					//DrawMarginFrame = true,
-					//Padding = new Thickness(1),
-					BorderBrush = Color.BrightMagenta,
+					BorderThickness = new Thickness (1), 
+					DrawMarginFrame = true,
+					Padding = new Thickness(1),
+					ForgroundColor = Color.BrightMagenta,
 				}
 				}
 			};
 			};
 
 

+ 26 - 26
UICatalog/Scenarios/View2Experiment.cs → UICatalog/Scenarios/ViewExperiments.cs

@@ -1,9 +1,9 @@
 using Terminal.Gui;
 using Terminal.Gui;
 
 
 namespace UICatalog.Scenarios {
 namespace UICatalog.Scenarios {
-	[ScenarioMetadata (Name: "View2Experiment", Description: "View2 Experiment")]
+	[ScenarioMetadata (Name: "_ View Experiments", Description: "v2 View Experiments")]
 	[ScenarioCategory ("Controls")]
 	[ScenarioCategory ("Controls")]
-	public class View2Experiment : Scenario {
+	public class ViewExperiments : Scenario {
 		public override void Init (ColorScheme colorScheme)
 		public override void Init (ColorScheme colorScheme)
 		{
 		{
 			Application.Init ();
 			Application.Init ();
@@ -19,30 +19,30 @@ namespace UICatalog.Scenarios {
 			};
 			};
 			Application.Top.Add (containerLabel);
 			Application.Top.Add (containerLabel);
 
 
-			var view2 = new View () {
+			var view = new View () {
 				X = 2,
 				X = 2,
-				Y = 2,
+				Y = 3,
 				Height = Dim.Fill (2),
 				Height = Dim.Fill (2),
 				Width = Dim.Fill (2),
 				Width = Dim.Fill (2),
-				Title = "View2"
+				Title = "View"
 			};
 			};
-			Application.Top.Add (view2);
+			Application.Top.Add (view);
 
 
-			view2.EnableFrames ();
-			view2.Margin.Thickness = new Thickness (2);
-			view2.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
-			view2.Margin.Data = "Margin";
-			view2.BorderFrame.Thickness = new Thickness (2);
-			view2.BorderFrame.BorderStyle = BorderStyle.Single;
-			//view2.BorderFrame.ColorScheme = view2.ColorScheme;
-			view2.BorderFrame.Data = "BorderFrame";
-			view2.Padding.Thickness = new Thickness (2);
-			view2.Padding.ColorScheme = Colors.ColorSchemes ["Error"];
-			view2.Padding.Data = "Padding";
+			view.InitializeFrames ();
+			view.Margin.Thickness = new Thickness (2);
+			view.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
+			view.Margin.Data = "Margin";
+			view.BorderFrame.Thickness = new Thickness (2);
+			view.BorderFrame.BorderStyle = BorderStyle.Single;
+			view.BorderFrame.ColorScheme = view.ColorScheme;
+			view.BorderFrame.Data = "BorderFrame";
+			view.Padding.Thickness = new Thickness (2);
+			view.Padding.ColorScheme = Colors.ColorSchemes ["Error"];
+			view.Padding.Data = "Padding";
 
 
 
 
 			containerLabel.LayoutComplete += (a) => {
 			containerLabel.LayoutComplete += (a) => {
-				containerLabel.Text = $"Container.Frame: {Application.Top.Frame} .Bounds: {Application.Top.Bounds}\nView2.Frame: {view2.Frame} .Bounds: {view2.Bounds}";
+				containerLabel.Text = $"Container.Frame: {Application.Top.Frame} .Bounds: {Application.Top.Bounds}\nView.Frame: {view.Frame} .Bounds: {view.Bounds}\nView.ContentArea: {view.ContentArea}";
 
 
 			};
 			};
 
 
@@ -54,7 +54,7 @@ namespace UICatalog.Scenarios {
 				Y = 1,
 				Y = 1,
 
 
 			};
 			};
-			view2.Add (label);
+			view.Add (label);
 
 
 			var edit = new TextField () {
 			var edit = new TextField () {
 				Text = "Right (label)",
 				Text = "Right (label)",
@@ -63,7 +63,7 @@ namespace UICatalog.Scenarios {
 				Width = 15,
 				Width = 15,
 				Height = 1
 				Height = 1
 			};
 			};
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "Right (edit) + 1",
 				Text = "Right (edit) + 1",
@@ -72,7 +72,7 @@ namespace UICatalog.Scenarios {
 				Width = 20	,
 				Width = 20	,
 				Height = 1
 				Height = 1
 			};
 			};
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "Center();50%",
 				Text = "Center();50%",
@@ -81,7 +81,7 @@ namespace UICatalog.Scenarios {
 				Width = 30,
 				Width = 30,
 				Height = 1
 				Height = 1
 			};
 			};
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "Center() - 1;60%",
 				Text = "Center() - 1;60%",
@@ -90,7 +90,7 @@ namespace UICatalog.Scenarios {
 				Width = 30,
 				Width = 30,
 				Height = 1
 				Height = 1
 			};
 			};
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "0 + Percent(50);70%",
 				Text = "0 + Percent(50);70%",
@@ -99,7 +99,7 @@ namespace UICatalog.Scenarios {
 				Width = 30,
 				Width = 30,
 				Height = 1
 				Height = 1
 			};
 			};
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "AnchorEnd[Right];AnchorEnd (1)",
 				Text = "AnchorEnd[Right];AnchorEnd (1)",
@@ -108,7 +108,7 @@ namespace UICatalog.Scenarios {
 				Height = 1
 				Height = 1
 			};
 			};
 			edit.X = Pos.AnchorEnd () - (Pos.Right (edit) - Pos.Left (edit));
 			edit.X = Pos.AnchorEnd () - (Pos.Right (edit) - Pos.Left (edit));
-			view2.Add (edit);
+			view.Add (edit);
 
 
 			edit = new TextField () {
 			edit = new TextField () {
 				Text = "Left;AnchorEnd (2)",
 				Text = "Left;AnchorEnd (2)",
@@ -117,7 +117,7 @@ namespace UICatalog.Scenarios {
 				Height = 1
 				Height = 1
 			};
 			};
 			edit.X = 0;
 			edit.X = 0;
-			view2.Add (edit);
+			view.Add (edit);
 		}
 		}
 	}
 	}
 }
 }

+ 3 - 3
UnitTests/Core/BorderTests.cs

@@ -20,8 +20,8 @@ namespace Terminal.Gui.CoreTests {
 			Assert.Equal (BorderStyle.None, b.BorderStyle);
 			Assert.Equal (BorderStyle.None, b.BorderStyle);
 			Assert.False (b.DrawMarginFrame);
 			Assert.False (b.DrawMarginFrame);
 			Assert.Equal (Thickness.Empty, b.BorderThickness);
 			Assert.Equal (Thickness.Empty, b.BorderThickness);
-			Assert.Equal (Color.Black, b.BorderBrush);
-			Assert.Equal (Color.Black, b.Background);
+			Assert.Equal (Color.Black, b.ForgroundColor);
+			Assert.Equal (Color.Black, b.BackgroundColor);
 			Assert.Equal (Thickness.Empty, b.Padding);
 			Assert.Equal (Thickness.Empty, b.Padding);
 			Assert.False (b.Effect3D);
 			Assert.False (b.Effect3D);
 			Assert.Equal (new Point (1, 1), b.Effect3DOffset);
 			Assert.Equal (new Point (1, 1), b.Effect3DOffset);
@@ -571,7 +571,7 @@ namespace Terminal.Gui.CoreTests {
 					BorderStyle = BorderStyle.Single,
 					BorderStyle = BorderStyle.Single,
 					DrawMarginFrame = true,
 					DrawMarginFrame = true,
 					Padding = new Thickness (1),
 					Padding = new Thickness (1),
-					BorderBrush = Color.White
+					ForgroundColor = Color.White
 				}
 				}
 			};
 			};