Преглед изворни кода

Added some more features and bug fixes.

BDisp пре 3 година
родитељ
комит
e02df8c043

+ 1 - 0
Terminal.Gui/Core/Border.cs

@@ -165,6 +165,7 @@ namespace Terminal.Gui {
 			{
 				ColorScheme = Colors.TopLevel;
 				Text = title ?? "";
+				Frame = frame;
 				if (border == null) {
 					Border = new Border () {
 						BorderStyle = BorderStyle.Single,

+ 34 - 18
Terminal.Gui/Core/TextFormatter.cs

@@ -136,7 +136,7 @@ namespace Terminal.Gui {
 			set {
 				text = value;
 
-				if (text.RuneCount > 0 && (Size.Width == 0 || Size.Height == 0 || Size.Width != text.ConsoleWidth)) {
+				if (text != null && text.RuneCount > 0 && (Size.Width == 0 || Size.Height == 0 || Size.Width != text.ConsoleWidth)) {
 					// Provide a default size (width = length of longest line, height = 1)
 					// TODO: It might makes more sense for the default to be width = length of first line?
 					Size = new Size (TextFormatter.MaxWidth (Text, int.MaxValue), 1);
@@ -154,9 +154,15 @@ namespace Terminal.Gui {
 		/// </summary>
 		public bool AutoSize { get; set; }
 
+		/// <summary>
+		/// Get or sets a flag if the wrapped text will keep the trailing spaces or
+		/// the trailing spaces will be trimmed (default).
+		/// </summary>
+		public bool PreserveTrailingSpaces { get; set; }
+
 		// TODO: Add Vertical Text Alignment
 		/// <summary>
-		/// Controls the horizontal text-alignment property. 
+		/// Controls the horizontal text-alignment property.
 		/// </summary>
 		/// <value>The text alignment.</value>
 		public TextAlignment Alignment {
@@ -327,18 +333,16 @@ namespace Terminal.Gui {
 					if (IsVerticalDirection (textDirection)) {
 						var colsWidth = GetSumMaxCharWidth (shown_text, 0, 1);
 						lines = Format (shown_text, Size.Height, textVerticalAlignment == VerticalTextAlignment.Justified, Size.Width > colsWidth,
-							false, 0, textDirection);
+							PreserveTrailingSpaces, 0, textDirection);
 						if (!AutoSize) {
 							colsWidth = GetMaxColsForWidth (lines, Size.Width);
 							if (lines.Count > colsWidth) {
-								for (int i = colsWidth; i < lines.Count; i++) {
-									lines.Remove (lines [i]);
-								}
+								lines.RemoveRange (colsWidth, lines.Count - colsWidth);
 							}
 						}
 					} else {
 						lines = Format (shown_text, Size.Width, textAlignment == TextAlignment.Justified, Size.Height > 1,
-							false, 0, textDirection);
+							PreserveTrailingSpaces, 0, textDirection);
 						if (!AutoSize && lines.Count > Size.Height) {
 							lines.RemoveRange (Size.Height, lines.Count - Size.Height);
 						}
@@ -468,7 +472,7 @@ namespace Terminal.Gui {
 			var runes = StripCRLF (text).ToRuneList ();
 			if (!preserveTrailingSpaces) {
 				if (IsHorizontalDirection (textDirection)) {
-					while ((end = start + GetMaxLengthForWidth (runes.GetRange (start, runes.Count - start), width)) < runes.Count) {
+					while ((end = start + Math.Max (GetMaxLengthForWidth (runes.GetRange (start, runes.Count - start), width), 1)) < runes.Count) {
 						while (runes [end] != ' ' && end > start)
 							end--;
 						if (end == start)
@@ -494,16 +498,25 @@ namespace Terminal.Gui {
 				}
 			} else {
 				while ((end = start) < runes.Count) {
-					end = GetNextWhiteSpace (start, width);
+					end = GetNextWhiteSpace (start, width, out bool incomplete);
+					if (end == 0 && incomplete) {
+						start = text.RuneCount;
+						break;
+					}
 					lines.Add (ustring.Make (runes.GetRange (start, end - start)));
 					start = end;
+					if (incomplete) {
+						start = text.RuneCount;
+						break;
+					}
 				}
 			}
 
-			int GetNextWhiteSpace (int from, int cWidth, int cLength = 0)
+			int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = 0)
 			{
 				var to = from;
 				var length = cLength;
+				incomplete = false;
 
 				while (length < cWidth && to < runes.Count) {
 					var rune = runes [to];
@@ -512,13 +525,19 @@ namespace Terminal.Gui {
 					} else {
 						length++;
 					}
+					if (length > cWidth) {
+						if (to >= runes.Count || (length > 1 && cWidth <= 1)) {
+							incomplete = true;
+						}
+						return to;
+					}
 					if (rune == ' ') {
 						if (length == cWidth) {
 							return to + 1;
 						} else if (length > cWidth) {
 							return to;
 						} else {
-							return GetNextWhiteSpace (to + 1, cWidth, length);
+							return GetNextWhiteSpace (to + 1, cWidth, out incomplete, length);
 						}
 					} else if (rune == '\t') {
 						length += tabWidth + 1;
@@ -527,7 +546,7 @@ namespace Terminal.Gui {
 						} else if (length > cWidth && tabWidth > cWidth) {
 							return to;
 						} else {
-							return GetNextWhiteSpace (to + 1, cWidth, length);
+							return GetNextWhiteSpace (to + 1, cWidth, out incomplete, length);
 						}
 					}
 					to++;
@@ -694,9 +713,6 @@ namespace Terminal.Gui {
 			if (width < 0) {
 				throw new ArgumentOutOfRangeException ("width cannot be negative");
 			}
-			if (preserveTrailingSpaces && !wordWrap) {
-				throw new ArgumentException ("if 'preserveTrailingSpaces' is true, then 'wordWrap' must be true either.");
-			}
 			List<ustring> lineResult = new List<ustring> ();
 
 			if (ustring.IsNullOrEmpty (text) || width == 0) {
@@ -1093,10 +1109,10 @@ namespace Terminal.Gui {
 				break;
 			}
 
-			for (int line = 0; line < linesFormated.Count; line++) {
-				var isVertical = IsVerticalDirection (textDirection);
+			var isVertical = IsVerticalDirection (textDirection);
 
-				if ((isVertical && (line > bounds.Width)) || (!isVertical && (line > bounds.Height)))
+			for (int line = 0; line < linesFormated.Count; line++) {
+				if ((isVertical && line > bounds.Width) || (!isVertical && line > bounds.Height))
 					continue;
 
 				var runes = lines [line].ToRunes ();

+ 267 - 151
Terminal.Gui/Core/View.cs

@@ -181,15 +181,28 @@ namespace Terminal.Gui {
 		/// </summary>
 		public event Action<Key> HotKeyChanged;
 
+		Key hotKey = Key.Null;
+
 		/// <summary>
 		/// Gets or sets the HotKey defined for this view. A user pressing HotKey on the keyboard while this view has focus will cause the Clicked event to fire.
 		/// </summary>
-		public virtual Key HotKey { get => TextFormatter.HotKey; set => TextFormatter.HotKey = value; }
+		public virtual Key HotKey {
+			get => hotKey;
+			set {
+				hotKey = TextFormatter.HotKey = value;
+			}
+		}
 
 		/// <summary>
 		/// Gets or sets the specifier character for the hotkey (e.g. '_'). Set to '\xffff' to disable hotkey support for this View instance. The default is '\xffff'. 
 		/// </summary>
-		public virtual Rune HotKeySpecifier { get => TextFormatter.HotKeySpecifier; set => TextFormatter.HotKeySpecifier = value; }
+		public virtual Rune HotKeySpecifier {
+			get => TextFormatter.HotKeySpecifier;
+			set {
+				TextFormatter.HotKeySpecifier = value;
+				SetHotKey ();
+			}
+		}
 
 		/// <summary>
 		/// This is the global setting that can be used as a global shortcut to invoke an action if provided.
@@ -445,8 +458,8 @@ namespace Terminal.Gui {
 					SuperView.SetNeedsDisplay (frame);
 					SuperView.SetNeedsDisplay (value);
 				}
-				frame = value;
-
+				frame = new Rect (value.X, value.Y, Math.Max (value.Width, 0), Math.Max (value.Height, 0));
+				TextFormatter.Size = GetBoundsTextFormatterSize ();
 				SetNeedsLayout ();
 				SetNeedsDisplay (frame);
 			}
@@ -513,17 +526,13 @@ namespace Terminal.Gui {
 		public Pos X {
 			get => x;
 			set {
-				if (!ValidatePosDim (x, value)) {
+				if (ForceValidatePosDim && !ValidatePosDim (x, value)) {
 					throw new ArgumentException ();
 				}
 
 				x = value;
-				SetNeedsLayout ();
-				if (x is Pos.PosAbsolute) {
-					frame = new Rect (x.Anchor (0), frame.Y, frame.Width, frame.Height);
-				}
-				TextFormatter.Size = GetBoundsTextFormatterSize ();
-				SetNeedsDisplay (frame);
+
+				ProcessResizeView ();
 			}
 		}
 
@@ -537,20 +546,15 @@ namespace Terminal.Gui {
 		public Pos Y {
 			get => y;
 			set {
-				if (!ValidatePosDim (y, value)) {
+				if (ForceValidatePosDim && !ValidatePosDim (y, value)) {
 					throw new ArgumentException ();
 				}
 
 				y = value;
-				SetNeedsLayout ();
-				if (y is Pos.PosAbsolute) {
-					frame = new Rect (frame.X, y.Anchor (0), frame.Width, frame.Height);
-				}
-				TextFormatter.Size = GetBoundsTextFormatterSize ();
-				SetNeedsDisplay (frame);
+
+				ProcessResizeView ();
 			}
 		}
-
 		Dim width, height;
 
 		/// <summary>
@@ -563,24 +567,20 @@ namespace Terminal.Gui {
 		public Dim Width {
 			get => width;
 			set {
-				if (!ValidatePosDim (width, value)) {
-					throw new ArgumentException ();
+				if (ForceValidatePosDim && !ValidatePosDim (width, value)) {
+					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Width));
 				}
 
 				width = value;
 
-				var isValidNewAutSize = autoSize ? IsValidAutoSizeWidth (width) : false;
+				if (ForceValidatePosDim) {
+					var isValidNewAutSize = autoSize && IsValidAutoSizeWidth (width);
 
-				if (IsInitialized && autoSize && !isValidNewAutSize) {
-					throw new InvalidOperationException ("Must set AutoSize to false before set the Width.");
-				}
-				SetMinWidthHeight ();
-				SetNeedsLayout ();
-				if (width is Dim.DimAbsolute) {
-					frame = new Rect (frame.X, frame.Y, width.Anchor (0), frame.Height);
+					if (IsAdded && autoSize && !isValidNewAutSize) {
+						throw new InvalidOperationException ("Must set AutoSize to false before set the Width.");
+					}
 				}
-				TextFormatter.Size = GetBoundsTextFormatterSize ();
-				SetNeedsDisplay (frame);
+				ProcessResizeView ();
 			}
 		}
 
@@ -592,27 +592,29 @@ namespace Terminal.Gui {
 		public Dim Height {
 			get => height;
 			set {
-				if (!ValidatePosDim (height, value)) {
-					throw new ArgumentException ();
+				if (ForceValidatePosDim && !ValidatePosDim (height, value)) {
+					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Height));
 				}
 
 				height = value;
 
-				var isValidNewAutSize = autoSize ? IsValidAutoSizeHeight (height) : false;
+				if (ForceValidatePosDim) {
+					var isValidNewAutSize = autoSize && IsValidAutoSizeHeight (height);
 
-				if (IsInitialized && autoSize && !isValidNewAutSize) {
-					throw new InvalidOperationException ("Must set AutoSize to false before set the Height.");
-				}
-				SetMinWidthHeight ();
-				SetNeedsLayout ();
-				if (height is Dim.DimAbsolute) {
-					frame = new Rect (frame.X, frame.Y, frame.Width, height.Anchor (0));
+					if (IsAdded && autoSize && !isValidNewAutSize) {
+						throw new InvalidOperationException ("Must set AutoSize to false before set the Height.");
+					}
 				}
-				TextFormatter.Size = GetBoundsTextFormatterSize ();
-				SetNeedsDisplay (frame);
+				ProcessResizeView ();
 			}
 		}
 
+		/// <summary>
+		/// Forces validation with <see cref="LayoutStyle.Computed"/> layout
+		///  to avoid breaking the <see cref="Pos"/> and <see cref="Dim"/> settings.
+		/// </summary>
+		public bool ForceValidatePosDim { get; set; }
+
 		bool ValidatePosDim (object oldvalue, object newValue)
 		{
 			if (!IsInitialized || layoutStyle == LayoutStyle.Absolute || oldvalue == null || oldvalue.GetType () == newValue.GetType () || this is Toplevel) {
@@ -626,27 +628,48 @@ namespace Terminal.Gui {
 			return false;
 		}
 
-		void SetMinWidthHeight ()
+		/// <summary>
+		/// Verifies if the minimum width or height can be sets in the view.
+		/// </summary>
+		/// <param name="size">The size.</param>
+		/// <returns><see langword="true"/> if the size can be set, <see langword="false"/>otherwise.</returns>
+		public bool GetMinWidthHeight (out Size size)
 		{
+			size = Size.Empty;
+
 			if (!AutoSize && !ustring.IsNullOrEmpty (TextFormatter.Text)) {
 				switch (TextFormatter.IsVerticalDirection (TextDirection)) {
 				case true:
 					var colWidth = TextFormatter.GetSumMaxCharWidth (new List<ustring> { TextFormatter.Text }, 0, 1);
-					if (Width == null || (Width is Dim.DimAbsolute && Width.Anchor (0) < colWidth)) {
-						width = colWidth;
-						Bounds = new Rect (Bounds.X, Bounds.Y, colWidth, Bounds.Height);
-						TextFormatter.Size = GetBoundsTextFormatterSize ();
+					if (frame.Width < colWidth && (Width == null || (Bounds.Width >= 0 && Width is Dim.DimAbsolute
+						&& Width.Anchor (0) >= 0 && Width.Anchor (0) < colWidth))) {
+						size = new Size (colWidth, Bounds.Height);
+						return true;
 					}
 					break;
 				default:
-					if (Height == null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0)) {
-						height = 1;
-						Bounds = new Rect (Bounds.X, Bounds.Y, Bounds.Width, 1);
-						TextFormatter.Size = GetBoundsTextFormatterSize ();
+					if (frame.Height < 1 && (Height == null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0))) {
+						size = new Size (Bounds.Width, 1);
+						return true;
 					}
 					break;
 				}
 			}
+			return false;
+		}
+
+		/// <summary>
+		/// Sets the minimum width or height if the view can be resized.
+		/// </summary>
+		/// <returns><see langword="true"/> if the size can be set, <see langword="false"/>otherwise.</returns>
+		public bool SetMinWidthHeight ()
+		{
+			if (GetMinWidthHeight (out Size size)) {
+				Bounds = new Rect (Bounds.Location, size);
+				TextFormatter.Size = GetBoundsTextFormatterSize ();
+				return true;
+			}
+			return false;
 		}
 
 		/// <summary>
@@ -755,7 +778,7 @@ namespace Terminal.Gui {
 		}
 
 		void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed,
-			TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null)
+		    TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null)
 		{
 			TextFormatter = new TextFormatter ();
 			TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged;
@@ -776,14 +799,45 @@ namespace Terminal.Gui {
 			} else {
 				r = rect;
 			}
-			x = Pos.At (r.X);
-			y = Pos.At (r.Y);
-			Width = r.Width;
-			Height = r.Height;
-
 			Frame = r;
 
 			Text = text;
+			UpdateTextFormatterText ();
+			ProcessResizeView ();
+		}
+
+		/// <summary>
+		/// Can be overridden if the <see cref="TextFormatter.Text"/> has
+		///  different format than the default.
+		/// </summary>
+		protected virtual void UpdateTextFormatterText ()
+		{
+			TextFormatter.Text = text;
+		}
+
+		/// <summary>
+		/// Can be overridden if the view resize behavior is
+		///  different than the default.
+		/// </summary>
+		protected virtual void ProcessResizeView ()
+		{
+			var _x = x is Pos.PosAbsolute ? x.Anchor (0) : frame.X;
+			var _y = y is Pos.PosAbsolute ? y.Anchor (0) : frame.Y;
+
+			if (AutoSize) {
+				var s = CalculateAutoSize ();
+				var w = width is Dim.DimAbsolute && width.Anchor (0) > s.Width ? width.Anchor (0) : s.Width;
+				var h = height is Dim.DimAbsolute && height.Anchor (0) > s.Height ? height.Anchor (0) : s.Height;
+				frame = new Rect (new Point (_x, _y), new Size (w, h));
+			} else {
+				var w = width is Dim.DimAbsolute ? width.Anchor (0) : frame.Width;
+				var h = height is Dim.DimAbsolute ? height.Anchor (0) : frame.Height;
+				frame = new Rect (new Point (_x, _y), new Size (w, h));
+				SetMinWidthHeight ();
+			}
+			TextFormatter.Size = GetBoundsTextFormatterSize ();
+			SetNeedsLayout ();
+			SetNeedsDisplay ();
 		}
 
 		private void TextFormatter_HotKeyChanged (Key obj)
@@ -1310,6 +1364,12 @@ namespace Terminal.Gui {
 		/// <param name="view">The subview being added.</param>
 		public virtual void OnAdded (View view)
 		{
+			view.IsAdded = true;
+			view.x = view.x ?? view.frame.X;
+			view.y = view.y ?? view.frame.Y;
+			view.width = view.width ?? view.frame.Width;
+			view.height = view.height ?? view.frame.Height;
+
 			view.Added?.Invoke (this);
 		}
 
@@ -1319,6 +1379,7 @@ namespace Terminal.Gui {
 		/// <param name="view">The subview being removed.</param>
 		public virtual void OnRemoved (View view)
 		{
+			view.IsAdded = false;
 			view.Removed?.Invoke (this);
 		}
 
@@ -1460,8 +1521,8 @@ namespace Terminal.Gui {
 				containerBounds.Width = Math.Min (containerBounds.Width, Driver.Clip.Width);
 				containerBounds.Height = Math.Min (containerBounds.Height, Driver.Clip.Height);
 				TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
-					HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
-					containerBounds);
+				    HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
+				    containerBounds);
 			}
 
 			// Invoke DrawContentEvent
@@ -2052,47 +2113,64 @@ namespace Terminal.Gui {
 		internal void SetRelativeLayout (Rect hostFrame)
 		{
 			int w, h, _x, _y;
+			var s = Size.Empty;
+
+			if (AutoSize) {
+				s = CalculateAutoSize ();
+			}
 
 			if (x is Pos.PosCenter) {
-				if (width == null)
-					w = hostFrame.Width;
-				else
+				if (width == null) {
+					w = AutoSize ? s.Width : hostFrame.Width;
+				} else {
 					w = width.Anchor (hostFrame.Width);
+					w = AutoSize && s.Width > w ? s.Width : w;
+				}
 				_x = x.Anchor (hostFrame.Width - w);
 			} else {
 				if (x == null)
 					_x = 0;
 				else
 					_x = x.Anchor (hostFrame.Width);
-				if (width == null)
-					w = hostFrame.Width;
-				else if (width is Dim.DimFactor && !((Dim.DimFactor)width).IsFromRemaining ())
+				if (width == null) {
+					w = AutoSize ? s.Width : hostFrame.Width;
+				} else if (width is Dim.DimFactor && !((Dim.DimFactor)width).IsFromRemaining ()) {
 					w = width.Anchor (hostFrame.Width);
-				else
+					w = AutoSize && s.Width > w ? s.Width : w;
+				} else {
 					w = Math.Max (width.Anchor (hostFrame.Width - _x), 0);
+					w = AutoSize && s.Width > w ? s.Width : w;
+				}
 			}
 
 			if (y is Pos.PosCenter) {
-				if (height == null)
-					h = hostFrame.Height;
-				else
+				if (height == null) {
+					h = AutoSize ? s.Height : hostFrame.Height;
+				} else {
 					h = height.Anchor (hostFrame.Height);
+					h = AutoSize && s.Height > h ? s.Height : h;
+				}
 				_y = y.Anchor (hostFrame.Height - h);
 			} else {
 				if (y == null)
 					_y = 0;
 				else
 					_y = y.Anchor (hostFrame.Height);
-				if (height == null)
-					h = hostFrame.Height;
-				else if (height is Dim.DimFactor && !((Dim.DimFactor)height).IsFromRemaining ())
+				if (height == null) {
+					h = AutoSize ? s.Height : hostFrame.Height;
+				} else if (height is Dim.DimFactor && !((Dim.DimFactor)height).IsFromRemaining ()) {
 					h = height.Anchor (hostFrame.Height);
-				else
+					h = AutoSize && s.Height > h ? s.Height : h;
+				} else {
 					h = Math.Max (height.Anchor (hostFrame.Height - _y), 0);
+					h = AutoSize && s.Height > h ? s.Height : h;
+				}
 			}
 			var r = new Rect (_x, _y, w, h);
 			if (Frame != r) {
 				Frame = new Rect (_x, _y, w, h);
+				if (!SetMinWidthHeight ())
+					TextFormatter.Size = GetBoundsTextFormatterSize ();
 			}
 		}
 
@@ -2281,7 +2359,7 @@ namespace Terminal.Gui {
 			}
 
 			if (SuperView != null && SuperView == Application.Top && LayoutNeeded
-				&& ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
+			    && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
 				SetRelativeLayout (SuperView.Frame);
 			}
 
@@ -2290,6 +2368,8 @@ namespace Terminal.Gui {
 			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 		}
 
+		ustring text;
+
 		/// <summary>
 		///   The text displayed by the <see cref="View"/>.
 		/// </summary>
@@ -2309,29 +2389,20 @@ namespace Terminal.Gui {
 		/// </para>
 		/// </remarks>
 		public virtual ustring Text {
-			get => TextFormatter.Text;
+			get => text;
 			set {
-				TextFormatter.Text = value;
-				var prevSize = frame.Size;
-				var canResize = ResizeView (autoSize);
-				var txtFmtSize = GetTextFormatterBoundsSize ();
-				if (canResize && txtFmtSize != Bounds.Size) {
-					Bounds = new Rect (new Point (Bounds.X, Bounds.Y), txtFmtSize);
-				} else if (!canResize && txtFmtSize != Bounds.Size) {
-					TextFormatter.Size = GetBoundsTextFormatterSize ();
-				}
-				SetMinWidthHeight ();
-				SetNeedsLayout ();
-				SetNeedsDisplay (new Rect (new Point (0, 0),
-					new Size (Math.Max (frame.Width, prevSize.Width), Math.Max (frame.Height, prevSize.Height))));
+				text = value;
+				SetHotKey ();
+				UpdateTextFormatterText ();
+				ProcessResizeView ();
 			}
 		}
 
 		/// <summary>
 		/// Used by <see cref="Text"/> to resize the view's <see cref="Bounds"/> with the <see cref="TextFormatter.Size"/>.
 		/// Setting <see cref="AutoSize"/> to true only work if the <see cref="Width"/> and <see cref="Height"/> are null or
-		///   <see cref="LayoutStyle.Absolute"/> values and doesn't work with <see cref="LayoutStyle.Computed"/> layout,
-		///   to avoid breaking the <see cref="Pos"/> and <see cref="Dim"/> settings.
+		///   <see cref="LayoutStyle.Absolute"/> values and doesn't work with <see cref="LayoutStyle.Computed"/> layout
+		///   and <see cref="ForceValidatePosDim"/> to avoid breaking the <see cref="Pos"/> and <see cref="Dim"/> settings.
 		/// </summary>
 		public virtual bool AutoSize {
 			get => autoSize;
@@ -2341,8 +2412,22 @@ namespace Terminal.Gui {
 				if (autoSize != v) {
 					autoSize = v;
 					TextFormatter.NeedsFormat = true;
-					SetNeedsLayout ();
-					SetNeedsDisplay ();
+					UpdateTextFormatterText ();
+					ProcessResizeView ();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Get or sets a flag if the wrapped text will keep the trailing spaces or
+		/// the trailing spaces will be trimmed (default).
+		/// </summary>
+		public virtual bool PreserveTrailingSpaces {
+			get => TextFormatter.PreserveTrailingSpaces;
+			set {
+				if (TextFormatter.PreserveTrailingSpaces != value) {
+					TextFormatter.PreserveTrailingSpaces = value;
+					TextFormatter.NeedsFormat = true;
 				}
 			}
 		}
@@ -2355,7 +2440,8 @@ namespace Terminal.Gui {
 			get => TextFormatter.Alignment;
 			set {
 				TextFormatter.Alignment = value;
-				SetNeedsDisplay ();
+				UpdateTextFormatterText ();
+				ProcessResizeView ();
 			}
 		}
 
@@ -2379,42 +2465,38 @@ namespace Terminal.Gui {
 			get => TextFormatter.Direction;
 			set {
 				if (TextFormatter.Direction != value) {
-					var isValidOldAutSize = autoSize ? IsValidAutoSize (out Size autSize) : false;
+					var isValidOldAutSize = autoSize && IsValidAutoSize (out Size autSize);
 					var directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
-						!= TextFormatter.IsHorizontalDirection (value);
+					    != TextFormatter.IsHorizontalDirection (value);
 
 					TextFormatter.Direction = value;
-
-					if ((IsInitialized && AutoSize) || (directionChanged && AutoSize && isValidOldAutSize)) {
-						ResizeView (true);
-					} else if (IsInitialized) {
-						var b = new Rect (Bounds.X, Bounds.Y, Bounds.Height, Bounds.Width);
-						SetWidthHeight (b);
+					UpdateTextFormatterText ();
+
+					if ((!ForceValidatePosDim && directionChanged && AutoSize)
+					    || (ForceValidatePosDim && directionChanged && AutoSize && isValidOldAutSize)) {
+						ProcessResizeView ();
+					} else if (directionChanged && IsAdded) {
+						SetWidthHeight (Bounds.Size);
+						SetMinWidthHeight ();
+					} else {
+						SetMinWidthHeight ();
 					}
-
 					TextFormatter.Size = GetBoundsTextFormatterSize ();
 					SetNeedsDisplay ();
 				}
 			}
 		}
 
-		bool isInitialized;
-
 		/// <summary>
 		/// Get or sets if  the <see cref="View"/> was already initialized.
 		/// This derived from <see cref="ISupportInitializeNotification"/> to allow notify all the views that are being initialized.
 		/// </summary>
-		public virtual bool IsInitialized {
-			get => isInitialized;
-			private set {
-				isInitialized = value;
-				SetMinWidthHeight ();
-				if (autoSize && !IsValidAutoSize (out Size autSize)) {
-					TextFormatter.AutoSize = false;
-					autoSize = false;
-				}
-			}
-		}
+		public virtual bool IsInitialized { get; set; }
+
+		/// <summary>
+		/// Gets information if the view was already added to the superview.
+		/// </summary>
+		public bool IsAdded { get; private set; }
 
 		bool oldEnabled;
 
@@ -2482,29 +2564,34 @@ namespace Terminal.Gui {
 			return $"{GetType ().Name}({Id})({Frame})";
 		}
 
+		void SetHotKey ()
+		{
+			TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk);
+			if (hotKey != hk) {
+				HotKey = hk;
+			}
+		}
+
 		bool ResizeView (bool autoSize)
 		{
 			if (!autoSize) {
 				return false;
 			}
 
-			var aSize = autoSize;
-			Rect nBounds = TextFormatter.CalcRect (Bounds.X, Bounds.Y, Text, TextFormatter.Direction);
-			if (TextFormatter.Size != nBounds.Size) {
-				TextFormatter.Size = nBounds.Size;
-			}
-			var fmtSize = GetTextFormatterBoundsSize ();
-			if ((fmtSize != Bounds.Size || fmtSize != nBounds.Size)
-				&& (((width == null || width is Dim.DimAbsolute) && (Bounds.Width == 0
-				|| autoSize && Bounds.Width != nBounds.Width))
-				|| ((height == null || height is Dim.DimAbsolute) && (Bounds.Height == 0
-				|| autoSize && Bounds.Height != nBounds.Height)))) {
-				aSize = SetWidthHeight (nBounds);
+			var aSize = true;
+			var nBoundsSize = CalculateAutoSize ();
+			if (nBoundsSize != Bounds.Size) {
+				if (ForceValidatePosDim) {
+					aSize = SetWidthHeight (nBoundsSize);
+				} else {
+					Bounds = new Rect (Bounds.X, Bounds.Y, nBoundsSize.Width, nBoundsSize.Height);
+				}
 			}
+			TextFormatter.Size = GetBoundsTextFormatterSize ();
 			return aSize;
 		}
 
-		bool SetWidthHeight (Rect nBounds)
+		bool SetWidthHeight (Size nBounds)
 		{
 			bool aSize = false;
 			var canSizeW = SetWidth (nBounds.Width - GetHotKeySpecifierLength (), out int rW);
@@ -2525,30 +2612,59 @@ namespace Terminal.Gui {
 			return aSize;
 		}
 
+		/// <summary>
+		/// Calculates the size to fit all text if <see cref="AutoSize"/> is true.
+		/// </summary>
+		/// <returns>The <see cref="Size"/></returns>
+		public Size CalculateAutoSize ()
+		{
+			var rect = TextFormatter.CalcRect (Bounds.X, Bounds.Y, TextFormatter.Text, TextFormatter.Direction);
+			return new Size (rect.Size.Width - GetHotKeySpecifierLength (),
+			    rect.Size.Height - GetHotKeySpecifierLength (false));
+		}
+
+		/// <summary>
+		/// Calculates the width to fit the text if <see cref="AutoSize"/> is true.
+		/// </summary>
+		/// <returns>The width length.</returns>
+		public int CalculateAutoSizeWidth ()
+		{
+			return CalculateAutoSize ().Width;
+		}
+
+		/// <summary>
+		/// Calculates the height to fit the text if <see cref="AutoSize"/> is true.
+		/// </summary>
+		/// <returns>The height length.</returns>
+		public int CalculateAutoSizeHeight ()
+		{
+			return CalculateAutoSize ().Height;
+		}
+
 		bool IsValidAutoSize (out Size autoSize)
 		{
 			var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection);
 			autoSize = new Size (rect.Size.Width - GetHotKeySpecifierLength (),
-				rect.Size.Height - GetHotKeySpecifierLength (false));
-			return !(!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)
-				|| frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength ()
-				|| frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false));
+			    rect.Size.Height - GetHotKeySpecifierLength (false));
+			return !(ForceValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute))
+			    || frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength ()
+			    || frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false));
 		}
 
 		bool IsValidAutoSizeWidth (Dim width)
 		{
 			var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection);
 			var dimValue = width.Anchor (0);
-			return !(!(width is Dim.DimAbsolute) || dimValue != rect.Size.Width
-				- GetHotKeySpecifierLength ());
+			return !(ForceValidatePosDim && (!(width is Dim.DimAbsolute)) || dimValue != rect.Size.Width
+			    - GetHotKeySpecifierLength ());
 		}
 
 		bool IsValidAutoSizeHeight (Dim height)
 		{
 			var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection);
 			var dimValue = height.Anchor (0);
-			return !(!(height is Dim.DimAbsolute) || dimValue != rect.Size.Height
-				- GetHotKeySpecifierLength (false));
+			return !(ForceValidatePosDim && (!(height is Dim.DimAbsolute)) || dimValue != rect.Size.Height
+			    - GetHotKeySpecifierLength (false));
 		}
 
 		/// <summary>
@@ -2560,12 +2676,12 @@ namespace Terminal.Gui {
 		{
 			if (isWidth) {
 				return TextFormatter.IsHorizontalDirection (TextDirection) &&
-					TextFormatter.Text?.Contains (HotKeySpecifier) == true
-					? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0;
+				    TextFormatter.Text?.Contains (HotKeySpecifier) == true
+				    ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0;
 			} else {
 				return TextFormatter.IsVerticalDirection (TextDirection) &&
-					TextFormatter.Text?.Contains (HotKeySpecifier) == true
-					? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0;
+				    TextFormatter.Text?.Contains (HotKeySpecifier) == true
+				    ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0;
 			}
 		}
 
@@ -2576,7 +2692,7 @@ namespace Terminal.Gui {
 		public Size GetTextFormatterBoundsSize ()
 		{
 			return new Size (TextFormatter.Size.Width - GetHotKeySpecifierLength (),
-				TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
+			    TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
 		}
 
 		/// <summary>
@@ -2589,7 +2705,7 @@ namespace Terminal.Gui {
 				return Bounds.Size;
 
 			return new Size (frame.Size.Width + GetHotKeySpecifierLength (),
-				frame.Size.Height + GetHotKeySpecifierLength (false));
+			    frame.Size.Height + GetHotKeySpecifierLength (false));
 		}
 
 		/// <summary>
@@ -2774,7 +2890,7 @@ namespace Terminal.Gui {
 			if (Width is Dim.DimCombine || Width is Dim.DimView || Width is Dim.DimFill) {
 				// It's a Dim.DimCombine and so can't be assigned. Let it have it's width anchored.
 				w = Width.Anchor (w);
-				canSetWidth = false;
+				canSetWidth = !ForceValidatePosDim;
 			} else if (Width is Dim.DimFactor factor) {
 				// Tries to get the SuperView width otherwise the view width.
 				var sw = SuperView != null ? SuperView.Frame.Width : w;
@@ -2782,7 +2898,7 @@ namespace Terminal.Gui {
 					sw -= Frame.X;
 				}
 				w = Width.Anchor (sw);
-				canSetWidth = false;
+				canSetWidth = !ForceValidatePosDim;
 			} else {
 				canSetWidth = true;
 			}
@@ -2798,7 +2914,7 @@ namespace Terminal.Gui {
 			if (Height is Dim.DimCombine || Height is Dim.DimView || Height is Dim.DimFill) {
 				// It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
 				h = Height.Anchor (h);
-				canSetHeight = false;
+				canSetHeight = !ForceValidatePosDim;
 			} else if (Height is Dim.DimFactor factor) {
 				// Tries to get the SuperView height otherwise the view height.
 				var sh = SuperView != null ? SuperView.Frame.Height : h;
@@ -2806,7 +2922,7 @@ namespace Terminal.Gui {
 					sh -= Frame.Y;
 				}
 				h = Height.Anchor (sh);
-				canSetHeight = false;
+				canSetHeight = !ForceValidatePosDim;
 			} else {
 				canSetHeight = true;
 			}
@@ -2844,8 +2960,8 @@ namespace Terminal.Gui {
 		/// <returns><c>true</c> if the width can be directly assigned, <c>false</c> otherwise.</returns>
 		public bool GetCurrentWidth (out int currentWidth)
 		{
-			SetRelativeLayout (SuperView == null ? Frame : SuperView.Frame);
-			currentWidth = Frame.Width;
+			SetRelativeLayout (SuperView == null ? frame : SuperView.frame);
+			currentWidth = frame.Width;
 
 			return CanSetWidth (0, out _);
 		}
@@ -2857,8 +2973,8 @@ namespace Terminal.Gui {
 		/// <returns><c>true</c> if the height can be directly assigned, <c>false</c> otherwise.</returns>
 		public bool GetCurrentHeight (out int currentHeight)
 		{
-			SetRelativeLayout (SuperView == null ? Frame : SuperView.Frame);
-			currentHeight = Frame.Height;
+			SetRelativeLayout (SuperView == null ? frame : SuperView.frame);
+			currentHeight = frame.Height;
 
 			return CanSetHeight (0, out _);
 		}

+ 17 - 62
Terminal.Gui/Views/Button.cs

@@ -31,8 +31,13 @@ namespace Terminal.Gui {
 	/// </para>
 	/// </remarks>
 	public class Button : View {
-		ustring text;
 		bool is_default;
+		Rune _leftBracket;
+		Rune _rightBracket;
+		Rune _leftDefault;
+		Rune _rightDefault;
+		Key hotKey = Key.Null;
+		Rune hotKeySpecifier;
 
 		/// <summary>
 		///   Initializes a new instance of <see cref="Button"/> using <see cref="LayoutStyle.Computed"/> layout.
@@ -92,16 +97,10 @@ namespace Terminal.Gui {
 			Initialize (text, is_default);
 		}
 
-		Rune _leftBracket;
-		Rune _rightBracket;
-		Rune _leftDefault;
-		Rune _rightDefault;
-		private Key hotKey = Key.Null;
-		private Rune hotKeySpecifier;
-
 		void Initialize (ustring text, bool is_default)
 		{
 			TextAlignment = TextAlignment.Centered;
+			VerticalTextAlignment = VerticalTextAlignment.Middle;
 
 			HotKeySpecifier = new Rune ('_');
 
@@ -113,8 +112,9 @@ namespace Terminal.Gui {
 			CanFocus = true;
 			AutoSize = true;
 			this.is_default = is_default;
-			this.text = text ?? string.Empty;
-			Update ();
+			Text = text ?? string.Empty;
+			UpdateTextFormatterText ();
+			ProcessResizeView ();
 
 			// Things this view knows how to do
 			AddCommand (Command.Accept, () => AcceptKey ());
@@ -127,21 +127,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		/// <inheritdoc/>>
-		public override ustring Text {
-			get {
-				return text;
-			}
-			set {
-				text = value;
-				TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk);
-				if (hotKey != hk) {
-					HotKey = hk;
-				}
-				Update ();
-			}
-		}
-
 		/// <summary>
 		/// Gets or sets whether the <see cref="Button"/> is the default action to activate in a dialog.
 		/// </summary>
@@ -150,7 +135,8 @@ namespace Terminal.Gui {
 			get => is_default;
 			set {
 				is_default = value;
-				Update ();
+				UpdateTextFormatterText ();
+				ProcessResizeView ();
 			}
 		}
 
@@ -183,43 +169,12 @@ namespace Terminal.Gui {
 		}
 
 		/// <inheritdoc/>
-		public override bool AutoSize {
-			get => base.AutoSize;
-			set {
-				base.AutoSize = value;
-				Update ();
-			}
-		}
-
-		internal void Update ()
+		protected override void UpdateTextFormatterText ()
 		{
 			if (IsDefault)
-				TextFormatter.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket);
+				TextFormatter.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + Text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket);
 			else
-				TextFormatter.Text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
-
-			int w = TextFormatter.Size.Width - GetHotKeySpecifierLength ();
-			GetCurrentWidth (out int cWidth);
-			var canSetWidth = SetWidth (w, out int rWidth);
-			if (canSetWidth && (cWidth < rWidth || AutoSize)) {
-				Width = rWidth;
-				w = rWidth;
-			} else if (!canSetWidth || !AutoSize) {
-				w = cWidth;
-			}
-			var layout = LayoutStyle;
-			bool layoutChanged = false;
-			if (!(Height is Dim.DimAbsolute)) {
-				// The height is always equal to 1 and must be Dim.DimAbsolute.
-				layoutChanged = true;
-				LayoutStyle = LayoutStyle.Absolute;
-			}
-			Height = 1;
-			if (layoutChanged) {
-				LayoutStyle = layout;
-			}
-			Frame = new Rect (Frame.Location, new Size (w, 1));
-			SetNeedsDisplay ();
+				TextFormatter.Text = ustring.Make (_leftBracket) + " " + Text + " " + ustring.Make (_rightBracket);
 		}
 
 		///<inheritdoc/>
@@ -322,9 +277,9 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override void PositionCursor ()
 		{
-			if (HotKey == Key.Unknown && text != "") {
+			if (HotKey == Key.Unknown && Text != "") {
 				for (int i = 0; i < TextFormatter.Text.RuneCount; i++) {
-					if (TextFormatter.Text [i] == text [0]) {
+					if (TextFormatter.Text [i] == Text [0]) {
 						Move (i, 0);
 						return;
 					}

+ 12 - 75
Terminal.Gui/Views/Checkbox.cs

@@ -13,7 +13,6 @@ namespace Terminal.Gui {
 	/// The <see cref="CheckBox"/> <see cref="View"/> shows an on/off toggle that the user can set
 	/// </summary>
 	public class CheckBox : View {
-		ustring text;
 		Key hotKey = Key.Null;
 		Rune hotKeySpecifier;
 		Rune charChecked;
@@ -71,7 +70,7 @@ namespace Terminal.Gui {
 		///   The size of <see cref="CheckBox"/> is computed based on the
 		///   text length. 
 		/// </remarks>
-		public CheckBox (int x, int y, ustring s, bool is_checked) : base (new Rect (x, y, s.Length + 4, 1))
+		public CheckBox (int x, int y, ustring s, bool is_checked) : base (new Rect (x, y, s.Length, 1))
 		{
 			Initialize (s, is_checked);
 		}
@@ -85,7 +84,8 @@ namespace Terminal.Gui {
 			CanFocus = true;
 			AutoSize = true;
 			Text = s;
-			Update ();
+			UpdateTextFormatterText ();
+			ProcessResizeView ();
 
 			// Things this view knows how to do
 			AddCommand (Command.ToggleChecked, () => ToggleChecked ());
@@ -95,55 +95,27 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.Space, Command.ToggleChecked);
 		}
 
-		void Update ()
+		/// <inheritdoc/>
+		protected override void UpdateTextFormatterText ()
 		{
 			switch (TextAlignment) {
 			case TextAlignment.Left:
 			case TextAlignment.Centered:
 			case TextAlignment.Justified:
-				if (Checked)
-					TextFormatter.Text = ustring.Make (charChecked) + " " + GetFormatterText ();
-				else
-					TextFormatter.Text = ustring.Make (charUnChecked) + " " + GetFormatterText ();
+				TextFormatter.Text = ustring.Make (Checked ? charChecked : charUnChecked) + " " + GetFormatterText ();
 				break;
 			case TextAlignment.Right:
-				if (Checked)
-					TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charChecked);
-				else
-					TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charUnChecked);
+				TextFormatter.Text = GetFormatterText () + " " + ustring.Make (Checked ? charChecked : charUnChecked);
 				break;
 			}
-
-			int w = TextFormatter.Size.Width - GetHotKeySpecifierLength ();
-			GetCurrentWidth (out int cWidth);
-			var canSetWidth = SetWidth (w, out int rWidth);
-			if (canSetWidth && (cWidth < rWidth || AutoSize)) {
-				Width = rWidth;
-				w = rWidth;
-			} else if (!canSetWidth || !AutoSize) {
-				w = cWidth;
-			}
-			var layout = LayoutStyle;
-			bool layoutChanged = false;
-			if (!(Height is Dim.DimAbsolute)) {
-				// The height is always equal to 1 and must be Dim.DimAbsolute.
-				layoutChanged = true;
-				LayoutStyle = LayoutStyle.Absolute;
-			}
-			Height = 1;
-			if (layoutChanged) {
-				LayoutStyle = layout;
-			}
-			Frame = new Rect (Frame.Location, new Size (w, 1));
-			SetNeedsDisplay ();
 		}
 
 		ustring GetFormatterText ()
 		{
-			if (AutoSize || ustring.IsNullOrEmpty (text)) {
-				return text;
+			if (AutoSize || ustring.IsNullOrEmpty (Text) || Frame.Width <= 2) {
+				return Text;
 			}
-			return text.RuneSubstring (0, Math.Min (Frame.Width - 2, text.RuneCount));
+			return Text.RuneSubstring (0, Math.Min (Frame.Width - 2, Text.RuneCount));
 		}
 
 		/// <inheritdoc/>
@@ -165,15 +137,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		/// <inheritdoc/>
-		public override bool AutoSize {
-			get => base.AutoSize;
-			set {
-				base.AutoSize = value;
-				Update ();
-			}
-		}
-
 		/// <summary>
 		///    The state of the <see cref="CheckBox"/>
 		/// </summary>
@@ -181,34 +144,8 @@ namespace Terminal.Gui {
 			get => @checked;
 			set {
 				@checked = value;
-				Update ();
-			}
-		}
-
-		/// <summary>
-		///   The text displayed by this <see cref="CheckBox"/>
-		/// </summary>
-		public new ustring Text {
-			get {
-				return text;
-			}
-
-			set {
-				text = value;
-				TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk);
-				if (hotKey != hk) {
-					HotKey = hk;
-				}
-				Update ();
-			}
-		}
-
-		///<inheritdoc/>
-		public override TextAlignment TextAlignment {
-			get => base.TextAlignment;
-			set {
-				base.TextAlignment = value;
-				Update ();
+				UpdateTextFormatterText ();
+				ProcessResizeView ();
 			}
 		}
 

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

@@ -109,7 +109,7 @@ namespace Terminal.Gui {
 
 		private void Initialize ()
 		{
-			if (Bounds.Height < minimumHeight && Height is Dim.DimAbsolute) {
+			if (Bounds.Height < minimumHeight && (Height == null || Height is Dim.DimAbsolute)) {
 				Height = minimumHeight;
 			}
 

+ 22 - 4
Terminal.Gui/Views/Label.cs

@@ -6,9 +6,6 @@
 //
 
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
 using NStack;
 
 namespace Terminal.Gui {
@@ -110,7 +107,7 @@ namespace Terminal.Gui {
 					SetNeedsDisplay ();
 				}
 
-				Clicked?.Invoke ();
+				OnClicked ();
 				return true;
 			}
 			return false;
@@ -123,5 +120,26 @@ namespace Terminal.Gui {
 
 			return base.OnEnter (view);
 		}
+
+		///<inheritdoc/>
+		public override bool ProcessHotKey (KeyEvent ke)
+		{
+			if (ke.Key == (Key.AltMask | HotKey)) {
+				if (!HasFocus) {
+					SetFocus ();
+				}
+				OnClicked ();
+				return true;
+			}
+			return base.ProcessHotKey (ke);
+		}
+
+		/// <summary>
+		/// Virtual method to invoke the <see cref="Clicked"/> event.
+		/// </summary>
+		public virtual void OnClicked ()
+		{
+			Clicked?.Invoke ();
+		}
 	}
 }

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

@@ -68,10 +68,10 @@ namespace Terminal.Gui {
 				}
 				child = value;
 				savedChild = new SavedPosDim () {
-					X = child?.X,
-					Y = child?.Y,
-					Width = child?.Width,
-					Height = child?.Height
+					X = child?.X ?? child?.Frame.X,
+					Y = child?.Y ?? child?.Frame.Y,
+					Width = child?.Width ?? child?.Frame.Width,
+					Height = child?.Height ?? child?.Frame.Height
 				};
 				if (child == null) {
 					Visible = false;

+ 20 - 14
Terminal.Gui/Views/RadioGroup.cs

@@ -26,7 +26,7 @@ namespace Terminal.Gui {
 		/// <param name="selected">The index of the item to be selected, the value is clamped to the number of items.</param>
 		public RadioGroup (ustring [] radioLabels, int selected = 0) : base ()
 		{
-			Initialize (radioLabels, selected);
+			Initialize (Rect.Empty, radioLabels, selected);
 		}
 
 		/// <summary>
@@ -37,7 +37,7 @@ namespace Terminal.Gui {
 		/// <param name="selected">The index of item to be selected, the value is clamped to the number of items.</param>
 		public RadioGroup (Rect rect, ustring [] radioLabels, int selected = 0) : base (rect)
 		{
-			Initialize (radioLabels, selected);
+			Initialize (rect, radioLabels, selected);
 		}
 
 		/// <summary>
@@ -52,7 +52,7 @@ namespace Terminal.Gui {
 			this (MakeRect (x, y, radioLabels != null ? radioLabels.ToList () : null), radioLabels, selected)
 		{ }
 
-		void Initialize (ustring [] radioLabels, int selected)
+		void Initialize (Rect rect, ustring [] radioLabels, int selected)
 		{
 			if (radioLabels == null) {
 				this.radioLabels = new List<ustring> ();
@@ -61,7 +61,11 @@ namespace Terminal.Gui {
 			}
 
 			this.selected = selected;
-			SetWidthHeight (this.radioLabels);
+			if (rect == Rect.Empty) {
+				SetWidthHeight (this.radioLabels);
+			} else {
+				Frame = rect;
+			}
 			CanFocus = true;
 
 			// Things this view knows how to do
@@ -102,6 +106,7 @@ namespace Terminal.Gui {
 				if (horizontalSpace != value && displayMode == DisplayModeLayout.Horizontal) {
 					horizontalSpace = value;
 					SetWidthHeight (radioLabels);
+					UpdateTextFormatterText ();
 					SetNeedsDisplay ();
 				}
 			}
@@ -112,7 +117,7 @@ namespace Terminal.Gui {
 			switch (displayMode) {
 			case DisplayModeLayout.Vertical:
 				var r = MakeRect (0, 0, radioLabels);
-				if (LayoutStyle == LayoutStyle.Computed) {
+				if (IsAdded && LayoutStyle == LayoutStyle.Computed) {
 					Width = r.Width;
 					Height = radioLabels.Count;
 				} else {
@@ -126,9 +131,11 @@ namespace Terminal.Gui {
 					length += item.length;
 				}
 				var hr = new Rect (0, 0, length, 1);
-				if (LayoutStyle == LayoutStyle.Computed) {
+				if (IsAdded && LayoutStyle == LayoutStyle.Computed) {
 					Width = hr.Width;
 					Height = 1;
+				} else {
+					Frame = new Rect (Frame.Location, new Size (hr.Width, radioLabels.Count));
 				}
 				break;
 			}
@@ -136,18 +143,17 @@ namespace Terminal.Gui {
 
 		static Rect MakeRect (int x, int y, List<ustring> radioLabels)
 		{
-			int width = 0;
-
 			if (radioLabels == null) {
-				return new Rect (x, y, width, 0);
+				return new Rect (x, y, 0, 0);
 			}
 
+			int width = 0;
+
 			foreach (var s in radioLabels)
-				width = Math.Max (s.RuneCount + 3, width);
+				width = Math.Max (s.ConsoleWidth + 3, width);
 			return new Rect (x, y, width, radioLabels.Count);
 		}
 
-
 		List<ustring> radioLabels = new List<ustring> ();
 
 		/// <summary>
@@ -176,7 +182,7 @@ namespace Terminal.Gui {
 				int length = 0;
 				for (int i = 0; i < radioLabels.Count; i++) {
 					start += length;
-					length = radioLabels [i].RuneCount + horizontalSpace;
+					length = radioLabels [i].ConsoleWidth + 2 + (i < radioLabels.Count - 1 ? horizontalSpace : 0);
 					horizontal.Add ((start, length));
 				}
 			}
@@ -188,7 +194,7 @@ namespace Terminal.Gui {
 		//	for (int i = 0; i < radioLabels.Count; i++) {
 		//		Move(0, i);
 		//		Driver.SetAttribute(ColorScheme.Normal);
-		//		Driver.AddStr(ustring.Make(new string (' ', radioLabels[i].RuneCount + 4)));
+		//		Driver.AddStr(ustring.Make(new string (' ', radioLabels[i].ConsoleWidth + 4)));
 		//	}
 		//	if (newRadioLabels.Count != radioLabels.Count) {
 		//		SetWidthHeight(newRadioLabels);
@@ -210,7 +216,7 @@ namespace Terminal.Gui {
 					break;
 				}
 				Driver.SetAttribute (GetNormalColor ());
-				Driver.AddStr (ustring.Make (new Rune [] { (i == selected ? Driver.Selected : Driver.UnSelected), ' ' }));
+				Driver.AddStr (ustring.Make (new Rune [] { i == selected ? Driver.Selected : Driver.UnSelected, ' ' }));
 				DrawHotString (radioLabels [i], HasFocus && i == cursor, ColorScheme);
 			}
 		}

+ 3 - 0
Terminal.Gui/Views/TextField.cs

@@ -474,6 +474,9 @@ namespace Terminal.Gui {
 
 		void Adjust ()
 		{
+			if (!IsAdded)
+				return;
+
 			int offB = OffSetBackground ();
 			if (point < first) {
 				first = point;

+ 14 - 0
UICatalog/Scenarios/AutoSizeAndDirectionText.cs

@@ -7,11 +7,14 @@ namespace UICatalog.Scenarios {
 		public override void Setup ()
 		{
 			var text = "Hello World";
+			//var text = "Hello World 你";
 			var color = Colors.Dialog;
 
 			var labelH = new Label (text, TextDirection.LeftRight_TopBottom) {
 				X = 1,
 				Y = 1,
+				Width = 11,
+				Height = 1,
 				ColorScheme = color
 			};
 			Win.Add (labelH);
@@ -19,6 +22,8 @@ namespace UICatalog.Scenarios {
 			var labelV = new Label (text, TextDirection.TopBottom_LeftRight) {
 				X = 70,
 				Y = 1,
+				Width = 1,
+				Height = 11,
 				ColorScheme = color
 			};
 			Win.Add (labelV);
@@ -59,6 +64,15 @@ namespace UICatalog.Scenarios {
 			ckbAutoSize.Toggled += (_) => labelH.AutoSize = labelV.AutoSize = ckbAutoSize.Checked;
 			Win.Add (ckbAutoSize);
 
+			var ckbPreserveTrailingSpaces = new CheckBox ("Preserve Trailing Spaces") {
+				X = Pos.Center (),
+				Y = Pos.Center () + 7,
+				Checked = labelH.PreserveTrailingSpaces = labelV.PreserveTrailingSpaces
+			};
+			ckbPreserveTrailingSpaces.Toggled += (_) =>
+					labelH.PreserveTrailingSpaces = labelV.PreserveTrailingSpaces = ckbPreserveTrailingSpaces.Checked;
+			Win.Add (ckbPreserveTrailingSpaces);
+
 			Win.KeyUp += (_) =>
 				labelH.Text = labelV.Text = text = editText.Text.ToString ();
 		}

+ 1 - 3
UICatalog/Scenarios/Dialogs.cs

@@ -103,8 +103,7 @@ namespace UICatalog.Scenarios {
 			label = new Label ("Button Style:") {
 				X = 0,
 				Y = Pos.Bottom (glyphsNotWords),
-				AutoSize = true,
-				TextAlignment = Terminal.Gui.TextAlignment.Right,
+				TextAlignment = Terminal.Gui.TextAlignment.Right
 			};
 			frame.Add (label);
 			var styleRadioGroup = new RadioGroup (new ustring [] { "Center", "Justify", "Left", "Right" }) {
@@ -133,7 +132,6 @@ namespace UICatalog.Scenarios {
 				Y = Pos.Bottom (frame) + 5,
 				Width = 25,
 				Height = 1,
-
 				ColorScheme = Colors.Error,
 			};
 			// glyphsNotWords

+ 22 - 23
UICatalog/Scenarios/Editor.cs

@@ -748,12 +748,7 @@ namespace UICatalog.Scenarios {
 
 		private View FindTab ()
 		{
-			var d = new View () {
-				X = 0,
-				Y = 0,
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
+			var d = new View ();
 			d.DrawContent += (e) => {
 				foreach (var v in d.Subviews) {
 					v.SetNeedsDisplay ();
@@ -762,10 +757,11 @@ namespace UICatalog.Scenarios {
 
 			var lblWidth = "Replace:".Length;
 
-			var label = new Label (0, 1, "Find:") {
+			var label = new Label ("Find:") {
+				Y = 1,
 				Width = lblWidth,
 				TextAlignment = TextAlignment.Right,
-				LayoutStyle = LayoutStyle.Computed
+				AutoSize = false
 			};
 			d.Add (label);
 
@@ -784,7 +780,8 @@ namespace UICatalog.Scenarios {
 				Width = 20,
 				Enabled = !txtToFind.Text.IsEmpty,
 				TextAlignment = TextAlignment.Centered,
-				IsDefault = true
+				IsDefault = true,
+				AutoSize = false
 			};
 			btnFindNext.Clicked += () => FindNext ();
 			d.Add (btnFindNext);
@@ -794,7 +791,8 @@ namespace UICatalog.Scenarios {
 				Y = Pos.Top (btnFindNext) + 1,
 				Width = 20,
 				Enabled = !txtToFind.Text.IsEmpty,
-				TextAlignment = TextAlignment.Centered
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
 			};
 			btnFindPrevious.Clicked += () => FindPrevious ();
 			d.Add (btnFindPrevious);
@@ -810,7 +808,8 @@ namespace UICatalog.Scenarios {
 				X = Pos.Right (txtToFind) + 1,
 				Y = Pos.Top (btnFindPrevious) + 2,
 				Width = 20,
-				TextAlignment = TextAlignment.Centered
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
 			};
 			btnCancel.Clicked += () => {
 				DisposeWinDialog ();
@@ -841,12 +840,7 @@ namespace UICatalog.Scenarios {
 
 		private View ReplaceTab ()
 		{
-			var d = new View () {
-				X = 0,
-				Y = 0,
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
+			var d = new View ();
 			d.DrawContent += (e) => {
 				foreach (var v in d.Subviews) {
 					v.SetNeedsDisplay ();
@@ -855,10 +849,11 @@ namespace UICatalog.Scenarios {
 
 			var lblWidth = "Replace:".Length;
 
-			var label = new Label (0, 1, "Find:") {
+			var label = new Label ("Find:") {
+				Y = 1,
 				Width = lblWidth,
 				TextAlignment = TextAlignment.Right,
-				LayoutStyle = LayoutStyle.Computed
+				AutoSize = false
 			};
 			d.Add (label);
 
@@ -877,7 +872,8 @@ namespace UICatalog.Scenarios {
 				Width = 20,
 				Enabled = !txtToFind.Text.IsEmpty,
 				TextAlignment = TextAlignment.Centered,
-				IsDefault = true
+				IsDefault = true,
+				AutoSize = false
 			};
 			btnFindNext.Clicked += () => ReplaceNext ();
 			d.Add (btnFindNext);
@@ -904,7 +900,8 @@ namespace UICatalog.Scenarios {
 				Y = Pos.Top (btnFindNext) + 1,
 				Width = 20,
 				Enabled = !txtToFind.Text.IsEmpty,
-				TextAlignment = TextAlignment.Centered
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
 			};
 			btnFindPrevious.Clicked += () => ReplacePrevious ();
 			d.Add (btnFindPrevious);
@@ -914,7 +911,8 @@ namespace UICatalog.Scenarios {
 				Y = Pos.Top (btnFindPrevious) + 1,
 				Width = 20,
 				Enabled = !txtToFind.Text.IsEmpty,
-				TextAlignment = TextAlignment.Centered
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
 			};
 			btnReplaceAll.Clicked += () => ReplaceAll ();
 			d.Add (btnReplaceAll);
@@ -931,7 +929,8 @@ namespace UICatalog.Scenarios {
 				X = Pos.Right (txtToFind) + 1,
 				Y = Pos.Top (btnReplaceAll) + 1,
 				Width = 20,
-				TextAlignment = TextAlignment.Centered
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
 			};
 			btnCancel.Clicked += () => {
 				DisposeWinDialog ();

+ 4 - 0
UICatalog/Scenarios/LabelsAsButtons.cs

@@ -90,6 +90,8 @@ namespace UICatalog.Scenarios {
 				Y = Pos.Bottom (Label) + 1,
 				HotKeySpecifier = (System.Rune)'_',
 				CanFocus = true,
+				TextAlignment = TextAlignment.Centered,
+				VerticalTextAlignment = VerticalTextAlignment.Middle
 			});
 			Label.Clicked += () => MessageBox.Query ("Message", "Question?", "Yes", "No");
 
@@ -159,6 +161,7 @@ namespace UICatalog.Scenarios {
 				ColorScheme = Colors.Error,
 				HotKeySpecifier = (System.Rune)'_',
 				CanFocus = true,
+				AutoSize = false
 			};
 			sizeBtn.Clicked += () => {
 				sizeBtn.Width = sizeBtn.Frame.Width + 5;
@@ -190,6 +193,7 @@ namespace UICatalog.Scenarios {
 				ColorScheme = Colors.Error,
 				HotKeySpecifier = (System.Rune)'_',
 				CanFocus = true,
+				AutoSize = false
 			};
 			sizeBtnA.Clicked += () => {
 				sizeBtnA.Frame = new Rect (sizeBtnA.Frame.X, sizeBtnA.Frame.Y, sizeBtnA.Frame.Width + 5, sizeBtnA.Frame.Height);

+ 4 - 2
UICatalog/Scenarios/Scrolling.cs

@@ -129,7 +129,8 @@ namespace UICatalog.Scenarios {
 				Y = 0,
 				Width = Dim.Fill (),  // FIXED: I don't think this should be needed; DimFill() should respect container's frame. X does.
 				Height = 2,
-				ColorScheme = Colors.Error
+				ColorScheme = Colors.Error,
+				AutoSize = false
 			};
 			scrollView.Add (horizontalRuler);
 			const string vrule = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n";
@@ -139,7 +140,8 @@ namespace UICatalog.Scenarios {
 				Y = 0,
 				Width = 1,
 				Height = Dim.Fill (),
-				ColorScheme = Colors.Error
+				ColorScheme = Colors.Error,
+				AutoSize = false
 			};
 			scrollView.Add (verticalRuler);
 

+ 2 - 2
UICatalog/Scenarios/TextAlignments.cs

@@ -22,8 +22,8 @@ namespace UICatalog.Scenarios {
 			var multiLineHeight = 5;
 
 			foreach (var alignment in alignments) {
-				singleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = 1, ColorScheme = Colors.Dialog };
-				multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = multiLineHeight, ColorScheme = Colors.Dialog };
+				singleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = 1, ColorScheme = Colors.Dialog, AutoSize = false };
+				multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = multiLineHeight, ColorScheme = Colors.Dialog, AutoSize = false };
 			}
 
 			// Add a label & text field so we can demo IsDefault

+ 1 - 1
UICatalog/Scenarios/TextAlignmentsAndDirection.cs

@@ -60,7 +60,7 @@ namespace UICatalog.Scenarios {
 
 			// Multi-Line
 
-			var container = new View () { X = 0, Y = Pos.Bottom (txtLabelHJ), Width = Dim.Fill (31), Height = Dim.Fill (7), ColorScheme = color2 };
+			var container = new View () { X = 0, Y = Pos.Bottom (txtLabelHJ), Width = Dim.Fill (31), Height = Dim.Fill (6), ColorScheme = color2 };
 
 			var txtLabelTL = new Label (txt) { X = 1 /*                    */, Y = 1, Width = Dim.Percent (100f / 3f), Height = Dim.Percent (100f / 3f), TextAlignment = TextAlignment.Left, VerticalTextAlignment = VerticalTextAlignment.Top, ColorScheme = color1 };
 			var txtLabelTC = new Label (txt) { X = Pos.Right (txtLabelTL) + 2, Y = 1, Width = Dim.Percent (100f / 3f), Height = Dim.Percent (100f / 3f), TextAlignment = TextAlignment.Centered, VerticalTextAlignment = VerticalTextAlignment.Top, ColorScheme = color1 };

+ 3 - 3
UICatalog/Scenarios/TextFormatterDemo.cs

@@ -26,7 +26,7 @@ namespace UICatalog.Scenarios {
 			string text = "Hello world, how are you today? Pretty neat!\nSecond line\n\nFourth Line.";
 			string unicode = "Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ\nτὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου.\nΜονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου.";
 
-			Label blockText = new Label () { ColorScheme = Colors.TopLevel, X = 0, Y = 0, Height = 10, Width = Dim.Fill (0) };
+			Label blockText = new Label () { ColorScheme = Colors.TopLevel, X = 0, Y = 0, Height = 10, Width = Dim.Fill (0), AutoSize = false };
 
 			var block = new StringBuilder ();
 			block.AppendLine ("  ▄████  █    ██  ██▓      ▄████▄    ██████ ");
@@ -56,8 +56,8 @@ namespace UICatalog.Scenarios {
 			var multiLineHeight = 5;
 
 			foreach (var alignment in alignments) {
-				singleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog };
-				multipleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog };
+				singleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog, AutoSize = false };
+				multipleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog, AutoSize = false };
 			}
 
 			var label = new Label ($"Demonstrating single-line (should clip):") { Y = Pos.Bottom (unicodeCheckBox) + 1 };

+ 10 - 10
UICatalog/Scenarios/Wizards.cs

@@ -26,6 +26,7 @@ namespace UICatalog.Scenarios {
 				Width = 15,
 				Height = 1,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
+				AutoSize = false
 			};
 			frame.Add (label);
 			var widthEdit = new TextField ("80") {
@@ -42,6 +43,7 @@ namespace UICatalog.Scenarios {
 				Width = Dim.Width (label),
 				Height = 1,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
+				AutoSize = false
 			};
 			frame.Add (label);
 			var heightEdit = new TextField ("20") {
@@ -58,6 +60,7 @@ namespace UICatalog.Scenarios {
 				Width = Dim.Width (label),
 				Height = 1,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
+				AutoSize = false
 			};
 			frame.Add (label);
 			var titleEdit = new TextField ("Title") {
@@ -87,14 +90,12 @@ namespace UICatalog.Scenarios {
 			label = new Label ("Action:") {
 				X = Pos.Center (),
 				Y = Pos.AnchorEnd (1),
-				AutoSize = true,
 				TextAlignment = Terminal.Gui.TextAlignment.Right,
 			};
 			Win.Add (label);
 			var actionLabel = new Label (" ") {
 				X = Pos.Right (label),
 				Y = Pos.AnchorEnd (1),
-				AutoSize = true,
 				ColorScheme = Colors.Error,
 			};
 
@@ -159,7 +160,7 @@ namespace UICatalog.Scenarios {
 						frameMsg = "Added to WizardStep directly";
 					}
 
-					var buttonLbl = new Label () { Text = "Second Step Button: ", AutoSize = true, X = 1, Y = 1 };
+					var buttonLbl = new Label () { Text = "Second Step Button: ", X = 1, Y = 1 };
 					var button = new Button () {
 						Text = "Press Me to Rename Step",
 						X = Pos.Right (buttonLbl),
@@ -170,10 +171,10 @@ namespace UICatalog.Scenarios {
 						MessageBox.Query ("Wizard Scenario", "This Wizard Step's title was changed to '2nd Step'");
 					};
 					viewForControls.Add (buttonLbl, button);
-					var lbl = new Label () { Text = "First Name: ", AutoSize = true, X = 1, Y = Pos.Bottom (buttonLbl) };
+					var lbl = new Label () { Text = "First Name: ", X = 1, Y = Pos.Bottom (buttonLbl) };
 					var firstNameField = new TextField () { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
 					viewForControls.Add (lbl, firstNameField);
-					lbl = new Label () { Text = "Last Name:  ", AutoSize = true, X = 1, Y = Pos.Bottom (lbl) };
+					lbl = new Label () { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
 					var lastNameField = new TextField () { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
 					viewForControls.Add (lbl, lastNameField);
 					var thirdStepEnabledCeckBox = new CheckBox () { Text = "Enable Step _3", Checked = false, X = Pos.Left (lastNameField), Y = Pos.Bottom (lastNameField) };
@@ -192,7 +193,7 @@ namespace UICatalog.Scenarios {
 					frame.Add (new TextField ("This is a TextField inside of the frame."));
 					viewForControls.Add (frame);
 					wizard.StepChanging += (args) => {
-						if (args.OldStep == secondStep && firstNameField.Text.IsEmpty ) {
+						if (args.OldStep == secondStep && firstNameField.Text.IsEmpty) {
 							args.Cancel = true;
 							var btn = MessageBox.ErrorQuery ("Second Step", "You must enter a First Name to continue", "Ok");
 						}
@@ -205,11 +206,10 @@ namespace UICatalog.Scenarios {
 					var step3Label = new Label () {
 						Text = "This step is optional.",
 						X = 0,
-						Y = 0,
-						AutoSize = true
+						Y = 0
 					};
 					thirdStep.Controls.Add (step3Label);
-					var progLbl = new Label () { Text = "Third Step ProgressBar: ", AutoSize = true, X = 1, Y = 10 };
+					var progLbl = new Label () { Text = "Third Step ProgressBar: ", X = 1, Y = 10 };
 					var progressBar = new ProgressBar () {
 						X = Pos.Right (progLbl),
 						Y = Pos.Top (progLbl),
@@ -221,7 +221,7 @@ namespace UICatalog.Scenarios {
 					thirdStepEnabledCeckBox.Toggled += (args) => {
 						thirdStep.Enabled = thirdStepEnabledCeckBox.Checked;
 					};
-	
+
 					// Add 4th step
 					var fourthStep = new Wizard.WizardStep ("Step Four");
 					wizard.AddStep (fourthStep);

+ 205 - 17
UnitTests/ButtonTests.cs

@@ -17,47 +17,57 @@ namespace Terminal.Gui.Views {
 			var btn = new Button ();
 			Assert.Equal (string.Empty, btn.Text);
 			Application.Top.Add (btn);
-			btn.Redraw (btn.Bounds);
-			Assert.Equal ("[  ]", GetContents (btn.Bounds.Width));
+			var rs = Application.Begin (Application.Top);
+
+			Assert.Equal ("[  ]", btn.TextFormatter.Text);
 			Assert.False (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
 			Assert.True (btn.CanFocus);
 			Assert.Equal (new Rect (0, 0, 4, 1), btn.Frame);
 			Assert.Equal (Key.Null, btn.HotKey);
+			var expected = @"
+[  ]
+";
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 
+			Application.End (rs);
 			btn = new Button ("ARGS", true) { Text = "Test" };
 			Assert.Equal ("Test", btn.Text);
 			Application.Top.Add (btn);
-			btn.Redraw (btn.Bounds);
-			Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width));
+			rs = Application.Begin (Application.Top);
+
+			Assert.Equal ("[◦ Test ◦]", btn.TextFormatter.Text);
 			Assert.True (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
 			Assert.True (btn.CanFocus);
 			Assert.Equal (new Rect (0, 0, 10, 1), btn.Frame);
 			Assert.Equal (Key.T, btn.HotKey);
+			expected = @"
+[◦ Test ◦]
+";
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 
+			Application.End (rs);
 			btn = new Button (3, 4, "Test", true);
 			Assert.Equal ("Test", btn.Text);
 			Application.Top.Add (btn);
-			btn.Redraw (btn.Bounds);
-			Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width));
+			rs = Application.Begin (Application.Top);
+
+			Assert.Equal ("[◦ Test ◦]", btn.TextFormatter.Text);
 			Assert.True (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
 			Assert.True (btn.CanFocus);
 			Assert.Equal (new Rect (3, 4, 10, 1), btn.Frame);
 			Assert.Equal (Key.T, btn.HotKey);
-		}
+			expected = @"
+   [◦ Test ◦]
+";
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 
-		private string GetContents (int width)
-		{
-			string output = "";
-			for (int i = 0; i < width; i++) {
-				output += (char)Application.Driver.Contents [0, i, 0];
-			}
-			return output;
+			Application.End (rs);
 		}
 
 		[Fact]
@@ -273,8 +283,7 @@ namespace Terminal.Gui.Views {
 			var btn = new Button () {
 				X = Pos.Center (),
 				Y = Pos.Center (),
-				Text = "Say Hello 你",
-				AutoSize = true
+				Text = "Say Hello 你"
 			};
 
 			var win = new Window () {
@@ -322,7 +331,7 @@ namespace Terminal.Gui.Views {
 				Text = "Say Hello 你",
 				AutoSize = true
 			};
-			btn.X = Pos.AnchorEnd () - Pos.Function (() => TextFormatter.GetTextWidth  (btn.TextFormatter.Text));
+			btn.X = Pos.AnchorEnd () - Pos.Function (() => TextFormatter.GetTextWidth (btn.TextFormatter.Text));
 
 			var win = new Window () {
 				Width = Dim.Fill (),
@@ -356,6 +365,185 @@ namespace Terminal.Gui.Views {
 │    [ Say Hello 你 changed ]│
 │                            │
 └────────────────────────────┘
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void AutoSize_False_With_Fixed_Width ()
+		{
+			var tab = new View ();
+
+			var lblWidth = 8;
+
+			var label = new Label ("Find:") {
+				Y = 1,
+				Width = lblWidth,
+				TextAlignment = TextAlignment.Right,
+				AutoSize = false
+			};
+			tab.Add (label);
+
+			var txtToFind = new TextField ("Testing buttons.") {
+				X = Pos.Right (label) + 1,
+				Y = Pos.Top (label),
+				Width = 20
+			};
+			tab.Add (txtToFind);
+
+			var btnFindNext = new Button ("Find _Next") {
+				X = Pos.Right (txtToFind) + 1,
+				Y = Pos.Top (label),
+				Width = 20,
+				Enabled = !txtToFind.Text.IsEmpty,
+				TextAlignment = TextAlignment.Centered,
+				IsDefault = true,
+				AutoSize = false
+			};
+			tab.Add (btnFindNext);
+
+			var btnFindPrevious = new Button ("Find _Previous") {
+				X = Pos.Right (txtToFind) + 1,
+				Y = Pos.Top (btnFindNext) + 1,
+				Width = 20,
+				Enabled = !txtToFind.Text.IsEmpty,
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
+			};
+			tab.Add (btnFindPrevious);
+
+			var btnCancel = new Button ("Cancel") {
+				X = Pos.Right (txtToFind) + 1,
+				Y = Pos.Top (btnFindPrevious) + 2,
+				Width = 20,
+				TextAlignment = TextAlignment.Centered,
+				AutoSize = false
+			};
+			tab.Add (btnCancel);
+
+			var ckbMatchCase = new CheckBox ("Match c_ase") {
+				X = 0,
+				Y = Pos.Top (txtToFind) + 2,
+				Checked = true
+			};
+			tab.Add (ckbMatchCase);
+
+			var ckbMatchWholeWord = new CheckBox ("Match _whole word") {
+				X = 0,
+				Y = Pos.Top (ckbMatchCase) + 1,
+				Checked = false
+			};
+			tab.Add (ckbMatchWholeWord);
+
+			var tabView = new TabView () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			tabView.AddTab (new TabView.Tab ("Find", tab), true);
+
+			var win = new Window ("Find") {
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+
+			tab.Width = label.Width + txtToFind.Width + btnFindNext.Width + 2;
+			tab.Height = btnFindNext.Height + btnFindPrevious.Height + btnCancel.Height + 4;
+
+			win.Add (tabView);
+			Application.Top.Add (win);
+
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (54, 11);
+
+			Assert.Equal (new Rect (0, 0, 54, 11), win.Frame);
+			Assert.Equal (new Rect (0, 0, 52, 9), tabView.Frame);
+			Assert.Equal (new Rect (0, 0, 50, 7), tab.Frame);
+			Assert.Equal (new Rect (0, 1, 8, 1), label.Frame);
+			Assert.Equal (new Rect (9, 1, 20, 1), txtToFind.Frame);
+
+			Assert.Equal (0, txtToFind.ScrollOffset);
+			Assert.Equal (16, txtToFind.CursorPosition);
+
+			Assert.Equal (new Rect (30, 1, 20, 1), btnFindNext.Frame);
+			Assert.Equal (new Rect (30, 2, 20, 1), btnFindPrevious.Frame);
+			Assert.Equal (new Rect (30, 4, 20, 1), btnCancel.Frame);
+			Assert.Equal (new Rect (0, 3, 12, 1), ckbMatchCase.Frame);
+			Assert.Equal (new Rect (0, 4, 18, 1), ckbMatchWholeWord.Frame);
+			var expected = @"
+┌ Find ──────────────────────────────────────────────┐
+│┌────┐                                              │
+││Find│                                              │
+││    └─────────────────────────────────────────────┐│
+││                                                  ││
+││   Find: Testing buttons.       [◦ Find Next ◦]   ││
+││                               [ Find Previous ]  ││
+││√ Match case                                      ││
+││╴ Match whole word                 [ Cancel ]     ││
+│└──────────────────────────────────────────────────┘│
+└────────────────────────────────────────────────────┘
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Pos_Center_Layout_AutoSize_True ()
+		{
+			var button = new Button ("Process keys") {
+				X = Pos.Center (),
+				Y = Pos.Center (),
+				IsDefault = true
+			};
+			var win = new Window () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			win.Add (button);
+			Application.Top.Add (win);
+
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (30, 5);
+			Assert.True (button.AutoSize);
+			Assert.Equal (new Rect (5, 1, 18, 1), button.Frame);
+			var expected = @"
+┌────────────────────────────┐
+│                            │
+│     [◦ Process keys ◦]     │
+│                            │
+└────────────────────────────┘
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Pos_Center_Layout_AutoSize_False ()
+		{
+			var button = new Button ("Process keys") {
+				X = Pos.Center (),
+				Y = Pos.Center (),
+				Width = 20,
+				IsDefault = true,
+				AutoSize = false
+			};
+			var win = new Window () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			win.Add (button);
+			Application.Top.Add (win);
+
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (30, 5);
+			Assert.False (button.AutoSize);
+			Assert.Equal (new Rect (4, 1, 20, 1), button.Frame);
+			var expected = @"
+┌────────────────────────────┐
+│                            │
+│     [◦ Process keys ◦]     │
+│                            │
+└────────────────────────────┘
 ";
 
 			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);

+ 43 - 1
UnitTests/CheckboxTests.cs

@@ -19,26 +19,34 @@ namespace Terminal.Gui.Views {
 		public void Constructors_Defaults ()
 		{
 			var ckb = new CheckBox ();
+			Assert.True (ckb.AutoSize);
 			Assert.False (ckb.Checked);
 			Assert.Equal (string.Empty, ckb.Text);
+			Assert.Equal ("╴ ", ckb.TextFormatter.Text);
 			Assert.True (ckb.CanFocus);
 			Assert.Equal (new Rect (0, 0, 2, 1), ckb.Frame);
 
 			ckb = new CheckBox ("Test", true);
+			Assert.True (ckb.AutoSize);
 			Assert.True (ckb.Checked);
 			Assert.Equal ("Test", ckb.Text);
+			Assert.Equal ("√ Test", ckb.TextFormatter.Text);
 			Assert.True (ckb.CanFocus);
 			Assert.Equal (new Rect (0, 0, 6, 1), ckb.Frame);
 
 			ckb = new CheckBox (1, 2, "Test");
+			Assert.True (ckb.AutoSize);
 			Assert.False (ckb.Checked);
 			Assert.Equal ("Test", ckb.Text);
+			Assert.Equal ("╴ Test", ckb.TextFormatter.Text);
 			Assert.True (ckb.CanFocus);
 			Assert.Equal (new Rect (1, 2, 6, 1), ckb.Frame);
 
 			ckb = new CheckBox (3, 4, "Test", true);
+			Assert.True (ckb.AutoSize);
 			Assert.True (ckb.Checked);
 			Assert.Equal ("Test", ckb.Text);
+			Assert.Equal ("√ Test", ckb.TextFormatter.Text);
 			Assert.True (ckb.CanFocus);
 			Assert.Equal (new Rect (3, 4, 6, 1), ckb.Frame);
 		}
@@ -106,7 +114,6 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("Check this out 你", checkBox.Text);
 			Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text);
 			Assert.True (checkBox.AutoSize);
-
 			var expected = @"
 ┌ Test Demo 你 ──────────────┐
 │                            │
@@ -123,12 +130,21 @@ namespace Terminal.Gui.Views {
 			checkBox.AutoSize = true;
 			bool first = false;
 			Application.RunMainLoopIteration (ref runstate, true, ref first);
+			Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame);
+			expected = @"
+┌ Test Demo 你 ──────────────┐
+│                            │
+│ ╴ Check this out 你        │
+│                            │
+└────────────────────────────┘
+";
 
 			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 30, 5), pos);
 
 			checkBox.Checked = true;
 			Application.RunMainLoopIteration (ref runstate, true, ref first);
+			Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame);
 			expected = @"
 ┌ Test Demo 你 ──────────────┐
 │                            │
@@ -141,8 +157,27 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (new Rect (0, 0, 30, 5), pos);
 
 			checkBox.AutoSize = false;
+			// It isn't auto-size so the height is guaranteed by the SetMinWidthHeight
 			checkBox.Text = "Check this out 你 changed";
 			Application.RunMainLoopIteration (ref runstate, true, ref first);
+			Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame);
+			expected = @"
+┌ Test Demo 你 ──────────────┐
+│                            │
+│ √ Check this out 你        │
+│                            │
+└────────────────────────────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 30, 5), pos);
+
+			checkBox.Width = 19;
+			// It isn't auto-size so the height is guaranteed by the SetMinWidthHeight
+			checkBox.Text = "Check this out 你 changed";
+			Application.RunMainLoopIteration (ref runstate, true, ref first);
+			Assert.False (checkBox.AutoSize);
+			Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame);
 			expected = @"
 ┌ Test Demo 你 ──────────────┐
 │                            │
@@ -156,6 +191,7 @@ namespace Terminal.Gui.Views {
 
 			checkBox.AutoSize = true;
 			Application.RunMainLoopIteration (ref runstate, true, ref first);
+			Assert.Equal (new Rect (1, 1, 27, 1), checkBox.Frame);
 			expected = @"
 ┌ Test Demo 你 ──────────────┐
 │                            │
@@ -191,6 +227,7 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (TextAlignment.Left, checkBox.TextAlignment);
 			Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame);
+			Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size);
 			Assert.Equal ("Check this out 你", checkBox.Text);
 			Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text);
 			Assert.False (checkBox.AutoSize);
@@ -244,6 +281,7 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (TextAlignment.Centered, checkBox.TextAlignment);
 			Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame);
+			Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size);
 			Assert.Equal ("Check this out 你", checkBox.Text);
 			Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text);
 			Assert.False (checkBox.AutoSize);
@@ -297,6 +335,7 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (TextAlignment.Justified, checkBox.TextAlignment);
 			Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame);
+			Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size);
 			Assert.Equal ("Check this out 你", checkBox.Text);
 			Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text);
 			Assert.False (checkBox.AutoSize);
@@ -313,6 +352,8 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (new Rect (0, 0, 30, 5), pos);
 
 			checkBox.Checked = true;
+			Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame);
+			Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size);
 			Application.Refresh ();
 			expected = @"
 ┌ Test Demo 你 ──────────────┐
@@ -350,6 +391,7 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (TextAlignment.Right, checkBox.TextAlignment);
 			Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame);
+			Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size);
 			Assert.Equal ("Check this out 你", checkBox.Text);
 			Assert.Equal ("Check this out 你 ╴", checkBox.TextFormatter.Text);
 			Assert.False (checkBox.AutoSize);

+ 45 - 7
UnitTests/ComboBoxTests.cs

@@ -1,25 +1,38 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using Terminal.Gui;
 using Xunit;
+using Xunit.Abstractions;
 
 namespace Terminal.Gui.Views {
 	public class ComboBoxTests {
+		ITestOutputHelper output;
+
+		public ComboBoxTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
 		[Fact]
 		public void Constructors_Defaults ()
 		{
 			var cb = new ComboBox ();
 			Assert.Equal (string.Empty, cb.Text);
 			Assert.Null (cb.Source);
+			Assert.False (cb.AutoSize);
+			Assert.Equal (new Rect (0, 0, 0, 2), cb.Frame);
 
 			cb = new ComboBox ("Test");
 			Assert.Equal ("Test", cb.Text);
 			Assert.Null (cb.Source);
+			Assert.False (cb.AutoSize);
+			Assert.Equal (new Rect (0, 0, 0, 2), cb.Frame);
 
 			cb = new ComboBox (new Rect (1, 2, 10, 20), new List<string> () { "One", "Two", "Three" });
 			Assert.Equal (string.Empty, cb.Text);
 			Assert.NotNull (cb.Source);
+			Assert.False (cb.AutoSize);
+			Assert.Equal (new Rect (1, 2, 10, 20), cb.Frame);
 		}
 
 		[Fact]
@@ -44,12 +57,12 @@ namespace Terminal.Gui.Views {
 		public void KeyBindings_Command ()
 		{
 			List<string> source = new List<string> () { "One", "Two", "Three" };
-			ComboBox cb = new ComboBox ();
+			ComboBox cb = new ComboBox () { Width = 10 };
 			cb.SetSource (source);
 			Application.Top.Add (cb);
 			Application.Top.FocusFirst ();
 			Assert.Equal (-1, cb.SelectedItem);
-			Assert.Equal(string.Empty,cb.Text);
+			Assert.Equal (string.Empty, cb.Text);
 			var opened = false;
 			cb.OpenSelectedItem += (_) => opened = true;
 			Assert.True (cb.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ())));
@@ -63,7 +76,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (cb.ProcessKey (new KeyEvent (Key.F4, new KeyModifiers ()))); // with no source also expand empty
 			Assert.True (cb.IsShow);
 			Assert.Equal (-1, cb.SelectedItem);
-			cb.SetSource(source);
+			cb.SetSource (source);
 			cb.Text = "";
 			Assert.True (cb.ProcessKey (new KeyEvent (Key.F4, new KeyModifiers ()))); // collapse
 			Assert.False (cb.IsShow);
@@ -106,8 +119,33 @@ namespace Terminal.Gui.Views {
 			Assert.True (cb.IsShow);
 			Assert.Equal (0, cb.SelectedItem);
 			Assert.Equal ("One", cb.Text);
+			Application.Begin (Application.Top);
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
+One      ▼
+One
+", output);
+
+			Assert.True (cb.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ())));
+			Assert.True (cb.IsShow);
+			Assert.Equal (1, cb.SelectedItem);
+			Assert.Equal ("Two", cb.Text);
+			Application.Begin (Application.Top);
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
+Two      ▼
+Two
+", output);
+
 			Assert.True (cb.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ())));
 			Assert.True (cb.IsShow);
+			Assert.Equal (2, cb.SelectedItem);
+			Assert.Equal ("Three", cb.Text);
+			Application.Begin (Application.Top);
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
+Three    ▼
+Three
+", output);
+			Assert.True (cb.ProcessKey (new KeyEvent (Key.PageUp, new KeyModifiers ())));
+			Assert.True (cb.IsShow);
 			Assert.Equal (1, cb.SelectedItem);
 			Assert.Equal ("Two", cb.Text);
 			Assert.True (cb.ProcessKey (new KeyEvent (Key.PageUp, new KeyModifiers ())));
@@ -167,10 +205,10 @@ namespace Terminal.Gui.Views {
 			var cb = new ComboBox ();
 			Application.Top.Add (cb);
 			Application.Top.FocusFirst ();
-			Assert.Null(cb.Source);
+			Assert.Null (cb.Source);
 			Assert.Equal (-1, cb.SelectedItem);
 			var source = new List<string> ();
-			cb.SetSource(source);
+			cb.SetSource (source);
 			Assert.NotNull (cb.Source);
 			Assert.Equal (0, cb.Source.Count);
 			Assert.Equal (-1, cb.SelectedItem);
@@ -197,7 +235,7 @@ namespace Terminal.Gui.Views {
 			Assert.False (cb.IsShow);
 			Assert.Equal (1, cb.SelectedItem); // retains last accept selected item
 			Assert.Equal ("", cb.Text); // clear text
-			cb.SetSource(new List<string> ());
+			cb.SetSource (new List<string> ());
 			Assert.Equal (0, cb.Source.Count);
 			Assert.Equal (-1, cb.SelectedItem);
 			Assert.Equal ("", cb.Text);

+ 115 - 56
UnitTests/DimTests.cs

@@ -250,7 +250,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact]
-		public void Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type ()
+		public void ForceValidatePosDim_True_Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type ()
 		{
 			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 
@@ -262,7 +262,8 @@ namespace Terminal.Gui.Core {
 			};
 			var v = new View ("v") {
 				Width = Dim.Width (w) - 2,
-				Height = Dim.Percent (10)
+				Height = Dim.Percent (10),
+				ForceValidatePosDim = true
 			};
 
 			w.Add (v);
@@ -273,6 +274,13 @@ namespace Terminal.Gui.Core {
 				Assert.Equal (2, w.Height = 2);
 				Assert.Throws<ArgumentException> (() => v.Width = 2);
 				Assert.Throws<ArgumentException> (() => v.Height = 2);
+				v.ForceValidatePosDim = false;
+				var exception = Record.Exception (() => v.Width = 2);
+				Assert.Null (exception);
+				Assert.Equal (2, v.Width);
+				exception = Record.Exception (() => v.Height = 2);
+				Assert.Null (exception);
+				Assert.Equal (2, v.Height);
 			};
 
 			Application.Iteration += () => Application.RequestStop ();
@@ -362,39 +370,51 @@ namespace Terminal.Gui.Core {
 			};
 
 			var v1 = new Button ("v1") {
+				AutoSize = false,
 				X = Pos.X (f1) + 2,
 				Y = Pos.Bottom (f1) + 2,
 				Width = Dim.Width (f1) - 2,
-				Height = Dim.Fill () - 2
+				Height = Dim.Fill () - 2,
+				ForceValidatePosDim = true
 			};
 
 			var v2 = new Button ("v2") {
+				AutoSize = false,
 				X = Pos.X (f2) + 2,
 				Y = Pos.Bottom (f2) + 2,
 				Width = Dim.Width (f2) - 2,
-				Height = Dim.Fill () - 2
+				Height = Dim.Fill () - 2,
+				ForceValidatePosDim = true
 			};
 
 			var v3 = new Button ("v3") {
+				AutoSize = false,
 				Width = Dim.Percent (10),
-				Height = Dim.Percent (10)
+				Height = Dim.Percent (10),
+				ForceValidatePosDim = true
 			};
 
 			var v4 = new Button ("v4") {
+				AutoSize = false,
 				Width = Dim.Sized (50),
-				Height = Dim.Sized (50)
+				Height = Dim.Sized (50),
+				ForceValidatePosDim = true
 			};
 
 			var v5 = new Button ("v5") {
+				AutoSize = false,
 				Width = Dim.Width (v1) - Dim.Width (v3),
-				Height = Dim.Height (v1) - Dim.Height (v3)
+				Height = Dim.Height (v1) - Dim.Height (v3),
+				ForceValidatePosDim = true
 			};
 
 			var v6 = new Button ("v6") {
+				AutoSize = false,
 				X = Pos.X (f2),
 				Y = Pos.Bottom (f2) + 2,
 				Width = Dim.Percent (20, true),
-				Height = Dim.Percent (20, true)
+				Height = Dim.Percent (20, true),
+				ForceValidatePosDim = true
 			};
 
 			w.Add (f1, f2, v1, v2, v3, v4, v5, v6);
@@ -421,7 +441,6 @@ namespace Terminal.Gui.Core {
 				Assert.Equal (47, v1.Frame.Width); // 49-2=47
 				Assert.Equal (89, v1.Frame.Height); // 98-5-2-2=89
 
-
 				Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=49,Y=0,Width=49,Height=5}))-Dim.Absolute(2))", v2.Width.ToString ());
 				Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v2.Height.ToString ());
 				Assert.Equal (47, v2.Frame.Width); // 49-2=47
@@ -471,26 +490,28 @@ namespace Terminal.Gui.Core {
 
 				v1.Text = "Button1";
 				Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=0,Y=0,Width=99,Height=5}))-Dim.Absolute(2))", v1.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v1.Height.ToString ());
+				Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v1.Height.ToString ());
 				Assert.Equal (97, v1.Frame.Width); // 99-2=97
-				Assert.Equal (1, v1.Frame.Height); // 1 because is Dim.DimAbsolute
+				Assert.Equal (189, v1.Frame.Height); // 198-2-7=189
 
 				v2.Text = "Button2";
 				Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=99,Y=0,Width=99,Height=5}))-Dim.Absolute(2))", v2.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v2.Height.ToString ());
+				Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v2.Height.ToString ());
 				Assert.Equal (97, v2.Frame.Width); // 99-2=97
-				Assert.Equal (1, v2.Frame.Height); // 1 because is Dim.DimAbsolute
+				Assert.Equal (189, v2.Frame.Height); // 198-2-7=189
 
 				v3.Text = "Button3";
 				Assert.Equal ("Dim.Factor(factor=0.1, remaining=False)", v3.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v3.Height.ToString ());
+				Assert.Equal ("Dim.Factor(factor=0.1, remaining=False)", v3.Height.ToString ());
 				Assert.Equal (19, v3.Frame.Width); // 198*10%=19 * Percent is related to the super-view if it isn't null otherwise the view width
-				Assert.Equal (1, v3.Frame.Height); // 1 because is Dim.DimAbsolute
+				Assert.Equal (19, v3.Frame.Height); // 199*10%=19
 
 				v4.Text = "Button4";
 				v4.AutoSize = false;
 				Assert.Equal ("Dim.Absolute(50)", v4.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ());
+				Assert.Equal ("Dim.Absolute(50)", v4.Height.ToString ());
+				Assert.Equal (50, v4.Frame.Width);
+				Assert.Equal (50, v4.Frame.Height);
 				v4.AutoSize = true;
 				Assert.Equal ("Dim.Absolute(11)", v4.Width.ToString ());
 				Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ());
@@ -498,16 +519,16 @@ namespace Terminal.Gui.Core {
 				Assert.Equal (1, v4.Frame.Height); // 1 because is Dim.DimAbsolute
 
 				v5.Text = "Button5";
-				Assert.Equal ("Dim.Combine(DimView(side=Width, target=Button()({X=2,Y=7,Width=97,Height=1}))-DimView(side=Width, target=Button()({X=0,Y=0,Width=19,Height=1})))", v5.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v5.Height.ToString ());
+				Assert.Equal ("Dim.Combine(DimView(side=Width, target=Button()({X=2,Y=7,Width=97,Height=189}))-DimView(side=Width, target=Button()({X=0,Y=0,Width=19,Height=19})))", v5.Width.ToString ());
+				Assert.Equal ("Dim.Combine(DimView(side=Height, target=Button()({X=2,Y=7,Width=97,Height=189}))-DimView(side=Height, target=Button()({X=0,Y=0,Width=19,Height=19})))", v5.Height.ToString ());
 				Assert.Equal (78, v5.Frame.Width); // 97-19=78
-				Assert.Equal (1, v5.Frame.Height); // 1 because is Dim.DimAbsolute
+				Assert.Equal (170, v5.Frame.Height); // 189-19=170
 
 				v6.Text = "Button6";
 				Assert.Equal ("Dim.Factor(factor=0.2, remaining=True)", v6.Width.ToString ());
-				Assert.Equal ("Dim.Absolute(1)", v6.Height.ToString ());
+				Assert.Equal ("Dim.Factor(factor=0.2, remaining=True)", v6.Height.ToString ());
 				Assert.Equal (19, v6.Frame.Width); // 99*20%=19
-				Assert.Equal (1, v6.Frame.Height); // 1 because is Dim.DimAbsolute
+				Assert.Equal (38, v6.Frame.Height); // 198-7*20=38
 			};
 
 			Application.Iteration += () => Application.RequestStop ();
@@ -649,56 +670,63 @@ namespace Terminal.Gui.Core {
 		private string [] expecteds = new string [21] {
 @"
 ┌────────────────────┐
-│View                │
+│View with long text │
+│                    │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View                │
+│View with long text │
+│Label 0             │
 │Label 0             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
+│Label 1             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
+│Label 2             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
 │Label 3             │
+│Label 3             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
 │Label 3             │
 │Label 4             │
+│Label 4             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
 │Label 3             │
 │Label 4             │
 │Label 5             │
+│Label 5             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -706,10 +734,11 @@ namespace Terminal.Gui.Core {
 │Label 4             │
 │Label 5             │
 │Label 6             │
+│Label 6             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -718,10 +747,11 @@ namespace Terminal.Gui.Core {
 │Label 5             │
 │Label 6             │
 │Label 7             │
+│Label 7             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -731,10 +761,11 @@ namespace Terminal.Gui.Core {
 │Label 6             │
 │Label 7             │
 │Label 8             │
+│Label 8             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -745,10 +776,11 @@ namespace Terminal.Gui.Core {
 │Label 7             │
 │Label 8             │
 │Label 9             │
+│Label 9             │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -760,10 +792,11 @@ namespace Terminal.Gui.Core {
 │Label 8             │
 │Label 9             │
 │Label 10            │
+│Label 10            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -776,10 +809,11 @@ namespace Terminal.Gui.Core {
 │Label 9             │
 │Label 10            │
 │Label 11            │
+│Label 11            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -793,10 +827,11 @@ namespace Terminal.Gui.Core {
 │Label 10            │
 │Label 11            │
 │Label 12            │
+│Label 12            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -811,10 +846,11 @@ namespace Terminal.Gui.Core {
 │Label 11            │
 │Label 12            │
 │Label 13            │
+│Label 13            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -830,10 +866,11 @@ namespace Terminal.Gui.Core {
 │Label 12            │
 │Label 13            │
 │Label 14            │
+│Label 14            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -850,10 +887,11 @@ namespace Terminal.Gui.Core {
 │Label 13            │
 │Label 14            │
 │Label 15            │
+│Label 15            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -871,10 +909,11 @@ namespace Terminal.Gui.Core {
 │Label 14            │
 │Label 15            │
 │Label 16            │
+│Label 16            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -893,10 +932,11 @@ namespace Terminal.Gui.Core {
 │Label 15            │
 │Label 16            │
 │Label 17            │
+│Label 17            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -916,10 +956,11 @@ namespace Terminal.Gui.Core {
 │Label 16            │
 │Label 17            │
 │Label 18            │
+│Label 18            │
 └────────────────────┘",
 @"
 ┌────────────────────┐
-│View               
+│View with long text
 │Label 0             │
 │Label 1             │
 │Label 2             │
@@ -940,7 +981,8 @@ namespace Terminal.Gui.Core {
 │Label 17            │
 │Label 18            │
 │Label 19            │
-└────────────────────┘"
+│Label 19            │
+└────────────────────┘",
 };
 
 		[Fact]
@@ -951,26 +993,32 @@ namespace Terminal.Gui.Core {
 
 			var top = Application.Top;
 
-			var view = new View ("View") { X = 0, Y = 0, Width = 20, Height = 0 };
+			// Although view height is zero the text it's draw due the SetMinWidthHeight method
+			var view = new View ("View with long text") { X = 0, Y = 0, Width = 20, Height = 0 };
 			var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
 			var count = 0;
 			var listLabels = new List<Label> ();
 
 			field.KeyDown += (k) => {
 				if (k.KeyEvent.Key == Key.Enter) {
-					((FakeDriver)Application.Driver).SetBufferSize (22, count + 3);
+					((FakeDriver)Application.Driver).SetBufferSize (22, count + 4);
 					var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expecteds [count], output);
-					Assert.Equal (new Rect (0, 0, 22, count + 3), pos);
+					Assert.Equal (new Rect (0, 0, 22, count + 4), pos);
 
 					if (count < 20) {
 						field.Text = $"Label {count}";
-						var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 20 };
+						var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 10 };
 						view.Add (label);
 						Assert.Equal ($"Label {count}", label.Text);
 						Assert.Equal ($"Pos.Absolute({count + 1})", label.Y.ToString ());
 						listLabels.Add (label);
-						Assert.Equal ($"Dim.Absolute({count + 1})", view.Height.ToString ());
-						view.Height += 1;
+						if (count == 0) {
+							Assert.Equal ($"Dim.Absolute({count})", view.Height.ToString ());
+							view.Height += 2;
+						} else {
+							Assert.Equal ($"Dim.Absolute({count + 1})", view.Height.ToString ());
+							view.Height += 1;
+						}
 						count++;
 					}
 					Assert.Equal ($"Dim.Absolute({count + 1})", view.Height.ToString ());
@@ -1072,29 +1120,36 @@ namespace Terminal.Gui.Core {
 
 			var top = Application.Top;
 
-			var view = new View ("View") { X = 0, Y = 0, Width = 20, Height = 0 };
+			// Although view height is zero the text it's draw due the SetMinWidthHeight method
+			var view = new View ("View with long text") { X = 0, Y = 0, Width = 20, Height = 0 };
 			var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
 			var count = 20;
 			var listLabels = new List<Label> ();
 
 			for (int i = 0; i < count; i++) {
 				field.Text = $"Label {i}";
-				var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 20 };
+				var label = new Label (field.Text) { X = 0, Y = view.Bounds.Height, Width = 10 };
 				view.Add (label);
 				Assert.Equal ($"Label {i}", label.Text);
 				Assert.Equal ($"Pos.Absolute({i + 1})", label.Y.ToString ());
 				listLabels.Add (label);
 
-				Assert.Equal ($"Dim.Absolute({i + 1})", view.Height.ToString ());
-				view.Height += 1;
-				Assert.Equal ($"Dim.Absolute({i + 2})", view.Height.ToString ());
+				if (i == 0) {
+					Assert.Equal ($"Dim.Absolute({i})", view.Height.ToString ());
+					view.Height += 2;
+					Assert.Equal ($"Dim.Absolute({i + 2})", view.Height.ToString ());
+				} else {
+					Assert.Equal ($"Dim.Absolute({i + 1})", view.Height.ToString ());
+					view.Height += 1;
+					Assert.Equal ($"Dim.Absolute({i + 2})", view.Height.ToString ());
+				}
 			}
 
 			field.KeyDown += (k) => {
 				if (k.KeyEvent.Key == Key.Enter) {
-					((FakeDriver)Application.Driver).SetBufferSize (22, count + 3);
+					((FakeDriver)Application.Driver).SetBufferSize (22, count + 4);
 					var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expecteds [count], output);
-					Assert.Equal (new Rect (0, 0, 22, count + 3), pos);
+					Assert.Equal (new Rect (0, 0, 22, count + 4), pos);
 
 					if (count > 0) {
 						Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
@@ -1103,6 +1158,10 @@ namespace Terminal.Gui.Core {
 						Assert.Equal ($"Dim.Absolute({count + 1})", view.Height.ToString ());
 						view.Height -= 1;
 						count--;
+						if (listLabels.Count > 0)
+							field.Text = listLabels [count - 1].Text;
+						else
+							field.Text = NStack.ustring.Empty;
 					}
 					Assert.Equal ($"Dim.Absolute({count + 1})", view.Height.ToString ());
 				}

+ 5 - 2
UnitTests/PanelViewTests.cs

@@ -350,7 +350,8 @@ namespace Terminal.Gui.Views {
 				Text = "This is a test\nwith a \nPanelView",
 				TextAlignment = TextAlignment.Centered,
 				Width = 24,
-				Height = 13
+				Height = 13,
+				AutoSize = false
 			};
 			var pv = new PanelView (label) {
 				Width = 24,
@@ -413,7 +414,7 @@ namespace Terminal.Gui.Views {
 		{
 			var top = Application.Top;
 			var win = new Window ();
-			var label = new Label ("Hello World") {
+			var label = new Label () {
 				ColorScheme = Colors.TopLevel,
 				Text = "This is a test\nwith a \nPanelView",
 				TextAlignment = TextAlignment.Centered
@@ -436,6 +437,8 @@ namespace Terminal.Gui.Views {
 
 			Application.Begin (top);
 
+			Assert.True (label.AutoSize);
+			Assert.False (pv.UsePanelFrame);
 			Assert.Equal (new Rect (0, 0, 14, 3), label.Frame);
 			Assert.Equal (new Rect (0, 0, 24, 13), pv.Frame);
 			Assert.Equal (new Rect (0, 0, 80, 25), win.Frame);

+ 179 - 13
UnitTests/PosTests.cs

@@ -1,17 +1,26 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.IO;
 using System.Linq;
 using Terminal.Gui;
+using Terminal.Gui.Views;
 using Xunit;
+using Xunit.Abstractions;
 
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 
 namespace Terminal.Gui.Core {
 	public class PosTests {
+		readonly ITestOutputHelper output;
+
+		public PosTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
 		[Fact]
 		public void New_Works ()
 		{
@@ -123,7 +132,7 @@ namespace Terminal.Gui.Core {
 				ColorScheme = Colors.Menu,
 				Width = Dim.Fill (),
 				X = Pos.Center (),
-				Y = Pos.Bottom (win) - 4  // two lines top border more two lines above border
+				Y = Pos.Bottom (win) - 3  // two lines top and bottom borders more one line above the bottom border
 			};
 
 			win.Add (label);
@@ -131,15 +140,78 @@ namespace Terminal.Gui.Core {
 			var top = Application.Top;
 			top.Add (win);
 			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (40, 10);
+
+			Assert.True (label.AutoSize);
+			Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
+			Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
+			Assert.Equal (new Rect (1, 1, 38, 8), win.Subviews [0].Frame);
+			Assert.Equal ("ContentView()({X=1,Y=1,Width=38,Height=8})", win.Subviews [0].ToString ());
+			Assert.Equal (new Rect (0, 0, 40, 10), new Rect (
+				win.Frame.Left, win.Frame.Top,
+				win.Frame.Right, win.Frame.Bottom));
+			Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
+			var expected = @"
+┌──────────────────────────────────────┐
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│    This should be the last line.     │
+└──────────────────────────────────────┘
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+		}
 
-			Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
-			Assert.Equal (new Rect (0, 0, 80, 25), win.Frame);
-			Assert.Equal (new Rect (1, 1, 78, 23), win.Subviews [0].Frame);
-			Assert.Equal ("ContentView()({X=1,Y=1,Width=78,Height=23})", win.Subviews [0].ToString ());
-			Assert.Equal (new Rect (0, 0, 80, 25), new Rect (
+		[Fact]
+		[AutoInitShutdown]
+		public void AnchorEnd_Better_Than_Bottom_Equal_Inside_Window ()
+		{
+			var win = new Window ();
+
+			var label = new Label ("This should be the last line.") {
+				TextAlignment = Terminal.Gui.TextAlignment.Centered,
+				ColorScheme = Colors.Menu,
+				Width = Dim.Fill (),
+				X = Pos.Center (),
+				Y = Pos.AnchorEnd (1)
+			};
+
+			win.Add (label);
+
+			var top = Application.Top;
+			top.Add (win);
+			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (40, 10);
+
+			Assert.True (label.AutoSize);
+			Assert.Equal (29, label.Text.Length);
+			Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
+			Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
+			Assert.Equal (new Rect (1, 1, 38, 8), win.Subviews [0].Frame);
+			Assert.Equal ("ContentView()({X=1,Y=1,Width=38,Height=8})", win.Subviews [0].ToString ());
+			Assert.Equal (new Rect (0, 0, 40, 10), new Rect (
 				win.Frame.Left, win.Frame.Top,
 				win.Frame.Right, win.Frame.Bottom));
-			Assert.Equal (new Rect (0, 21, 78, 1), label.Frame);
+			Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
+			var expected = @"
+┌──────────────────────────────────────┐
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│                                      │
+│    This should be the last line.     │
+└──────────────────────────────────────┘
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 		}
 
 		[Fact]
@@ -153,17 +225,18 @@ namespace Terminal.Gui.Core {
 				ColorScheme = Colors.Menu,
 				Width = Dim.Fill (),
 				X = Pos.Center (),
-				Y = Pos.Bottom (win) - 4  // two lines top border more two lines above border
+				Y = Pos.Bottom (win) - 4  // two lines top and bottom borders more two lines above border
 			};
 
 			win.Add (label);
 
-			var menu = new MenuBar ();
-			var status = new StatusBar ();
+			var menu = new MenuBar (new MenuBarItem [] { new ("Menu", "", null) });
+			var status = new StatusBar (new StatusItem [] { new (Key.F1, "~F1~ Help", null) });
 			var top = Application.Top;
 			top.Add (win, menu, status);
 			Application.Begin (top);
 
+			Assert.True (label.AutoSize);
 			Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
 			Assert.Equal (new Rect (0, 0, 80, 1), menu.Frame);
 			Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
@@ -173,6 +246,98 @@ namespace Terminal.Gui.Core {
 				win.Frame.Left, win.Frame.Top,
 				win.Frame.Right, win.Frame.Bottom));
 			Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
+			var expected = @"
+  Menu
+┌──────────────────────────────────────────────────────────────────────────────┐
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                        This should be the last line.                         │
+└──────────────────────────────────────────────────────────────────────────────┘
+ F1 Help
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void AnchorEnd_Better_Than_Bottom_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
+		{
+			var win = new Window ();
+
+			var label = new Label ("This should be the last line.") {
+				TextAlignment = Terminal.Gui.TextAlignment.Centered,
+				ColorScheme = Colors.Menu,
+				Width = Dim.Fill (),
+				X = Pos.Center (),
+				Y = Pos.AnchorEnd (1)
+			};
+
+			win.Add (label);
+
+			var menu = new MenuBar (new MenuBarItem [] { new ("Menu", "", null) });
+			var status = new StatusBar (new StatusItem [] { new (Key.F1, "~F1~ Help", null) });
+			var top = Application.Top;
+			top.Add (win, menu, status);
+			Application.Begin (top);
+
+			Assert.True (label.AutoSize);
+			Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
+			Assert.Equal (new Rect (0, 0, 80, 1), menu.Frame);
+			Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
+			Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
+			Assert.Equal (new Rect (1, 1, 78, 21), win.Subviews [0].Frame);
+			Assert.Equal (new Rect (0, 1, 80, 24), new Rect (
+				win.Frame.Left, win.Frame.Top,
+				win.Frame.Right, win.Frame.Bottom));
+			Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
+			var expected = @"
+  Menu
+┌──────────────────────────────────────────────────────────────────────────────┐
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                                                                              │
+│                        This should be the last line.                         │
+└──────────────────────────────────────────────────────────────────────────────┘
+ F1 Help
+";
+
+			GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 		}
 
 		[Fact]
@@ -533,7 +698,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact]
-		public void Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
+		public void ForceValidatePosDim_True_Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
 		{
 			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 
@@ -545,7 +710,8 @@ namespace Terminal.Gui.Core {
 			};
 			var v = new View ("v") {
 				X = Pos.Center (),
-				Y = Pos.Percent (10)
+				Y = Pos.Percent (10),
+				ForceValidatePosDim = true
 			};
 
 			w.Add (v);

+ 82 - 22
UnitTests/RadioGroupTests.cs

@@ -4,46 +4,60 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Xunit;
+using Xunit.Abstractions;
 
 namespace Terminal.Gui.Views {
 	public class RadioGroupTests {
+		readonly ITestOutputHelper output;
+
+		public RadioGroupTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
 		[Fact]
 		public void Constructors_Defaults ()
 		{
 			var rg = new RadioGroup ();
 			Assert.True (rg.CanFocus);
 			Assert.Empty (rg.RadioLabels);
-			Assert.Equal (0, rg.X);
-			Assert.Equal (0, rg.Y);
-			Assert.Equal (0, rg.Width);
-			Assert.Equal (0, rg.Height);
+			Assert.Null (rg.X);
+			Assert.Null (rg.Y);
+			Assert.Null (rg.Width);
+			Assert.Null (rg.Height);
+			Assert.Equal (Rect.Empty, rg.Frame);
 			Assert.Equal (0, rg.SelectedItem);
 
 			rg = new RadioGroup (new NStack.ustring [] { "Test" });
 			Assert.True (rg.CanFocus);
 			Assert.Single (rg.RadioLabels);
-			Assert.Equal (0, rg.X);
-			Assert.Equal (0, rg.Y);
-			Assert.Equal (7, rg.Width);
-			Assert.Equal (1, rg.Height);
+			Assert.Null (rg.X);
+			Assert.Null (rg.Y);
+			Assert.Null (rg.Width);
+			Assert.Null (rg.Height);
+			Assert.Equal (new Rect (0, 0, 7, 1), rg.Frame);
 			Assert.Equal (0, rg.SelectedItem);
 
 			rg = new RadioGroup (new Rect (1, 2, 20, 5), new NStack.ustring [] { "Test" });
 			Assert.True (rg.CanFocus);
 			Assert.Single (rg.RadioLabels);
-			Assert.Equal (1, rg.X);
-			Assert.Equal (2, rg.Y);
-			Assert.Equal (20, rg.Width);
-			Assert.Equal (5, rg.Height);
+			Assert.Equal (LayoutStyle.Absolute, rg.LayoutStyle);
+			Assert.Null (rg.X);
+			Assert.Null (rg.Y);
+			Assert.Null (rg.Width);
+			Assert.Null (rg.Height);
+			Assert.Equal (new Rect (1, 2, 20, 5), rg.Frame);
 			Assert.Equal (0, rg.SelectedItem);
 
 			rg = new RadioGroup (1, 2, new NStack.ustring [] { "Test" });
 			Assert.True (rg.CanFocus);
 			Assert.Single (rg.RadioLabels);
-			Assert.Equal (1, rg.X);
-			Assert.Equal (2, rg.Y);
-			Assert.Equal (7, rg.Width);
-			Assert.Equal (1, rg.Height);
+			Assert.Equal (LayoutStyle.Absolute, rg.LayoutStyle);
+			Assert.Null (rg.X);
+			Assert.Null (rg.Y);
+			Assert.Null (rg.Width);
+			Assert.Null (rg.Height);
+			Assert.Equal (new Rect (1, 2, 7, 1), rg.Frame);
 			Assert.Equal (0, rg.SelectedItem);
 		}
 
@@ -56,32 +70,78 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (0, rg.SelectedItem);
 		}
 
-		[Fact]
-		public void DisplayMode_Width_Height_HorizontalSpace ()
+		[Fact, AutoInitShutdown]
+		public void DisplayMode_Width_Height_Vertical_Horizontal_Space ()
 		{
-			var rg = new RadioGroup (new NStack.ustring [] { "Test", "New Test" });
+			var rg = new RadioGroup (new NStack.ustring [] { "Test", "New Test 你" });
+			var win = new Window () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill (),
+				Title = "Test Demo 你"
+			};
+			win.Add (rg);
+			Application.Top.Add (win);
+
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (30, 5);
+
 			Assert.Equal (DisplayModeLayout.Vertical, rg.DisplayMode);
 			Assert.Equal (2, rg.RadioLabels.Length);
 			Assert.Equal (0, rg.X);
 			Assert.Equal (0, rg.Y);
-			Assert.Equal (11, rg.Width);
+			Assert.Equal (14, rg.Width);
 			Assert.Equal (2, rg.Height);
+			var expected = @"
+┌ Test Demo 你 ──────────────┐
+│● Test                      │
+│◌ New Test 你               │
+│                            │
+└────────────────────────────┘
+";
+
+			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 30, 5), pos);
 
 			rg.DisplayMode = DisplayModeLayout.Horizontal;
+			Application.Refresh ();
+
 			Assert.Equal (DisplayModeLayout.Horizontal, rg.DisplayMode);
 			Assert.Equal (2, rg.HorizontalSpace);
 			Assert.Equal (0, rg.X);
 			Assert.Equal (0, rg.Y);
-			Assert.Equal (16, rg.Width);
+			Assert.Equal (21, rg.Width);
 			Assert.Equal (1, rg.Height);
 
+			expected = @"
+┌ Test Demo 你 ──────────────┐
+│● Test  ◌ New Test 你       │
+│                            │
+│                            │
+└────────────────────────────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 30, 5), pos);
+
 			rg.HorizontalSpace = 4;
+			Application.Refresh ();
+
 			Assert.Equal (DisplayModeLayout.Horizontal, rg.DisplayMode);
 			Assert.Equal (4, rg.HorizontalSpace);
 			Assert.Equal (0, rg.X);
 			Assert.Equal (0, rg.Y);
-			Assert.Equal (20, rg.Width);
+			Assert.Equal (23, rg.Width);
 			Assert.Equal (1, rg.Height);
+			expected = @"
+┌ Test Demo 你 ──────────────┐
+│● Test    ◌ New Test 你     │
+│                            │
+│                            │
+└────────────────────────────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 30, 5), pos);
 		}
 
 		[Fact]

+ 10 - 8
UnitTests/ScrollViewTests.cs

@@ -11,25 +11,27 @@ namespace Terminal.Gui.Views {
 		public void Constructors_Defaults ()
 		{
 			var sv = new ScrollView ();
+			Assert.Equal (LayoutStyle.Computed, sv.LayoutStyle);
 			Assert.True (sv.CanFocus);
 			Assert.Equal (new Rect (0, 0, 0, 0), sv.Frame);
 			Assert.Equal (Rect.Empty, sv.Frame);
-			Assert.Equal (0, sv.X);
-			Assert.Equal (0, sv.Y);
-			Assert.Equal (0, sv.Width);
-			Assert.Equal (0, sv.Height);
+			Assert.Null (sv.X);
+			Assert.Null (sv.Y);
+			Assert.Null (sv.Width);
+			Assert.Null (sv.Height);
 			Assert.Equal (Point.Empty, sv.ContentOffset);
 			Assert.Equal (Size.Empty, sv.ContentSize);
 			Assert.True (sv.AutoHideScrollBars);
 			Assert.True (sv.KeepContentAlwaysInViewport);
 
 			sv = new ScrollView (new Rect (1, 2, 20, 10));
+			Assert.Equal (LayoutStyle.Absolute, sv.LayoutStyle);
 			Assert.True (sv.CanFocus);
 			Assert.Equal (new Rect (1, 2, 20, 10), sv.Frame);
-			Assert.Equal (1, sv.X);
-			Assert.Equal (2, sv.Y);
-			Assert.Equal (20, sv.Width);
-			Assert.Equal (10, sv.Height);
+			Assert.Null (sv.X);
+			Assert.Null (sv.Y);
+			Assert.Null (sv.Width);
+			Assert.Null (sv.Height);
 			Assert.Equal (Point.Empty, sv.ContentOffset);
 			Assert.Equal (Size.Empty, sv.ContentSize);
 			Assert.True (sv.AutoHideScrollBars);

+ 1 - 1
UnitTests/StatusBarTests.cs

@@ -34,7 +34,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (Dim.Fill (), sb.Width);
 			Assert.Equal (1, sb.Height);
 
-			Assert.Equal (0, sb.Y);
+			Assert.Null (sb.Y);
 
 			var driver = new FakeDriver ();
 			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));

+ 28 - 10
UnitTests/TextFieldTests.cs

@@ -1181,35 +1181,53 @@ namespace Terminal.Gui.Views {
 
 		[Fact]
 		[AutoInitShutdown]
-		public void Test_RootKeyEvent_Cancel()
+		public void Test_RootKeyEvent_Cancel ()
 		{
 			Application.RootKeyEvent += SuppressKey;
 
-			var tf = new TextField();
+			var tf = new TextField ();
 
 			Application.Top.Add (tf);
 			Application.Begin (Application.Top);
-			
-			Application.Driver.SendKeys('a',ConsoleKey.A,false,false,false);
-			Assert.Equal("a", tf.Text.ToString ());
+
+			Application.Driver.SendKeys ('a', ConsoleKey.A, false, false, false);
+			Assert.Equal ("a", tf.Text.ToString ());
 
 			// SuppressKey suppresses the 'j' key
-			Application.Driver.SendKeys('j',ConsoleKey.A,false,false,false);
-			Assert.Equal("a", tf.Text.ToString ());
+			Application.Driver.SendKeys ('j', ConsoleKey.A, false, false, false);
+			Assert.Equal ("a", tf.Text.ToString ());
 
 			Application.RootKeyEvent -= SuppressKey;
 
 			// Now that the delegate has been removed we can type j again
-			Application.Driver.SendKeys('j',ConsoleKey.A,false,false,false);
-			Assert.Equal("aj", tf.Text.ToString ());
+			Application.Driver.SendKeys ('j', ConsoleKey.A, false, false, false);
+			Assert.Equal ("aj", tf.Text.ToString ());
 		}
 
 		private bool SuppressKey (KeyEvent arg)
 		{
-			if(arg.KeyValue == 'j')
+			if (arg.KeyValue == 'j')
 				return true;
 
 			return false;
 		}
+
+		[Fact, AutoInitShutdown]
+		public void ScrollOffset_Initialize ()
+		{
+			var tf = new TextField ("Testing Scrolls.") {
+				X = 1,
+				Y = 1,
+				Width = 20
+			};
+			Assert.Equal (0, tf.ScrollOffset);
+			Assert.Equal (16, tf.CursorPosition);
+
+			Application.Top.Add (tf);
+			Application.Begin (Application.Top);
+
+			Assert.Equal (0, tf.ScrollOffset);
+			Assert.Equal (16, tf.CursorPosition);
+		}
 	}
 }

Разлика између датотеке није приказан због своје велике величине
+ 148 - 37
UnitTests/TextFormatterTests.cs


+ 1 - 0
UnitTests/ToplevelTests.cs

@@ -37,6 +37,7 @@ namespace Terminal.Gui.Core {
 
 			Application.Iteration += () => {
 				if (iterations == 0) {
+					Assert.False (Application.Top.AutoSize);
 					Assert.Equal ("Top1", Application.Top.Text);
 					Assert.Equal (0, Application.Top.Frame.X);
 					Assert.Equal (0, Application.Top.Frame.Y);

+ 598 - 156
UnitTests/ViewTests.cs

@@ -29,11 +29,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.Null (r.ColorScheme);
-			Assert.Equal (Dim.Sized (0), r.Width);
-			Assert.Equal (Dim.Sized (0), r.Height);
-			// FIXED: Pos needs equality implemented
-			Assert.Equal (Pos.At (0), r.X);
-			Assert.Equal (Pos.At (0), r.Y);
+			Assert.Null (r.Width);
+			Assert.Null (r.Height);
+			Assert.Null (r.X);
+			Assert.Null (r.Y);
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.Empty (r.Subviews);
@@ -54,10 +53,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.Null (r.ColorScheme);
-			Assert.NotNull (r.Width);       // All view Dim are initialized now,
-			Assert.NotNull (r.Height);      // avoiding Dim errors.
-			Assert.NotNull (r.X);           // All view Pos are initialized now,
-			Assert.NotNull (r.Y);           // avoiding Pos errors.
+			Assert.Null (r.Width);       // All view Dim are initialized now in the IsAdded setter,
+			Assert.Null (r.Height);      // avoiding Dim errors.
+			Assert.Null (r.X);           // All view Pos are initialized now in the IsAdded setter,
+			Assert.Null (r.Y);           // avoiding Pos errors.
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.Empty (r.Subviews);
@@ -78,10 +77,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (1, 2, 3, 4), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.Null (r.ColorScheme);
-			Assert.NotNull (r.Width);
-			Assert.NotNull (r.Height);
-			Assert.NotNull (r.X);
-			Assert.NotNull (r.Y);
+			Assert.Null (r.Width);
+			Assert.Null (r.Height);
+			Assert.Null (r.X);
+			Assert.Null (r.Y);
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.Empty (r.Subviews);
@@ -102,10 +101,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (0, 0, 1, 13), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.Null (r.ColorScheme);
-			Assert.NotNull (r.Width);       // All view Dim are initialized now,
-			Assert.NotNull (r.Height);      // avoiding Dim errors.
-			Assert.NotNull (r.X);           // All view Pos are initialized now,
-			Assert.NotNull (r.Y);           // avoiding Pos errors.
+			Assert.Null (r.Width);       // All view Dim are initialized now in the IsAdded setter,
+			Assert.Null (r.Height);      // avoiding Dim errors.
+			Assert.Null (r.X);           // All view Pos are initialized now in the IsAdded setter,
+			Assert.Null (r.Y);           // avoiding Pos errors.
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.Empty (r.Subviews);
@@ -1082,19 +1081,19 @@ namespace Terminal.Gui.Core {
 
 			// Default Constructor
 			view = new View ();
-			Assert.Equal (0, view.X);
-			Assert.Equal (0, view.Y);
-			Assert.Equal (0, view.Width);
-			Assert.Equal (0, view.Height);
+			Assert.Null (view.X);
+			Assert.Null (view.Y);
+			Assert.Null (view.Width);
+			Assert.Null (view.Height);
 			Assert.True (view.Frame.IsEmpty);
 			Assert.True (view.Bounds.IsEmpty);
 
 			// Constructor
 			view = new View (1, 2, "");
-			Assert.NotNull (view.X);
-			Assert.NotNull (view.Y);
-			Assert.NotNull (view.Width);
-			Assert.NotNull (view.Height);
+			Assert.Null (view.X);
+			Assert.Null (view.Y);
+			Assert.Null (view.Width);
+			Assert.Null (view.Height);
 			Assert.False (view.Frame.IsEmpty);
 			Assert.True (view.Bounds.IsEmpty);
 
@@ -1177,7 +1176,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact, AutoInitShutdown]
-		public void SetWidth_CanSetWidth ()
+		public void SetWidth_CanSetWidth_ForceValidatePosDim ()
 		{
 			var top = new View () {
 				X = 0,
@@ -1186,7 +1185,8 @@ namespace Terminal.Gui.Core {
 			};
 
 			var v = new View () {
-				Width = Dim.Fill ()
+				Width = Dim.Fill (),
+				ForceValidatePosDim = true
 			};
 			top.Add (v);
 
@@ -1215,7 +1215,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact, AutoInitShutdown]
-		public void SetHeight_CanSetHeight ()
+		public void SetHeight_CanSetHeight_ForceValidatePosDim ()
 		{
 			var top = new View () {
 				X = 0,
@@ -1224,7 +1224,8 @@ namespace Terminal.Gui.Core {
 			};
 
 			var v = new View () {
-				Height = Dim.Fill ()
+				Height = Dim.Fill (),
+				ForceValidatePosDim = true
 			};
 			top.Add (v);
 
@@ -1267,11 +1268,17 @@ namespace Terminal.Gui.Core {
 			};
 			top.Add (v);
 
-			Assert.False (v.GetCurrentWidth (out int cWidth));
+			Assert.False (v.AutoSize);
+			Assert.True (v.GetCurrentWidth (out int cWidth));
 			Assert.Equal (80, cWidth);
 
 			v.Width = Dim.Fill (1);
-			Assert.False (v.GetCurrentWidth (out cWidth));
+			Assert.True (v.GetCurrentWidth (out cWidth));
+			Assert.Equal (79, cWidth);
+
+			v.AutoSize = true;
+
+			Assert.True (v.GetCurrentWidth (out cWidth));
 			Assert.Equal (79, cWidth);
 		}
 
@@ -1289,11 +1296,17 @@ namespace Terminal.Gui.Core {
 			};
 			top.Add (v);
 
-			Assert.False (v.GetCurrentHeight (out int cHeight));
+			Assert.False (v.AutoSize);
+			Assert.True (v.GetCurrentHeight (out int cHeight));
 			Assert.Equal (20, cHeight);
 
 			v.Height = Dim.Fill (1);
-			Assert.False (v.GetCurrentHeight (out cHeight));
+			Assert.True (v.GetCurrentHeight (out cHeight));
+			Assert.Equal (19, cHeight);
+
+			v.AutoSize = true;
+
+			Assert.True (v.GetCurrentHeight (out cHeight));
 			Assert.Equal (19, cHeight);
 		}
 
@@ -1373,46 +1386,59 @@ namespace Terminal.Gui.Core {
 		public void AutoSize_False_ResizeView_With_Dim_Fill_After_IsInitialized ()
 		{
 			var win = new Window (new Rect (0, 0, 30, 80), "");
-			var label = new Label () { Width = Dim.Fill (), Height = Dim.Fill () };
+			var label = new Label () { AutoSize = false, Width = Dim.Fill (), Height = Dim.Fill () };
 			win.Add (label);
 			Application.Top.Add (win);
 
 			// Text is empty so height=0
-			Assert.True (label.AutoSize);
+			Assert.False (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=0,Height=0}", label.Bounds.ToString ());
 
 			label.Text = "New text\nNew line";
 			Application.Top.LayoutSubviews ();
 
-			Assert.True (label.AutoSize);
+			Assert.False (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=78}", label.Bounds.ToString ());
+			Assert.False (label.IsInitialized);
 
 			Application.Begin (Application.Top);
+			Assert.True (label.IsInitialized);
 			Assert.False (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=78}", label.Bounds.ToString ());
 		}
 
 		[Fact, AutoInitShutdown]
-		public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_After_IsInitialized ()
+		public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_After_IsAdded_And_IsInitialized ()
 		{
 			var win = new Window (new Rect (0, 0, 30, 80), "");
 			var label = new Label () { Width = Dim.Fill () };
 			win.Add (label);
 			Application.Top.Add (win);
 
+			Assert.True (label.IsAdded);
+
 			// Text is empty so height=0
 			Assert.True (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=0,Height=0}", label.Bounds.ToString ());
 
-			label.Text = "New text\nNew line";
+			label.Text = "First line\nSecond line";
 			Application.Top.LayoutSubviews ();
 
 			Assert.True (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=2}", label.Bounds.ToString ());
+			Assert.False (label.IsInitialized);
 
 			Application.Begin (Application.Top);
-			Assert.False (label.AutoSize);
+
+			Assert.True (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=2}", label.Bounds.ToString ());
+			Assert.True (label.IsInitialized);
+
+			label.AutoSize = false;
+			Application.Refresh ();
+
+			Assert.False (label.AutoSize);
+			Assert.Equal ("{X=0,Y=0,Width=28,Height=1}", label.Bounds.ToString ());
 		}
 
 		[Fact, AutoInitShutdown]
@@ -1422,26 +1448,37 @@ namespace Terminal.Gui.Core {
 			var label = new Label () { Width = Dim.Fill () };
 			win.Add (label);
 			Application.Top.Add (win);
+
+			// Text is empty so height=0
+			Assert.True (label.AutoSize);
+			Assert.Equal ("{X=0,Y=0,Width=0,Height=0}", label.Bounds.ToString ());
+
 			Application.Begin (Application.Top);
 
-			Assert.False (label.AutoSize);
+			Assert.True (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=0}", label.Bounds.ToString ());
 
-			// Here the SetMinWidthHeight ensuring the minimum height
-			label.Text = "New text\nNew line";
+			label.Text = "First line\nSecond line";
 			Application.Refresh ();
 
+			// Here the AutoSize ensuring the right size
+			Assert.True (label.AutoSize);
+			Assert.Equal ("{X=0,Y=0,Width=28,Height=2}", label.Bounds.ToString ());
+
+			label.AutoSize = false;
+			Application.Refresh ();
+
+			// Here the SetMinWidthHeight ensuring the minimum height
 			Assert.False (label.AutoSize);
 			Assert.Equal ("{X=0,Y=0,Width=28,Height=1}", label.Bounds.ToString ());
 
-			label.AutoSize = true;
+			label.Text = "First changed line\nSecond changed line\nNew line";
 			Application.Refresh ();
 
-			// Here the AutoSize ensuring the right height
-			Assert.True (label.AutoSize);
-			Assert.Equal ("{X=0,Y=0,Width=28,Height=2}", label.Bounds.ToString ());
+			Assert.False (label.AutoSize);
+			Assert.Equal ("{X=0,Y=0,Width=28,Height=1}", label.Bounds.ToString ());
 
-			label.Text = "New changed text\nNew changed line\nNew line";
+			label.AutoSize = true;
 			Application.Refresh ();
 
 			Assert.True (label.AutoSize);
@@ -1449,7 +1486,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact, AutoInitShutdown]
-		public void AutoSize_True_Setting_With_Height_Sets_AutoSize_False_Horizontal ()
+		public void AutoSize_True_Setting_With_Height_Horizontal ()
 		{
 			var label = new Label ("Hello") { Width = 10, Height = 2 };
 			var viewX = new View ("X") { X = Pos.Right (label) };
@@ -1458,7 +1495,7 @@ namespace Terminal.Gui.Core {
 			Application.Top.Add (label, viewX, viewY);
 			Application.Begin (Application.Top);
 
-			Assert.False (label.AutoSize);
+			Assert.True (label.AutoSize);
 			Assert.Equal (new Rect (0, 0, 10, 2), label.Frame);
 
 			var expected = @"
@@ -1469,10 +1506,25 @@ Y
 
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 11, 3), pos);
+
+			label.AutoSize = false;
+			Application.Refresh ();
+
+			Assert.False (label.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 2), label.Frame);
+
+			expected = @"
+Hello     X
+
+Y
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 11, 3), pos);
 		}
 
 		[Fact, AutoInitShutdown]
-		public void AutoSize_True_Setting_With_Height_Sets_AutoSize_False_Vertical ()
+		public void AutoSize_True_Setting_With_Height_Vertical ()
 		{
 			var label = new Label ("Hello") { Width = 2, Height = 10, TextDirection = TextDirection.TopBottom_LeftRight };
 			var viewX = new View ("X") { X = Pos.Right (label) };
@@ -1481,7 +1533,7 @@ Y
 			Application.Top.Add (label, viewX, viewY);
 			Application.Begin (Application.Top);
 
-			Assert.False (label.AutoSize);
+			Assert.True (label.AutoSize);
 			Assert.Equal (new Rect (0, 0, 2, 10), label.Frame);
 
 			var expected = @"
@@ -1500,6 +1552,29 @@ Y
 
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 3, 11), pos);
+
+			label.AutoSize = false;
+			Application.Refresh ();
+
+			Assert.False (label.AutoSize);
+			Assert.Equal (new Rect (0, 0, 2, 10), label.Frame);
+
+			expected = @"
+H X
+e
+l
+l
+o
+
+
+
+
+
+Y
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 3, 11), pos);
 		}
 
 		[Theory]
@@ -1573,11 +1648,16 @@ Y
 			view.SetRelativeLayout (top.Bounds);
 			Assert.Equal (79, view.Bounds.Width);
 			Assert.Equal (24, view.Bounds.Height);
+			view.X = 0;
+			view.Y = 0;
+			view.SetRelativeLayout (top.Bounds);
+			Assert.Equal (80, view.Bounds.Width);
+			Assert.Equal (25, view.Bounds.Height);
 			bool layoutStarted = false;
-			view.LayoutStarted += (_) => { layoutStarted = true; };
+			view.LayoutStarted += (_) => layoutStarted = true;
 			view.OnLayoutStarted (null);
 			Assert.True (layoutStarted);
-			view.LayoutComplete += (_) => { layoutStarted = false; };
+			view.LayoutComplete += (_) => layoutStarted = false;
 			view.OnLayoutComplete (null);
 			Assert.False (layoutStarted);
 			view.X = Pos.Center () - 41;
@@ -1778,13 +1858,12 @@ Y
 			Application.Top.Add (lbl);
 			Application.Begin (Application.Top);
 
+			Assert.True (lbl.AutoSize);
 			Assert.Equal ("123 ", GetContents ());
 
 			lbl.Text = "12";
 
-			if (!lbl.SuperView.NeedDisplay.IsEmpty) {
-				lbl.SuperView.Redraw (lbl.SuperView.NeedDisplay);
-			}
+			lbl.SuperView.Redraw (lbl.SuperView.NeedDisplay);
 
 			Assert.Equal ("12  ", GetContents ());
 
@@ -2485,68 +2564,90 @@ Y
 			win.Add (horizontalView, verticalView);
 			Application.Top.Add (win);
 			Application.Begin (Application.Top);
-			((FakeDriver)Application.Driver).SetBufferSize (22, 22);
+			((FakeDriver)Application.Driver).SetBufferSize (32, 32);
 
+			Assert.False (horizontalView.AutoSize);
+			Assert.False (verticalView.AutoSize);
 			Assert.Equal (new Rect (0, 0, 20, 1), horizontalView.Frame);
 			Assert.Equal (new Rect (0, 3, 1, 20), verticalView.Frame);
 			var expected = @"
-┌────────────────────┐
-│First line Second li│
-│                    │
-│                    │
-│F                   │
-│i                   │
-│r                   │
-│s                   │
-│t                   │
-│                    │
-│l                   │
-│i                   │
-│n                   │
-│e                   │
-│                    │
-│S                   │
-│e                   │
-│c                   │
-│o                   │
-│n                   │
-│d                   │
-└────────────────────┘
+┌──────────────────────────────┐
+│First line Second li          │
+│                              │
+│                              │
+│F                             │
+│i                             │
+│r                             │
+│s                             │
+│t                             │
+│                              │
+│l                             │
+│i                             │
+│n                             │
+│e                             │
+│                              │
+│S                             │
+│e                             │
+│c                             │
+│o                             │
+│n                             │
+│d                             │
+│                              │
+│l                             │
+│i                             │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+└──────────────────────────────┘
 ";
 
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
-			Assert.Equal (new Rect (0, 0, 22, 22), pos);
+			Assert.Equal (new Rect (0, 0, 32, 32), pos);
 
 			verticalView.Text = $"最初の行{Environment.NewLine}二行目";
 			Application.Top.Redraw (Application.Top.Bounds);
 			Assert.Equal (new Rect (0, 3, 2, 20), verticalView.Frame);
 			expected = @"
-┌────────────────────┐
-│First line Second li│
-│                    │
-│                    │
-│最                  │
-│初                  │
-│の                  │
-│行                  │
-│                    │
-│二                  │
-│行                  │
-│目                  │
-│                    │
-│                    │
-│                    │
-│                    │
-│                    │
-│                    │
-│                    │
-│                    │
-│                    │
-└────────────────────┘
+┌──────────────────────────────┐
+│First line Second li          │
+│                              │
+│                              │
+│最                            │
+│初                            │
+│の                            │
+│行                            │
+│                              │
+│二                            │
+│行                            │
+│目                            │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+│                              │
+└──────────────────────────────┘
 ";
 
 			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
-			Assert.Equal (new Rect (0, 0, 22, 22), pos);
+			Assert.Equal (new Rect (0, 0, 32, 32), pos);
 		}
 
 		[Fact, AutoInitShutdown]
@@ -2563,6 +2664,10 @@ Y
 			Assert.False (view.AutoSize);
 			Assert.Equal (TextDirection.LeftRight_TopBottom, view.TextDirection);
 			Assert.Equal (Rect.Empty, view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view.Height.ToString ());
 			var expected = @"
 ┌────────────────────┐
 │                    │
@@ -2591,10 +2696,15 @@ Y
 			var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 22, 22), pos);
 
-			view.AutoSize = true;
 			view.Text = "Hello World";
-			Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+			view.Width = 11;
 			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
 │Hello World         │
@@ -2623,9 +2733,51 @@ Y
 			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 22, 22), pos);
 
+			view.AutoSize = true;
+			view.Text = "Hello Worlds";
+			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 12, 1), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view.Height.ToString ());
+			expected = @"
+┌────────────────────┐
+│Hello Worlds        │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+└────────────────────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
 			view.TextDirection = TextDirection.TopBottom_LeftRight;
-			Assert.Equal (new Rect (0, 0, 1, 11), view.Frame);
 			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 11, 12), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
 │H                   │
@@ -2639,7 +2791,7 @@ Y
 │r                   │
 │l                   │
 │d                   │
-│ 
+│s
 │                    │
 │                    │
 │                    │
@@ -2655,22 +2807,27 @@ Y
 			Assert.Equal (new Rect (0, 0, 22, 22), pos);
 
 			view.AutoSize = false;
-			view.Text = "Hello Worlds";
-			Assert.Equal (new Rect (0, 0, 1, 11), view.Frame);
+			view.Height = 1;
 			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
-│H                   │
-│e                   │
-│l                   │
-│l                   │
-│o                   │
+│HelloWorlds         │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
+│                    │
 │                    │
-│W                   │
-│o                   │
-│r                   │
-│l                   │
-│d                   │
 │                    │
 │                    │
 │                    │
@@ -2686,9 +2843,14 @@ Y
 			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 22, 22), pos);
 
-			view.TextDirection = TextDirection.LeftRight_TopBottom;
-			Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+			view.PreserveTrailingSpaces = true;
 			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
 │Hello World         │
@@ -2717,13 +2879,31 @@ Y
 			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 22, 22), pos);
 
-			view.AutoSize = true;
-			Assert.Equal (new Rect (0, 0, 12, 1), view.Frame);
+			view.PreserveTrailingSpaces = false;
+			var f = view.Frame;
+			view.Width = f.Height;
+			view.Height = f.Width;
+			view.TextDirection = TextDirection.TopBottom_LeftRight;
 			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 1, 11), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
-│Hello Worlds        │
+│H                   │
+│e                   │
+│l                   │
+│l                   │
+│o                   │
 │                    │
+│W                   │
+│o                   │
+│r                   │
+│l                   │
+│d                   │
 │                    │
 │                    │
 │                    │
@@ -2733,7 +2913,34 @@ Y
 │                    │
 │                    │
 │                    │
+└────────────────────┘
+";
+
+			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+			Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+			view.AutoSize = true;
+			Application.Refresh ();
+
+			Assert.Equal (new Rect (0, 0, 1, 12), view.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(11)", view.Height.ToString ());
+			expected = @"
+┌────────────────────┐
+│H                   │
+│e                   │
+│l                   │
+│l                   │
+│o                   │
 │                    │
+│W                   │
+│o                   │
+│r                   │
+│l                   │
+│d                   │
+│s                   │
 │                    │
 │                    │
 │                    │
@@ -2780,7 +2987,15 @@ Y
 			Assert.Equal (new Size (10, 1), horizontalView.TextFormatter.Size);
 			Assert.Equal (new Size (2, 9), verticalView.TextFormatter.Size);
 			Assert.Equal (new Rect (0, 0, 9, 1), horizontalView.Frame);
+			Assert.Equal ("Pos.Absolute(0)", horizontalView.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", horizontalView.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(9)", horizontalView.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", horizontalView.Height.ToString ());
 			Assert.Equal (new Rect (0, 3, 2, 8), verticalView.Frame);
+			Assert.Equal ("Pos.Absolute(0)", verticalView.X.ToString ());
+			Assert.Equal ("Pos.Absolute(3)", verticalView.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(2)", verticalView.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(8)", verticalView.Height.ToString ());
 			var expected = @"
 ┌────────────────────┐
 │Finish 終           │
@@ -2813,7 +3028,12 @@ Y
 			Application.Top.Redraw (Application.Top.Bounds);
 			Assert.True (horizontalView.AutoSize);
 			Assert.True (verticalView.AutoSize);
+			// height was initialized with 8 and is kept as minimum
 			Assert.Equal (new Rect (0, 3, 2, 8), verticalView.Frame);
+			Assert.Equal ("Pos.Absolute(0)", verticalView.X.ToString ());
+			Assert.Equal ("Pos.Absolute(3)", verticalView.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(2)", verticalView.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(8)", verticalView.Height.ToString ());
 			expected = @"
 ┌────────────────────┐
 │Finish 終           │
@@ -2935,32 +3155,155 @@ Y
 		}
 
 		[Fact, AutoInitShutdown]
-		public void AutoSize_Exceptions ()
+		public void AutoSize_False_Equal_Before_And_After_IsInitialized_With_Differents_Orders ()
 		{
-			var exception = Record.Exception (() => new View () { Text = "Say Hello 你", AutoSize = true, Width = 10 });
-			Assert.Null (exception);
+			var view1 = new View () { Text = "Say Hello view1 你", AutoSize = false, Width = 10, Height = 5 };
+			var view2 = new View () { Text = "Say Hello view2 你", Width = 10, Height = 5, AutoSize = false };
+			var view3 = new View () { AutoSize = false, Width = 10, Height = 5, Text = "Say Hello view3 你" };
+			var view4 = new View () {
+				Text = "Say Hello view4 你",
+				AutoSize = false,
+				Width = 10,
+				Height = 5,
+				TextDirection = TextDirection.TopBottom_LeftRight
+			};
+			var view5 = new View () {
+				Text = "Say Hello view5 你",
+				Width = 10,
+				Height = 5,
+				AutoSize = false,
+				TextDirection = TextDirection.TopBottom_LeftRight
+			};
+			var view6 = new View () {
+				AutoSize = false,
+				Width = 10,
+				Height = 5,
+				TextDirection = TextDirection.TopBottom_LeftRight,
+				Text = "Say Hello view6 你",
+			};
+			Application.Top.Add (view1, view2, view3, view4, view5, view6);
+
+			Assert.False (view1.IsInitialized);
+			Assert.False (view2.IsInitialized);
+			Assert.False (view3.IsInitialized);
+			Assert.False (view4.IsInitialized);
+			Assert.False (view5.IsInitialized);
+			Assert.False (view1.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view1.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view1.Height.ToString ());
+			Assert.False (view2.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view2.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view2.Height.ToString ());
+			Assert.False (view3.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view3.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view3.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view3.Height.ToString ());
+			Assert.False (view4.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view4.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view4.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view4.Height.ToString ());
+			Assert.False (view5.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view5.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view5.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view5.Height.ToString ());
+			Assert.False (view6.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view6.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view6.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view6.Height.ToString ());
+
+			Application.Begin (Application.Top);
 
-			var view1 = new View () { Text = "Say Hello view1 你", AutoSize = true, Width = 10 };
-			var view2 = new View () { Text = "Say Hello view2 你", Height = 10, AutoSize = true };
-			var view3 = new View () { Text = "Say Hello view3 你", Width = 10 };
+			Assert.True (view1.IsInitialized);
+			Assert.True (view2.IsInitialized);
+			Assert.True (view3.IsInitialized);
+			Assert.True (view4.IsInitialized);
+			Assert.True (view5.IsInitialized);
+			Assert.False (view1.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view1.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view1.Height.ToString ());
+			Assert.False (view2.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view2.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view2.Height.ToString ());
+			Assert.False (view3.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view3.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view3.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view3.Height.ToString ());
+			Assert.False (view4.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view4.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view4.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view4.Height.ToString ());
+			Assert.False (view5.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view5.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view5.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view5.Height.ToString ());
+			Assert.False (view6.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 5), view6.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view6.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view6.Height.ToString ());
+		}
+
+		[Fact, AutoInitShutdown]
+		public void AutoSize_True_Equal_Before_And_After_IsInitialized_With_Differents_Orders ()
+		{
+			var view1 = new View () { Text = "Say Hello view1 你", AutoSize = true, Width = 10, Height = 5 };
+			var view2 = new View () { Text = "Say Hello view2 你", Width = 10, Height = 5, AutoSize = true };
+			var view3 = new View () { AutoSize = true, Width = 10, Height = 5, Text = "Say Hello view3 你" };
 			var view4 = new View () {
 				Text = "Say Hello view4 你",
-				Height = 10,
 				AutoSize = true,
+				Width = 10,
+				Height = 5,
 				TextDirection = TextDirection.TopBottom_LeftRight
 			};
 			var view5 = new View () {
 				Text = "Say Hello view5 你",
-				Height = 10,
+				Width = 10,
+				Height = 5,
+				AutoSize = true,
 				TextDirection = TextDirection.TopBottom_LeftRight
 			};
-			Application.Top.Add (view1, view2, view3, view4, view5);
+			var view6 = new View () {
+				AutoSize = true,
+				Width = 10,
+				Height = 5,
+				TextDirection = TextDirection.TopBottom_LeftRight,
+				Text = "Say Hello view6 你",
+			};
+			Application.Top.Add (view1, view2, view3, view4, view5, view6);
 
 			Assert.False (view1.IsInitialized);
 			Assert.False (view2.IsInitialized);
 			Assert.False (view3.IsInitialized);
 			Assert.False (view4.IsInitialized);
 			Assert.False (view5.IsInitialized);
+			Assert.True (view1.AutoSize);
+			Assert.Equal (new Rect (0, 0, 18, 5), view1.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view1.Height.ToString ());
+			Assert.True (view2.AutoSize);
+			Assert.Equal (new Rect (0, 0, 18, 5), view2.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view2.Height.ToString ());
+			Assert.True (view3.AutoSize);
+			Assert.Equal (new Rect (0, 0, 18, 5), view3.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view3.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view3.Height.ToString ());
+			Assert.True (view4.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 17), view4.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view4.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view4.Height.ToString ());
+			Assert.True (view5.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 17), view5.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view5.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view5.Height.ToString ());
+			Assert.True (view6.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 17), view6.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view6.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view6.Height.ToString ());
 
 			Application.Begin (Application.Top);
 
@@ -2969,31 +3312,130 @@ Y
 			Assert.True (view3.IsInitialized);
 			Assert.True (view4.IsInitialized);
 			Assert.True (view5.IsInitialized);
-
-			Assert.False (view1.AutoSize);
-			Assert.Equal (new Rect (0, 0, 10, 1), view1.Frame);
+			Assert.True (view1.AutoSize);
+			Assert.Equal (new Rect (0, 0, 18, 5), view1.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view1.Height.ToString ());
 			Assert.True (view2.AutoSize);
-			Assert.Equal (new Rect (0, 0, 18, 1), view2.Frame);
-			Assert.False (view3.AutoSize);
-			Assert.Equal (new Rect (0, 0, 10, 1), view3.Frame);
+			Assert.Equal (new Rect (0, 0, 18, 5), view2.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view2.Height.ToString ());
+			Assert.True (view3.AutoSize);
+			Assert.Equal (new Rect (0, 0, 18, 5), view3.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view3.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view3.Height.ToString ());
 			Assert.True (view4.AutoSize);
-			Assert.Equal (new Rect (0, 0, 2, 17), view4.Frame);
-			Assert.False (view5.AutoSize);
-			Assert.Equal (new Rect (0, 0, 2, 10), view5.Frame);
-
-			exception = Record.Exception (() => view1.Width = 20);
-			Assert.Null (exception);
-			Assert.Equal (new Rect (0, 0, 20, 1), view1.Frame);
-			Assert.Throws<InvalidOperationException> (() => view2.Height = 10);
-			exception = Record.Exception (() => view3.Width = 20);
-			Assert.Null (exception);
-			Assert.Equal (new Rect (0, 0, 20, 1), view3.Frame);
-			exception = Record.Exception (() => view4.TextDirection = TextDirection.LeftRight_TopBottom);
-			Assert.Null (exception);
-			Assert.Equal (new Rect (0, 0, 18, 1), view4.Frame);
-			exception = Record.Exception (() => view5.TextDirection = TextDirection.LeftRight_TopBottom);
-			Assert.Null (exception);
-			Assert.Equal (new Rect (0, 0, 10, 2), view5.Frame);
+			Assert.Equal (new Rect (0, 0, 10, 17), view4.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view4.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view4.Height.ToString ());
+			Assert.True (view5.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 17), view5.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view5.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view5.Height.ToString ());
+			Assert.True (view6.AutoSize);
+			Assert.Equal (new Rect (0, 0, 10, 17), view6.Frame);
+			Assert.Equal ("Dim.Absolute(10)", view6.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(5)", view6.Height.ToString ());
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Setting_Frame_Dont_Respect_AutoSize_True_On_Layout_Absolute ()
+		{
+			var view1 = new View (new Rect (0, 0, 10, 0)) { Text = "Say Hello view1 你", AutoSize = true };
+			var view2 = new View (new Rect (0, 0, 0, 10)) {
+				Text = "Say Hello view2 你",
+				AutoSize = true,
+				TextDirection = TextDirection.TopBottom_LeftRight
+			};
+			Application.Top.Add (view1, view2);
+
+			var rs = Application.Begin (Application.Top);
+
+			Assert.True (view1.AutoSize);
+			Assert.Equal (LayoutStyle.Absolute, view1.LayoutStyle);
+			Assert.Equal (new Rect (0, 0, 18, 1), view1.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view1.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view1.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(18)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view1.Height.ToString ());
+			Assert.True (view2.AutoSize);
+			Assert.Equal (LayoutStyle.Absolute, view2.LayoutStyle);
+			Assert.Equal (new Rect (0, 0, 2, 17), view2.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view2.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view2.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(2)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(17)", view2.Height.ToString ());
+
+			view1.Frame = new Rect (0, 0, 25, 4);
+			bool firstIteration = false;
+			Application.RunMainLoopIteration (ref rs, true, ref firstIteration);
+
+			Assert.True (view1.AutoSize);
+			Assert.Equal (LayoutStyle.Absolute, view1.LayoutStyle);
+			Assert.Equal (new Rect (0, 0, 25, 4), view1.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view1.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view1.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(18)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(1)", view1.Height.ToString ());
+
+			view2.Frame = new Rect (0, 0, 1, 25);
+			Application.RunMainLoopIteration (ref rs, true, ref firstIteration);
+
+			Assert.True (view2.AutoSize);
+			Assert.Equal (LayoutStyle.Absolute, view2.LayoutStyle);
+			Assert.Equal (new Rect (0, 0, 1, 25), view2.Frame);
+			Assert.Equal ("Pos.Absolute(0)", view2.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view2.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(2)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(17)", view2.Height.ToString ());
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Pos_Dim_Are_Null_If_Not_Initialized_On_Constructor_IsAdded_False ()
+		{
+			var top = Application.Top;
+			var view1 = new View ();
+			Assert.False (view1.IsAdded);
+			Assert.Null (view1.X);
+			Assert.Null (view1.Y);
+			Assert.Null (view1.Width);
+			Assert.Null (view1.Height);
+			top.Add (view1);
+			Assert.True (view1.IsAdded);
+			Assert.Equal ("Pos.Absolute(0)", view1.X.ToString ());
+			Assert.Equal ("Pos.Absolute(0)", view1.Y.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view1.Width.ToString ());
+			Assert.Equal ("Dim.Absolute(0)", view1.Height.ToString ());
+
+			var view2 = new View () {
+				X = Pos.Center (),
+				Y = Pos.Center (),
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			Assert.False (view2.IsAdded);
+			Assert.Equal ("Pos.Center", view2.X.ToString ());
+			Assert.Equal ("Pos.Center", view2.Y.ToString ());
+			Assert.Equal ("Dim.Fill(margin=0)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Fill(margin=0)", view2.Height.ToString ());
+			top.Add (view2);
+			Assert.True (view2.IsAdded);
+			Assert.Equal ("Pos.Center", view2.X.ToString ());
+			Assert.Equal ("Pos.Center", view2.Y.ToString ());
+			Assert.Equal ("Dim.Fill(margin=0)", view2.Width.ToString ());
+			Assert.Equal ("Dim.Fill(margin=0)", view2.Height.ToString ());
+		}
+
+		[Fact]
+		public void IsAdded_Added_Removed ()
+		{
+			var top = new Toplevel ();
+			var view = new View ();
+			Assert.False (view.IsAdded);
+			top.Add (view);
+			Assert.True (view.IsAdded);
+			top.Remove (view);
+			Assert.False (view.IsAdded);
 		}
 	}
 }

+ 12 - 13
UnitTests/WindowTests.cs

@@ -33,9 +33,8 @@ namespace Terminal.Gui.Core {
 			Assert.NotNull (r.ColorScheme);
 			Assert.Equal (Dim.Fill (0), r.Width);
 			Assert.Equal (Dim.Fill (0), r.Height);
-			// FIXED: Pos needs equality implemented
-			Assert.Equal (Pos.At (0), r.X);
-			Assert.Equal (Pos.At (0), r.Y);
+			Assert.Null (r.X);
+			Assert.Null (r.Y);
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.NotEmpty (r.Subviews);
@@ -57,10 +56,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.NotNull (r.ColorScheme);
-			Assert.NotNull (r.Width);       // All view Dim are initialized now,
-			Assert.NotNull (r.Height);      // avoiding Dim errors.
-			Assert.NotNull (r.X);           // All view Pos are initialized now,
-			Assert.NotNull (r.Y);           // avoiding Pos errors.
+			Assert.Null (r.Width);       // All view Dim are initialized now in the IsAdded setter,
+			Assert.Null (r.Height);      // avoiding Dim errors.
+			Assert.Null (r.X);           // All view Pos are initialized now in the IsAdded setter,
+			Assert.Null (r.Y);           // avoiding Pos errors.
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.NotEmpty (r.Subviews);
@@ -82,10 +81,10 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (new Rect (1, 2, 3, 4), r.Frame);
 			Assert.Null (r.Focused);
 			Assert.NotNull (r.ColorScheme);
-			Assert.NotNull (r.Width);
-			Assert.NotNull (r.Height);
-			Assert.NotNull (r.X);
-			Assert.NotNull (r.Y);
+			Assert.Null (r.Width);
+			Assert.Null (r.Height);
+			Assert.Null (r.X);
+			Assert.Null (r.Y);
 			Assert.False (r.IsCurrentTop);
 			Assert.Empty (r.Id);
 			Assert.NotEmpty (r.Subviews);
@@ -94,7 +93,7 @@ namespace Terminal.Gui.Core {
 			Assert.Null (r.SuperView);
 			Assert.Null (r.MostFocused);
 			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
-			r.Dispose();
+			r.Dispose ();
 		}
 
 		[Fact]
@@ -115,7 +114,7 @@ namespace Terminal.Gui.Core {
 
 			expectedOld = string.Empty;
 			r.Title = expectedDuring = expectedAfter = "title";
-			Assert.Equal (expectedAfter, r.Title.ToString());
+			Assert.Equal (expectedAfter, r.Title.ToString ());
 
 			expectedOld = r.Title.ToString();
 			r.Title = expectedDuring = expectedAfter = "a different title";

Неке датотеке нису приказане због велике количине промена