Răsfoiți Sursa

Renames `Frame`->`Adornment`; changes `Frame` to have a `Border` subclass (#3158)

Tig 1 an în urmă
părinte
comite
7fe95cb9c7
57 a modificat fișierele cu 2389 adăugiri și 1907 ștergeri
  1. 1 1
      Terminal.Gui/Application.cs
  2. 2 2
      Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
  3. 2 0
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  4. 2 1
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  5. 3 0
      Terminal.Gui/Drawing/Cell.cs
  6. 4 5
      Terminal.Gui/Drawing/Color.cs
  7. 177 0
      Terminal.Gui/View/Adornment/Adornment.cs
  8. 345 0
      Terminal.Gui/View/Adornment/Border.cs
  9. 37 0
      Terminal.Gui/View/Adornment/Margin.cs
  10. 37 0
      Terminal.Gui/View/Adornment/Padding.cs
  11. 0 446
      Terminal.Gui/View/Frame.cs
  12. 92 116
      Terminal.Gui/View/Layout/ViewLayout.cs
  13. 7 11
      Terminal.Gui/View/View.cs
  14. 21 7
      Terminal.Gui/View/ViewDrawing.cs
  15. 1 1
      Terminal.Gui/Views/ColorPicker.cs
  16. 1 1
      Terminal.Gui/Views/DatePicker.cs
  17. 1 1
      Terminal.Gui/Views/FrameView.cs
  18. 2 2
      Terminal.Gui/Views/Line.cs
  19. 1 1
      Terminal.Gui/Views/Menu/Menu.cs
  20. 4 4
      Terminal.Gui/Views/MessageBox.cs
  21. 1 1
      Terminal.Gui/Views/ProgressBar.cs
  22. 4 4
      Terminal.Gui/Views/RadioGroup.cs
  23. 4 4
      Terminal.Gui/Views/Slider.cs
  24. 1 1
      Terminal.Gui/Views/TileView.cs
  25. 3 3
      Terminal.Gui/Views/Toplevel.cs
  26. 4 0
      UICatalog/Properties/launchSettings.json
  27. 441 0
      UICatalog/Scenarios/Adornments.cs
  28. 0 1
      UICatalog/Scenarios/DatePickers.cs
  29. 0 399
      UICatalog/Scenarios/Frames.cs
  30. 2 2
      UICatalog/Scenarios/LineDrawing.cs
  31. 2 2
      UICatalog/Scenarios/ProgressBarStyles.cs
  32. 14 19
      UICatalog/Scenarios/ViewExperiments.cs
  33. 2 2
      UnitTests/Application/ApplicationTests.cs
  34. 9 9
      UnitTests/Clipboard/ClipboardTests.cs
  35. 2 2
      UnitTests/Configuration/ConfigurationMangerTests.cs
  36. 1 1
      UnitTests/Drawing/AttributeTests.cs
  37. 136 100
      UnitTests/TestHelpers.cs
  38. 140 0
      UnitTests/View/Adornment/AdornmentTests.cs
  39. 740 0
      UnitTests/View/Adornment/BorderTests.cs
  40. 48 0
      UnitTests/View/Adornment/MarginTests.cs
  41. 43 0
      UnitTests/View/Adornment/PaddingTests.cs
  42. 0 44
      UnitTests/View/BorderTests.cs
  43. 5 5
      UnitTests/View/DrawTests.cs
  44. 3 664
      UnitTests/View/FrameTests.cs
  45. 2 2
      UnitTests/View/Text/AutoSizeTextTests.cs
  46. 4 4
      UnitTests/View/ViewTests.cs
  47. 0 1
      UnitTests/Views/AllViewsTests.cs
  48. 6 6
      UnitTests/Views/ComboBoxTests.cs
  49. 1 1
      UnitTests/Views/DatePickerTests.cs
  50. 4 4
      UnitTests/Views/MenuBarTests.cs
  51. 2 2
      UnitTests/Views/OverlappedTests.cs
  52. 4 4
      UnitTests/Views/RuneCellTests.cs
  53. 5 5
      UnitTests/Views/ScrollViewTests.cs
  54. 10 10
      UnitTests/Views/TableViewTests.cs
  55. 2 2
      UnitTests/Views/TextFieldTests.cs
  56. 2 2
      UnitTests/Views/TextViewTests.cs
  57. 2 2
      UnitTests/Views/TreeViewTests.cs

+ 1 - 1
Terminal.Gui/Application.cs

@@ -1227,7 +1227,7 @@ public static partial class Application {
 			}
 		}
 
-		bool FrameHandledMouseEvent (Frame frame)
+		bool FrameHandledMouseEvent (Adornment frame)
 		{
 			if (frame?.Thickness.Contains (frame.FrameToScreen (), a.MouseEvent.X, a.MouseEvent.Y) ?? false) {
 				var boundsPoint = frame.ScreenToBounds (a.MouseEvent.X, a.MouseEvent.Y);

+ 2 - 2
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -535,13 +535,13 @@ public abstract class ConsoleDriver {
 		Off = 0b_0000_0000,
 
 		/// <summary>
-		/// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a 
+		/// When enabled, <see cref="View.OnDrawAdornments"/> will draw a 
 		/// ruler in the frame for any side with a padding value greater than 0.
 		/// </summary>
 		FrameRuler = 0b_0000_0001,
 
 		/// <summary>
-		/// When enabled, <see cref="Frame.OnDrawFrames"/> will draw a 
+		/// When enabled, <see cref="View.OnDrawAdornments"/> will draw a 
 		/// 'L', 'R', 'T', and 'B' when clearing <see cref="Thickness"/>'s instead of ' '.
 		/// </summary>
 		FramePadding = 0b_0000_0010

+ 2 - 0
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -43,6 +43,8 @@ public class FakeDriver : ConsoleDriver {
 
 	public FakeDriver ()
 	{
+		Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
+		Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
 		if (FakeBehaviors.UseFakeClipboard) {
 			Clipboard = new FakeClipboard (FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException, FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse);
 		} else {

+ 2 - 1
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -825,7 +825,8 @@ internal class WindowsDriver : ConsoleDriver {
 
 		// TODO: if some other Windows-based terminal supports true color, update this logic to not
 		// force 16color mode (.e.g ConEmu which really doesn't work well at all).
-		_isWindowsTerminal = Environment.GetEnvironmentVariable ("WT_SESSION") != null;
+		_isWindowsTerminal = _isWindowsTerminal = Environment.GetEnvironmentVariable ("WT_SESSION") != null ||
+		                                          Environment.GetEnvironmentVariable ("VSAPPIDNAME") != null;
 		if (!_isWindowsTerminal) {
 			Force16Colors = true;
 		}

+ 3 - 0
Terminal.Gui/Drawing/Cell.cs

@@ -40,4 +40,7 @@ public class Cell {
 	/// been modified since the last time it was drawn.
 	/// </summary>
 	public bool IsDirty { get; set; }
+
+	/// <inheritdoc />
+	public override string ToString () => $"[{Rune}, {Attribute}]";
 }

+ 4 - 5
Terminal.Gui/Drawing/Color.cs

@@ -730,7 +730,6 @@ public readonly struct Attribute : IEquatable<Attribute> {
 	/// <summary>
 	/// Default empty attribute.
 	/// </summary>
-	/// </remarks>
 	public static readonly Attribute Default = new (Color.White, Color.Black);
 
 	/// <summary>
@@ -890,7 +889,7 @@ public readonly struct Attribute : IEquatable<Attribute> {
 	/// <inheritdoc/>
 	public override string ToString () =>
 		// Note, Unit tests are dependent on this format
-		$"{Foreground},{Background}";
+		$"[{Foreground},{Background}]";
 }
 
 /// <summary>
@@ -966,7 +965,7 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	}
 
 	/// <summary>
-	/// The foreground and background color for text when the view is highlighted (hot).
+	/// The foreground and background color for text in a non-focused view that indicates a <see cref="View.HotKey"/>.
 	/// </summary>
 	public Attribute HotNormal {
 		get => _hotNormal;
@@ -974,7 +973,7 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	}
 
 	/// <summary>
-	/// The foreground and background color for text when the view is highlighted (hot) and has focus.
+	/// The foreground and background color for for text in a focused view that indicates a <see cref="View.HotKey"/>.
 	/// </summary>
 	public Attribute HotFocus {
 		get => _hotFocus;
@@ -982,7 +981,7 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	}
 
 	/// <summary>
-	/// The default foreground and background color for text, when the view is disabled.
+	/// The default foreground and background color for text when the view is disabled.
 	/// </summary>
 	public Attribute Disabled {
 		get => _disabled;

+ 177 - 0
Terminal.Gui/View/Adornment/Adornment.cs

@@ -0,0 +1,177 @@
+using System;
+
+namespace Terminal.Gui;
+
+// TODO: v2 - Missing 3D effect - 3D effects will be drawn by a mechanism separate from Adornments
+// TODO: v2 - If a Adornment has focus, navigation keys (e.g Command.NextView) should cycle through SubViews of the Adornments
+// QUESTION: How does a user navigate out of an Adornment to another Adornment, or back into the Parent's SubViews?
+
+/// <summary>
+/// Adornments are a special form of <see cref="View"/> that appear outside of the <see cref="View.Bounds"/>:
+/// <see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>. They are defined using the <see cref="Thickness"/>
+/// class, which specifies the thickness of the sides of a rectangle. 
+/// </summary>
+/// <remarsk>
+/// <para>
+/// There is no prevision for creating additional subclasses of Adornment. It is not abstract to enable unit testing.
+/// </para>
+/// <para>
+/// Each of <see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/> can be customized.
+/// </para>
+/// </remarsk>
+public class Adornment : View {
+	/// <inheritdoc />
+	public Adornment () { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */ }
+
+	/// <summary>
+	/// Constructs a new adornment for the view specified by <paramref name="parent"/>.
+	/// </summary>
+	/// <param name="parent"></param>
+	public Adornment (View parent) => Parent = parent;
+
+	Thickness _thickness = Thickness.Empty;
+
+	/// <summary>
+	/// The Parent of this Adornment (the View this Adornment surrounds).
+	/// </summary>
+	/// <remarks>
+	/// Adornments are distinguished from typical View classes in that they are not sub-views,
+	/// but have a parent/child relationship with their containing View.
+	/// </remarks>
+	public View Parent { get; set; }
+
+	/// <summary>
+	/// Adornments cannot be used as sub-views (see <see cref="Parent"/>); this method always throws an <see cref="InvalidOperationException"/>.
+	/// TODO: Are we sure?
+	/// </summary>
+	public override View SuperView {
+		get => null;
+		set => throw new NotImplementedException ();
+	}
+
+	/// <summary>
+	/// Adornments only render to their <see cref="Parent"/>'s or Parent's SuperView's LineCanvas,
+	/// so setting this property throws an <see cref="InvalidOperationException"/>.
+	/// </summary>
+	public override bool SuperViewRendersLineCanvas {
+		get => false; // throw new NotImplementedException ();
+		set => throw new NotImplementedException ();
+	}
+
+	/// <summary>
+	/// Defines the rectangle that the <see cref="Adornment"/> will use to draw its content.
+	/// </summary>
+	public Thickness Thickness {
+		get => _thickness;
+		set {
+			var prev = _thickness;
+			_thickness = value;
+			if (prev != _thickness) {
+
+				Parent?.LayoutAdornments ();
+				OnThicknessChanged (prev);
+			}
+
+		}
+	}
+
+	/// <summary>
+	/// Gets the rectangle that describes the inner area of the Adornment. The Location is always (0,0).
+	/// </summary>
+	public override Rect Bounds {
+		get => Thickness?.GetInside (new Rect (Point.Empty, Frame.Size)) ?? new Rect (Point.Empty, Frame.Size);
+		set => throw new InvalidOperationException ("It makes no sense to set Bounds of a Thickness.");
+	}
+
+	internal override Adornment CreateAdornment (Type adornmentType)
+	{
+		/* Do nothing - Adornments do not have Adornments */
+		return null;
+	}
+
+	internal override void LayoutAdornments ()
+	{
+		/* Do nothing - Adornments do not have Adornments */
+	}
+
+	/// <inheritdoc/>
+	public override void BoundsToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
+	{
+		// Adornments are *Children* of a View, not SubViews. Thus View.BoundsToScreen will not work.
+		// To get the screen-relative coordinates of a Adornment, we need to know who
+		// the Parent is
+		var parentFrame = Parent?.Frame ?? Frame;
+		rrow = row + parentFrame.Y;
+		rcol = col + parentFrame.X;
+
+		// We now have rcol/rrow in coordinates relative to our View's SuperView. If our View's SuperView has
+		// a SuperView, keep going...
+		Parent?.SuperView?.BoundsToScreen (rcol, rrow, out rcol, out rrow, clipped);
+	}
+
+	/// <inheritdoc/>
+	public override Rect FrameToScreen ()
+	{
+		// Adornments are *Children* of a View, not SubViews. Thus View.FrameToScreen will not work.
+		// To get the screen-relative coordinates of a Adornment, we need to know who
+		// the Parent is
+		var ret = Parent?.Frame ?? Frame;
+		ret.Size = Frame.Size;
+
+		ret.Location = Parent?.FrameToScreen ().Location ?? ret.Location;
+
+		// We now have coordinates relative to our View. If our View's SuperView has
+		// a SuperView, keep going...
+		return ret;
+	}
+
+	/// <summary>
+	/// Does nothing for Adornment
+	/// </summary>
+	/// <returns></returns>
+	public override bool OnDrawAdornments () => false;
+
+	/// <summary>
+	/// Does nothing for Adornment
+	/// </summary>
+	/// <returns></returns>
+	public override bool OnRenderLineCanvas () => false;
+	
+	/// <summary>
+	/// Redraws the Adornments that comprise the <see cref="Adornment"/>.
+	/// </summary>
+	public override void OnDrawContent (Rect contentArea)
+	{
+		if (Thickness == Thickness.Empty) {
+			return;
+		}
+
+		var screenBounds = BoundsToScreen (Frame);
+
+		Attribute normalAttr = GetNormalColor ();
+
+		// This just draws/clears the thickness, not the insides.
+		Driver.SetAttribute (normalAttr);
+		Thickness.Draw (screenBounds, (string)(Data ?? string.Empty));
+
+		if (!string.IsNullOrEmpty (TextFormatter.Text)) {
+			if (TextFormatter != null) {
+				TextFormatter.Size = Frame.Size;
+				TextFormatter.NeedsFormat = true;
+			}
+		}
+
+		TextFormatter?.Draw (screenBounds, normalAttr, normalAttr, Rect.Empty, false);
+		//base.OnDrawContent (contentArea);
+	}
+
+	/// <summary>
+	/// Called whenever the <see cref="Thickness"/> property changes.
+	/// </summary>
+	public virtual void OnThicknessChanged (Thickness previousThickness) => ThicknessChanged?.Invoke (this, new ThicknessEventArgs { Thickness = Thickness, PreviousThickness = previousThickness });
+
+	/// <summary>
+	/// Fired whenever the <see cref="Thickness"/> property changes.
+	/// </summary>
+	public event EventHandler<ThicknessEventArgs> ThicknessChanged;
+}

+ 345 - 0
Terminal.Gui/View/Adornment/Border.cs

@@ -0,0 +1,345 @@
+using System;
+using System.Linq;
+
+namespace Terminal.Gui;
+
+/// <summary>
+/// The Border for a <see cref="View"/>. 
+/// </summary>
+/// <remarks>
+/// <para>
+/// Renders a border around the view with the <see cref="View.Title"/>. A border using <see cref="LineStyle"/>
+/// will be drawn on the sides of <see cref="Thickness"/> that are greater than zero. 
+/// </para>
+/// <para>
+/// The <see cref="View.Title"/> of <see cref="Adornment.Parent"/> will be drawn based on the value of <see cref="Thickness.Top"/>:
+/// </para>
+/// <para>
+/// If <c>1</c>:
+/// <code>
+/// ┌┤1234├──┐
+/// │        │
+/// └────────┘
+/// </code>
+/// </para>
+/// <para>
+/// If <c>2</c>:
+/// <code>
+///  ┌────┐
+/// ┌┤1234├──┐
+/// │        │
+/// └────────┘
+/// </code>
+/// </para>
+/// <para>
+/// If <c>3</c>:
+/// <code>
+///  ┌────┐
+/// ┌┤1234├──┐
+/// │└────┘  │
+/// │        │
+/// └────────┘
+/// </code>
+/// </para>
+/// <para/>
+/// <para>
+/// See the <see cref="Adornment"/> class. 
+/// </para>
+/// </remarks>
+public class Border : Adornment {
+	LineStyle? _lineStyle = null;
+
+	/// <inheritdoc />
+	public Border () { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */ }
+
+	/// <inheritdoc />
+	public Border (View parent) : base (parent) { /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */ }
+
+	/// <summary>
+	/// The color scheme for the Border. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/> scheme.
+	/// color scheme.
+	/// </summary>
+	public override ColorScheme ColorScheme {
+		get {
+			if (base.ColorScheme != null) {
+				return base.ColorScheme;
+			}
+			return Parent?.ColorScheme;
+		}
+		set {
+			base.ColorScheme = value;
+			Parent?.SetNeedsDisplay ();
+		}
+	}
+
+	/// <summary>
+	/// Sets the style of the border by changing the <see cref="Thickness"/>. This is a helper API for
+	/// setting the <see cref="Thickness"/> to <c>(1,1,1,1)</c> and setting the line style of the
+	/// views that comprise the border. If set to <see cref="LineStyle.None"/> no border will be drawn.
+	/// </summary>
+	public new LineStyle LineStyle {
+		get {
+			if (_lineStyle.HasValue) {
+				return _lineStyle.Value;
+			}
+			// TODO: Make Border.LineStyle inherit from the SuperView hierarchy
+			// TODO: Right now, Window and FrameView use CM to set BorderStyle, which negates
+			// TODO: all this.
+			return Parent.SuperView?.BorderStyle ?? LineStyle.None;
+		}
+		set => _lineStyle = value;
+	}
+
+	/// <inheritdoc />
+	public override void OnDrawContent (Rect contentArea)
+	{
+		base.OnDrawContent (contentArea);
+
+		if (Thickness == Thickness.Empty) {
+			return;
+		}
+
+		//Driver.SetAttribute (Colors.Error.Normal);
+		var screenBounds = BoundsToScreen (Frame);
+
+		//OnDrawSubviews (bounds); 
+
+		// TODO: v2 - this will eventually be two controls: "BorderView" and "Label" (for the title)
+
+		// The border adornment (and title) are drawn at the outermost edge of border; 
+		// For Border
+		// ...thickness extends outward (border/title is always as far in as possible)
+		var borderBounds = new Rect (
+			screenBounds.X + Math.Max (0, Thickness.Left - 1),
+			screenBounds.Y + Math.Max (0, Thickness.Top - 1),
+			Math.Max (0, screenBounds.Width - Math.Max (0, Math.Max (0, Thickness.Left - 1) + Math.Max (0, Thickness.Right - 1))),
+			Math.Max (0, screenBounds.Height - Math.Max (0, Math.Max (0, Thickness.Top - 1) + Math.Max (0, Thickness.Bottom - 1))));
+
+		var topTitleLineY = borderBounds.Y;
+		var titleY = borderBounds.Y;
+		var titleBarsLength = 0; // the little vertical thingies
+		var maxTitleWidth = Math.Min (Parent.Title.GetColumns (), Math.Min (screenBounds.Width - 4, borderBounds.Width - 4));
+		var sideLineLength = borderBounds.Height;
+		var canDrawBorder = borderBounds.Width > 0 && borderBounds.Height > 0;
+
+		if (!string.IsNullOrEmpty (Parent?.Title)) {
+			if (Thickness.Top == 2) {
+				topTitleLineY = borderBounds.Y - 1;
+				titleY = topTitleLineY + 1;
+				titleBarsLength = 2;
+			}
+
+			// ┌────┐
+			//┌┘View└
+			//│
+			if (Thickness.Top == 3) {
+				topTitleLineY = borderBounds.Y - (Thickness.Top - 1);
+				titleY = topTitleLineY + 1;
+				titleBarsLength = 3;
+				sideLineLength++;
+			}
+
+			// ┌────┐
+			//┌┘View└
+			//│
+			if (Thickness.Top > 3) {
+				topTitleLineY = borderBounds.Y - 2;
+				titleY = topTitleLineY + 1;
+				titleBarsLength = 3;
+				sideLineLength++;
+			}
+
+		}
+
+		if (canDrawBorder && Thickness.Top > 0 && maxTitleWidth > 0 && !string.IsNullOrEmpty (Parent?.Title)) {
+			var prevAttr = Driver.GetAttribute ();
+			Driver.SetAttribute (Parent.HasFocus ? Parent.GetFocusColor () : Parent.GetNormalColor ());
+			DrawTitle (new Rect (borderBounds.X, titleY, maxTitleWidth, 1), Parent?.Title);
+			Driver.SetAttribute (prevAttr);
+		}
+
+		if (canDrawBorder && LineStyle != LineStyle.None) {
+			var lc = Parent?.LineCanvas;
+
+			var drawTop = Thickness.Top > 0 && Frame.Width > 1 && Frame.Height > 1;
+			var drawLeft = Thickness.Left > 0 && (Frame.Height > 1 || Thickness.Top == 0);
+			var drawBottom = Thickness.Bottom > 0 && Frame.Width > 1;
+			var drawRight = Thickness.Right > 0 && (Frame.Height > 1 || Thickness.Top == 0);
+
+			var prevAttr = Driver.GetAttribute ();
+			if (ColorScheme != null) {
+				Driver.SetAttribute (GetNormalColor ());
+			} else {
+				Driver.SetAttribute (Parent.GetNormalColor ());
+			}
+
+			if (drawTop) {
+				// ╔╡Title╞═════╗
+				// ╔╡╞═════╗
+				if (borderBounds.Width < 4 || string.IsNullOrEmpty (Parent?.Title)) {
+					// ╔╡╞╗ should be ╔══╗
+					lc.AddLine (new Point (borderBounds.Location.X, titleY), borderBounds.Width, Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+				} else {
+
+					// ┌────┐
+					//┌┘View└
+					//│
+					if (Thickness.Top == 2) {
+						lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+					}
+					// ┌────┐
+					//┌┘View└
+					//│
+					if (borderBounds.Width >= 4 && Thickness.Top > 2) {
+						lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+						lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY + 2), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+					}
+
+					// ╔╡Title╞═════╗
+					// Add a short horiz line for ╔╡
+					lc.AddLine (new Point (borderBounds.Location.X, titleY), 2, Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+					// Add a vert line for ╔╡
+					lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), titleBarsLength, Orientation.Vertical, LineStyle.Single, Driver.GetAttribute ());
+					// Add a vert line for ╞
+					lc.AddLine (new Point (borderBounds.X + 1 + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2) - 1, topTitleLineY), titleBarsLength, Orientation.Vertical, LineStyle.Single, Driver.GetAttribute ());
+					// Add the right hand line for ╞═════╗
+					lc.AddLine (new Point (borderBounds.X + 1 + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2) - 1, titleY), borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+				}
+			}
+			if (drawLeft) {
+				lc.AddLine (new Point (borderBounds.Location.X, titleY), sideLineLength, Orientation.Vertical, LineStyle, Driver.GetAttribute ());
+			}
+			if (drawBottom) {
+				lc.AddLine (new Point (borderBounds.X, borderBounds.Y + borderBounds.Height - 1), borderBounds.Width, Orientation.Horizontal, LineStyle, Driver.GetAttribute ());
+			}
+			if (drawRight) {
+				lc.AddLine (new Point (borderBounds.X + borderBounds.Width - 1, titleY), sideLineLength, Orientation.Vertical, LineStyle, Driver.GetAttribute ());
+			}
+			Driver.SetAttribute (prevAttr);
+
+			// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
+			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
+				// Top
+				var hruler = new Ruler { Length = screenBounds.Width, Orientation = Orientation.Horizontal };
+				if (drawTop) {
+					hruler.Draw (new Point (screenBounds.X, screenBounds.Y));
+				}
+
+				// Redraw title 
+				if (drawTop && maxTitleWidth > 0 && !string.IsNullOrEmpty (Parent?.Title)) {
+					prevAttr = Driver.GetAttribute ();
+					if (ColorScheme != null) {
+						Driver.SetAttribute (HasFocus ? GetHotNormalColor () : GetNormalColor ());
+					} else {
+						Driver.SetAttribute (Parent.HasFocus ? Parent.GetHotNormalColor () : Parent.GetNormalColor ());
+					}
+					DrawTitle (new Rect (borderBounds.X, titleY, Parent.Title.GetColumns (), 1), Parent?.Title);
+					Driver.SetAttribute (prevAttr);
+				}
+
+				//Left
+				var vruler = new Ruler { Length = screenBounds.Height - 2, Orientation = Orientation.Vertical };
+				if (drawLeft) {
+					vruler.Draw (new Point (screenBounds.X, screenBounds.Y + 1), 1);
+				}
+
+				// Bottom
+				if (drawBottom) {
+					hruler.Draw (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1));
+				}
+
+				// Right
+				if (drawRight) {
+					vruler.Draw (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y + 1), 1);
+				}
+
+			}
+		}
+
+		//base.OnDrawContent (contentArea);
+	}
+
+	/// <summary>
+	/// Draws the title for a Window-style view.
+	/// </summary>
+	/// <param name="region">Screen relative region where the title will be drawn.</param>
+	/// <param name="title">The title.</param>
+	public void DrawTitle (Rect region, string title)
+	{
+		var width = region.Width;
+		if (!string.IsNullOrEmpty (title)) {
+			Driver.Move (region.X + 2, region.Y);
+			//Driver.AddRune (' ');
+			var str = title.EnumerateRunes ().Sum (r => Math.Max (r.GetColumns (), 1)) >= width
+				? TextFormatter.Format (title, width, false, false) [0] : title;
+			Driver.AddStr (str);
+		}
+	}
+
+	/// <summary>
+	/// Draws a frame in the current view, clipped by the boundary of this view
+	/// </summary>
+	/// <param name="region">View-relative region for the frame to be drawn.</param>
+	/// <param name="clear">If set to <see langword="true"/> it clear the region.</param>
+	[Obsolete ("This method is obsolete in v2. Use use LineCanvas or Frame instead.", false)]
+	public void DrawFrame (Rect region, bool clear)
+	{
+		var savedClip = ClipToBounds ();
+		var screenBounds = BoundsToScreen (region);
+
+		if (clear) {
+			Driver.FillRect (region);
+		}
+
+		var lc = new LineCanvas ();
+		var drawTop = region.Width > 1 && region.Height > 1;
+		var drawLeft = region.Width > 1 && region.Height > 1;
+		var drawBottom = region.Width > 1 && region.Height > 1;
+		var drawRight = region.Width > 1 && region.Height > 1;
+
+		if (drawTop) {
+			lc.AddLine (screenBounds.Location, screenBounds.Width, Orientation.Horizontal, LineStyle);
+		}
+		if (drawLeft) {
+			lc.AddLine (screenBounds.Location, screenBounds.Height, Orientation.Vertical, LineStyle);
+		}
+		if (drawBottom) {
+			lc.AddLine (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1), screenBounds.Width, Orientation.Horizontal, LineStyle);
+		}
+		if (drawRight) {
+			lc.AddLine (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y), screenBounds.Height, Orientation.Vertical, LineStyle);
+		}
+		foreach (var p in lc.GetMap ()) {
+			Driver.Move (p.Key.X, p.Key.Y);
+			Driver.AddRune (p.Value);
+		}
+		lc.Clear ();
+
+		// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
+		if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
+			// Top
+			var hruler = new Ruler { Length = screenBounds.Width, Orientation = Orientation.Horizontal };
+			if (drawTop) {
+				hruler.Draw (new Point (screenBounds.X, screenBounds.Y));
+			}
+
+			//Left
+			var vruler = new Ruler { Length = screenBounds.Height - 2, Orientation = Orientation.Vertical };
+			if (drawLeft) {
+				vruler.Draw (new Point (screenBounds.X, screenBounds.Y + 1), 1);
+			}
+
+			// Bottom
+			if (drawBottom) {
+				hruler.Draw (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1));
+			}
+
+			// Right
+			if (drawRight) {
+				vruler.Draw (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y + 1), 1);
+			}
+		}
+
+		Driver.Clip = savedClip;
+	}
+}

+ 37 - 0
Terminal.Gui/View/Adornment/Margin.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Linq;
+
+namespace Terminal.Gui;
+
+/// <summary>
+/// The Margin for a <see cref="View"/>. 
+/// </summary>
+/// <remarks>
+/// <para>
+/// See the <see cref="Adornment"/> class. 
+/// </para>
+/// </remarks>
+public class Margin : Adornment {
+	/// <inheritdoc />
+	public Margin () { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */ }
+
+	/// <inheritdoc />
+	public Margin (View parent) : base (parent) { /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */ }
+
+	/// <summary>
+	/// The color scheme for the Margin. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/>'s <see cref="View.SuperView"/> scheme.
+	/// color scheme.
+	/// </summary>
+	public override ColorScheme ColorScheme {
+		get {
+			if (base.ColorScheme != null) {
+				return base.ColorScheme;
+			}
+			return Parent?.SuperView?.ColorScheme ?? Colors.TopLevel;
+		}
+		set {
+			base.ColorScheme = value;
+			Parent?.SetNeedsDisplay ();
+		}
+	}
+}

+ 37 - 0
Terminal.Gui/View/Adornment/Padding.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Linq;
+
+namespace Terminal.Gui;
+
+/// <summary>
+/// The Padding for a <see cref="View"/>. 
+/// </summary>
+/// <remarks>
+/// <para>
+/// See the <see cref="Adornment"/> class. 
+/// </para>
+/// </remarks>
+public class Padding : Adornment {
+	/// <inheritdoc />
+	public Padding () { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */ }
+
+	/// <inheritdoc />
+	public Padding (View parent) : base (parent) { /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */ }
+	
+	/// <summary>
+	/// The color scheme for the Padding. If set to <see langword="null"/>, gets the <see cref="Adornment.Parent"/> scheme.
+	/// color scheme.
+	/// </summary>
+	public override ColorScheme ColorScheme {
+		get {
+			if (base.ColorScheme != null) {
+				return base.ColorScheme;
+			}
+			return Parent?.ColorScheme;
+		}
+		set {
+			base.ColorScheme = value;
+			Parent?.SetNeedsDisplay ();
+		}
+	}
+}

+ 0 - 446
Terminal.Gui/View/Frame.cs

@@ -1,446 +0,0 @@
-using System.Text;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Xml.Linq;
-using static Terminal.Gui.TileView;
-
-namespace Terminal.Gui {
-
-	// TODO: v2 - Missing 3D effect - 3D effects will be drawn by a mechanism separate from Frames
-	// TODO: v2 - If a Frame has focus, navigation keys (e.g Command.NextView) should cycle through SubViews of the Frame
-	// QUESTION: How does a user navigate out of a Frame to another Frame, or back into the Parent's SubViews?
-
-	/// <summary>
-	/// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
-	/// enabling borders, menus, etc... 
-	/// </summary>
-	public class Frame : View {
-		private Thickness _thickness = Thickness.Empty;
-
-		internal override void CreateFrames () { /* Do nothing - Frames do not have Frames */ }
-		internal override void LayoutFrames () { /* Do nothing - Frames do not have Frames */ }
-
-		/// <summary>
-		/// The Parent of this Frame (the View this Frame surrounds).
-		/// </summary>
-		public View Parent { get; set; }
-
-		/// <summary>
-		/// Frames cannot be used as sub-views, so this method always throws an <see cref="InvalidOperationException"/>.
-		/// TODO: Are we sure?
-		/// </summary>
-		public override View SuperView {
-			get {
-				return null;
-			}
-			set {
-				throw new NotImplementedException ();
-			}
-		}
-
-		/// <inheritdoc/>
-		public override void BoundsToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
-		{
-			// Frames are *Children* of a View, not SubViews. Thus View.BoundsToScreen will not work.
-			// To get the screen-relative coordinates of a Frame, we need to know who
-			// the Parent is
-			var parentFrame = Parent?.Frame ?? Frame;
-			rrow = row + parentFrame.Y;
-			rcol = col + parentFrame.X;
-
-			// We now have rcol/rrow in coordinates relative to our View's SuperView. If our View's SuperView has
-			// a SuperView, keep going...
-			Parent?.SuperView?.BoundsToScreen (rcol, rrow, out rcol, out rrow, clipped);
-		}
-
-		/// <inheritdoc/>
-		public override Rect FrameToScreen ()
-		{
-			// Frames are *Children* of a View, not SubViews. Thus View.FrameToScreen will not work.
-			// To get the screen-relative coordinates of a Frame, we need to know who
-			// the Parent is
-			var ret = Parent?.Frame ?? Frame;
-			ret.Size = Frame.Size;
-
-			ret.Location = Parent?.FrameToScreen ().Location ?? ret.Location;
-
-			// We now have coordinates relative to our View. If our View's SuperView has
-			// a SuperView, keep going...
-			return ret;
-		}
-
-		/// <summary>
-		/// Does nothing for Frame
-		/// </summary>
-		/// <returns></returns>
-		public override bool OnDrawFrames () => false;
-
-		/// <summary>
-		/// Does nothing for Frame
-		/// </summary>
-		/// <returns></returns>
-		public override bool OnRenderLineCanvas () => false;
-
-		/// <summary>
-		/// Frames only render to their Parent or Parent's SuperView's LineCanvas,
-		/// so this always throws an <see cref="InvalidOperationException"/>.
-		/// </summary>
-		public override bool SuperViewRendersLineCanvas {
-			get {
-				return false;// throw new NotImplementedException ();
-			}
-			set {
-				throw new NotImplementedException ();
-			}
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="clipRect"></param>
-		public virtual void OnDrawSubViews (Rect clipRect)
-		{
-			// TODO: Enable subviews of Frames (adornments).
-			//	if (Subviews == null) {
-			//		return;
-			//	}
-
-			//	foreach (var view in Subviews) {
-			//		// BUGBUG: v2 - shouldn't this be !view.LayoutNeeded? Why draw if layout is going to happen and we'll just draw again?
-			//		if (view.LayoutNeeded) {
-			//			view.LayoutSubviews ();
-			//		}
-			//		if ((view.Visible && !view.NeedDisplay.IsEmpty && view.Frame.Width > 0 && view.Frame.Height > 0) || view.ChildNeedsDisplay) {
-			//			view.Redraw (view.Bounds);
-
-			//			view.NeedDisplay = Rect.Empty;
-			//			// BUGBUG - v2 why does this need to be set to false?
-			//			// Shouldn't it be set when the subviews draw?
-			//			view.ChildNeedsDisplay = false;
-			//		}
-			//	}
-
-		}
-
-		/// <summary>
-		/// Redraws the Frames that comprise the <see cref="Frame"/>.
-		/// </summary>
-		public override void OnDrawContent (Rect contentArea)
-		{
-			if (Thickness == Thickness.Empty) {
-				return;
-			}
-
-			if (ColorScheme != null) {
-				Driver.SetAttribute (GetNormalColor ());
-			} else {
-				if (Id == "Padding") {
-					Driver.SetAttribute (new Attribute (Parent.ColorScheme.HotNormal.Background, Parent.ColorScheme.HotNormal.Foreground));
-				} else {
-					Driver.SetAttribute (Parent.GetNormalColor ());
-				}
-			}
-
-			//Driver.SetAttribute (Colors.Error.Normal);
-			var screenBounds = BoundsToScreen (Frame);
-
-			// This just draws/clears the thickness, not the insides.
-			Thickness.Draw (screenBounds, (string)(Data != null ? Data : string.Empty));
-
-			//OnDrawSubviews (bounds); 
-
-			// TODO: v2 - this will eventually be two controls: "BorderView" and "Label" (for the title)
-
-			// The border frame (and title) are drawn at the outermost edge of border; 
-			// For Border
-			// ...thickness extends outward (border/title is always as far in as possible)
-			var borderBounds = new Rect (
-				screenBounds.X + Math.Max (0, Thickness.Left - 1),
-				screenBounds.Y + Math.Max (0, Thickness.Top - 1),
-				Math.Max (0, screenBounds.Width - Math.Max (0, Math.Max (0, Thickness.Left - 1) + Math.Max (0, Thickness.Right - 1))),
-				Math.Max (0, screenBounds.Height - Math.Max (0, Math.Max (0, Thickness.Top - 1) + Math.Max (0, Thickness.Bottom - 1))));
-
-			var topTitleLineY = borderBounds.Y;
-			var titleY = borderBounds.Y;
-			var titleBarsLength = 0; // the little vertical thingies
-			var maxTitleWidth = Math.Min (Parent.Title.GetColumns (), Math.Min (screenBounds.Width - 4, borderBounds.Width - 4));
-			var sideLineLength = borderBounds.Height;
-			var canDrawBorder = borderBounds.Width > 0 && borderBounds.Height > 0;
-
-			if (!string.IsNullOrEmpty (Parent?.Title)) {
-				if (Thickness.Top == 2) {
-					topTitleLineY = borderBounds.Y - 1;
-					titleY = topTitleLineY + 1;
-					titleBarsLength = 2;
-				}
-
-				// ┌────┐
-				//┌┘View└
-				//│
-				if (Thickness.Top == 3) {
-					topTitleLineY = borderBounds.Y - (Thickness.Top - 1);
-					titleY = topTitleLineY + 1;
-					titleBarsLength = 3;
-					sideLineLength++;
-				}
-
-				// ┌────┐
-				//┌┘View└
-				//│
-				if (Thickness.Top > 3) {
-					topTitleLineY = borderBounds.Y - 2;
-					titleY = topTitleLineY + 1;
-					titleBarsLength = 3;
-					sideLineLength++;
-				}
-
-			}
-
-			if (Id == "Border" && canDrawBorder && Thickness.Top > 0 && maxTitleWidth > 0 && !string.IsNullOrEmpty (Parent?.Title)) {
-				var prevAttr = Driver.GetAttribute ();
-				if (ColorScheme != null) {
-					Driver.SetAttribute (HasFocus ? GetHotNormalColor () : GetNormalColor ());
-				} else {
-					Driver.SetAttribute (Parent.HasFocus ? Parent.GetHotNormalColor () : Parent.GetNormalColor ());
-				}
-				DrawTitle (new Rect (borderBounds.X, titleY, maxTitleWidth, 1), Parent?.Title);
-				Driver.SetAttribute (prevAttr);
-			}
-
-			if (Id == "Border" && canDrawBorder && BorderStyle != LineStyle.None) {
-				LineCanvas lc = Parent?.LineCanvas;
-
-				var drawTop = Thickness.Top > 0 && Frame.Width > 1 && Frame.Height > 1;
-				var drawLeft = Thickness.Left > 0 && (Frame.Height > 1 || Thickness.Top == 0);
-				var drawBottom = Thickness.Bottom > 0 && Frame.Width > 1;
-				var drawRight = Thickness.Right > 0 && (Frame.Height > 1 || Thickness.Top == 0);
-
-				var prevAttr = Driver.GetAttribute ();
-				if (ColorScheme != null) {
-					Driver.SetAttribute (GetNormalColor ());
-				} else {
-					Driver.SetAttribute (Parent.GetNormalColor ());
-				}
-
-				if (drawTop) {
-					// ╔╡Title╞═════╗
-					// ╔╡╞═════╗
-					if (borderBounds.Width < 4 || string.IsNullOrEmpty (Parent?.Title)) {
-						// ╔╡╞╗ should be ╔══╗
-						lc.AddLine (new Point (borderBounds.Location.X, titleY), borderBounds.Width, Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-					} else {
-
-						// ┌────┐
-						//┌┘View└
-						//│
-						if (Thickness.Top == 2) {
-							lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-						}
-						// ┌────┐
-						//┌┘View└
-						//│
-						if (borderBounds.Width >= 4 && Thickness.Top > 2) {
-							lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-							lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY + 2), Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-						}
-
-						// ╔╡Title╞═════╗
-						// Add a short horiz line for ╔╡
-						lc.AddLine (new Point (borderBounds.Location.X, titleY), 2, Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-						// Add a vert line for ╔╡
-						lc.AddLine (new Point (borderBounds.X + 1, topTitleLineY), titleBarsLength, Orientation.Vertical, LineStyle.Single, Driver.GetAttribute ());
-						// Add a vert line for ╞
-						lc.AddLine (new Point (borderBounds.X + 1 + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2) - 1, topTitleLineY), titleBarsLength, Orientation.Vertical, LineStyle.Single, Driver.GetAttribute ());
-						// Add the right hand line for ╞═════╗
-						lc.AddLine (new Point (borderBounds.X + 1 + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2) - 1, titleY), borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2), Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-					}
-				}
-				if (drawLeft) {
-					lc.AddLine (new Point (borderBounds.Location.X, titleY), sideLineLength, Orientation.Vertical, BorderStyle, Driver.GetAttribute ());
-				}
-				if (drawBottom) {
-					lc.AddLine (new Point (borderBounds.X, borderBounds.Y + borderBounds.Height - 1), borderBounds.Width, Orientation.Horizontal, BorderStyle, Driver.GetAttribute ());
-				}
-				if (drawRight) {
-					lc.AddLine (new Point (borderBounds.X + borderBounds.Width - 1, titleY), sideLineLength, Orientation.Vertical, BorderStyle, Driver.GetAttribute ());
-				}
-				Driver.SetAttribute (prevAttr);
-
-				// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
-				if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
-					// Top
-					var hruler = new Ruler () { Length = screenBounds.Width, Orientation = Orientation.Horizontal };
-					if (drawTop) {
-						hruler.Draw (new Point (screenBounds.X, screenBounds.Y));
-					}
-
-					// Redraw title 
-					if (drawTop && Id == "Border" && maxTitleWidth > 0 && !string.IsNullOrEmpty (Parent?.Title)) {
-						prevAttr = Driver.GetAttribute ();
-						if (ColorScheme != null) {
-							Driver.SetAttribute (HasFocus ? GetHotNormalColor () : GetNormalColor ());
-						} else {
-							Driver.SetAttribute (Parent.HasFocus ? Parent.GetHotNormalColor () : Parent.GetNormalColor ());
-						}
-						DrawTitle (new Rect (borderBounds.X, titleY, Parent.Title.GetColumns (), 1), Parent?.Title);
-						Driver.SetAttribute (prevAttr);
-					}
-
-					//Left
-					var vruler = new Ruler () { Length = screenBounds.Height - 2, Orientation = Orientation.Vertical };
-					if (drawLeft) {
-						vruler.Draw (new Point (screenBounds.X, screenBounds.Y + 1), 1);
-					}
-
-					// Bottom
-					if (drawBottom) {
-						hruler.Draw (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1));
-					}
-
-					// Right
-					if (drawRight) {
-						vruler.Draw (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y + 1), 1);
-					}
-
-				}
-			}
-
-			ClearNeedsDisplay ();
-		}
-
-		// TODO: v2 - Frame.BorderStyle is temporary - Eventually the border will be drawn by a "BorderView" that is a subview of the Frame.
-		/// <summary>
-		/// 
-		/// </summary>
-		public new LineStyle BorderStyle { get; set; } = LineStyle.None;
-
-		/// <summary>
-		/// Defines the rectangle that the <see cref="Frame"/> will use to draw its content. 
-		/// </summary>
-		public Thickness Thickness {
-			get { return _thickness; }
-			set {
-				var prev = _thickness;
-				_thickness = value;
-				if (prev != _thickness) {
-
-					Parent?.LayoutFrames ();
-					OnThicknessChanged (prev);
-				}
-
-			}
-		}
-
-		/// <summary>
-		/// Called whenever the <see cref="Thickness"/> property changes.
-		/// </summary>
-		public virtual void OnThicknessChanged (Thickness previousThickness)
-		{
-			ThicknessChanged?.Invoke (this, new ThicknessEventArgs () { Thickness = Thickness, PreviousThickness = previousThickness });
-		}
-
-		/// <summary>
-		/// Fired whenever the <see cref="Thickness"/> property changes.
-		/// </summary>
-		public event EventHandler<ThicknessEventArgs> ThicknessChanged;
-
-		/// <summary>
-		/// Gets the rectangle that describes the inner area of the frame. The Location is always (0,0).
-		/// </summary>
-		public override Rect Bounds {
-			get {
-				return Thickness?.GetInside (new Rect (Point.Empty, Frame.Size)) ?? new Rect (Point.Empty, Frame.Size);
-			}
-			set {
-				throw new InvalidOperationException ("It makes no sense to set Bounds of a Thickness.");
-			}
-		}
-
-		/// <summary>
-		/// Draws the title for a Window-style view.
-		/// </summary>
-		/// <param name="region">Screen relative region where the title will be drawn.</param>
-		/// <param name="title">The title.</param>
-		public void DrawTitle (Rect region, string title)
-		{
-			var width = region.Width;
-			if (!string.IsNullOrEmpty (title)) {
-				Driver.Move (region.X + 2, region.Y);
-				//Driver.AddRune (' ');
-				var str = title.EnumerateRunes ().Sum (r => Math.Max (r.GetColumns (), 1)) >= width
-					? TextFormatter.Format (title, width, false, false) [0] : title;
-				Driver.AddStr (str);
-			}
-		}
-
-		/// <summary>
-		/// Draws a frame in the current view, clipped by the boundary of this view
-		/// </summary>
-		/// <param name="region">View-relative region for the frame to be drawn.</param>
-		/// <param name="clear">If set to <see langword="true"/> it clear the region.</param>
-		[ObsoleteAttribute ("This method is obsolete in v2. Use use LineCanvas or Frame instead.", false)]
-		public void DrawFrame (Rect region, bool clear)
-		{
-			var savedClip = ClipToBounds ();
-			var screenBounds = BoundsToScreen (region);
-
-			if (clear) {
-				Driver.FillRect (region);
-			}
-
-			var lc = new LineCanvas ();
-			var drawTop = region.Width > 1 && region.Height > 1;
-			var drawLeft = region.Width > 1 && region.Height > 1;
-			var drawBottom = region.Width > 1 && region.Height > 1;
-			var drawRight = region.Width > 1 && region.Height > 1;
-
-			if (drawTop) {
-				lc.AddLine (screenBounds.Location, screenBounds.Width, Orientation.Horizontal, BorderStyle);
-			}
-			if (drawLeft) {
-				lc.AddLine (screenBounds.Location, screenBounds.Height, Orientation.Vertical, BorderStyle);
-			}
-			if (drawBottom) {
-				lc.AddLine (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1), screenBounds.Width, Orientation.Horizontal, BorderStyle);
-			}
-			if (drawRight) {
-				lc.AddLine (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y), screenBounds.Height, Orientation.Vertical, BorderStyle);
-			}
-			foreach (var p in lc.GetMap ()) {
-				Driver.Move (p.Key.X, p.Key.Y);
-				Driver.AddRune (p.Value);
-			}
-			lc.Clear ();
-
-			// TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
-			if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) {
-				// Top
-				var hruler = new Ruler () { Length = screenBounds.Width, Orientation = Orientation.Horizontal };
-				if (drawTop) {
-					hruler.Draw (new Point (screenBounds.X, screenBounds.Y));
-				}
-
-				//Left
-				var vruler = new Ruler () { Length = screenBounds.Height - 2, Orientation = Orientation.Vertical };
-				if (drawLeft) {
-					vruler.Draw (new Point (screenBounds.X, screenBounds.Y + 1), 1);
-				}
-
-				// Bottom
-				if (drawBottom) {
-					hruler.Draw (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1));
-				}
-
-				// Right
-				if (drawRight) {
-					vruler.Draw (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y + 1), 1);
-				}
-			}
-
-			Driver.Clip = savedClip;
-		}
-
-	}
-}

+ 92 - 116
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -86,7 +86,7 @@ public partial class View {
 
 			// TODO: Figure out if the below can be optimized.
 			if (IsInitialized /*|| LayoutStyle == LayoutStyle.Absolute*/) {
-				LayoutFrames ();
+				LayoutAdornments ();
 				SetTextFormatterSize ();
 				SetNeedsLayout ();
 				SetNeedsDisplay ();
@@ -100,21 +100,19 @@ public partial class View {
 	/// </summary>
 	/// <remarks>
 	///         <para>
-	///         The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
-	///         content
-	///         and are not clipped by the View's Clip Area.
+	///         The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
+	///         content and are not clipped by the View's Clip Area.
 	///         </para>
 	///         <para>
-	///         Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
-	///         will change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout
-	///         of the
-	///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
+	///         Changing the size of an adornment (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
+	///         will change the size of <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout
+	///         of the <see cref="SuperView"/> and its <see cref="Subviews"/>.
 	///         </para>
 	/// </remarks>
-	public Frame Margin { get; private set; }
+	public Margin Margin { get; private set; }
 
 	/// <summary>
-	/// The frame (specified as a <see cref="Thickness"/>) inside of the view that offsets the <see cref="Bounds"/> from the
+	/// The adornment (specified as a <see cref="Thickness"/>) inside of the view that offsets the <see cref="Bounds"/> from the
 	/// <see cref="Margin"/>.
 	/// The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title.
 	/// The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and
@@ -125,9 +123,8 @@ public partial class View {
 	///         <see cref="BorderStyle"/> provides a simple helper for turning a simple border frame on or off.
 	///         </para>
 	///         <para>
-	///         The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
-	///         content
-	///         and are not clipped by the View's Clip Area.
+	///         The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
+	///         content and are not clipped by the View's Clip Area.
 	///         </para>
 	///         <para>
 	///         Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
@@ -136,7 +133,7 @@ public partial class View {
 	///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
 	///         </para>
 	/// </remarks>
-	public Frame Border { get; private set; }
+	public Border Border { get; private set; }
 
 	/// <summary>
 	/// Gets or sets whether the view has a one row/col thick border.
@@ -145,12 +142,12 @@ public partial class View {
 	///         <para>
 	///         This is a helper for manipulating the view's <see cref="Border"/>. Setting this property to any value other
 	///         than
-	///         <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s <see cref="Frame.Thickness"/>
+	///         <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s <see cref="Adornment.Thickness"/>
 	///         to `1` and <see cref="BorderStyle"/> to the value.
 	///         </para>
 	///         <para>
 	///         Setting this property to <see cref="LineStyle.None"/> is equivalent to setting <see cref="Border"/>'s
-	///         <see cref="Frame.Thickness"/>
+	///         <see cref="Adornment.Thickness"/>
 	///         to `0` and <see cref="BorderStyle"/> to <see cref="LineStyle.None"/>.
 	///         </para>
 	///         <para>
@@ -158,18 +155,15 @@ public partial class View {
 	///         </para>
 	/// </remarks>
 	public LineStyle BorderStyle {
-		get => Border?.BorderStyle ?? LineStyle.None;
+		get => Border.LineStyle;
 		set {
-			if (Border == null) {
-				throw new InvalidOperationException ("Border is null; this is likely a bug.");
-			}
 			if (value != LineStyle.None) {
 				Border.Thickness = new Thickness (1);
 			} else {
 				Border.Thickness = new Thickness (0);
 			}
-			Border.BorderStyle = value;
-			LayoutFrames ();
+			Border.LineStyle = value;
+			LayoutAdornments ();
 			SetNeedsLayout ();
 		}
 	}
@@ -180,9 +174,8 @@ public partial class View {
 	/// </summary>
 	/// <remarks>
 	///         <para>
-	///         The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
-	///         content
-	///         and are not clipped by the View's Clip Area.
+	///         The adornments (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's
+	///         content and are not clipped by the View's Clip Area.
 	///         </para>
 	///         <para>
 	///         Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
@@ -191,24 +184,73 @@ public partial class View {
 	///         <see cref="SuperView"/> and its <see cref="Subviews"/>.
 	///         </para>
 	/// </remarks>
-	public Frame Padding { get; private set; }
+	public Padding Padding { get; private set; }
 
 	/// <summary>
 	///         <para>
-	///         Gets the LayoutStyle for the <see cref="View"/>.
-	///         </para>
-	///         <para>
-	///         If Absolute, the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
-	///         <see cref="View.Height"/>
-	///         objects are all absolute values and are not relative. The position and size of the view is described by
-	///         <see cref="View.Frame"/>.
-	///         </para>
-	///         <para>
-	///         If Computed, one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
-	///         <see cref="View.Height"/>
-	///         objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.
+	///         Gets the thickness describing the sum of the Adornments' thicknesses.
 	///         </para>
 	/// </summary>
+	/// <returns>A thickness that describes the sum of the Adornments' thicknesses.</returns>
+	public Thickness GetAdornmentsThickness ()
+	{
+		int left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left;
+		int top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top;
+		int right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right;
+		int bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom;
+		return new Thickness (left, top, right, bottom);
+	}
+
+	/// <summary>
+	/// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
+	/// <see cref="Margin"/>, <see cref="Border"/> and <see cref="Padding"/>.
+	/// </summary>
+	public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
+
+	/// <summary>
+	/// This internal method is overridden by Adornment to do nothing to prevent recursion during View construction.
+	/// And, because Adornments don't have Adornments. It's internal to support unit tests.
+	/// </summary>
+	/// <param name="adornment"></param>
+	/// <exception cref="ArgumentNullException"></exception>
+	/// <exception cref="ArgumentException"></exception>
+	internal virtual Adornment CreateAdornment (Type adornmentType)
+	{
+		void ThicknessChangedHandler (object sender, EventArgs e)
+		{
+			if (IsInitialized) {
+				LayoutAdornments ();
+			}
+			SetNeedsLayout ();
+			SetNeedsDisplay ();
+		}
+
+		Adornment adornment;
+
+		adornment = Activator.CreateInstance (adornmentType, this) as Adornment;
+		adornment.ThicknessChanged += ThicknessChangedHandler;
+
+		return adornment;
+	}
+
+	/// <summary>
+	/// Controls how the View's <see cref="Frame"/> is computed during <see cref="LayoutSubviews"/>. If the style is set to
+	/// <see cref="LayoutStyle.Absolute"/>, LayoutSubviews does not change the <see cref="Frame"/>.
+	/// If the style is <see cref="LayoutStyle.Computed"/> the <see cref="Frame"/> is updated using
+	/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Setting this property to <see cref="LayoutStyle.Absolute"/> will cause <see cref="Frame"/> to determine the
+	/// size and position of the view. <see cref="X"/> and <see cref="Y"/> will be set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
+	/// </para>
+	/// <para>
+	/// Setting this property to <see cref="LayoutStyle.Computed"/> will cause the view to use the <see cref="LayoutSubviews"/> method to 
+	/// size and position of the view. If either of the <see cref="X"/> and <see cref="Y"/> properties are `null` they will be set to <see cref="Pos.PosAbsolute"/> using
+	/// the current value of <see cref="Frame"/>. 
+	/// If either of the <see cref="Width"/> and <see cref="Height"/> properties are `null` they will be set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
+	/// </para>
+	/// </remarks>
 	/// <value>The layout style.</value>
 	public LayoutStyle LayoutStyle {
 		get {
@@ -252,8 +294,13 @@ public partial class View {
 				Debug.WriteLine ($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug in {this}");
 			}
 #endif // DEBUG
-			var frameRelativeBounds = FrameGetInsideBounds ();
-			return new Rect (default, frameRelativeBounds.Size);
+			// BUGBUG: I think there's a bug here. This should be && not ||
+			if (Margin == null || Border == null || Padding == null) {
+				return new Rect (default, Frame.Size);
+			}
+			var width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
+			var height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical);
+			return new Rect (Point.Empty, new Size (width, height));
 		}
 		set {
 			// TODO: Should we enforce Bounds.X/Y == 0? The code currently ignores value.X/Y which is
@@ -470,76 +517,7 @@ public partial class View {
 	/// </summary>
 	public event EventHandler Initialized;
 
-	/// <summary>
-	/// Helper to get the total thickness of the <see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>.
-	/// </summary>
-	/// <returns>A thickness that describes the sum of the Frames' thicknesses.</returns>
-	public Thickness GetFramesThickness ()
-	{
-		var left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left;
-		var top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top;
-		var right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right;
-		var bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom;
-		return new Thickness (left, top, right, bottom);
-	}
-
-	/// <summary>
-	/// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
-	/// <see cref="Margin"/>, <see cref="Border"/> and <see cref="Padding"/>.
-	/// </summary>
-	public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
-
-	/// <summary>
-	/// Creates the view's <see cref="Frame"/> objects. This internal method is overridden by Frame to do nothing
-	/// to prevent recursion during View construction.
-	/// </summary>
-	internal virtual void CreateFrames ()
-	{
-		void ThicknessChangedHandler (object sender, EventArgs e)
-		{
-			if (IsInitialized) {
-				LayoutFrames ();
-			}
-			SetNeedsLayout ();
-			SetNeedsDisplay ();
-		}
-
-		if (Margin != null) {
-			Margin.ThicknessChanged -= ThicknessChangedHandler;
-			Margin.Dispose ();
-		}
-		Margin = new Frame { Id = "Margin", Thickness = new Thickness (0) };
-		Margin.ThicknessChanged += ThicknessChangedHandler;
-		Margin.Parent = this;
 
-		if (Border != null) {
-			Border.ThicknessChanged -= ThicknessChangedHandler;
-			Border.Dispose ();
-		}
-		Border = new Frame { Id = "Border", Thickness = new Thickness (0) };
-		Border.ThicknessChanged += ThicknessChangedHandler;
-		Border.Parent = this;
-
-		// TODO: Create View.AddAdornment
-
-		if (Padding != null) {
-			Padding.ThicknessChanged -= ThicknessChangedHandler;
-			Padding.Dispose ();
-		}
-		Padding = new Frame { Id = "Padding", Thickness = new Thickness (0) };
-		Padding.ThicknessChanged += ThicknessChangedHandler;
-		Padding.Parent = this;
-	}
-
-	Rect FrameGetInsideBounds ()
-	{
-		if (Margin == null || Border == null || Padding == null) {
-			return new Rect (default, Frame.Size);
-		}
-		var width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
-		var height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical);
-		return new Rect (Point.Empty, new Size (width, height));
-	}
 
 	// Diagnostics to highlight when X or Y is read before the view has been initialized
 	Pos VerifyIsInitialized (Pos pos, string member)
@@ -588,7 +566,7 @@ public partial class View {
 		// TODO: Determine what, if any of the below is actually needed here.
 		if (IsInitialized) {
 			SetFrameToFitText ();
-			LayoutFrames ();
+			LayoutAdornments ();
 			SetTextFormatterSize ();
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
@@ -856,10 +834,8 @@ public partial class View {
 
 			if (IsInitialized) {
 				// TODO: Figure out what really is needed here. All unit tests (except AutoSize) pass as-is
-				//LayoutFrames ();
 				SetTextFormatterSize ();
 				SetNeedsLayout ();
-				//SetNeedsDisplay ();
 			}
 
 			// BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
@@ -1019,12 +995,12 @@ public partial class View {
 	} // TopologicalSort
 
 	/// <summary>
-	/// Overriden by <see cref="Frame"/> to do nothing, as the <see cref="Frame"/> does not have frames.
+	/// Overriden by <see cref="Adornment"/> to do nothing, as the <see cref="Adornment"/> does not have adornments.
 	/// </summary>
-	internal virtual void LayoutFrames ()
+	internal virtual void LayoutAdornments ()
 	{
 		if (Margin == null) {
-			return; // CreateFrames() has not been called yet
+			return; // CreateAdornments () has not been called yet
 		}
 
 		if (Margin.Frame.Size != Frame.Size) {
@@ -1083,7 +1059,7 @@ public partial class View {
 			return;
 		}
 
-		LayoutFrames ();
+		LayoutAdornments ();
 
 		var oldBounds = Bounds;
 		OnLayoutStarted (new LayoutEventArgs { OldBounds = oldBounds });

+ 7 - 11
Terminal.Gui/View/View.cs

@@ -68,7 +68,7 @@ namespace Terminal.Gui;
 /// points. The Width and Height properties are of type
 /// <see cref="Dim"/> and can use absolute position,
 /// percentages, and anchors. These are useful as they will take
-/// care of repositioning views when view's frames are resized or
+/// care of repositioning views when view's adornments are resized or
 /// if the terminal size changes.
 /// </para>
 /// <para>
@@ -88,7 +88,7 @@ namespace Terminal.Gui;
 /// The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has
 /// changed. The default processing system will keep the size and dimensions
 /// for views that use the <see cref="LayoutStyle.Absolute"/>, and will recompute the
-/// frames for the vies that use <see cref="LayoutStyle.Computed"/>.
+/// Adornments for the views that use <see cref="LayoutStyle.Computed"/>.
 /// </para>
 /// <para>
 /// Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews
@@ -430,9 +430,9 @@ public partial class View : Responder, ISupportInitializeNotification {
 	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
 	///         </para>
 	/// </remarks>
-	/// <param name="rect">Location.</param>
+	/// <param name="frame">Location.</param>
 	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-	public View (Rect rect, string text) => SetInitialProperties (text, rect, LayoutStyle.Absolute);
+	public View (Rect frame, string text) => SetInitialProperties (text, frame, LayoutStyle.Absolute);
 
 
 	/// <summary>
@@ -493,7 +493,9 @@ public partial class View : Responder, ISupportInitializeNotification {
 
 		AddCommands ();
 
-		CreateFrames ();
+		Margin = CreateAdornment (typeof (Margin)) as Margin;
+		Border = CreateAdornment (typeof (Border)) as Border;
+		Padding = CreateAdornment (typeof (Padding)) as Padding;
 	}
 
 	/// <summary>
@@ -534,12 +536,6 @@ public partial class View : Responder, ISupportInitializeNotification {
 		if (!IsInitialized) {
 			_oldCanFocus = CanFocus;
 			_oldTabIndex = _tabIndex;
-
-
-			// TODO: Figure out why ScrollView and other tests fail if this call is put here 
-			// instead of the constructor.
-			//InitializeFrames ();
-
 		}
 
 		//throw new InvalidOperationException ("The view is already initialized.");

+ 21 - 7
Terminal.Gui/View/ViewDrawing.cs

@@ -58,7 +58,7 @@ public partial class View {
 	/// Gets or sets whether this View will use it's SuperView's <see cref="LineCanvas"/> for
 	/// rendering any border lines. If <see langword="true"/> the rendering of any borders drawn
 	/// by this Frame will be done by it's parent's SuperView. If <see langword="false"/> (the default)
-	/// this View's <see cref="OnDrawFrames()"/> method will be called to render the borders.
+	/// this View's <see cref="OnDrawAdornments"/> method will be called to render the borders.
 	/// </summary>
 	public virtual bool SuperViewRendersLineCanvas { get; set; } = false;
 
@@ -87,7 +87,14 @@ public partial class View {
 	/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
 	/// If it's overridden can return other values.
 	/// </returns>
-	public virtual Attribute GetFocusColor () => Enabled ? ColorScheme.Focus : ColorScheme.Disabled;
+	public virtual Attribute GetFocusColor ()
+	{
+		var cs = ColorScheme;
+		if (ColorScheme == null) {
+			cs = new ColorScheme ();
+		}
+		return Enabled ? cs.Focus : cs.Disabled;
+	}
 
 	/// <summary>
 	/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
@@ -97,7 +104,14 @@ public partial class View {
 	/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
 	/// If it's overridden can return other values.
 	/// </returns>
-	public virtual Attribute GetHotNormalColor () => Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled;
+	public virtual Attribute GetHotNormalColor ()
+	{
+		var cs = ColorScheme;
+		if (ColorScheme == null) {
+			cs = new ColorScheme ();
+		}
+		return Enabled ? cs.HotNormal : cs.Disabled;
+	}
 
 	/// <summary>
 	/// Displays the specified character in the specified column and row of the View.
@@ -334,7 +348,7 @@ public partial class View {
 	/// method will cause the <see cref="LineCanvas"/> be prepared to be rendered.
 	/// </summary>
 	/// <returns></returns>
-	public virtual bool OnDrawFrames ()
+	public virtual bool OnDrawAdornments ()
 	{
 		if (!IsInitialized) {
 			return false;
@@ -372,7 +386,7 @@ public partial class View {
 		if (!CanBeVisible (this)) {
 			return;
 		}
-		OnDrawFrames ();
+		OnDrawAdornments ();
 
 		var prevClip = ClipToBounds ();
 
@@ -474,7 +488,7 @@ public partial class View {
 	{
 		if (NeedsDisplay) {
 			if (SuperView != null) {
-				Clear (BoundsToScreen (Bounds));
+				Clear (BoundsToScreen (contentArea));
 			}
 
 			if (!string.IsNullOrEmpty (TextFormatter.Text)) {
@@ -483,7 +497,7 @@ public partial class View {
 				}
 			}
 			// This should NOT clear 
-			TextFormatter?.Draw (BoundsToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
+			TextFormatter?.Draw (BoundsToScreen (contentArea), HasFocus ? GetFocusColor () : GetNormalColor (),
 				HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
 				Rect.Empty, false);
 			SetSubViewNeedsDisplay ();

+ 1 - 1
Terminal.Gui/Views/ColorPicker.cs

@@ -112,7 +112,7 @@ public class ColorPicker : View {
 		AddCommands ();
 		AddKeyBindings ();
 		LayoutStarted += (o, a) => {
-			var thickness = GetFramesThickness ();
+			var thickness = GetAdornmentsThickness ();
 			Width = _cols * BoxWidth + thickness.Vertical;
 			Height = _rows * BoxHeight + thickness.Horizontal;
 		};

+ 1 - 1
Terminal.Gui/Views/DatePicker.cs

@@ -8,7 +8,7 @@ using System.Data;
 using System.Globalization;
 using System.Linq;
 
-namespace Terminal.Gui.Views;
+namespace Terminal.Gui;
 
 /// <summary>
 /// The <see cref="DatePicker"/> <see cref="View"/> Date Picker.

+ 1 - 1
Terminal.Gui/Views/FrameView.cs

@@ -50,7 +50,7 @@ namespace Terminal.Gui {
 		{
 			this.Title = title;
 			Border.Thickness = new Thickness (1);
-			Border.BorderStyle = DefaultBorderStyle;
+			Border.LineStyle = DefaultBorderStyle;
 			//Border.ColorScheme = ColorScheme;
 			Border.Data = "Border";
 		}

+ 2 - 2
Terminal.Gui/Views/Line.cs

@@ -23,7 +23,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <inheritdoc/>
-		public override bool OnDrawFrames ()
+		public override bool OnDrawAdornments ()
 		{
 			var screenBounds = BoundsToScreen (Bounds);
 			LineCanvas lc;
@@ -43,7 +43,7 @@ namespace Terminal.Gui {
 		/// <inheritdoc/>
 		public override void OnDrawContent (Rect contentArea)
 		{
-			OnDrawFrames ();
+			OnDrawAdornments ();
 		}
 	}
 }

+ 1 - 1
Terminal.Gui/Views/Menu/Menu.cs

@@ -633,7 +633,7 @@ class Menu : View {
 		Driver.Clip = new Rect (0, 0, Driver.Cols, Driver.Rows);
 		Driver.SetAttribute (GetNormalColor ());
 
-		OnDrawFrames ();
+		OnDrawAdornments ();
 		OnRenderLineCanvas ();
 
 		for (int i = Bounds.Y; i < _barItems.Children.Length; i++) {

+ 4 - 4
Terminal.Gui/Views/MessageBox.cs

@@ -303,20 +303,20 @@ namespace Terminal.Gui {
 				// TODO: replace with Dim.Fit when implemented
 				var maxBounds = d.SuperView?.Bounds ?? Application.Top.Bounds;
 				if (wrapMessage) {
-					messageLabel.TextFormatter.Size = new Size (maxBounds.Size.Width - d.GetFramesThickness ().Horizontal, maxBounds.Size.Height - d.GetFramesThickness ().Vertical);
+					messageLabel.TextFormatter.Size = new Size (maxBounds.Size.Width - d.GetAdornmentsThickness ().Horizontal, maxBounds.Size.Height - d.GetAdornmentsThickness ().Vertical);
 				}
 				var msg = messageLabel.TextFormatter.Format ();
 				var messageSize = messageLabel.TextFormatter.GetFormattedSize ();
 
 				// Ensure the width fits the text + buttons
-				var newWidth = Math.Max (width, Math.Max (messageSize.Width + d.GetFramesThickness ().Horizontal,
-								d.GetButtonsWidth () + d.buttons.Count + d.GetFramesThickness ().Horizontal));
+				var newWidth = Math.Max (width, Math.Max (messageSize.Width + d.GetAdornmentsThickness ().Horizontal,
+								d.GetButtonsWidth () + d.buttons.Count + d.GetAdornmentsThickness ().Horizontal));
 				if (newWidth > d.Frame.Width) {
 					d.Width = newWidth;
 				}
 				// Ensure height fits the text + vspace + buttons
 				var lastLine = messageLabel.TextFormatter.Lines [^1];
-				d.Height = Math.Max (height, messageSize.Height + (lastLine.EndsWith ("\r\n") || lastLine.EndsWith ('\n') ? 1 : 2) + d.GetFramesThickness ().Vertical);
+				d.Height = Math.Max (height, messageSize.Height + (lastLine.EndsWith ("\r\n") || lastLine.EndsWith ('\n') ? 1 : 2) + d.GetAdornmentsThickness ().Vertical);
 				d.SetRelativeLayout (d.SuperView?.Frame ?? Application.Top.Frame);
 			};
 

+ 1 - 1
Terminal.Gui/Views/ProgressBar.cs

@@ -83,7 +83,7 @@ public class ProgressBar : View {
 	void ProgressBar_LayoutStarted (object sender, EventArgs e)
 	{
 		// TODO: use Dim.Auto
-		Height = 1 + GetFramesThickness ().Vertical;
+		Height = 1 + GetAdornmentsThickness ().Vertical;
 	}
 
 	float _fraction;

+ 4 - 4
Terminal.Gui/Views/RadioGroup.cs

@@ -124,8 +124,8 @@ public class RadioGroup : View {
 		case Orientation.Vertical:
 			var r = MakeRect (0, 0, radioLabels);
 			if (IsInitialized) {
-				Width = r.Width + GetFramesThickness ().Horizontal;
-				Height = radioLabels.Count + GetFramesThickness ().Vertical;
+				Width = r.Width + GetAdornmentsThickness ().Horizontal;
+				Height = radioLabels.Count + GetAdornmentsThickness ().Vertical;
 			}
 			break;
 
@@ -136,8 +136,8 @@ public class RadioGroup : View {
 				length += item.length;
 			}
 			if (IsInitialized) {
-				Width = length + GetFramesThickness ().Vertical;
-				Height = 1 + GetFramesThickness ().Horizontal;
+				Width = length + GetAdornmentsThickness ().Vertical;
+				Height = 1 + GetAdornmentsThickness ().Horizontal;
 			}
 			break;
 		}

+ 4 - 4
Terminal.Gui/Views/Slider.cs

@@ -808,12 +808,12 @@ public class Slider<T> : View {
 		Height = 0;
 		if (_config._sliderOrientation == Orientation.Horizontal) {
 			Bounds = new Rect (Bounds.Location,
-				new Size (int.Min (SuperView.Bounds.Width - GetFramesThickness ().Horizontal, CalcBestLength ()),
-					int.Min (SuperView.Bounds.Height - GetFramesThickness ().Vertical, CalcThickness ())));
+				new Size (int.Min (SuperView.Bounds.Width - GetAdornmentsThickness ().Horizontal, CalcBestLength ()),
+					int.Min (SuperView.Bounds.Height - GetAdornmentsThickness ().Vertical, CalcThickness ())));
 		} else {
 			Bounds = new Rect (Bounds.Location,
-				new Size (int.Min (SuperView.Bounds.Width - GetFramesThickness ().Horizontal, CalcThickness ()),
-					int.Min (SuperView.Bounds.Height - GetFramesThickness ().Vertical, CalcBestLength ())));
+				new Size (int.Min (SuperView.Bounds.Width - GetAdornmentsThickness ().Horizontal, CalcThickness ()),
+					int.Min (SuperView.Bounds.Height - GetAdornmentsThickness ().Vertical, CalcBestLength ())));
 		}
 	}
 

+ 1 - 1
Terminal.Gui/Views/TileView.cs

@@ -301,7 +301,7 @@ namespace Terminal.Gui {
 		/// Overridden so no Frames get drawn (BUGBUG: v2 fix this hack)
 		/// </summary>
 		/// <returns></returns>
-		public override bool OnDrawFrames ()
+		public override bool OnDrawAdornments ()
 		{
 			return false;
 		}

+ 3 - 3
Terminal.Gui/Views/Toplevel.cs

@@ -560,7 +560,7 @@ public partial class Toplevel : View {
 			superView = top.SuperView;
 		}
 		if (superView.Margin != null && superView == top.SuperView) {
-			maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
+			maxWidth -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
 		}
 		if (top.Frame.Width <= maxWidth) {
 			nx = Math.Max (targetX, 0);
@@ -607,7 +607,7 @@ public partial class Toplevel : View {
 			maxWidth = statusVisible ? top.SuperView.Frame.Height - 1 : top.SuperView.Frame.Height;
 		}
 		if (superView.Margin != null && superView == top.SuperView) {
-			maxWidth -= superView.GetFramesThickness ().Top + superView.GetFramesThickness ().Bottom;
+			maxWidth -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
 		}
 		ny = Math.Min (ny, maxWidth);
 		if (top.Frame.Height <= maxWidth) {
@@ -644,7 +644,7 @@ public partial class Toplevel : View {
 		bool layoutSubviews = false;
 		int maxWidth = 0;
 		if (superView.Margin != null && superView == top.SuperView) {
-			maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
+			maxWidth -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
 		}
 		if ((superView != top || top?.SuperView != null || top != Application.Top && top.Modal || top?.SuperView == null && top.IsOverlapped)
 		    // BUGBUG: Prevously PositionToplevel required LayotuStyle.Computed

+ 4 - 0
UICatalog/Properties/launchSettings.json

@@ -69,6 +69,10 @@
     "ListView & ComboBox": {
       "commandName": "Project",
       "commandLineArgs": "\"ListView & ComboBox\""
+    },
+    "Frames Demo": {
+      "commandName": "Project",
+      "commandLineArgs": "\"Frames Demo\""
     }
   }
 }

+ 441 - 0
UICatalog/Scenarios/Adornments.cs

@@ -0,0 +1,441 @@
+using System;
+using System.Linq;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("Adornments Demo", "Demonstrates Margin, Border, and Padding on Views.")]
+[ScenarioCategory ("Layout")]
+[ScenarioCategory ("Borders")]
+public class Adornments : Scenario {
+
+	public override void Init ()
+	{
+		Application.Init ();
+		ConfigurationManager.Themes.Theme = Theme;
+		ConfigurationManager.Apply ();
+		Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+
+		var view = new Window { Title = "The Window" };
+		var tf1 = new TextField ("TextField") { Width = 10 };
+		var color = new ColorPicker () { Title = "BG", BoxHeight = 1, BoxWidth =1, X = Pos.AnchorEnd(11) };
+		color.BorderStyle = LineStyle.RoundedDotted;
+		color.ColorChanged += (s, e) => {
+			color.SuperView.ColorScheme = new ColorScheme (color.SuperView.ColorScheme) {
+				Normal = new Attribute(color.SuperView.ColorScheme.Normal.Foreground, e.Color)
+			};
+		};
+
+		var button = new Button ("Press me!") {
+			X = Pos.Center (),
+			Y = Pos.Center ()
+		};
+		button.Clicked += (s, e) => MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
+
+		var label = new TextView () {
+			X = Pos.Center (),
+			Y = Pos.Bottom (button),
+			Title = "Title",
+			Text = "I have a 3 row top border.\nMy border inherits from the SuperView.",
+			Width = 40,
+			Height = 6 // TODO: Use Dim.Auto
+		};
+		label.Border.Thickness = new Thickness (1, 3, 1, 1);
+
+		var tf2 = new Button ("Button") {
+			X = Pos.AnchorEnd (10),
+			Y = Pos.AnchorEnd (1),
+			Width = 10
+		};
+		var tv = new Label {
+			Y = Pos.AnchorEnd (3),
+			Width = 25,
+			Height = Dim.Fill (),
+			Text = "Label\nY=AnchorEnd(3),Height=Dim.Fill()"
+		};
+
+		view.Margin.Data = "Margin";
+		view.Margin.Thickness = new Thickness (3);
+
+		view.Border.Data = "Border";
+		view.Border.Thickness = new Thickness (3);
+
+		view.Padding.Data = "Padding";
+		view.Padding.Thickness = new Thickness (3);
+
+		view.Add (tf1, color, button, label, tf2, tv);
+
+		var editor = new AdornmentsEditor {
+			Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
+			ColorScheme = Colors.ColorSchemes [TopLevelColorScheme],
+		};
+		view.X = 36;
+		view.Y = 0;
+		view.Width = Dim.Fill ();
+		view.Height = Dim.Fill ();
+
+		editor.Initialized += (s, e) => {
+			editor.ViewToEdit = view;
+		};
+		//view.Margin.ColorScheme = new ColorScheme (Colors.Dialog);
+		//view.Border.ColorScheme = new ColorScheme (Colors.Error);
+		//view.Padding.ColorScheme = new ColorScheme (Colors.Menu);
+
+		Application.Run (editor);
+		Application.Shutdown ();
+	}
+
+	public override void Run () { }
+
+	public class AdornmentEditor : View {
+		readonly ColorPicker _backgroundColorPicker = new () {
+			Title = "BG",
+			BoxWidth = 1,
+			BoxHeight = 1,
+			BorderStyle = LineStyle.Single,
+			SuperViewRendersLineCanvas = true
+		};
+
+		readonly ColorPicker _foregroundColorPicker = new () {
+			Title = "FG",
+			BoxWidth = 1,
+			BoxHeight = 1,
+			BorderStyle = LineStyle.Single,
+			SuperViewRendersLineCanvas = true
+		};
+
+		TextField _bottomEdit;
+		bool _isUpdating;
+		TextField _leftEdit;
+		TextField _rightEdit;
+		Thickness _thickness;
+		TextField _topEdit;
+
+		public AdornmentEditor ()
+		{
+			Margin.Thickness = new Thickness (0);
+			BorderStyle = LineStyle.Double;
+			Initialized += AdornmentEditor_Initialized;
+		}
+
+		public Attribute Color {
+			get => new (_foregroundColorPicker.SelectedColor, _backgroundColorPicker.SelectedColor);
+			set {
+				_foregroundColorPicker.SelectedColor = value.Foreground.ColorName;
+				_backgroundColorPicker.SelectedColor = value.Background.ColorName;
+			}
+		}
+
+		public Thickness Thickness {
+			get => _thickness;
+			set {
+				if (_isUpdating) {
+					return;
+				}
+				_thickness = value;
+				ThicknessChanged?.Invoke (this, new ThicknessEventArgs { Thickness = Thickness });
+				if (IsInitialized) {
+					_isUpdating = true;
+					if (_topEdit.Text != _thickness.Top.ToString ()) {
+						_topEdit.Text = _thickness.Top.ToString ();
+					}
+					if (_leftEdit.Text != _thickness.Left.ToString ()) {
+						_leftEdit.Text = _thickness.Left.ToString ();
+					}
+					if (_rightEdit.Text != _thickness.Right.ToString ()) {
+						_rightEdit.Text = _thickness.Right.ToString ();
+					}
+					if (_bottomEdit.Text != _thickness.Bottom.ToString ()) {
+						_bottomEdit.Text = _thickness.Bottom.ToString ();
+					}
+					_isUpdating = false;
+				}
+			}
+		}
+
+		public event EventHandler<ThicknessEventArgs> ThicknessChanged;
+
+		public event EventHandler<Attribute> AttributeChanged;
+
+		void AdornmentEditor_Initialized (object sender, EventArgs e)
+		{
+			var editWidth = 3;
+
+			_topEdit = new TextField ("") {
+				X = Pos.Center (),
+				Y = 0,
+				Width = editWidth
+			};
+			_topEdit.TextChanging += Edit_TextChanging;
+			Add (_topEdit);
+
+			_leftEdit = new TextField ("") {
+				X = Pos.Left (_topEdit) - editWidth,
+				Y = Pos.Bottom (_topEdit),
+				Width = editWidth
+			};
+			_leftEdit.TextChanging += Edit_TextChanging;
+			Add (_leftEdit);
+
+			_rightEdit = new TextField ("") {
+				X = Pos.Right (_topEdit),
+				Y = Pos.Bottom (_topEdit),
+				Width = editWidth
+			};
+			_rightEdit.TextChanging += Edit_TextChanging;
+			Add (_rightEdit);
+
+			_bottomEdit = new TextField ("") {
+				X = Pos.Center (),
+				Y = Pos.Bottom (_leftEdit),
+				Width = editWidth
+			};
+			_bottomEdit.TextChanging += Edit_TextChanging;
+			Add (_bottomEdit);
+
+			var copyTop = new Button ("Copy Top") {
+				X = Pos.Center () + 1,
+				Y = Pos.Bottom (_bottomEdit)
+			};
+			copyTop.Clicked += (s, e) => {
+				Thickness = new Thickness (Thickness.Top);
+				if (string.IsNullOrEmpty (_topEdit.Text)) {
+					_topEdit.Text = "0";
+				}
+				_bottomEdit.Text = _leftEdit.Text = _rightEdit.Text = _topEdit.Text;
+			};
+			Add (copyTop);
+
+			// Foreground ColorPicker.
+			_foregroundColorPicker.X = -1;
+			_foregroundColorPicker.Y = Pos.Bottom (copyTop) + 1;
+			_foregroundColorPicker.SelectedColor = Color.Foreground.ColorName;
+			_foregroundColorPicker.ColorChanged += (o, a) =>
+				AttributeChanged?.Invoke (this,
+					new Attribute (_foregroundColorPicker.SelectedColor, _backgroundColorPicker.SelectedColor));
+			Add (_foregroundColorPicker);
+
+			// Background ColorPicker.
+			_backgroundColorPicker.X = Pos.Right (_foregroundColorPicker) - 1;
+			_backgroundColorPicker.Y = Pos.Top (_foregroundColorPicker);
+			_backgroundColorPicker.SelectedColor = Color.Background.ColorName;
+			_backgroundColorPicker.ColorChanged += (o, a) =>
+				AttributeChanged?.Invoke (this,
+					new Attribute (
+						_foregroundColorPicker.SelectedColor,
+						_backgroundColorPicker.SelectedColor));
+			Add (_backgroundColorPicker);
+
+			_topEdit.Text = $"{Thickness.Top}";
+			_leftEdit.Text = $"{Thickness.Left}";
+			_rightEdit.Text = $"{Thickness.Right}";
+			_bottomEdit.Text = $"{Thickness.Bottom}";
+
+			LayoutSubviews ();
+			Height = GetAdornmentsThickness ().Vertical + 4 + 4;
+			Width = GetAdornmentsThickness ().Horizontal + _foregroundColorPicker.Frame.Width * 2 - 3;
+		}
+
+		void Edit_TextChanging (object sender, TextChangingEventArgs e)
+		{
+			try {
+				if (string.IsNullOrEmpty (e.NewText)) {
+					e.Cancel = true;
+					((TextField)sender).Text = "0";
+					return;
+				}
+				switch (sender.ToString ()) {
+				case var s when s == _topEdit.ToString ():
+					Thickness = new Thickness (Thickness.Left,
+						int.Parse (e.NewText), Thickness.Right,
+						Thickness.Bottom);
+					break;
+				case var s when s == _leftEdit.ToString ():
+					Thickness = new Thickness (int.Parse (e.NewText),
+						Thickness.Top, Thickness.Right,
+						Thickness.Bottom);
+					break;
+				case var s when s == _rightEdit.ToString ():
+					Thickness = new Thickness (Thickness.Left,
+						Thickness.Top, int.Parse (e.NewText),
+						Thickness.Bottom);
+					break;
+				case var s when s == _bottomEdit.ToString ():
+					Thickness = new Thickness (Thickness.Left,
+						Thickness.Top, Thickness.Right,
+						int.Parse (e.NewText));
+					break;
+				}
+			} catch {
+				if (!string.IsNullOrEmpty (e.NewText)) {
+					e.Cancel = true;
+				}
+			}
+		}
+	}
+
+	public class AdornmentsEditor : Window {
+		AdornmentEditor _borderEditor;
+		CheckBox _diagCheckBox;
+		AdornmentEditor _marginEditor;
+		String _origTitle = string.Empty;
+		AdornmentEditor _paddingEditor;
+		View _viewToEdit;
+
+		public View ViewToEdit {
+			get => _viewToEdit;
+			set {
+				_origTitle = value.Title;
+				_viewToEdit = value;
+
+				_marginEditor = new AdornmentEditor {
+					X = 0,
+					Y = 0,
+					Title = "Margin",
+					Thickness = _viewToEdit.Margin.Thickness,
+					Color = new Attribute (_viewToEdit.Margin.ColorScheme.Normal),
+					SuperViewRendersLineCanvas = true
+				};
+				_marginEditor.ThicknessChanged += Editor_ThicknessChanged;
+				_marginEditor.AttributeChanged += Editor_AttributeChanged;
+				Add (_marginEditor);
+
+				_borderEditor = new AdornmentEditor {
+					X = Pos.Left (_marginEditor),
+					Y = Pos.Bottom (_marginEditor),
+					Title = "Border",
+					Thickness = _viewToEdit.Border.Thickness,
+					Color = new Attribute (_viewToEdit.Border.ColorScheme.Normal),
+					SuperViewRendersLineCanvas = true
+				};
+				_borderEditor.ThicknessChanged += Editor_ThicknessChanged;
+				_borderEditor.AttributeChanged += Editor_AttributeChanged;
+				Add (_borderEditor);
+
+
+				var borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast<LineStyle> ().ToList ();
+				var rbBorderStyle = new RadioGroup (borderStyleEnum.Select (
+					e => e.ToString ()).ToArray ()) {
+
+					X = Pos.Right (_borderEditor) - 1,
+					Y = Pos.Top (_borderEditor),
+					SelectedItem = (int)_viewToEdit.Border.LineStyle,
+					BorderStyle = LineStyle.Double,
+					Title = "Border Style",
+					SuperViewRendersLineCanvas = true
+				};
+				Add (rbBorderStyle);
+
+				rbBorderStyle.SelectedItemChanged += (s, e) => {
+					var prevBorderStyle = _viewToEdit.BorderStyle;
+					_viewToEdit.Border.LineStyle = (LineStyle)e.SelectedItem;
+					if (_viewToEdit.Border.LineStyle == LineStyle.None) {
+						_viewToEdit.Border.Thickness = new Thickness (0);
+					} else if (prevBorderStyle == LineStyle.None && _viewToEdit.Border.LineStyle != LineStyle.None) {
+						_viewToEdit.Border.Thickness = new Thickness (1);
+					}
+					_borderEditor.Thickness = new Thickness (_viewToEdit.Border.Thickness.Left, _viewToEdit.Border.Thickness.Top,
+						_viewToEdit.Border.Thickness.Right, _viewToEdit.Border.Thickness.Bottom);
+					_viewToEdit.SetNeedsDisplay ();
+					LayoutSubviews ();
+				};
+
+				var ckbTitle = new CheckBox ("Show Title") {
+					BorderStyle = LineStyle.Double,
+					X = Pos.Left (_borderEditor),
+					Y = Pos.Bottom (_borderEditor) - 1,
+					Width = Dim.Width (_borderEditor),
+					Checked = true,
+					SuperViewRendersLineCanvas = true
+				};
+				ckbTitle.Toggled += (sender, args) => {
+					if (ckbTitle.Checked == true) {
+						_viewToEdit.Title = _origTitle;
+					} else {
+						_viewToEdit.Title = string.Empty;
+					}
+				};
+				Add (ckbTitle);
+
+				_paddingEditor = new AdornmentEditor {
+					X = Pos.Left (_borderEditor),
+					Y = Pos.Bottom (rbBorderStyle),
+					Title = "Padding",
+					Thickness = _viewToEdit.Padding.Thickness,
+					Color = new Attribute (_viewToEdit.Padding.ColorScheme.Normal),
+					SuperViewRendersLineCanvas = true
+				};
+				_paddingEditor.ThicknessChanged += Editor_ThicknessChanged;
+				_paddingEditor.AttributeChanged += Editor_AttributeChanged;
+				Add (_paddingEditor);
+
+				_diagCheckBox = new CheckBox {
+					Text = "Diagnostics",
+					Y = Pos.Bottom (_paddingEditor)
+				};
+				_diagCheckBox.Toggled += (s, e) => {
+					if (e.NewValue == true) {
+						ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.FramePadding | ConsoleDriver.DiagnosticFlags.FrameRuler;
+					} else {
+						ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+					}
+				};
+
+				Add (_diagCheckBox);
+				Add (_viewToEdit);
+
+				_viewToEdit.LayoutComplete += (s, e) => {
+					if (ckbTitle.Checked == true) {
+						_viewToEdit.Title = _origTitle;
+					} else {
+						_viewToEdit.Title = string.Empty;
+					}
+				};
+			}
+		}
+
+		void Editor_AttributeChanged (object sender, Attribute attr)
+		{
+			switch (sender.ToString ()) {
+			case var s when s == _marginEditor.ToString ():
+				_viewToEdit.Margin.ColorScheme = new ColorScheme (_viewToEdit.Margin.ColorScheme) { Normal = attr };
+				break;
+			case var s when s == _borderEditor.ToString ():
+				_viewToEdit.Border.ColorScheme = new ColorScheme (_viewToEdit.Border.ColorScheme) { Normal = attr };
+				break;
+			case var s when s == _paddingEditor.ToString ():
+				_viewToEdit.Padding.ColorScheme = new ColorScheme (_viewToEdit.Padding.ColorScheme) { Normal = attr };
+				break;
+			}
+		}
+
+		void Editor_ThicknessChanged (object sender, ThicknessEventArgs e)
+		{
+			try {
+				switch (sender.ToString ()) {
+				case var s when s == _marginEditor.ToString ():
+					_viewToEdit.Margin.Thickness = e.Thickness;
+					break;
+				case var s when s == _borderEditor.ToString ():
+					_viewToEdit.Border.Thickness = e.Thickness;
+					break;
+				case var s when s == _paddingEditor.ToString ():
+					_viewToEdit.Padding.Thickness = e.Thickness;
+					break;
+				}
+			} catch {
+				switch (sender.ToString ()) {
+				case var s when s == _marginEditor.ToString ():
+					_viewToEdit.Margin.Thickness = e.PreviousThickness;
+					break;
+				case var s when s == _borderEditor.ToString ():
+					_viewToEdit.Border.Thickness = e.PreviousThickness;
+					break;
+				case var s when s == _paddingEditor.ToString ():
+					_viewToEdit.Padding.Thickness = e.PreviousThickness;
+					break;
+				}
+			}
+		}
+	}
+}

+ 0 - 1
UICatalog/Scenarios/DatePickers.cs

@@ -1,5 +1,4 @@
 using Terminal.Gui;
-using Terminal.Gui.Views;
 
 namespace UICatalog.Scenarios;
 [ScenarioMetadata (Name: "Date Picker", Description: "Demonstrates how to use DatePicker class")]

+ 0 - 399
UICatalog/Scenarios/Frames.cs

@@ -1,399 +0,0 @@
-using System;
-using System.Linq;
-using Terminal.Gui;
-
-namespace UICatalog.Scenarios {
-	[ScenarioMetadata (Name: "Frames Demo", Description: "Demonstrates Margin, Border, and Padding on Views.")]
-	[ScenarioCategory ("Layout")]
-	[ScenarioCategory ("Borders")]
-	public class Frames : Scenario {
-		public class FrameEditor : View {
-			private Thickness _thickness;
-			private TextField _topEdit;
-			private TextField _leftEdit;
-			private TextField _rightEdit;
-			private TextField _bottomEdit;
-			private bool _isUpdating;
-
-			private ColorPicker _foregroundColorPicker;
-			private ColorPicker _backgroundColorPicker;
-
-			public Terminal.Gui.Attribute Color { get; set; }
-
-			public Thickness Thickness {
-				get => _thickness;
-				set {
-					if (_isUpdating) {
-						return;
-					}
-					_thickness = value;
-					ThicknessChanged?.Invoke (this, new ThicknessEventArgs () { Thickness = Thickness });
-					if (IsInitialized) {
-						_isUpdating = true;
-						if (_topEdit.Text != _thickness.Top.ToString ()) {
-							_topEdit.Text = _thickness.Top.ToString ();
-						}
-						if (_leftEdit.Text != _thickness.Left.ToString ()) {
-							_leftEdit.Text = _thickness.Left.ToString ();
-						}
-						if (_rightEdit.Text != _thickness.Right.ToString ()) {
-							_rightEdit.Text = _thickness.Right.ToString ();
-						}
-						if (_bottomEdit.Text != _thickness.Bottom.ToString ()) {
-							_bottomEdit.Text = _thickness.Bottom.ToString ();
-						}
-						_isUpdating = false;
-					}
-				}
-			}
-
-			public event EventHandler<ThicknessEventArgs> ThicknessChanged;
-			public event EventHandler<Terminal.Gui.Attribute> AttributeChanged;
-
-			public FrameEditor ()
-			{
-				Margin.Thickness = new Thickness (0);
-				BorderStyle = LineStyle.Double;
-				Initialized += FrameEditor_Initialized; ;
-			}
-
-			void FrameEditor_Initialized (object sender, EventArgs e)
-			{
-				var editWidth = 3;
-
-				_topEdit = new TextField ("") {
-					X = Pos.Center (),
-					Y = 0,
-					Width = editWidth
-				};
-				_topEdit.TextChanging += Edit_TextChanging;
-				Add (_topEdit);
-
-				_leftEdit = new TextField ("") {
-					X = Pos.Left (_topEdit) - editWidth,
-					Y = Pos.Bottom (_topEdit),
-					Width = editWidth
-				};
-				_leftEdit.TextChanging += Edit_TextChanging;
-				Add (_leftEdit);
-
-				_rightEdit = new TextField ("") {
-					X = Pos.Right (_topEdit),
-					Y = Pos.Bottom (_topEdit),
-					Width = editWidth
-				};
-				_rightEdit.TextChanging += Edit_TextChanging;
-				Add (_rightEdit);
-
-				_bottomEdit = new TextField ("") {
-					X = Pos.Center (),
-					Y = Pos.Bottom (_leftEdit),
-					Width = editWidth
-				};
-				_bottomEdit.TextChanging += Edit_TextChanging;
-				Add (_bottomEdit);
-
-				var copyTop = new Button ("Copy Top") {
-					X = Pos.Center () + 1,
-					Y = Pos.Bottom (_bottomEdit)
-				};
-				copyTop.Clicked += (s, e) => {
-					Thickness = new Thickness (Thickness.Top);
-					if (string.IsNullOrEmpty (_topEdit.Text)) {
-						_topEdit.Text = "0";
-					}
-					_bottomEdit.Text = _leftEdit.Text = _rightEdit.Text = _topEdit.Text;
-				};
-				Add (copyTop);
-
-				// Foreground ColorPicker.
-				_foregroundColorPicker = new ColorPicker () {
-					Title = "FG",
-					BoxWidth = 1,
-					BoxHeight = 1,
-					X = -1,
-					Y = Pos.Bottom (copyTop) + 1,
-					BorderStyle = LineStyle.Single,
-					SuperViewRendersLineCanvas = true
-				};
-				_foregroundColorPicker.ColorChanged += (o, a) =>
-					AttributeChanged?.Invoke (this,
-						new Attribute (_foregroundColorPicker.SelectedColor, _backgroundColorPicker.SelectedColor));
-				Add (_foregroundColorPicker);
-
-				// Background ColorPicker.
-				_backgroundColorPicker = new ColorPicker () {
-					Title = "BG",
-					BoxWidth = 1,
-					BoxHeight = 1,
-					X = Pos.Right (_foregroundColorPicker) - 1,
-					Y = Pos.Top (_foregroundColorPicker),
-					BorderStyle = LineStyle.Single,
-					SuperViewRendersLineCanvas = true
-				};
-
-				_backgroundColorPicker.ColorChanged += (o, a) =>
-					AttributeChanged?.Invoke (this,
-						new Terminal.Gui.Attribute (
-							_foregroundColorPicker.SelectedColor,
-							_backgroundColorPicker.SelectedColor));
-				Add (_backgroundColorPicker);
-
-				_topEdit.Text = $"{Thickness.Top}";
-				_leftEdit.Text = $"{Thickness.Left}";
-				_rightEdit.Text = $"{Thickness.Right}";
-				_bottomEdit.Text = $"{Thickness.Bottom}";
-
-				LayoutSubviews ();
-				Height = GetFramesThickness ().Vertical + 4 + 4;
-				Width = GetFramesThickness ().Horizontal + _foregroundColorPicker.Frame.Width * 2 - 3;
-			}
-
-			private void Edit_TextChanging (object sender, TextChangingEventArgs e)
-			{
-				try {
-					if (string.IsNullOrEmpty (e.NewText.ToString ())) {
-						e.Cancel = true;
-						((TextField)sender).Text = "0";
-						return;
-					}
-					switch (sender.ToString ()) {
-					case var s when s == _topEdit.ToString ():
-						Thickness = new Thickness (Thickness.Left,
-							int.Parse (e.NewText), Thickness.Right,
-							Thickness.Bottom);
-						break;
-					case var s when s == _leftEdit.ToString ():
-						Thickness = new Thickness (int.Parse (e.NewText),
-							Thickness.Top, Thickness.Right,
-							Thickness.Bottom);
-						break;
-					case var s when s == _rightEdit.ToString ():
-						Thickness = new Thickness (Thickness.Left,
-							Thickness.Top, int.Parse (e.NewText),
-							Thickness.Bottom);
-						break;
-					case var s when s == _bottomEdit.ToString ():
-						Thickness = new Thickness (Thickness.Left,
-							Thickness.Top, Thickness.Right,
-							int.Parse (e.NewText));
-						break;
-					}
-				} catch {
-					if (!string.IsNullOrEmpty (e.NewText)) {
-						e.Cancel = true;
-					}
-				}
-			}
-		}
-
-		public class FramesEditor : Window {
-			private View _viewToEdit;
-			private FrameEditor _marginEditor;
-			private FrameEditor _borderEditor;
-			private FrameEditor _paddingEditor;
-			private String _origTitle = string.Empty;
-
-			public FramesEditor ()
-			{
-			}
-
-			public View ViewToEdit {
-				get {
-					return _viewToEdit;
-				}
-				set {
-					_origTitle = value.Title;
-					_viewToEdit = value;
-
-					_viewToEdit.Margin.ColorScheme = new ColorScheme (Colors.ColorSchemes ["Toplevel"]);
-					_marginEditor = new FrameEditor () {
-						X = 0,
-						Y = 0,
-						Title = "Margin",
-						Thickness = _viewToEdit.Margin.Thickness,
-						SuperViewRendersLineCanvas = true
-					};
-					_marginEditor.ThicknessChanged += Editor_ThicknessChanged;
-					_marginEditor.AttributeChanged += Editor_AttributeChanged;
-					Add (_marginEditor);
-
-					_viewToEdit.Border.ColorScheme = new ColorScheme (Colors.ColorSchemes ["Base"]);
-					_borderEditor = new FrameEditor () {
-						X = Pos.Left (_marginEditor),
-						Y = Pos.Bottom (_marginEditor),
-						Title = "Border",
-						Thickness = _viewToEdit.Border.Thickness,
-						SuperViewRendersLineCanvas = true
-					};
-					_borderEditor.ThicknessChanged += Editor_ThicknessChanged;
-					_borderEditor.AttributeChanged += Editor_AttributeChanged;
-					Add (_borderEditor);
-
-					_viewToEdit.Padding.ColorScheme = new ColorScheme (Colors.ColorSchemes ["Error"]);
-
-					var borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast<LineStyle> ().ToList ();
-					var rbBorderStyle = new RadioGroup (borderStyleEnum.Select (
-						e => e.ToString ()).ToArray ()) {
-
-						X = Pos.Right (_borderEditor) - 1,
-						Y = Pos.Top (_borderEditor),
-						SelectedItem = (int)_viewToEdit.Border.BorderStyle,
-						BorderStyle = LineStyle.Double,
-						Title = "Border Style",
-						SuperViewRendersLineCanvas = true
-					};
-					Add (rbBorderStyle);
-
-					rbBorderStyle.SelectedItemChanged += (s, e) => {
-						var prevBorderStyle = _viewToEdit.BorderStyle;
-						_viewToEdit.Border.BorderStyle = (LineStyle)e.SelectedItem;
-						if (_viewToEdit.Border.BorderStyle == LineStyle.None) {
-							_viewToEdit.Border.Thickness = new Thickness (0);
-						} else if (prevBorderStyle == LineStyle.None && _viewToEdit.Border.BorderStyle != LineStyle.None) {
-							_viewToEdit.Border.Thickness = new Thickness (1);
-						}
-						_borderEditor.Thickness = new Thickness (_viewToEdit.Border.Thickness.Left, _viewToEdit.Border.Thickness.Top,
-							_viewToEdit.Border.Thickness.Right, _viewToEdit.Border.Thickness.Bottom);
-						_viewToEdit.SetNeedsDisplay ();
-						LayoutSubviews ();
-					};
-
-					var ckbTitle = new CheckBox ("Show Title") {
-						BorderStyle = LineStyle.Double,
-						X = Pos.Left (_borderEditor),
-						Y = Pos.Bottom (_borderEditor) - 1,
-						Width = Dim.Width (_borderEditor),
-						Checked = true,
-						SuperViewRendersLineCanvas = true
-					};
-					ckbTitle.Toggled += (sender, args) => {
-						if (ckbTitle.Checked == true) {
-							_viewToEdit.Title = _origTitle;
-						} else {
-							_viewToEdit.Title = string.Empty;
-						}
-					};
-					Add (ckbTitle);
-
-					_paddingEditor = new FrameEditor () {
-						X = Pos.Left (_borderEditor),
-						Y = Pos.Bottom (rbBorderStyle),
-						Title = "Padding",
-						Thickness = _viewToEdit.Padding.Thickness,
-						SuperViewRendersLineCanvas = true
-					};
-					_paddingEditor.ThicknessChanged += Editor_ThicknessChanged;
-					_paddingEditor.AttributeChanged += Editor_AttributeChanged;
-					Add (_paddingEditor);
-					Add (_viewToEdit);
-
-					_viewToEdit.LayoutComplete += (s, e) => {
-						if (ckbTitle.Checked == true) {
-							_viewToEdit.Title = _origTitle;
-						} else {
-							_viewToEdit.Title = string.Empty;
-						}
-					};
-				}
-			}
-
-			private void Editor_AttributeChanged (object sender, Terminal.Gui.Attribute attr)
-			{
-				switch (sender.ToString ()) {
-				case var s when s == _marginEditor.ToString ():
-					_viewToEdit.Margin.ColorScheme = new ColorScheme (_viewToEdit.Margin.ColorScheme) { Normal = attr };
-					break;
-				case var s when s == _borderEditor.ToString ():
-					_viewToEdit.Border.ColorScheme = new ColorScheme (_viewToEdit.Border.ColorScheme) { Normal = attr };
-					break;
-				case var s when s == _paddingEditor.ToString ():
-					_viewToEdit.Padding.ColorScheme = new ColorScheme (_viewToEdit.Padding.ColorScheme) { Normal = attr };
-					break;
-				}
-			}
-
-			private void Editor_ThicknessChanged (object sender, ThicknessEventArgs e)
-			{
-				try {
-					switch (sender.ToString ()) {
-					case var s when s == _marginEditor.ToString ():
-						_viewToEdit.Margin.Thickness = e.Thickness;
-						break;
-					case var s when s == _borderEditor.ToString ():
-						_viewToEdit.Border.Thickness = e.Thickness;
-						break;
-					case var s when s == _paddingEditor.ToString ():
-						_viewToEdit.Padding.Thickness = e.Thickness;
-						break;
-					}
-				} catch {
-					switch (sender.ToString ()) {
-					case var s when s == _marginEditor.ToString ():
-						_viewToEdit.Margin.Thickness = e.PreviousThickness;
-						break;
-					case var s when s == _borderEditor.ToString ():
-						_viewToEdit.Border.Thickness = e.PreviousThickness;
-						break;
-					case var s when s == _paddingEditor.ToString ():
-						_viewToEdit.Padding.Thickness = e.PreviousThickness;
-						break;
-					}
-				}
-			}
-		}
-
-		public override void Init ()
-		{
-			Application.Init ();
-			ConfigurationManager.Themes.Theme = Theme;
-			ConfigurationManager.Apply ();
-			Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
-
-			var view = new Window ();
-			var tf1 = new TextField ("TextField") { Width = 10 };
-
-			var button = new Button ("Press me!") {
-				X = Pos.Center (),
-				Y = Pos.Center (),
-			};
-			button.Clicked += (s, e) => MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
-			var label = new Label ($"I'm a {view.GetType ().Name}") {
-				X = Pos.Center (),
-				Y = Pos.Center () - 1,
-			};
-			var tf2 = new Button ("Button") {
-				X = Pos.AnchorEnd (10),
-				Y = Pos.AnchorEnd (1),
-				Width = 10
-			};
-			var tv = new Label () {
-				Y = Pos.AnchorEnd (2),
-				Width = 25,
-				Height = Dim.Fill (),
-				Text = "Label\nY=AnchorEnd(2),Height=Dim.Fill()"
-			};
-
-			view.Margin.Thickness = new Thickness (3);
-			view.Padding.Thickness = new Thickness (1);
-
-			view.Add (tf1, button, label, tf2, tv);
-
-			var editor = new FramesEditor () {
-				Title =$"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
-				ViewToEdit = view
-			};
-			view.X = 36;
-			view.Y = 0;
-			view.Width = Dim.Fill ();
-			view.Height = Dim.Fill ();
-
-			Application.Run (editor);
-			Application.Shutdown ();
-		}
-
-		public override void Run ()
-		{
-		}
-	}
-}

+ 2 - 2
UICatalog/Scenarios/LineDrawing.cs

@@ -55,8 +55,8 @@ namespace UICatalog.Scenarios {
 			private void ToolsView_Initialized (object sender, EventArgs e)
 			{
 				LayoutSubviews ();
-				Width = Math.Max (_colorPicker.Frame.Width, _stylePicker.Frame.Width) + GetFramesThickness ().Horizontal;
-				Height = _colorPicker.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetFramesThickness ().Vertical;
+				Width = Math.Max (_colorPicker.Frame.Width, _stylePicker.Frame.Width) + GetAdornmentsThickness ().Horizontal;
+				Height = _colorPicker.Frame.Height + _stylePicker.Frame.Height + _addLayerBtn.Frame.Height + GetAdornmentsThickness ().Vertical;
 				SuperView.LayoutSubviews ();
 			}
 

+ 2 - 2
UICatalog/Scenarios/ProgressBarStyles.cs

@@ -2,7 +2,7 @@
 using System.Linq;
 using System.Threading;
 using Terminal.Gui;
-using static UICatalog.Scenarios.Frames;
+using static UICatalog.Scenarios.Adornments;
 
 namespace UICatalog.Scenarios;
 
@@ -25,7 +25,7 @@ public class ProgressBarStyles : Scenario {
 		ConfigurationManager.Themes.Theme = Theme;
 		ConfigurationManager.Apply ();
 
-		var editor = new FramesEditor {
+		var editor = new AdornmentsEditor {
 			Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
 			BorderStyle = LineStyle.Single
 		};

+ 14 - 19
UICatalog/Scenarios/ViewExperiments.cs

@@ -41,7 +41,7 @@ namespace UICatalog.Scenarios {
 			view.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
 			view.Margin.Data = "Margin";
 			view.Border.Thickness = new Thickness (3);
-			view.Border.BorderStyle = LineStyle.Single;
+			view.Border.LineStyle = LineStyle.Single;
 			view.Border.ColorScheme = view.ColorScheme;
 			view.Border.Data = "Border";
 			view.Padding.Thickness = new Thickness (2);
@@ -62,7 +62,7 @@ namespace UICatalog.Scenarios {
 			window1.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
 			window1.Margin.Data = "Margin";
 			window1.Border.Thickness = new Thickness (1);
-			window1.Border.BorderStyle = LineStyle.Single;
+			window1.Border.LineStyle = LineStyle.Single;
 			window1.Border.ColorScheme = view.ColorScheme;
 			window1.Border.Data = "Border";
 			window1.Padding.Thickness = new Thickness (0);
@@ -86,7 +86,7 @@ namespace UICatalog.Scenarios {
 			window2.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
 			window2.Margin.Data = "Margin";
 			window2.Border.Thickness = new Thickness (1, 1, 1, 1);
-			window2.Border.BorderStyle = LineStyle.Single;
+			window2.Border.LineStyle = LineStyle.Single;
 			window2.Border.ColorScheme = view.ColorScheme;
 			window2.Border.Data = "Border";
 			window2.Padding.Thickness = new Thickness (1, 1, 0, 0);
@@ -110,7 +110,7 @@ namespace UICatalog.Scenarios {
 			view4.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
 			view4.Margin.Data = "Margin";
 			view4.Border.Thickness = new Thickness (1, 1, 1, 1);
-			view4.Border.BorderStyle = LineStyle.Single;
+			view4.Border.LineStyle = LineStyle.Single;
 			view4.Border.ColorScheme = view.ColorScheme;
 			view4.Border.Data = "Border";
 			view4.Padding.Thickness = new Thickness (0, 0, 1, 1);
@@ -133,7 +133,7 @@ namespace UICatalog.Scenarios {
 			view5.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
 			view5.Margin.Data = "Margin";
 			view5.Border.Thickness = new Thickness (1, 1, 1, 1);
-			view5.Border.BorderStyle = LineStyle.Single;
+			view5.Border.LineStyle = LineStyle.Single;
 			view5.Border.ColorScheme = view.ColorScheme;
 			view5.Border.Data = "Border";
 			view5.Padding.Thickness = new Thickness (0, 0, 0, 0);
@@ -169,23 +169,18 @@ namespace UICatalog.Scenarios {
 			};
 			view.Add (edit);
 
-			edit = new TextField () {
+			var label50 = new View () {
+				Title = "Border Inherit Demo",
 				Text = "Center();50%",
 				X = Pos.Center (),
 				Y = Pos.Percent (50),
 				Width = 30,
-				Height = 1
+				TextAlignment = TextAlignment.Centered,
+				//Height = 1
 			};
-			view.Add (edit);
-
-			edit = new TextField () {
-				Text = "Center() - 1;60%",
-				X = Pos.Center () - 1,
-				Y = Pos.Percent (60),
-				Width = 30,
-				Height = 1
-			};
-			view.Add (edit);
+			label50.Border.Thickness = new Thickness (1, 3, 1, 1);
+			label50.Height = 5;
+			view.Add (label50);
 
 			edit = new TextField () {
 				Text = "0 + Percent(50);70%",
@@ -220,8 +215,8 @@ namespace UICatalog.Scenarios {
 
 			view.X = Pos.Center ();
 
-			var editor = new Frames.FramesEditor () {
-				Title = $"Frames Editor",
+			var editor = new Adornments.AdornmentsEditor () {
+				Title = $"Adornments Editor",
 				X = 0,
 				Y = Pos.Bottom (containerLabel),
 				Width = Dim.Fill (),

+ 2 - 2
UnitTests/Application/ApplicationTests.cs

@@ -489,7 +489,7 @@ public class ApplicationTests {
 			// 1
 			Colors.Base.Normal
 		};
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 1111100000
 1111100000
 1111100000
@@ -518,7 +518,7 @@ public class ApplicationTests {
 			// 1
 			Colors.Base.Normal
 		};
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 0000000000
 0111110000
 0111110000

+ 9 - 9
UnitTests/Clipboard/ClipboardTests.cs

@@ -13,21 +13,21 @@ public class ClipboardTests {
 		this.output = output;
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
+	[Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
 	public void IClipboard_GetClipBoardData_Throws_NotSupportedException ()
 	{
 		var iclip = Application.Driver.Clipboard;
 		Assert.Throws<NotSupportedException> (() => iclip.GetClipboardData ());
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
+	[Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
 	public void IClipboard_SetClipBoardData_Throws_NotSupportedException ()
 	{
 		var iclip = Application.Driver.Clipboard;
 		Assert.Throws<NotSupportedException> (() => iclip.SetClipboardData ("foo"));
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: true)]
+	[Fact, AutoInitShutdown (useFakeClipboard: true)]
 	public void Contents_Fake_Gets_Sets ()
 	{
 		if (!Clipboard.IsSupported) {
@@ -44,7 +44,7 @@ public class ClipboardTests {
 		Assert.Equal (clipText, Clipboard.Contents);
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: false)]
+	[Fact, AutoInitShutdown (useFakeClipboard: false)]
 	public void Contents_Gets_Sets ()
 	{
 		if (!Clipboard.IsSupported) {
@@ -61,7 +61,7 @@ public class ClipboardTests {
 		Assert.Equal (clipText, Clipboard.Contents);
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: false)]
+	[Fact, AutoInitShutdown (useFakeClipboard: false)]
 	public void Contents_Gets_Sets_When_IsSupportedFalse ()
 	{
 
@@ -79,7 +79,7 @@ public class ClipboardTests {
 		Assert.Equal (clipText, Clipboard.Contents);
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: true)]
+	[Fact, AutoInitShutdown (useFakeClipboard: true)]
 	public void Contents_Fake_Gets_Sets_When_IsSupportedFalse ()
 	{
 
@@ -97,7 +97,7 @@ public class ClipboardTests {
 		Assert.Equal (clipText, Clipboard.Contents);
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: false)]
+	[Fact, AutoInitShutdown (useFakeClipboard: false)]
 	public void IsSupported_Get ()
 	{
 		if (Clipboard.IsSupported) {
@@ -107,7 +107,7 @@ public class ClipboardTests {
 		}
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: false)]
+	[Fact, AutoInitShutdown (useFakeClipboard: false)]
 	public void TryGetClipboardData_Gets_From_OS_Clipboard ()
 	{
 		string clipText = "The TryGetClipboardData_Gets_From_OS_Clipboard unit test pasted this to the OS clipboard.";
@@ -126,7 +126,7 @@ public class ClipboardTests {
 		}
 	}
 
-	[Fact] [AutoInitShutdown (useFakeClipboard: false)]
+	[Fact, AutoInitShutdown (useFakeClipboard: false)]
 	public void TrySetClipboardData_Sets_The_OS_Clipboard ()
 	{
 		string clipText = "The TrySetClipboardData_Sets_The_OS_Clipboard unit test pasted this to the OS clipboard.";

+ 2 - 2
UnitTests/Configuration/ConfigurationMangerTests.cs

@@ -307,14 +307,14 @@ public class ConfigurationManagerTests {
 		Settings.Update (stream, "TestConfigurationManagerToJson");
 	}
 
-	[Fact] [AutoInitShutdown (configLocation: ConfigLocations.None)]
+	[Fact, AutoInitShutdown (configLocation: ConfigLocations.None)]
 	public void TestConfigurationManagerInitDriver_NoLocations ()
 	{
 
 
 	}
 
-	[Fact] [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)]
+	[Fact, AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)]
 	public void TestConfigurationManagerInitDriver ()
 	{
 		Assert.Equal ("Default", Themes.Theme);

+ 1 - 1
UnitTests/Drawing/AttributeTests.cs

@@ -364,7 +364,7 @@ public class AttributeTests {
 		// Arrange
 		var foregroundColor = new Color (0, 0, 255);
 		var backgroundColor = new Color (255, 255, 255);
-		var expectedString = $"{foregroundColor},{backgroundColor}";
+		var expectedString = $"[{foregroundColor},{backgroundColor}]";
 
 		// Act
 		var attribute = new Attribute (foregroundColor, backgroundColor);

+ 136 - 100
UnitTests/TestHelpers.cs

@@ -1,45 +1,56 @@
-using System;
+using CsvHelper.Configuration.Attributes;
+using System;
 using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
 using System.Linq;
+using System.Reflection;
 using System.Text;
-using Xunit.Abstractions;
-using Xunit;
 using System.Text.RegularExpressions;
-using System.Reflection;
-using System.Diagnostics;
-
-using Attribute = Terminal.Gui.Attribute;
-using Microsoft.VisualStudio.TestPlatform.Utilities;
+using Xunit;
+using Xunit.Abstractions;
 using Xunit.Sdk;
-using System.Globalization;
-using System.IO;
 
 namespace Terminal.Gui;
+
 // This class enables test functions annotated with the [AutoInitShutdown] attribute to 
 // automatically call Application.Init at start of the test and Application.Shutdown after the
 // test exits. 
 // 
 // This is necessary because a) Application is a singleton and Init/Shutdown must be called
 // as a pair, and b) all unit test functions should be atomic..
-[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
+[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
+public class AutoInitShutdownAttribute : BeforeAfterTestAttribute {
+	readonly Type _driverType;
+
 	/// <summary>
 	/// Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and
 	/// Application.Shutdown are automatically called Before/After a test runs.
 	/// </summary>
 	/// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
 	/// <param name="autoShutdown">If true, Application.Shutdown will be called After the test runs.</param>
-	/// <param name="consoleDriverType">Determines which ConsoleDriver (FakeDriver, WindowsDriver, 
+	/// <param name="consoleDriverType">
+	/// Determines which ConsoleDriver (FakeDriver, WindowsDriver,
 	/// CursesDriver, NetDriver) will be used when Application.Init is called. If null FakeDriver will be used.
-	/// Only valid if <paramref name="autoInit"/> is true.</param>
-	/// <param name="useFakeClipboard">If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>. 
-	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
-	/// <param name="fakeClipboardAlwaysThrowsNotSupportedException">Only valid if <paramref name="autoInit"/> is true.
-	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
-	/// <param name="fakeClipboardIsSupportedAlwaysTrue">Only valid if <paramref name="autoInit"/> is true.
-	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
-	/// <param name="configLocation">Determines what config file locations <see cref="ConfigurationManager"/> will 
-	/// load from.</param>
+	/// Only valid if <paramref name="autoInit"/> is true.
+	/// </param>
+	/// <param name="useFakeClipboard">
+	/// If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>.
+	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
+	/// </param>
+	/// <param name="fakeClipboardAlwaysThrowsNotSupportedException">
+	/// Only valid if <paramref name="autoInit"/> is true.
+	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
+	/// </param>
+	/// <param name="fakeClipboardIsSupportedAlwaysTrue">
+	/// Only valid if <paramref name="autoInit"/> is true.
+	/// Only valid if <see cref="ConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
+	/// </param>
+	/// <param name="configLocation">
+	/// Determines what config file locations <see cref="ConfigurationManager"/> will
+	/// load from.
+	/// </param>
 	public AutoInitShutdownAttribute (bool autoInit = true,
 		Type consoleDriverType = null,
 		bool useFakeClipboard = true,
@@ -57,7 +68,6 @@ public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
 	}
 
 	bool AutoInit { get; }
-	Type _driverType;
 
 	public override void Before (MethodInfo methodUnderTest)
 	{
@@ -91,12 +101,9 @@ public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
 	}
 }
 
-[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-public class TestRespondersDisposed : Xunit.Sdk.BeforeAfterTestAttribute {
-	public TestRespondersDisposed ()
-	{
-		CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
-	}
+[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
+public class TestRespondersDisposed : BeforeAfterTestAttribute {
+	public TestRespondersDisposed () => CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
 
 	public override void Before (MethodInfo methodUnderTest)
 	{
@@ -117,21 +124,20 @@ public class TestRespondersDisposed : Xunit.Sdk.BeforeAfterTestAttribute {
 	}
 }
 
-[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-public class SetupFakeDriverAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
+[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
+public class SetupFakeDriverAttribute : BeforeAfterTestAttribute {
 	/// <summary>
-	/// Enables test functions annotated with the [SetupFakeDriver] attribute to 
-	/// set Application.Driver to new FakeDriver(). 
+	/// Enables test functions annotated with the [SetupFakeDriver] attribute to
+	/// set Application.Driver to new FakeDriver(). The driver is setup with
+	/// 10 rows and columns.
 	/// </summary>
-	public SetupFakeDriverAttribute ()
-	{
-	}
+	public SetupFakeDriverAttribute () { }
 
 	public override void Before (MethodInfo methodUnderTest)
 	{
 		Debug.WriteLine ($"Before: {methodUnderTest.Name}");
 		Assert.Null (Application.Driver);
-		Application.Driver = new FakeDriver ();
+		Application.Driver = new FakeDriver () { Rows = 10, Cols = 10 };
 	}
 
 	public override void After (MethodInfo methodUnderTest)
@@ -144,31 +150,22 @@ public class SetupFakeDriverAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
 partial class TestHelpers {
 	[GeneratedRegex ("\\s+$", RegexOptions.Multiline)]
 	private static partial Regex TrailingWhiteSpaceRegEx ();
+
 	[GeneratedRegex ("^\\s+", RegexOptions.Multiline)]
 	private static partial Regex LeadingWhitespaceRegEx ();
 
-#pragma warning disable xUnit1013 // Public method should be marked as test
-	/// <summary>
-	/// Asserts that the driver contents match the expected contents, optionally ignoring any trailing whitespace.
-	/// </summary>
-	/// <param name="expectedLook"></param>
-	/// <param name="output"></param>
-	/// <param name="driver">The ConsoleDriver to use. If null <see cref="Application.Driver"/> will be used.</param>
-	/// <param name="ignoreLeadingWhitespace"></param>
-	public static void AssertDriverContentsAre (string expectedLook, ITestOutputHelper output, ConsoleDriver driver = null, bool ignoreLeadingWhitespace = false)
+	public static string DriverContentsToString (ConsoleDriver driver = null)
 	{
-#pragma warning restore xUnit1013 // Public method should be marked as test
-
 		var sb = new StringBuilder ();
 		driver ??= Application.Driver;
 
 		var contents = driver.Contents;
 
-		for (int r = 0; r < driver.Rows; r++) {
-			for (int c = 0; c < driver.Cols; c++) {
-				Rune rune = contents [r, c].Rune;
-				if (rune.DecodeSurrogatePair (out char [] spair)) {
-					sb.Append (spair);
+		for (var r = 0; r < driver.Rows; r++) {
+			for (var c = 0; c < driver.Cols; c++) {
+				var rune = contents [r, c].Rune;
+				if (rune.DecodeSurrogatePair (out var sp)) {
+					sb.Append (sp);
 				} else {
 					sb.Append ((char)rune.Value);
 				}
@@ -183,9 +180,25 @@ partial class TestHelpers {
 			sb.AppendLine ();
 		}
 
-		var actualLook = sb.ToString ();
+		return sb.ToString ();
+	}
 
-		if (string.Equals (expectedLook, actualLook)) return;
+#pragma warning disable xUnit1013 // Public method should be marked as test
+	/// <summary>
+	/// Asserts that the driver contents match the expected contents, optionally ignoring any trailing whitespace.
+	/// </summary>
+	/// <param name="expectedLook"></param>
+	/// <param name="output"></param>
+	/// <param name="driver">The ConsoleDriver to use. If null <see cref="Application.Driver"/> will be used.</param>
+	/// <param name="ignoreLeadingWhitespace"></param>
+	public static void AssertDriverContentsAre (string expectedLook, ITestOutputHelper output, ConsoleDriver driver = null, bool ignoreLeadingWhitespace = false)
+	{
+#pragma warning restore xUnit1013 // Public method should be marked as test
+		var actualLook = DriverContentsToString (driver);
+
+		if (string.Equals (expectedLook, actualLook)) {
+			return;
+		}
 
 		// get rid of trailing whitespace on each line (and leading/trailing whitespace of start/end of full string)
 		expectedLook = TrailingWhiteSpaceRegEx ().Replace (expectedLook, "").Trim ();
@@ -203,7 +216,7 @@ partial class TestHelpers {
 		// If test is about to fail show user what things looked like
 		if (!string.Equals (expectedLook, actualLook)) {
 			output?.WriteLine ("Expected:" + Environment.NewLine + expectedLook);
-			output?.WriteLine ("But Was:" + Environment.NewLine + actualLook);
+			output?.WriteLine (" But Was:" + Environment.NewLine + actualLook);
 		}
 
 		Assert.Equal (expectedLook, actualLook);
@@ -231,13 +244,13 @@ partial class TestHelpers {
 		for (var r = 0; r < driver.Rows; r++) {
 			var runes = new List<Rune> ();
 			for (var c = 0; c < driver.Cols; c++) {
-				Rune rune = contents [r, c].Rune;
+				var rune = contents [r, c].Rune;
 				if (rune != (Rune)' ') {
 					if (x == -1) {
 						x = c;
 						y = r;
-						for (int i = 0; i < c; i++) {
-							runes.InsertRange (i, new List<Rune> () { (Rune)' ' });
+						for (var i = 0; i < c; i++) {
+							runes.InsertRange (i, new List<Rune> { (Rune)' ' });
 						}
 					}
 					if (rune.GetColumns () > 1) {
@@ -248,25 +261,31 @@ partial class TestHelpers {
 					}
 					h = r - y + 1;
 				}
-				if (x > -1) runes.Add (rune);
+				if (x > -1) {
+					runes.Add (rune);
+				}
 				// See Issue #2616
 				//foreach (var combMark in contents [r, c].CombiningMarks) {
 				//	runes.Add (combMark);
 				//}
 			}
-			if (runes.Count > 0) lines.Add (runes);
+			if (runes.Count > 0) {
+				lines.Add (runes);
+			}
 		}
 
 		// Remove unnecessary empty lines
 		if (lines.Count > 0) {
-			for (var r = lines.Count - 1; r > h - 1; r--) lines.RemoveAt (r);
+			for (var r = lines.Count - 1; r > h - 1; r--) {
+				lines.RemoveAt (r);
+			}
 		}
 
 		// Remove trailing whitespace on each line
 		foreach (var row in lines) {
 			for (var c = row.Count - 1; c >= 0; c--) {
 				var rune = row [c];
-				if (rune != (Rune)' ' || (row.Sum (x => x.GetColumns ()) == w)) {
+				if (rune != (Rune)' ' || row.Sum (x => x.GetColumns ()) == w) {
 					break;
 				}
 				row.RemoveAt (c);
@@ -274,8 +293,8 @@ partial class TestHelpers {
 		}
 
 		// Convert Rune list to string
-		for (int r = 0; r < lines.Count; r++) {
-			var line = Terminal.Gui.StringExtensions.ToString (lines [r]).ToString ();
+		for (var r = 0; r < lines.Count; r++) {
+			var line = StringExtensions.ToString (lines [r]);
 			if (r == lines.Count - 1) {
 				sb.Append (line);
 			} else {
@@ -294,11 +313,15 @@ partial class TestHelpers {
 		actualLook = actualLook.Replace ("\r\n", "\n");
 
 		// Remove the first and the last line ending from the expectedLook
-		if (expectedLook.StartsWith ("\n")) expectedLook = expectedLook [1..];
-		if (expectedLook.EndsWith ("\n")) expectedLook = expectedLook [..^1];
+		if (expectedLook.StartsWith ("\n")) {
+			expectedLook = expectedLook [1..];
+		}
+		if (expectedLook.EndsWith ("\n")) {
+			expectedLook = expectedLook [..^1];
+		}
 
 		output?.WriteLine ("Expected:" + Environment.NewLine + expectedLook);
-		output?.WriteLine ("But Was:" + Environment.NewLine + actualLook);
+		output?.WriteLine (" But Was:" + Environment.NewLine + actualLook);
 
 		Assert.Equal (expectedLook, actualLook);
 		return new Rect (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
@@ -306,48 +329,62 @@ partial class TestHelpers {
 
 #pragma warning disable xUnit1013 // Public method should be marked as test
 	/// <summary>
-	/// Verifies the console was rendered using the given <paramref name="expectedColors"/> at the given locations.
-	/// Pass a bitmap of indexes into <paramref name="expectedColors"/> as <paramref name="expectedLook"/> and the
+	/// Verifies the console was rendered using the given <paramref name="expectedAttribute"/> at the given locations.
+	/// Pass a bitmap of indexes into <paramref name="expectedAttribute"/> as <paramref name="expectedLook"/> and the
 	/// test method will verify those colors were used in the row/col of the console during rendering
 	/// </summary>
-	/// <param name="expectedLook">Numbers between 0 and 9 for each row/col of the console.  Must be valid indexes of <paramref name="expectedColors"/></param>
+	/// <param name="expectedLook">
+	/// Numbers between 0 and 9 for each row/col of the console.  Must be valid indexes of
+	/// <paramref name="expectedAttribute"/>
+	/// </param>
 	/// <param name="driver">The ConsoleDriver to use. If null <see cref="Application.Driver"/> will be used.</param>
-	/// <param name="expectedColors"></param>
-	public static void AssertDriverColorsAre (string expectedLook, ConsoleDriver driver = null, params Attribute [] expectedColors)
+	/// <param name="expectedAttribute"></param>
+	public static void AssertDriverAttributesAre (string expectedLook, ConsoleDriver driver = null, params Attribute [] expectedAttribute)
 	{
 #pragma warning restore xUnit1013 // Public method should be marked as test
 
-		if (expectedColors.Length > 10) throw new ArgumentException ("This method only works for UIs that use at most 10 colors");
+		if (expectedAttribute.Length > 10) {
+			throw new ArgumentException ("This method only works for UIs that use at most 10 colors");
+		}
 
 		expectedLook = expectedLook.Trim ();
 		driver ??= Application.Driver;
 
 		var contents = driver.Contents;
 
-		var r = 0;
-		foreach (var line in expectedLook.Split ('\n').Select (l => l.Trim ())) {
+		var line = 0;
+		foreach (var lineString in expectedLook.Split ('\n').Select (l => l.Trim ())) {
 
-			for (var c = 0; c < line.Length; c++) {
+			for (var c = 0; c < lineString.Length; c++) {
 
-				var val = contents [r, c].Attribute;
+				var val = contents [line, c].Attribute;
 
-				var match = expectedColors.Where (e => e == val).ToList ();
+				var match = expectedAttribute.Where (e => e == val).ToList ();
 				switch (match.Count) {
 				case 0:
-					throw new Exception ($"Unexpected color {val} was used at row {r} and col {c} (indexes start at 0).  Color value was {val} (expected colors were {string.Join (",", expectedColors.Select (c => c.PlatformColor.ToString ()))})");
+					throw new Exception ($"{DriverContentsToString (driver)}\n" +
+					                     $"Expected Attribute {val} at Contents[{line},{c}] {contents [line, c]}' was not found.\n" +
+							     $"  Expected: {string.Join (",", expectedAttribute.Select (c => c))}\n" +
+					                     $"  But Was: <not found>");
 				case > 1:
 					throw new ArgumentException ($"Bad value for expectedColors, {match.Count} Attributes had the same Value");
 				}
 
-				var colorUsed = Array.IndexOf (expectedColors, match [0]).ToString () [0];
-				var userExpected = line [c];
+				var colorUsed = Array.IndexOf (expectedAttribute, match [0]).ToString () [0];
+				var userExpected = lineString [c];
 
-				if (colorUsed != userExpected) throw new Exception ($"Colors used did not match expected at row {r} and col {c} (indexes start at 0).  Color index used was {colorUsed} ({val}) but test expected {userExpected} ({expectedColors [int.Parse (userExpected.ToString ())].PlatformColor}) (these are indexes into the expectedColors array)");
+				if (colorUsed != userExpected) {
+					throw new Exception ($"{DriverContentsToString (driver)}\n" +
+						$"Unexpected Attribute at Contents[{line},{c}] {contents [line, c]}.'\n" +
+						$"  Expected: {userExpected} ({expectedAttribute [int.Parse (userExpected.ToString ())]})\n" +
+						$"  But Was:   {colorUsed} ({val})\n");
+				}
 			}
 
-			r++;
+			line++;
 		}
 	}
+
 	/// <summary>
 	/// Verifies the console used all the <paramref name="expectedColors"/> when rendering.
 	/// If one or more of the expected colors are not used then the failure will output both
@@ -392,12 +429,14 @@ partial class TestHelpers {
 
 #pragma warning disable xUnit1013 // Public method should be marked as test
 	/// <summary>
-	/// Verifies two strings are equivalent. If the assert fails, output will be generated to standard 
+	/// Verifies two strings are equivalent. If the assert fails, output will be generated to standard
 	/// output showing the expected and actual look.
 	/// </summary>
 	/// <param name="output"></param>
-	/// <param name="expectedLook">A string containing the expected look. Newlines should be specified as "\r\n" as
-	/// they will be converted to <see cref="Environment.NewLine"/> to make tests platform independent.</param>
+	/// <param name="expectedLook">
+	/// A string containing the expected look. Newlines should be specified as "\r\n" as
+	/// they will be converted to <see cref="Environment.NewLine"/> to make tests platform independent.
+	/// </param>
 	/// <param name="actualLook"></param>
 	public static void AssertEqual (ITestOutputHelper output, string expectedLook, string actualLook)
 	{
@@ -407,14 +446,14 @@ partial class TestHelpers {
 		// If test is about to fail show user what things looked like
 		if (!string.Equals (expectedLook, actualLook)) {
 			output?.WriteLine ("Expected:" + Environment.NewLine + expectedLook);
-			output?.WriteLine ("But Was:" + Environment.NewLine + actualLook);
+			output?.WriteLine (" But Was:" + Environment.NewLine + actualLook);
 		}
 
 		Assert.Equal (expectedLook, actualLook);
 	}
 #pragma warning restore xUnit1013 // Public method should be marked as test
 
-	private static string ReplaceNewLinesToPlatformSpecific (string toReplace)
+	static string ReplaceNewLinesToPlatformSpecific (string toReplace)
 	{
 		var replaced = toReplace;
 
@@ -431,19 +470,16 @@ partial class TestHelpers {
 	/// Gets a list of instances of all classes derived from View.
 	/// </summary>
 	/// <returns>List of View objects</returns>
-	public static List<View> GetAllViews ()
-	{
-		return typeof (View).Assembly.GetTypes ()
-			.Where (type => type.IsClass && !type.IsAbstract && type.IsPublic && type.IsSubclassOf (typeof (View)))
-			.Select (type => GetTypeInitializer (type, type.GetConstructor (Array.Empty<Type> ()))).ToList ();
-	}
+	public static List<View> GetAllViews () => typeof (View).Assembly.GetTypes ()
+		.Where (type => type.IsClass && !type.IsAbstract && type.IsPublic && type.IsSubclassOf (typeof (View)))
+		.Select (type => GetTypeInitializer (type, type.GetConstructor (Array.Empty<Type> ()))).ToList ();
 
-	private static View GetTypeInitializer (Type type, ConstructorInfo ctor)
+	static View GetTypeInitializer (Type type, ConstructorInfo ctor)
 	{
 		View viewType = null;
 
 		if (type.IsGenericType && type.IsTypeDefinition) {
-			List<Type> gTypes = new List<Type> ();
+			var gTypes = new List<Type> ();
 
 			foreach (var args in type.GetGenericArguments ()) {
 				gTypes.Add (typeof (object));
@@ -453,9 +489,9 @@ partial class TestHelpers {
 			Assert.IsType (type, (View)Activator.CreateInstance (type));
 
 		} else {
-			ParameterInfo [] paramsInfo = ctor.GetParameters ();
+			var paramsInfo = ctor.GetParameters ();
 			Type paramType;
-			List<object> pTypes = new List<object> ();
+			var pTypes = new List<object> ();
 
 			if (type.IsGenericType) {
 				foreach (var args in type.GetGenericArguments ()) {
@@ -491,7 +527,7 @@ partial class TestHelpers {
 		return viewType;
 	}
 
-	private static void AddArguments (Type paramType, List<object> pTypes)
+	static void AddArguments (Type paramType, List<object> pTypes)
 	{
 		if (paramType == typeof (Rect)) {
 			pTypes.Add (Rect.Empty);

+ 140 - 0
UnitTests/View/Adornment/AdornmentTests.cs

@@ -0,0 +1,140 @@
+using System;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class AdornmentTests {
+	readonly ITestOutputHelper _output;
+
+	public AdornmentTests (ITestOutputHelper output)
+	{
+		_output = output;
+	}
+
+	[Fact]
+	public void Setting_SuperView_Throws ()
+	{
+		var adornment = new Adornment (null);
+		Assert.Throws<NotImplementedException> (() => adornment.SuperView = new View ());
+	}
+
+	[Fact]
+	public void Setting_SuperViewRendersLineCanvas_Throws ()
+	{
+		var adornment = new Adornment (null);
+		Assert.Throws<NotImplementedException> (() => adornment.SuperViewRendersLineCanvas = true);
+	}
+
+	[Fact]
+	public void Setting_Thickness_Changes_Parent_Bounds ()
+	{
+		var parent = new View () {
+			Width = 10,
+			Height = 10
+		};
+		parent.BeginInit ();
+		parent.EndInit ();
+
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Frame);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Bounds);
+
+		parent.Margin.Thickness = new Thickness (1);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Frame);
+		Assert.Equal (new Rect (0, 0, 8, 8), parent.Bounds);
+	}
+
+	[Fact]
+	public void Setting_Thickness_Raises_ThicknessChanged ()
+	{
+		var adornment = new Adornment (null);
+		var super = new View ();
+		var raised = false;
+		adornment.ThicknessChanged += (s, e) => {
+			raised = true;
+			Assert.Equal (Thickness.Empty, e.PreviousThickness);
+			Assert.Equal (new Thickness (1, 2, 3, 4), e.Thickness);
+			Assert.Equal (new Thickness (1, 2, 3, 4), adornment.Thickness);
+		};
+		adornment.Thickness = new Thickness (1, 2, 3, 4);
+		Assert.True (raised);
+	}
+
+	[Fact]
+	public void Setting_Bounds_Throws ()
+	{
+		var adornment = new Adornment (null);
+		Assert.Throws<InvalidOperationException> (() => adornment.Bounds = new Rect (1, 2, 3, 4));
+	}
+
+	[Fact]
+	public void GetAdornmentsThickness ()
+	{
+		var view = new View ();
+		Assert.Equal (Thickness.Empty, view.GetAdornmentsThickness ());
+
+		view.Margin.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (1), view.GetAdornmentsThickness ());
+
+		view.Border.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (2), view.GetAdornmentsThickness ());
+
+		view.Padding.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (3), view.GetAdornmentsThickness ());
+
+		view.Padding.Thickness = new Thickness (2);
+		Assert.Equal (new Thickness (4), view.GetAdornmentsThickness ());
+
+		view.Padding.Thickness = new Thickness (1, 2, 3, 4);
+		Assert.Equal (new Thickness (3, 4, 5, 6), view.GetAdornmentsThickness ());
+
+		view.Margin.Thickness = new Thickness (1, 2, 3, 4);
+		Assert.Equal (new Thickness (3, 5, 7, 9), view.GetAdornmentsThickness ());
+		view.Dispose ();
+	}
+
+	[Fact]
+	public void FrameToScreen_Uses_Parent_Not_SuperView ()
+	{
+		var parent = new View () {
+			X = 1,
+			Y = 2,
+			Width = 10,
+			Height = 10
+		};
+
+		parent.BeginInit ();
+		parent.EndInit ();
+
+		Assert.Equal (new Rect (1, 2, 10, 10), parent.Frame);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Bounds);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Margin.Frame);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Margin.Bounds);
+
+		Assert.Null (parent.Margin.SuperView);
+		Assert.Equal (new Rect (1, 2, 10, 10), parent.Margin.FrameToScreen ());
+	}
+
+	[Fact]
+	public void BoundsToScreen_Uses_Parent_Not_SuperView ()
+	{
+		var parent = new View () {
+			X = 1,
+			Y = 2,
+			Width = 10,
+			Height = 10
+		};
+
+		parent.BeginInit ();
+		parent.EndInit ();
+
+		Assert.Equal (new Rect (1, 2, 10, 10), parent.Frame);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Bounds);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Margin.Frame);
+		Assert.Equal (new Rect (0, 0, 10, 10), parent.Margin.Bounds);
+
+		Assert.Null (parent.Margin.SuperView);
+		var boundsAsScreen = parent.Margin.BoundsToScreen (new Rect (1, 2, 5, 5));
+		Assert.Equal (new Rect (2, 4, 5, 5), boundsAsScreen);
+	}
+}

+ 740 - 0
UnitTests/View/Adornment/BorderTests.cs

@@ -0,0 +1,740 @@
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+public class BorderTests {
+	readonly ITestOutputHelper _output;
+
+	public BorderTests (ITestOutputHelper output)
+	{
+		_output = output;
+	}
+
+	[Fact]
+	public void View_BorderStyle_Defaults ()
+	{
+		var view = new View ();
+		Assert.Equal (LineStyle.None, view.BorderStyle);
+		Assert.Equal (Thickness.Empty, view.Border.Thickness);
+		view.Dispose ();
+	}
+
+	[Fact]
+	public void View_SetBorderStyle ()
+	{
+		var view = new View ();
+		view.BorderStyle = LineStyle.Single;
+		Assert.Equal (LineStyle.Single, view.BorderStyle);
+		Assert.Equal (new Thickness (1), view.Border.Thickness);
+
+		view.BorderStyle = LineStyle.Double;
+		Assert.Equal (LineStyle.Double, view.BorderStyle);
+		Assert.Equal (new Thickness (1), view.Border.Thickness);
+
+		view.BorderStyle = LineStyle.None;
+		Assert.Equal (LineStyle.None, view.BorderStyle);
+		Assert.Equal (Thickness.Empty, view.Border.Thickness);
+		view.Dispose ();
+	}
+
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	public void Border_With_Title_Size_Height (int height)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (20, height);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (height) {
+		case 0:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
+";
+			break;
+		case 1:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
+────────────────────";
+			break;
+		case 2:
+			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
+			expected = @"
+┌┤1234├────────────┐
+└──────────────────┘
+";
+			break;
+		case 3:
+			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
+			expected = @"
+┌┤1234├────────────┐
+│                  │
+└──────────────────┘
+";
+			break;
+		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 3);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
+│
+│
+│";
+			break;
+		case 2:
+			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
+			expected = @"
+┌┐
+││
+└┘";
+			break;
+		case 3:
+			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
+			expected = @"
+┌─┐
+│ │
+└─┘
+";
+			break;
+		case 4:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤├┐
+│  │
+└──┘";
+			break;
+		case 5:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤1├┐
+│   │
+└───┘";
+			break;
+		case 6:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤12├┐
+│    │
+└────┘";
+			break;
+		case 7:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤123├┐
+│     │
+└─────┘";
+			break;
+		case 8:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤1234├┐
+│      │
+└──────┘";
+			break;
+		case 9:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤1234├─┐
+│       │
+└───────┘";
+			break;
+		case 10:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
+┌┤1234├──┐
+│        │
+└────────┘";
+			break;
+		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+	}
+
+	[Fact, AutoInitShutdown]
+	public void NoSuperView ()
+	{
+		var win = new Window () {
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (3, 3);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
+┌─┐
+│ │
+└─┘";
+
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+	}
+
+	[Fact, AutoInitShutdown]
+	public void HasSuperView ()
+	{
+		Application.Top.BorderStyle = LineStyle.Double;
+
+		var frame = new FrameView () {
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		Application.Top.Add (frame);
+		var rs = Application.Begin (Application.Top);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (5, 5);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
+╔═══╗
+║┌─┐║
+║│ │║
+║└─┘║
+╚═══╝";
+
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+	[Fact, AutoInitShutdown]
+	public void HasSuperView_Title ()
+	{
+		Application.Top.BorderStyle = LineStyle.Double;
+
+		var frame = new FrameView () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		Application.Top.Add (frame);
+		var rs = Application.Begin (Application.Top);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (10, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
+╔════════╗
+║┌┤1234├┐║
+║└──────┘║
+╚════════╝";
+
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+
+	[Theory]
+	[InlineData (0, 0, 0, 1, 1)]
+	[InlineData (1, 0, 0, 2, 2)]
+	[InlineData (2, 0, 0, 3, 3)]
+	[InlineData (1, 1, 0, 3, 2)]
+	[InlineData (1, 0, 1, 2, 3)]
+	[InlineData (1, 1, 1, 3, 3)]
+	[InlineData (1, 10, 10, 12, 12)]
+	public void FrameToScreen_SuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var super = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 20,
+			Height = 20,
+			BorderStyle = LineStyle.Single
+		};
+
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		super.Add (view);
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
+
+	[Theory]
+	[InlineData (0, 0, 0, 2, 2)]
+	[InlineData (1, 0, 0, 4, 4)]
+	[InlineData (2, 0, 0, 6, 6)]
+	[InlineData (1, 1, 0, 5, 4)]
+	[InlineData (1, 0, 1, 4, 5)]
+	[InlineData (1, 1, 1, 5, 5)]
+	[InlineData (1, 10, 10, 14, 14)]
+	public void FrameToScreen_NestedSuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var superSuper = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 30,
+			Height = 30,
+			BorderStyle = LineStyle.Single
+		};
+
+		var super = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 20,
+			Height = 20,
+			BorderStyle = LineStyle.Single
+		};
+		superSuper.Add (super);
+
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		super.Add (view);
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
+
+
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Two_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 2;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
+			expected = @"
+║
+║
+║";
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
+			expected = @"
+╔╗
+║║
+╚╝";
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
+			expected = @"
+╔═╗
+║ ║
+╚═╝";
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
+			expected = @"
+ ╒╕ 
+╔╛╘╗
+║  ║
+╚══╝";
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
+			expected = @"
+ ╒═╕ 
+╔╛1╘╗
+║   ║
+╚═══╝";
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
+			expected = @"
+ ╒══╕ 
+╔╛12╘╗
+║    ║
+╚════╝";
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
+			expected = @"
+ ╒═══╕ 
+╔╛123╘╗
+║     ║
+╚═════╝";
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
+			expected = @"
+ ╒════╕ 
+╔╛1234╘╗
+║      ║
+╚══════╝";
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
+			expected = @"
+ ╒════╕  
+╔╛1234╘═╗
+║       ║
+╚═══════╝";
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+			expected = @"
+ ╒════╕   
+╔╛1234╘══╗
+║        ║
+╚════════╝";
+			break;
+		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 3;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
+			expected = @"
+║
+║
+║";
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
+			expected = @"
+╔╗
+║║
+╚╝";
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
+			expected = @"
+╔═╗
+║ ║
+╚═╝";
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
+			expected = @"
+ ╒╕ 
+╔╡╞╗
+║╘╛║
+╚══╝";
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
+			expected = @"
+ ╒═╕ 
+╔╡1╞╗
+║╘═╛║
+╚═══╝";
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
+			expected = @"
+ ╒══╕ 
+╔╡12╞╗
+║╘══╛║
+╚════╝";
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
+			expected = @"
+ ╒═══╕ 
+╔╡123╞╗
+║╘═══╛║
+╚═════╝";
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
+			expected = @"
+ ╒════╕ 
+╔╡1234╞╗
+║╘════╛║
+╚══════╝";
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
+			expected = @"
+ ╒════╕  
+╔╡1234╞═╗
+║╘════╛ ║
+╚═══════╝";
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+			expected = @"
+ ╒════╕   
+╔╡1234╞══╗
+║╘════╛  ║
+╚════════╝";
+			break;
+		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Four_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 4;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 5);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 5), win.Frame);
+			expected = @"
+║
+║
+║";
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 5), win.Frame);
+			expected = @"
+╔╗
+║║
+╚╝";
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 5), win.Frame);
+			expected = @"
+╔═╗
+║ ║
+╚═╝";
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 5), win.Frame);
+			expected = @"
+ ╒╕ 
+╔╡╞╗
+║╘╛║
+╚══╝";
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 5), win.Frame);
+			expected = @"
+ ╒═╕ 
+╔╡1╞╗
+║╘═╛║
+╚═══╝";
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 5), win.Frame);
+			expected = @"
+ ╒══╕ 
+╔╡12╞╗
+║╘══╛║
+╚════╝";
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 5), win.Frame);
+			expected = @"
+ ╒═══╕ 
+╔╡123╞╗
+║╘═══╛║
+╚═════╝";
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 5), win.Frame);
+			expected = @"
+ ╒════╕ 
+╔╡1234╞╗
+║╘════╛║
+╚══════╝";
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 5), win.Frame);
+			expected = @"
+ ╒════╕  
+╔╡1234╞═╗
+║╘════╛ ║
+╚═══════╝";
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 5), win.Frame);
+			expected = @"
+ ╒════╕   
+╔╡1234╞══╗
+║╘════╛  ║
+╚════════╝";
+			break;
+		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
+
+	[Fact, SetupFakeDriver]
+	public void Border_Uses_Parent_ColorScheme ()
+	{
+		var view = new View () {
+			Title = "A",
+			Height = 2,
+			Width = 5
+		};
+		view.Border.Thickness = new Thickness (0, 1, 0, 0);
+		view.Border.LineStyle = LineStyle.Single;
+		view.ColorScheme = new ColorScheme () {
+			Normal = new Attribute (Color.Red, Color.Green),
+			Focus = new Attribute (Color.Green, Color.Red),
+		};
+		Assert.Equal (Colors.Error.Normal.Foreground, view.ColorScheme.Normal.Foreground);
+		Assert.Equal (ColorName.Red, view.Border.GetNormalColor ().Foreground.ColorName);
+		Assert.Equal (ColorName.Green, view.Border.GetFocusColor ().Foreground.ColorName);
+		Assert.Equal (view.GetNormalColor(), view.Border.GetNormalColor ());
+		Assert.Equal (view.GetFocusColor (), view.Border.GetFocusColor ());
+
+		view.BeginInit ();
+		view.EndInit ();
+		view.Draw ();
+
+		var expected = @"─┤A├─";
+		TestHelpers.AssertDriverContentsAre (expected, _output);
+		TestHelpers.AssertDriverAttributesAre ("00000", null, view.ColorScheme.Normal);
+	}
+
+	[Fact, SetupFakeDriver]
+	public void Border_Parent_HasFocus_Title_Uses_FocusAttribute ()
+	{
+		var view = new View () {
+			Title = "A",
+			Height = 2,
+			Width = 5
+		};
+		view.Border.Thickness = new Thickness (0, 1, 0, 0);
+		view.Border.LineStyle = LineStyle.Single;
+		view.ColorScheme = new ColorScheme () {
+			Normal = new Attribute (Color.Red, Color.Green),
+			Focus = new Attribute (Color.Green, Color.Red),
+		};
+		Assert.NotEqual (view.ColorScheme.Normal.Foreground, view.ColorScheme.Focus.Foreground);
+		Assert.Equal (ColorName.Red, view.Border.GetNormalColor ().Foreground.ColorName);
+		Assert.Equal (ColorName.Green, view.Border.GetFocusColor ().Foreground.ColorName);
+		Assert.Equal (view.GetFocusColor (), view.Border.GetFocusColor ());
+
+		view.BeginInit ();
+		view.EndInit ();
+		view.Draw ();
+
+		var expected = @"─┤A├─";
+		TestHelpers.AssertDriverContentsAre (expected, _output);
+		TestHelpers.AssertDriverAttributesAre ("00000", null, view.ColorScheme.Normal);
+
+		view.CanFocus = true;
+		view.SetFocus ();
+		view.Draw ();
+		Assert.Equal (view.GetFocusColor (), view.Border.GetFocusColor ());
+		Assert.Equal (view.ColorScheme.Focus.Foreground, view.Border.GetFocusColor ().Foreground);
+		Assert.Equal (view.ColorScheme.Normal.Foreground, view.Border.GetNormalColor ().Foreground);
+		TestHelpers.AssertDriverAttributesAre ("00100", null, view.ColorScheme.Normal, view.GetFocusColor ());
+	}
+}

+ 48 - 0
UnitTests/View/Adornment/MarginTests.cs

@@ -0,0 +1,48 @@
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+public class MarginTests {
+	readonly ITestOutputHelper _output;
+
+	public MarginTests (ITestOutputHelper output)
+	{
+		_output = output;
+	}
+
+	[Fact, SetupFakeDriver]
+	public void Margin_Uses_SuperView_ColorScheme ()
+	{
+		((FakeDriver)Application.Driver).SetBufferSize (5, 5);
+		var view = new View () {
+			Height = 3,
+			Width = 3
+		};
+		view.Margin.Thickness = new Thickness (1);
+
+		var superView = new View ();
+		
+		superView.ColorScheme = new ColorScheme () {
+			Normal = new Attribute (Color.Red, Color.Green),
+			Focus = new Attribute (Color.Green, Color.Red),
+		};
+
+		superView.Add (view);
+		Assert.Equal (ColorName.Red, view.Margin.GetNormalColor ().Foreground.ColorName);
+		Assert.Equal (ColorName.Red, superView.GetNormalColor ().Foreground.ColorName);
+		Assert.Equal (superView.GetNormalColor (), view.Margin.GetNormalColor ());
+		Assert.Equal (superView.GetFocusColor (), view.Margin.GetFocusColor ());
+
+		superView.BeginInit ();
+		superView.EndInit ();
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.FramePadding;
+		view.Draw ();
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+
+		TestHelpers.AssertDriverContentsAre (@"
+LTR
+L R
+BBB", _output);
+		TestHelpers.AssertDriverAttributesAre ("0", null, superView.GetNormalColor ());
+	}
+}

+ 43 - 0
UnitTests/View/Adornment/PaddingTests.cs

@@ -0,0 +1,43 @@
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+public class PaddingTests {
+	readonly ITestOutputHelper _output;
+
+	public PaddingTests (ITestOutputHelper output)
+	{
+		_output = output;
+	}
+
+	[Fact, SetupFakeDriver]
+	public void Padding_Uses_Parent_ColorScheme ()
+	{
+		((FakeDriver)Application.Driver).SetBufferSize (5, 5);
+		var view = new View () {
+			Height = 3,
+			Width = 3
+		};
+		view.Padding.Thickness = new Thickness (1);
+
+		view.ColorScheme = new ColorScheme () {
+			Normal = new Attribute (Color.Red, Color.Green),
+			Focus = new Attribute (Color.Green, Color.Red),
+		};
+		
+		Assert.Equal (ColorName.Red, view.Padding.GetNormalColor ().Foreground.ColorName);
+		Assert.Equal (view.GetNormalColor (), view.Padding.GetNormalColor ());
+
+		view.BeginInit ();
+		view.EndInit ();
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.FramePadding;
+		view.Draw ();
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+
+		TestHelpers.AssertDriverContentsAre (@"
+LTR
+L R
+BBB", _output);
+		TestHelpers.AssertDriverAttributesAre ("0", null, view.GetNormalColor ());
+	}
+}

+ 0 - 44
UnitTests/View/BorderTests.cs

@@ -1,44 +0,0 @@
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Terminal.Gui.ViewTests;
-public class BorderTests {
-	readonly ITestOutputHelper _output;
-
-	public BorderTests (ITestOutputHelper output)
-	{
-		this._output = output;
-	}
-
-	[Fact]
-	public void View_BorderStyle_Defaults ()
-	{
-		var view = new View ();
-		Assert.Equal (LineStyle.None, view.BorderStyle);
-		Assert.Equal (Thickness.Empty, view.Border.Thickness);
-		view.Dispose ();
-	}
-
-	[Fact]
-	public void View_SetBorderStyle ()
-	{
-		var view = new View ();
-		view.BorderStyle = LineStyle.Single;
-		Assert.Equal (LineStyle.Single, view.BorderStyle);
-		Assert.Equal (new Thickness (1), view.Border.Thickness);
-
-		view.BorderStyle = LineStyle.Double;
-		Assert.Equal (LineStyle.Double, view.BorderStyle);
-		Assert.Equal (new Thickness (1), view.Border.Thickness);
-
-		view.BorderStyle = LineStyle.None;
-		Assert.Equal (LineStyle.None, view.BorderStyle);
-		Assert.Equal (Thickness.Empty, view.Border.Thickness);
-		view.Dispose ();
-	}
-
-	//[Fact]
-	//public void View_BorderStyleChanged ()
-	//{
-	//}
-}

+ 5 - 5
UnitTests/View/DrawTests.cs

@@ -99,8 +99,8 @@ public class DrawTests {
 			Colors.Base.HotNormal
 		};
 
-		TestHelpers.AssertDriverColorsAre (@"
-0020000000
+		TestHelpers.AssertDriverAttributesAre (@"
+0010000000
 0000000000
 0111000000
 0000000000", Application.Driver, expectedColors);
@@ -148,8 +148,8 @@ public class DrawTests {
 			Colors.Base.HotNormal
 		};
 
-		TestHelpers.AssertDriverColorsAre (@"
-0022000000
+		TestHelpers.AssertDriverAttributesAre (@"
+0011000000
 0000000000
 0111000000
 0000000000", Application.Driver, expectedColors);
@@ -187,7 +187,7 @@ e
 s     
 t     ", _output);
 
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 000000
 0
 0

+ 3 - 664
UnitTests/View/FrameTests.cs

@@ -7,7 +7,7 @@ public class FrameTests {
 
 	public FrameTests (ITestOutputHelper output)
 	{
-		this._output = output;
+		_output = output;
 	}
 
 	// Test FrameToScreen
@@ -17,7 +17,7 @@ public class FrameTests {
 	[InlineData (0, 1, 0, 1)]
 	[InlineData (1, 1, 1, 1)]
 	[InlineData (10, 10, 10, 10)]
-	void FrameToScreen_NoSuperView (int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	public void FrameToScreen_NoSuperView (int frameX, int frameY, int expectedScreenX, int expectedScreenY)
 	{
 		var view = new View () {
 			X = frameX,
@@ -38,7 +38,7 @@ public class FrameTests {
 	[InlineData (1, 0, 1, 1, 2)]
 	[InlineData (1, 1, 1, 2, 2)]
 	[InlineData (1, 10, 10, 11, 11)]
-	void FrameToScreen_SuperView (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	public void FrameToScreen_SuperView (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
 	{
 		var super = new View() {
 			X = superOffset,
@@ -58,665 +58,4 @@ public class FrameTests {
 		var actual = view.FrameToScreen ();
 		Assert.Equal (expected, actual);
 	}
-
-	[Theory]
-	[InlineData (0, 0, 0, 1, 1)]
-	[InlineData (1, 0, 0, 2, 2)]
-	[InlineData (2, 0, 0, 3, 3)]
-	[InlineData (1, 1, 0, 3, 2)]
-	[InlineData (1, 0, 1, 2, 3)]
-	[InlineData (1, 1, 1, 3, 3)]
-	[InlineData (1, 10, 10, 12, 12)]
-	void FrameToScreen_SuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
-	{
-		var super = new View () {
-			X = superOffset,
-			Y = superOffset,
-			Width = 20,
-			Height = 20,
-			BorderStyle = LineStyle.Single
-		};
-
-		var view = new View () {
-			X = frameX,
-			Y = frameY,
-			Width = 10,
-			Height = 10
-		};
-		super.Add (view);
-		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
-		var actual = view.FrameToScreen ();
-		Assert.Equal (expected, actual);
-	}
-
-	[Theory]
-	[InlineData (0, 0, 0, 2, 2)]
-	[InlineData (1, 0, 0, 4, 4)]
-	[InlineData (2, 0, 0, 6, 6)]
-	[InlineData (1, 1, 0, 5, 4)]
-	[InlineData (1, 0, 1, 4, 5)]
-	[InlineData (1, 1, 1, 5, 5)]
-	[InlineData (1, 10, 10, 14, 14)]
-	void FrameToScreen_NestedSuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
-	{
-		var superSuper = new View () {
-			X = superOffset,
-			Y = superOffset,
-			Width = 30,
-			Height = 30,
-			BorderStyle = LineStyle.Single
-		};
-
-		var super = new View () {
-			X = superOffset,
-			Y = superOffset,
-			Width = 20,
-			Height = 20,
-			BorderStyle = LineStyle.Single
-		};
-		superSuper.Add (super);
-
-		var view = new View () {
-			X = frameX,
-			Y = frameY,
-			Width = 10,
-			Height = 10
-		};
-		super.Add (view);
-		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
-		var actual = view.FrameToScreen ();
-		Assert.Equal (expected, actual);
-	}
-
-
-	[Fact]
-	public void GetFramesThickness ()
-	{
-		var view = new View ();
-		Assert.Equal (Thickness.Empty, view.GetFramesThickness ());
-
-		view.Margin.Thickness = new Thickness (1);
-		Assert.Equal (new Thickness (1), view.GetFramesThickness ());
-
-		view.Border.Thickness = new Thickness (1);
-		Assert.Equal (new Thickness (2), view.GetFramesThickness ());
-
-		view.Padding.Thickness = new Thickness (1);
-		Assert.Equal (new Thickness (3), view.GetFramesThickness ());
-
-		view.Padding.Thickness = new Thickness (2);
-		Assert.Equal (new Thickness (4), view.GetFramesThickness ());
-
-		view.Padding.Thickness = new Thickness (1, 2, 3, 4);
-		Assert.Equal (new Thickness (3, 4, 5, 6), view.GetFramesThickness ());
-
-		view.Margin.Thickness = new Thickness (1, 2, 3, 4);
-		Assert.Equal (new Thickness (3, 5, 7, 9), view.GetFramesThickness ());
-		view.Dispose ();
-	}
-
-	[Theory, AutoInitShutdown]
-	[InlineData (0)]
-	[InlineData (1)]
-	[InlineData (2)]
-	[InlineData (3)]
-	public void Border_With_Title_Size_Height (int height)
-	{
-		var win = new Window () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill ()
-		};
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (20, height);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = string.Empty;
-
-		switch (height) {
-		case 0:
-			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-			expected = @"
-";
-			break;
-		case 1:
-			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-			expected = @"
-────────────────────";
-			break;
-		case 2:
-			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
-			expected = @"
-┌┤1234├────────────┐
-└──────────────────┘
-";
-			break;
-		case 3:
-			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
-			expected = @"
-┌┤1234├────────────┐
-│                  │
-└──────────────────┘
-";
-			break;
-		}
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
-
-	[Theory, AutoInitShutdown]
-	[InlineData (0)]
-	[InlineData (1)]
-	[InlineData (2)]
-	[InlineData (3)]
-	[InlineData (4)]
-	[InlineData (5)]
-	[InlineData (6)]
-	[InlineData (7)]
-	[InlineData (8)]
-	[InlineData (9)]
-	[InlineData (10)]
-	public void Border_With_Title_Size_Width (int width)
-	{
-		var win = new Window () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill ()
-		};
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (width, 3);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = string.Empty;
-
-		switch (width) {
-		case 1:
-			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-			expected = @"
-│
-│
-│";
-			break;
-		case 2:
-			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
-			expected = @"
-┌┐
-││
-└┘";
-			break;
-		case 3:
-			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
-			expected = @"
-┌─┐
-│ │
-└─┘
-";
-			break;
-		case 4:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤├┐
-│  │
-└──┘";
-			break;
-		case 5:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤1├┐
-│   │
-└───┘";
-			break;
-		case 6:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤12├┐
-│    │
-└────┘";
-			break;
-		case 7:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤123├┐
-│     │
-└─────┘";
-			break;
-		case 8:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤1234├┐
-│      │
-└──────┘";
-			break;
-		case 9:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤1234├─┐
-│       │
-└───────┘";
-			break;
-		case 10:
-			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-			expected = @"
-┌┤1234├──┐
-│        │
-└────────┘";
-			break;
-		}
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-	}
-
-	[Fact, AutoInitShutdown]
-	public void NoSuperView ()
-	{
-		var win = new Window () {
-			Width = Dim.Fill (),
-			Height = Dim.Fill ()
-		};
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (3, 3);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = @"
-┌─┐
-│ │
-└─┘";
-
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-	}
-
-	[Fact, AutoInitShutdown]
-	public void HasSuperView ()
-	{
-		Application.Top.BorderStyle = LineStyle.Double;
-
-		var frame = new FrameView () {
-			Width = Dim.Fill (),
-			Height = Dim.Fill ()
-		};
-
-		Application.Top.Add (frame);
-		var rs = Application.Begin (Application.Top);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (5, 5);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = @"
-╔═══╗
-║┌─┐║
-║│ │║
-║└─┘║
-╚═══╝";
-
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
-
-	[Fact, AutoInitShutdown]
-	public void HasSuperView_Title ()
-	{
-		Application.Top.BorderStyle = LineStyle.Double;
-
-		var frame = new FrameView () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill ()
-		};
-
-		Application.Top.Add (frame);
-		var rs = Application.Begin (Application.Top);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (10, 4);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = @"
-╔════════╗
-║┌┤1234├┐║
-║└──────┘║
-╚════════╝";
-
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
-
-	[Theory, AutoInitShutdown]
-	[InlineData (0)]
-	[InlineData (1)]
-	[InlineData (2)]
-	[InlineData (3)]
-	[InlineData (4)]
-	[InlineData (5)]
-	[InlineData (6)]
-	[InlineData (7)]
-	[InlineData (8)]
-	[InlineData (9)]
-	[InlineData (10)]
-	public void Border_With_Title_Border_Double_Thickness_Top_Two_Size_Width (int width)
-	{
-		var win = new Window () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill (),
-			BorderStyle = LineStyle.Double,
-		};
-		win.Border.Thickness.Top = 2;
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = string.Empty;
-
-		switch (width) {
-		case 1:
-			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
-			expected = @"
-║
-║
-║";
-			break;
-		case 2:
-			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
-			expected = @"
-╔╗
-║║
-╚╝";
-			break;
-		case 3:
-			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
-			expected = @"
-╔═╗
-║ ║
-╚═╝";
-			break;
-		case 4:
-			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
-			expected = @"
- ╒╕ 
-╔╛╘╗
-║  ║
-╚══╝";
-			break;
-		case 5:
-			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
-			expected = @"
- ╒═╕ 
-╔╛1╘╗
-║   ║
-╚═══╝";
-			break;
-		case 6:
-			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
-			expected = @"
- ╒══╕ 
-╔╛12╘╗
-║    ║
-╚════╝";
-			break;
-		case 7:
-			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
-			expected = @"
- ╒═══╕ 
-╔╛123╘╗
-║     ║
-╚═════╝";
-			break;
-		case 8:
-			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
-			expected = @"
- ╒════╕ 
-╔╛1234╘╗
-║      ║
-╚══════╝";
-			break;
-		case 9:
-			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
-			expected = @"
- ╒════╕  
-╔╛1234╘═╗
-║       ║
-╚═══════╝";
-			break;
-		case 10:
-			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
-			expected = @"
- ╒════╕   
-╔╛1234╘══╗
-║        ║
-╚════════╝";
-			break;
-		}
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
-
-	[Theory, AutoInitShutdown]
-	[InlineData (0)]
-	[InlineData (1)]
-	[InlineData (2)]
-	[InlineData (3)]
-	[InlineData (4)]
-	[InlineData (5)]
-	[InlineData (6)]
-	[InlineData (7)]
-	[InlineData (8)]
-	[InlineData (9)]
-	[InlineData (10)]
-	public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int width)
-	{
-		var win = new Window () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill (),
-			BorderStyle = LineStyle.Double,
-		};
-		win.Border.Thickness.Top = 3;
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = string.Empty;
-
-		switch (width) {
-		case 1:
-			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
-			expected = @"
-║
-║
-║";
-			break;
-		case 2:
-			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
-			expected = @"
-╔╗
-║║
-╚╝";
-			break;
-		case 3:
-			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
-			expected = @"
-╔═╗
-║ ║
-╚═╝";
-			break;
-		case 4:
-			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
-			expected = @"
- ╒╕ 
-╔╡╞╗
-║╘╛║
-╚══╝";
-			break;
-		case 5:
-			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
-			expected = @"
- ╒═╕ 
-╔╡1╞╗
-║╘═╛║
-╚═══╝";
-			break;
-		case 6:
-			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
-			expected = @"
- ╒══╕ 
-╔╡12╞╗
-║╘══╛║
-╚════╝";
-			break;
-		case 7:
-			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
-			expected = @"
- ╒═══╕ 
-╔╡123╞╗
-║╘═══╛║
-╚═════╝";
-			break;
-		case 8:
-			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
-			expected = @"
- ╒════╕ 
-╔╡1234╞╗
-║╘════╛║
-╚══════╝";
-			break;
-		case 9:
-			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
-			expected = @"
- ╒════╕  
-╔╡1234╞═╗
-║╘════╛ ║
-╚═══════╝";
-			break;
-		case 10:
-			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
-			expected = @"
- ╒════╕   
-╔╡1234╞══╗
-║╘════╛  ║
-╚════════╝";
-			break;
-		}
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
-
-	[Theory, AutoInitShutdown]
-	[InlineData (0)]
-	[InlineData (1)]
-	[InlineData (2)]
-	[InlineData (3)]
-	[InlineData (4)]
-	[InlineData (5)]
-	[InlineData (6)]
-	[InlineData (7)]
-	[InlineData (8)]
-	[InlineData (9)]
-	[InlineData (10)]
-	public void Border_With_Title_Border_Double_Thickness_Top_Four_Size_Width (int width)
-	{
-		var win = new Window () {
-			Title = "1234",
-			Width = Dim.Fill (),
-			Height = Dim.Fill (),
-			BorderStyle = LineStyle.Double,
-		};
-		win.Border.Thickness.Top = 4;
-
-		var rs = Application.Begin (win);
-		bool firstIteration = false;
-
-		((FakeDriver)Application.Driver).SetBufferSize (width, 5);
-		Application.RunIteration (ref rs, ref firstIteration);
-		var expected = string.Empty;
-
-		switch (width) {
-		case 1:
-			Assert.Equal (new Rect (0, 0, 1, 5), win.Frame);
-			expected = @"
-║
-║
-║";
-			break;
-		case 2:
-			Assert.Equal (new Rect (0, 0, 2, 5), win.Frame);
-			expected = @"
-╔╗
-║║
-╚╝";
-			break;
-		case 3:
-			Assert.Equal (new Rect (0, 0, 3, 5), win.Frame);
-			expected = @"
-╔═╗
-║ ║
-╚═╝";
-			break;
-		case 4:
-			Assert.Equal (new Rect (0, 0, 4, 5), win.Frame);
-			expected = @"
- ╒╕ 
-╔╡╞╗
-║╘╛║
-╚══╝";
-			break;
-		case 5:
-			Assert.Equal (new Rect (0, 0, 5, 5), win.Frame);
-			expected = @"
- ╒═╕ 
-╔╡1╞╗
-║╘═╛║
-╚═══╝";
-			break;
-		case 6:
-			Assert.Equal (new Rect (0, 0, 6, 5), win.Frame);
-			expected = @"
- ╒══╕ 
-╔╡12╞╗
-║╘══╛║
-╚════╝";
-			break;
-		case 7:
-			Assert.Equal (new Rect (0, 0, 7, 5), win.Frame);
-			expected = @"
- ╒═══╕ 
-╔╡123╞╗
-║╘═══╛║
-╚═════╝";
-			break;
-		case 8:
-			Assert.Equal (new Rect (0, 0, 8, 5), win.Frame);
-			expected = @"
- ╒════╕ 
-╔╡1234╞╗
-║╘════╛║
-╚══════╝";
-			break;
-		case 9:
-			Assert.Equal (new Rect (0, 0, 9, 5), win.Frame);
-			expected = @"
- ╒════╕  
-╔╡1234╞═╗
-║╘════╛ ║
-╚═══════╝";
-			break;
-		case 10:
-			Assert.Equal (new Rect (0, 0, 10, 5), win.Frame);
-			expected = @"
- ╒════╕   
-╔╡1234╞══╗
-║╘════╛  ║
-╚════════╝";
-			break;
-		}
-		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
-		Application.End (rs);
-	}
 }

+ 2 - 2
UnitTests/View/Text/AutoSizeTextTests.cs

@@ -2513,7 +2513,7 @@ Y
 		Application.End (rs);
 	}
 
-	[Theory] [AutoInitShutdown]
+	[Theory, AutoInitShutdown]
 	[InlineData (true)]
 	[InlineData (false)]
 	public void View_Draw_Horizontal_Simple_TextAlignments (bool autoSize)
@@ -2568,7 +2568,7 @@ Y
 		Assert.Equal (new Rect (0, 0, width + 2, 6), pos);
 	}
 
-	[Theory] [AutoInitShutdown]
+	[Theory, AutoInitShutdown]
 	[InlineData (true)]
 	[InlineData (false)]
 	public void View_Draw_Vertical_Simple_TextAlignments (bool autoSize)

+ 4 - 4
UnitTests/View/ViewTests.cs

@@ -862,7 +862,7 @@ public class ViewTests {
 		view.Dispose ();
 	}
 
-	[Theory] [AutoInitShutdown]
+	[Theory, AutoInitShutdown]
 	[InlineData (true)]
 	[InlineData (false)]
 	public void Clear_Does_Not_Spillover_Its_Parent (bool label)
@@ -903,11 +903,11 @@ cccccccccccccccccccc", output);
 						Colors.Base.Focus
 					};
 		if (label) {
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 111111111111111111110
 111111111111111111110", Application.Driver, attributes);
 		} else {
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 222222222222222222220
 111111111111111111110", Application.Driver, attributes);
 		}
@@ -919,7 +919,7 @@ cccccccccccccccccccc", output);
 			v.SetFocus ();
 			Assert.True (v.HasFocus);
 			Application.Refresh ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 222222222222222222220
 111111111111111111110", Application.Driver, attributes);
 		}

+ 0 - 1
UnitTests/Views/AllViewsTests.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Terminal.Gui.Views;
 using Xunit;
 using Xunit.Abstractions;
 

+ 6 - 6
UnitTests/Views/ComboBoxTests.cs

@@ -839,7 +839,7 @@ Three ", output);
 				cb.Subviews [1].GetNormalColor ()
 			};
 
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 222222
 222222
@@ -851,7 +851,7 @@ Three ", output);
 			Assert.Equal (-1, cb.SelectedItem);
 			Assert.Equal ("", cb.Text);
 			cb.Draw ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 222222
 000002
@@ -863,7 +863,7 @@ Three ", output);
 			Assert.Equal (-1, cb.SelectedItem);
 			Assert.Equal ("", cb.Text);
 			cb.Draw ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 222222
 222222
@@ -881,7 +881,7 @@ Three ", output);
 			Assert.Equal (2, cb.SelectedItem);
 			Assert.Equal ("Three", cb.Text);
 			cb.Draw ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 222222
 222222
@@ -893,7 +893,7 @@ Three ", output);
 			Assert.Equal (2, cb.SelectedItem);
 			Assert.Equal ("Three", cb.Text);
 			cb.Draw ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 222222
 000002
@@ -905,7 +905,7 @@ Three ", output);
 			Assert.Equal (2, cb.SelectedItem);
 			Assert.Equal ("Three", cb.Text);
 			cb.Draw ();
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 000000
 000002
 222222

+ 1 - 1
UnitTests/Views/DatePickerTests.cs

@@ -1,6 +1,6 @@
 using System;
 using System.Globalization;
-using Terminal.Gui.Views;
+using Terminal.Gui;
 using Xunit;
 
 namespace Terminal.Gui.ViewsTests;

+ 4 - 4
UnitTests/Views/MenuBarTests.cs

@@ -1539,7 +1539,7 @@ Edit
 			menu.ColorScheme.Disabled
 		};
 
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 00000000000000", Application.Driver, attributes);
 
 		Assert.True (menu.MouseEvent (new MouseEvent {
@@ -1549,7 +1549,7 @@ Edit
 			View = menu
 		}));
 		top.Draw ();
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 11111100000000
 00000000000000
 01111111111110
@@ -1565,7 +1565,7 @@ Edit
 			View = top.Subviews [1]
 		}));
 		top.Subviews [1].Draw ();
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 11111100000000
 00000000000000
 01111111111110
@@ -1581,7 +1581,7 @@ Edit
 			View = top.Subviews [1]
 		}));
 		top.Subviews [1].Draw ();
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 11111100000000
 00000000000000
 01111111111110

+ 2 - 2
UnitTests/Views/OverlappedTests.cs

@@ -708,7 +708,7 @@ public class OverlappedTests {
 			// 1
 			Colors.Base.Normal
 		};
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 0000000000
 0111110000
 0111110000
@@ -732,7 +732,7 @@ public class OverlappedTests {
   │   │
   │   │
   └───┘", _output);
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 0000000000
 0000000000
 0011111000

+ 4 - 4
UnitTests/Views/RuneCellTests.cs

@@ -119,12 +119,12 @@ Error   ";
 2222220000
 3333000000
 4444400000";
-			TestHelpers.AssertDriverColorsAre (expectedColor, driver: Application.Driver, attributes);
+			TestHelpers.AssertDriverAttributesAre (expectedColor, driver: Application.Driver, attributes);
 
 			tv.WordWrap = true;
 			Application.Refresh ();
 			TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
-			TestHelpers.AssertDriverColorsAre (expectedColor, driver: Application.Driver, attributes);
+			TestHelpers.AssertDriverAttributesAre (expectedColor, driver: Application.Driver, attributes);
 
 			tv.CursorPosition = new Point (6, 2);
 			tv.SelectionStartColumn = 0;
@@ -152,7 +152,7 @@ Dialogror ";
 4444444444
 4444000000
 4444444440";
-			TestHelpers.AssertDriverColorsAre (expectedColor, driver: Application.Driver, attributes);
+			TestHelpers.AssertDriverAttributesAre (expectedColor, driver: Application.Driver, attributes);
 
 			tv.Undo ();
 			tv.CursorPosition = new Point (0, 3);
@@ -183,7 +183,7 @@ ror       ";
 4444000000
 4444440000
 4440000000";
-			TestHelpers.AssertDriverColorsAre (expectedColor, driver: Application.Driver, attributes);
+			TestHelpers.AssertDriverAttributesAre (expectedColor, driver: Application.Driver, attributes);
 
 			Application.End (rs);
 		}

+ 5 - 5
UnitTests/Views/ScrollViewTests.cs

@@ -445,7 +445,7 @@ namespace Terminal.Gui.ViewsTests {
 
 			public override bool OnEnter (View view)
 			{
-				Border.BorderStyle = LineStyle.None;
+				Border.LineStyle = LineStyle.None;
 				Border.Thickness = new Thickness (0);
 				labelFill.Visible = true;
 				view = this;
@@ -454,7 +454,7 @@ namespace Terminal.Gui.ViewsTests {
 
 			public override bool OnLeave (View view)
 			{
-				Border.BorderStyle = LineStyle.Single;
+				Border.LineStyle = LineStyle.Single;
 				Border.Thickness = new Thickness (1);
 				labelFill.Visible = false;
 				if (view == null)
@@ -503,7 +503,7 @@ namespace Terminal.Gui.ViewsTests {
 						Colors.Base.Normal
 					};
 
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 00000000000000000000000
 00000000000000000000000
 00000000000000000000000
@@ -542,7 +542,7 @@ namespace Terminal.Gui.ViewsTests {
                        
                At 15,15", output);
 
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 00000000000000000000000
 00000000000000000000000
 00000000000000000000000
@@ -580,7 +580,7 @@ namespace Terminal.Gui.ViewsTests {
                        
                At 15,15", output);
 
-			TestHelpers.AssertDriverColorsAre (@"
+			TestHelpers.AssertDriverAttributesAre (@"
 00000000000000000000000
 00000000000000000000000
 00000000000000000000000

+ 10 - 10
UnitTests/Views/TableViewTests.cs

@@ -836,7 +836,7 @@ namespace Terminal.Gui.ViewsTests {
 01000
 ";
 
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,				
 				// 1
@@ -883,7 +883,7 @@ namespace Terminal.Gui.ViewsTests {
 			var invertFocus = new Attribute (tv.ColorScheme.Focus.Background, tv.ColorScheme.Focus.Foreground);
 			var invertHotNormal = new Attribute (tv.ColorScheme.HotNormal.Background, tv.ColorScheme.HotNormal.Foreground);
 
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,				
 				// 1
@@ -938,7 +938,7 @@ namespace Terminal.Gui.ViewsTests {
 21222
 ";
 
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,				
 				// 1
@@ -971,7 +971,7 @@ namespace Terminal.Gui.ViewsTests {
 			// now we only see 2 colors used (the selected cell color and Normal
 			// rowHighlight should no longer be used because the delegate returned null
 			// (now that the cell value is 5 - which does not match the conditional)
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,
 				// 1
@@ -1030,7 +1030,7 @@ namespace Terminal.Gui.ViewsTests {
 01020
 ";
 
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,				
 				// 1
@@ -1063,7 +1063,7 @@ namespace Terminal.Gui.ViewsTests {
 			// now we only see 2 colors used (the selected cell color and Normal
 			// cellHighlight should no longer be used because the delegate returned null
 			// (now that the cell value is 5 - which does not match the conditional)
-			TestHelpers.AssertDriverColorsAre (expectedColors, driver: Application.Driver, new Attribute [] {
+			TestHelpers.AssertDriverAttributesAre (expectedColors, driver: Application.Driver, new Attribute [] {
 				// 0
 				tv.ColorScheme.Normal,				
 				// 1
@@ -2112,7 +2112,7 @@ namespace Terminal.Gui.ViewsTests {
 00000000000000000000
 01111101101111111110
 ";
-			TestHelpers.AssertDriverColorsAre (expected, driver: Application.Driver, new Attribute [] { tv.ColorScheme.Normal, color });
+			TestHelpers.AssertDriverAttributesAre (expected, driver: Application.Driver, new Attribute [] { tv.ColorScheme.Normal, color });
 
 		}
 
@@ -2232,7 +2232,7 @@ namespace Terminal.Gui.ViewsTests {
 0111110
 0000000";
 
-			TestHelpers.AssertDriverColorsAre (expected, driver: Application.Driver, normal, focus);
+			TestHelpers.AssertDriverAttributesAre (expected, driver: Application.Driver, normal, focus);
 		}
 
 		[Fact, AutoInitShutdown]
@@ -2289,7 +2289,7 @@ namespace Terminal.Gui.ViewsTests {
 0101010
 0000000";
 
-			TestHelpers.AssertDriverColorsAre (expected, driver: Application.Driver, normal, focus);
+			TestHelpers.AssertDriverAttributesAre (expected, driver: Application.Driver, normal, focus);
 		}
 
 		[Fact, AutoInitShutdown]
@@ -2784,7 +2784,7 @@ A B C
 000000
 111111";
 
-			TestHelpers.AssertDriverColorsAre (expected, driver: Application.Driver, normal, focus);
+			TestHelpers.AssertDriverAttributesAre (expected, driver: Application.Driver, normal, focus);
 		}
 
 		public static DataTableSource BuildTable (int cols, int rows)

+ 2 - 2
UnitTests/Views/TextFieldTests.cs

@@ -59,14 +59,14 @@ public class TextFieldTests {
 			};
 
 		//                                             TAB to jump between text fields.
-		TestHelpers.AssertDriverColorsAre ("0000000", driver: Application.Driver, attributes);
+		TestHelpers.AssertDriverAttributesAre ("0000000", driver: Application.Driver, attributes);
 		_textField.NewKeyDownEvent (new (KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask));
 
 		bool first = true;
 		Application.RunIteration (ref rs, ref first);
 		Assert.Equal (4, _textField.CursorPosition);
 		//                                             TAB to jump between text fields.
-		TestHelpers.AssertDriverColorsAre ("1111000", driver: Application.Driver, attributes);
+		TestHelpers.AssertDriverAttributesAre ("1111000", driver: Application.Driver, attributes);
 	}
 
 	[Fact]

+ 2 - 2
UnitTests/Views/TextViewTests.cs

@@ -293,7 +293,7 @@ public class TextViewTests {
 			};
 
 		//                                             TAB to jump between text fields.
-		TestHelpers.AssertDriverColorsAre ("0000000", driver: Application.Driver, attributes);
+		TestHelpers.AssertDriverAttributesAre ("0000000", driver: Application.Driver, attributes);
 
 		_textView.NewKeyDownEvent (new (KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask));
 
@@ -301,7 +301,7 @@ public class TextViewTests {
 		Application.RunIteration (ref rs, ref first);
 		Assert.Equal (new Point (4, 0), _textView.CursorPosition);
 		//                                             TAB to jump between text fields.
-		TestHelpers.AssertDriverColorsAre ("1111000", driver: Application.Driver, attributes);
+		TestHelpers.AssertDriverAttributesAre ("1111000", driver: Application.Driver, attributes);
 	}
 
 	[Fact]

+ 2 - 2
UnitTests/Views/TreeViewTests.cs

@@ -840,7 +840,7 @@ public class TreeViewTests {
 └─pink
 ", _output);
 		// Should all be the same color
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 0000000000
 0000000000
 0000000000
@@ -869,7 +869,7 @@ public class TreeViewTests {
 ", _output);
 		// but now the item (only not lines) appear
 		// in pink when they are the word "pink"
-		TestHelpers.AssertDriverColorsAre (@"
+		TestHelpers.AssertDriverAttributesAre (@"
 00000000
 00001111
 0000000000