Browse Source

Updated API docs. Cleaned up code.

Tig Kindel 1 year ago
parent
commit
5e93af47eb

+ 100 - 148
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -7,52 +7,69 @@ using System.Linq;
 namespace Terminal.Gui;
 
 /// <summary>
-/// Determines the LayoutStyle for a <see cref="View"/>, if Absolute, during <see cref="View.LayoutSubviews"/>, the
-/// value from the <see cref="View.Frame"/> will be used, if the value is Computed, then <see cref="View.Frame"/>
-/// will be updated from the X, Y <see cref="Pos"/> objects and the Width and Height <see cref="Dim"/> objects.
+///         <para>
+///         Indicates the LayoutStyle for the <see cref="View"/>.
+///         </para>
+///         <para>
+///         If Absolute, the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
+///         <see cref="View.Height"/>
+///         objects are all absolute values and are not relative. The position and size of the view is described by
+///         <see cref="View.Frame"/>.
+///         </para>
+///         <para>
+///         If Computed, one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
+///         <see cref="View.Height"/>
+///         objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.
+///         </para>
 /// </summary>
 public enum LayoutStyle {
 	/// <summary>
-	/// The position and size of the view are based <see cref="View.Frame"/>.
+	/// Indicates the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and <see cref="View.Height"/>
+	/// objects are all absolute values and are not relative. The position and size of the view is described by
+	/// <see cref="View.Frame"/>.
 	/// </summary>
 	Absolute,
 
 	/// <summary>
-	/// The position and size of the view will be computed based on
-	/// <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and <see cref="View.Height"/>.
-	/// <see cref="View.Frame"/> will
-	/// provide the absolute computed values.
+	/// Indicates one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
+	/// <see cref="View.Height"/>
+	/// objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.  The position and size of the
+	/// view
+	/// will be computed based on these objects at layout time. <see cref="View.Frame"/> will provide the absolute computed
+	/// values.
 	/// </summary>
 	Computed
 }
 
 public partial class View {
 	bool _autoSize;
-
-	/// <summary>
-	/// Backing property for Frame - The frame for the object. Relative to the SuperView's Bounds.
-	/// </summary>
 	Rect _frame;
+	Dim _height = Dim.Sized (0);
+	Dim _width = Dim.Sized (0);
+	Pos _x = Pos.At (0);
+	Pos _y = Pos.At (0);
 
 	/// <summary>
-	/// Gets or sets location and size of the view. The frame is relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
+	/// Gets or sets the absolute location and dimension of the view.
 	/// </summary>
 	/// <value>
-	/// The rectangle describing the location and size of the view, in coordinates relative to the
-	/// <see cref="SuperView"/>.
+	/// The rectangle describing absolute location and dimension of the view,
+	/// in coordinates relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
 	/// </value>
 	/// <remarks>
 	///         <para>
-	///         Change the Frame when using the <see cref="LayoutStyle.Absolute"/> layout style to move or resize views.
+	///         Frame is relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
 	///         </para>
 	///         <para>
-	///         Altering the Frame will change <see cref="LayoutStyle"/> to <see cref="LayoutStyle.Absolute"/>.
-	///         Additionally, <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> will be set
-	///         to the values of the Frame (using <see cref="Pos.PosAbsolute"/> and <see cref="Dim.DimAbsolute"/>).
+	///         Setting Frame will set <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/>
+	///         to the values of the corresponding properties of the <paramref name="value"/> parameter.
 	///         </para>
 	///         <para>
-	///         Altering the Frame will eventually (when the view is next drawn) cause the
-	///         <see cref="LayoutSubview(View, Rect)"/> and <see cref="OnDrawContent(Rect)"/> methods to be called.
+	///         This causes <see cref="LayoutStyle"/> to be <see cref="LayoutStyle.Absolute"/>.
+	///         </para>
+	///         <para>
+	///         Altering the Frame will eventually (when the view hierarchy is next laid out via  see cref="LayoutSubviews"/>)
+	///         cause <see cref="LayoutSubview(View, Rect)"/> and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
 	/// </remarks>
 	public Rect Frame {
@@ -177,39 +194,28 @@ public partial class View {
 	public Frame Padding { get; private set; }
 
 	/// <summary>
-	/// Controls how the View's <see cref="Frame"/> is computed during <see cref="LayoutSubviews"/>. If the style is set to
-	/// <see cref="LayoutStyle.Absolute"/>, LayoutSubviews does not change the <see cref="Frame"/>.
-	/// If the style is <see cref="LayoutStyle.Computed"/> the <see cref="Frame"/> is updated using
-	/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
-	/// </summary>
-	/// <remarks>
 	///         <para>
-	///         Setting this property to <see cref="LayoutStyle.Absolute"/> will cause <see cref="Frame"/> to determine the
-	///         size and position of the view. <see cref="X"/> and <see cref="Y"/> will be set to <see cref="Dim.DimAbsolute"/>
-	///         using <see cref="Frame"/>.
+	///         Indicates the LayoutStyle for the <see cref="View"/>.
 	///         </para>
 	///         <para>
-	///         Setting this property to <see cref="LayoutStyle.Computed"/> will cause the view to use the
-	///         <see cref="LayoutSubviews"/> method to
-	///         size and position of the view. If either of the <see cref="X"/> and <see cref="Y"/> properties are `null` they
-	///         will be set to <see cref="Pos.PosAbsolute"/> using
-	///         the current value of <see cref="Frame"/>.
-	///         If either of the <see cref="Width"/> and <see cref="Height"/> properties are `null` they will be set to
-	///         <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
+	///         If Absolute, the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, and
+	///         <see cref="View.Height"/>
+	///         objects are all absolute values and are not relative. The position and size of the view is described by
+	///         <see cref="View.Frame"/>.
 	///         </para>
-	/// </remarks>
+	///         <para>
+	///         If Computed, one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
+	///         <see cref="View.Height"/>
+	///         objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.
+	///         </para>
+	/// </summary>
 	/// <value>The layout style.</value>
 	public LayoutStyle LayoutStyle {
 		get {
 			if (_x is Pos.PosAbsolute && _y is Pos.PosAbsolute && _width is Dim.DimAbsolute && _height is Dim.DimAbsolute) {
 				return LayoutStyle.Absolute;
-			} else {
-				return LayoutStyle.Computed;
 			}
-		}
-		set {
-			// TODO: Remove this setter and make LayoutStyle read-only for real.
-			throw new InvalidOperationException ("LayoutStyle is read-only.");
+			return LayoutStyle.Computed;
 		}
 	}
 
@@ -221,16 +227,15 @@ public partial class View {
 	/// <remarks>
 	///         <para>
 	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value of Bounds is indeterminate until
-	///         the
-	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+	///         the view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
 	///         called.
 	///         </para>
 	///         <para>
-	///         Updates to the Bounds updates <see cref="Frame"/>, and has the same side effects as updating the
+	///         Updates to the Bounds updates <see cref="Frame"/>, and has the same effect as updating the
 	///         <see cref="Frame"/>.
 	///         </para>
 	///         <para>
-	///         Altering the Bounds will eventually (when the view is next drawn) cause the
+	///         Altering the Bounds will eventually (when the view is next laid out) cause the
 	///         <see cref="LayoutSubview(View, Rect)"/>
 	///         and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
@@ -247,31 +252,27 @@ public partial class View {
 				Debug.WriteLine ($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug in {this}");
 			}
 #endif // DEBUG
-			//var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
 			var frameRelativeBounds = FrameGetInsideBounds ();
 			return new Rect (default, frameRelativeBounds.Size);
 		}
 		set {
-			// BUGBUG: Margin etc.. can be null (if typeof(Frame))
 			Frame = new Rect (Frame.Location,
-			    new Size (
-				value.Size.Width + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal,
-				value.Size.Height + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical
-			    )
+				new Size (
+					value.Size.Width + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal,
+					value.Size.Height + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical
+				)
 			);
 		}
 	}
 
-	Pos _x = Pos.At (0);
-
 	/// <summary>
 	/// Gets or sets the X position for the view (the column).
 	/// </summary>
 	/// <value>The <see cref="Pos"/> object representing the X position.</value>
 	/// <remarks>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the
-	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+	///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the
+	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Rect)"/> has been
 	///         called.
 	///         </para>
 	///         <para>
@@ -280,13 +281,12 @@ public partial class View {
 	///         <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the
-	///         <see cref="Frame"/> to be updated. If
+	///         Changing this property will cause <see cref="Frame"/> to be updated. If
 	///         the new value is not of type <see cref="Pos.PosAbsolute"/> the <see cref="LayoutStyle"/> will change to
 	///         <see cref="LayoutStyle.Computed"/>.
 	///         </para>
 	///         <para>
-	///         <see langword="null"/> is the same as <c>Pos.Absolute(0)</c>.
+	///         The default value is <c>Pos.At (0)</c>.
 	///         </para>
 	/// </remarks>
 	public Pos X {
@@ -297,16 +297,14 @@ public partial class View {
 		}
 	}
 
-	Pos _y = Pos.At (0);
-
 	/// <summary>
 	/// Gets or sets the Y position for the view (the row).
 	/// </summary>
 	/// <value>The <see cref="Pos"/> object representing the Y position.</value>
 	/// <remarks>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the
-	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+	///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the
+	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Rect)"/> has been
 	///         called.
 	///         </para>
 	///         <para>
@@ -315,13 +313,12 @@ public partial class View {
 	///         <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the
-	///         <see cref="Frame"/> to be updated. If
+	///         Changing this property will cause <see cref="Frame"/> to be updated. If
 	///         the new value is not of type <see cref="Pos.PosAbsolute"/> the <see cref="LayoutStyle"/> will change to
 	///         <see cref="LayoutStyle.Computed"/>.
 	///         </para>
 	///         <para>
-	///         <see langword="null"/> is the same as <c>Pos.Absolute(0)</c>.
+	///         The default value is <c>Pos.At (0)</c>.
 	///         </para>
 	/// </remarks>
 	public Pos Y {
@@ -332,16 +329,14 @@ public partial class View {
 		}
 	}
 
-	Dim _width = Dim.Sized (0);
-
 	/// <summary>
 	/// Gets or sets the width of the view.
 	/// </summary>
 	/// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
 	/// <remarks>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the
-	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+	///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the
+	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Rect)"/> has been
 	///         called.
 	///         </para>
 	///         <para>
@@ -350,11 +345,13 @@ public partial class View {
 	///         and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the
-	///         <see cref="Frame"/> to be updated. If
+	///         Changing this property will cause <see cref="Frame"/> to be updated. If
 	///         the new value is not of type <see cref="Dim.DimAbsolute"/> the <see cref="LayoutStyle"/> will change to
 	///         <see cref="LayoutStyle.Computed"/>.
 	///         </para>
+	///         <para>
+	///         The default value is <c>Dim.Sized (0)</c>.
+	///         </para>
 	/// </remarks>
 	public Dim Width {
 		get => VerifyIsInitialized (_width, nameof (Width));
@@ -372,16 +369,14 @@ public partial class View {
 		}
 	}
 
-	Dim _height = Dim.Sized (0);
-
 	/// <summary>
 	/// Gets or sets the height of the view.
 	/// </summary>
 	/// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
 	/// <remarks>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the
-	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+	///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the
+	///         view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Rect)"/> has been
 	///         called.
 	///         </para>
 	///         <para>
@@ -390,11 +385,13 @@ public partial class View {
 	///         and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	///         </para>
 	///         <para>
-	///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the
-	///         <see cref="Frame"/> to be updated. If
+	///         Changing this property will cause <see cref="Frame"/> to be updated. If
 	///         the new value is not of type <see cref="Dim.DimAbsolute"/> the <see cref="LayoutStyle"/> will change to
 	///         <see cref="LayoutStyle.Computed"/>.
 	///         </para>
+	///         <para>
+	///         The default value is <c>Dim.Sized (0)</c>.
+	///         </para>
 	/// </remarks>
 	public Dim Height {
 		get => VerifyIsInitialized (_height, nameof (Height));
@@ -428,7 +425,7 @@ public partial class View {
 
 	/// <summary>
 	/// Gets or sets a flag that determines whether the View will be automatically resized to fit the <see cref="Text"/>
-	/// within <see cref="Bounds"/>
+	/// within <see cref="Bounds"/>.
 	/// <para>
 	/// The default is <see langword="false"/>. Set to <see langword="true"/> to turn on AutoSize. If <see langword="true"/>
 	/// then
@@ -528,7 +525,7 @@ public partial class View {
 		if (Margin == null || Border == null || Padding == null) {
 			return new Rect (default, Frame.Size);
 		}
-		var width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
+		var width = Math.Max (0,  Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
 		var height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical);
 		return new Rect (Point.Empty, new Size (width, height));
 	}
@@ -556,69 +553,25 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Throws an <see cref="ArgumentException"/> if <paramref name="newValue"/> is <see cref="Pos.PosAbsolute"/> or
-	/// <see cref="Dim.DimAbsolute"/>.
-	/// Used when <see cref="ValidatePosDim"/> is turned on to verify correct <see cref="LayoutStyle.Computed"/> behavior.
+	/// Called whenever the view needs to be resized. Sets <see cref="Frame"/> and triggers a <see cref="LayoutSubviews()"/>
+	/// call.
 	/// </summary>
 	/// <remarks>
-	/// Does not verify if this view is Toplevel (WHY??!?).
-	/// </remarks>
-	/// <param name="prop">The property name.</param>
-	/// <param name="oldValue"></param>
-	/// <param name="newValue"></param>
-	void CheckAbsolute (string prop, object oldValue, object newValue)
-	{
-		if (!IsInitialized || !ValidatePosDim || oldValue == null || oldValue.GetType () == newValue.GetType () || this is Toplevel) {
-			return;
-		}
-
-		if (oldValue.GetType () != newValue.GetType () && newValue is (Pos.PosAbsolute or Dim.DimAbsolute)) {
-			throw new ArgumentException ($@"{prop} must not be Absolute if LayoutStyle is Computed", prop);
-		}
-	}
-
-	/// <summary>
-	/// Called whenever the view needs to be resized. Sets <see cref="Frame"/> and
-	/// triggers a <see cref="LayoutSubviews()"/> call.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	/// Sets the <see cref="Frame"/>.
-	/// </para>
-	/// <para>
-	/// Can be overridden if the view resize behavior is different than the default.
-	/// </para>
+	///         <para>
+	///         Sets the <see cref="Frame"/>.
+	///         </para>
+	///         <para>
+	///         Can be overridden if the view resize behavior is different than the default.
+	///         </para>
 	/// </remarks>
 	protected virtual void OnResizeNeeded ()
 	{
-		//// TODO: Determine if this API should change Frame as it does.
-		//// TODO: Is it correct behavior? Shouldn't the Frame be changed when SetRelativeLayout
-		//// TODO: is eventually called because SetNeedsLayout get set?
-		//var actX = _x is Pos.PosAbsolute ? _x.Anchor (0) : _frame.X;
-		//var actY = _y is Pos.PosAbsolute ? _y.Anchor (0) : _frame.Y;
-		//if (AutoSize) {
-		//	//if (TextAlignment == TextAlignment.Justified) {
-		//	//	throw new InvalidOperationException ("TextAlignment.Justified cannot be used with AutoSize");
-		//	//}
-		//	var s = GetAutoSize ();
-		//	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;
-		//	// Set Frame to cause Pos/Dim to be set. By Definition AutoSize = true means LayoutStyleAbsolute
-		//	Frame = new Rect (new Point (actX, actY), 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;
-		//	//// BUGBUG: v2 - ? - If layoutstyle is absolute, this overwrites the current frame h/w with 0. Hmmm...
-		//	//// This is needed for DimAbsolute values by setting the frame before LayoutSubViews.
-		//	_frame = new Rect (new Point (actX, actY), new Size (w, h)); // Set frame, not Frame!
-		//}
-
-		// First try SuperView.Bounds, then Application.Top, then Driver
+		// First try SuperView.Bounds, then Application.Top, then Driver.Bounds.
 		// Finally, if none of those are valid, use int.MaxValue (for Unit tests).
-		var relativeBounds = SuperView is { IsInitialized: true } ? SuperView.Bounds :
-					((Application.Top != null && Application.Top.IsInitialized) ? Application.Top.Bounds : 
-					Application.Driver?.Bounds ?? 
-					new Rect (0, 0, int.MaxValue, int.MaxValue));
+		var relativeBounds = SuperView is { IsInitialized: true }        ? SuperView.Bounds :
+			Application.Top != null && Application.Top.IsInitialized ? Application.Top.Bounds :
+										   Application.Driver?.Bounds ??
+										   new Rect (0, 0, int.MaxValue, int.MaxValue);
 		SetRelativeLayout (relativeBounds);
 
 		// TODO: Determine what, if any of the below is actually needed here.
@@ -745,7 +698,6 @@ public partial class View {
 		return ret;
 	}
 
-	// TODO: Come up with a better name for this method. "SetRelativeLayout" lacks clarity and confuses. AdjustSizeAndPosition?
 	/// <summary>
 	/// Applies the view's position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
 	/// <see cref="Height"/>) to
@@ -795,7 +747,7 @@ public partial class View {
 
 				case Dim.DimCombine combine:
 					// TODO: Move combine logic into DimCombine?
-					var leftNewDim = GetNewDimension (combine._left, location, dimension, autosize);
+					var leftNewDim = GetNewDimension (combine._left,   location, dimension, autosize);
 					var rightNewDim = GetNewDimension (combine._right, location, dimension, autosize);
 					if (combine._add) {
 						newDimension = leftNewDim + rightNewDim;
@@ -842,7 +794,7 @@ public partial class View {
 			case Pos.PosCombine combine:
 				// TODO: Move combine logic into PosCombine?
 				int left, right;
-				(left, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._left, dim, autosizeDimension);
+				(left, newDimension) = GetNewLocationAndDimension (width,  superviewBounds, combine._left,  dim, autosizeDimension);
 				(right, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._right, dim, autosizeDimension);
 				if (combine._add) {
 					newLocation = left + right;
@@ -949,7 +901,7 @@ public partial class View {
 			}
 			return;
 		case Pos.PosCombine pc:
-			CollectPos (pc._left, from, ref nNodes, ref nEdges);
+			CollectPos (pc._left,  from, ref nNodes, ref nEdges);
 			CollectPos (pc._right, from, ref nNodes, ref nEdges);
 			break;
 		}
@@ -968,7 +920,7 @@ public partial class View {
 			}
 			return;
 		case Dim.DimCombine dc:
-			CollectDim (dc._left, from, ref nNodes, ref nEdges);
+			CollectDim (dc._left,  from, ref nNodes, ref nEdges);
 			CollectDim (dc._right, from, ref nNodes, ref nEdges);
 			break;
 		}
@@ -984,7 +936,7 @@ public partial class View {
 			}
 			CollectPos (v.X, v, ref nNodes, ref nEdges);
 			CollectPos (v.Y, v, ref nNodes, ref nEdges);
-			CollectDim (v.Width, v, ref nNodes, ref nEdges);
+			CollectDim (v.Width,  v, ref nNodes, ref nEdges);
 			CollectDim (v.Height, v, ref nNodes, ref nEdges);
 		}
 	}
@@ -1228,10 +1180,10 @@ public partial class View {
 	{
 		var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
 		autoSize = new Size (rect.Size.Width - GetHotKeySpecifierLength (),
-		    rect.Size.Height - GetHotKeySpecifierLength (false));
+			rect.Size.Height - GetHotKeySpecifierLength (false));
 		return !(ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) ||
-		     _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () ||
-		     _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false));
+			 _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () ||
+			 _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false));
 	}
 
 	bool IsValidAutoSizeWidth (Dim width)

+ 393 - 322
Terminal.Gui/View/View.cs

@@ -1,313 +1,137 @@
 using System;
 using System.ComponentModel;
+using System.Diagnostics;
 
 namespace Terminal.Gui;
 
 #region API Docs
 /// <summary>
-/// View is the base class for all views on the screen and represents a visible element that can render itself and 
+/// View is the base class for all views on the screen and represents a visible element that can render itself and
 /// contains zero or more nested views, called SubViews. View provides basic functionality for layout, positioning,
 /// and drawing. In addition, View provides keyboard and mouse event handling.
 /// </summary>
 /// <remarks>
 /// <list type="table">
-///	<listheader>
-///	<term>Term</term><description>Definition</description>
-///	</listheader>
-///	<item>
-///	<term>SubView</term><description>A View that is contained in another view and will be rendered as part of the containing view's ContentArea. 
-/// SubViews are added to another view via the <see cref="View.Add(View)"/>` method. A View may only be a SubView of a single View. </description>
-///	</item>
-///	<item>
-///		<term>SuperView</term><description>The View that is a container for SubViews.</description>
-///	</item>
+///         <listheader>
+///                 <term>Term</term><description>Definition</description>
+///         </listheader>
+///         <item>
+///                 <term>SubView</term>
+///                 <description>
+///                 A View that is contained in another view and will be rendered as part of the containing view's
+///                 ContentArea.
+///                 SubViews are added to another view via the <see cref="View.Add(View)"/>` method. A View may only be a
+///                 SubView of a single View.
+///                 </description>
+///         </item>
+///         <item>
+///                 <term>SuperView</term><description>The View that is a container for SubViews.</description>
+///         </item>
 /// </list>
 /// <para>
 /// Focus is a concept that is used to describe which View is currently receiving user input. Only Views that are
 /// <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
 /// </para>
 /// <para>
-///    Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that
-///    the cursor is placed in a location that makes sense. Unix terminals do not have
-///    a way of hiding the cursor, so it can be distracting to have the cursor left at
-///    the last focused view. So views should make sure that they place the cursor
-///    in a visually sensible place.
+/// Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that
+/// the cursor is placed in a location that makes sense. Unix terminals do not have
+/// a way of hiding the cursor, so it can be distracting to have the cursor left at
+/// the last focused view. So views should make sure that they place the cursor
+/// in a visually sensible place.
 /// </para>
 /// <para>
-///    The View defines the base functionality for user interface elements in Terminal.Gui. Views
-///    can contain one or more subviews, can respond to user input and render themselves on the screen.
+/// The View defines the base functionality for user interface elements in Terminal.Gui. Views
+/// can contain one or more subviews, can respond to user input and render themselves on the screen.
 /// </para>
 /// <para>
-///    Views supports two layout styles: <see cref="LayoutStyle.Absolute"/> or <see cref="LayoutStyle.Computed"/>. 
-///    The choice as to which layout style is used by the View 
-///    is determined when the View is initialized. To create a View using Absolute layout, call a constructor that takes a
-///    Rect parameter to specify the absolute position and size (the View.<see cref="View.Frame "/>). To create a View 
-///    using Computed layout use a constructor that does not take a Rect parameter and set the X, Y, Width and Height 
-///    properties on the view. Both approaches use coordinates that are relative to the container they are being added to. 
+/// View supports two layout styles: <see cref="LayoutStyle.Absolute"/> or <see cref="LayoutStyle.Computed"/>.
+/// The style is determined by the values of <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and
+/// <see cref="Height"/>.
+/// If any of these is set to non-absolute <see cref="Pos"/> or <see cref="Dim"/> object,
+/// then the layout style is <see cref="LayoutStyle.Computed"/>. Otherwise it is <see cref="LayoutStyle.Absolute"/>.
 /// </para>
 /// <para>
-///    To switch between Absolute and Computed layout, use the <see cref="LayoutStyle"/> property. 
+/// To create a View using Absolute layout, call a constructor that takes a
+/// Rect parameter to specify the absolute position and size or simply set <see cref="View.Frame "/>). To create a View
+/// using Computed layout use a constructor that does not take a Rect parameter and set the X, Y, Width and Height
+/// properties on the view to non-absolute values. Both approaches use coordinates that are relative to the
+/// <see cref="Bounds"/> of the <see cref="SuperView"/> the View is added to.
 /// </para>
 /// <para>
-///    Computed layout is more flexible and supports dynamic console apps where controls adjust layout
-///    as the terminal resizes or other Views change size or position. The X, Y, Width and Height 
-///    properties are Dim and Pos objects that dynamically update the position of a view.
-///    The X and Y properties are of type <see cref="Pos"/>
-///    and you can use either absolute positions, percentages or anchor
-///    points. The Width and Height properties are of type
-///    <see cref="Dim"/> and can use absolute position,
-///    percentages and anchors. These are useful as they will take
-///    care of repositioning views when view's frames are resized or
-///    if the terminal size changes.
+/// Computed layout is more flexible and supports dynamic console apps where controls adjust layout
+/// as the terminal resizes or other Views change size or position. The
+/// <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and
+/// <see cref="Height"/> properties are <see cref="Dim"/> and <see cref="Pos"/> objects that dynamically update the
+/// position of a view.
+/// The X and Y properties are of type <see cref="Pos"/>
+/// and you can use either absolute positions, percentages, or anchor
+/// points. The Width and Height properties are of type
+/// <see cref="Dim"/> and can use absolute position,
+/// percentages, and anchors. These are useful as they will take
+/// care of repositioning views when view's frames are resized or
+/// if the terminal size changes.
 /// </para>
 /// <para>
-///    Absolute layout requires specifying coordinates and sizes of Views explicitly, and the
-///    View will typically stay in a fixed position and size. To change the position and size use the
-///    <see cref="Frame"/> property.
+/// Absolute layout requires specifying coordinates and sizes of Views explicitly, and the
+/// View will typically stay in a fixed position and size. To change the position and size use the
+/// <see cref="Frame"/> property.
 /// </para>
 /// <para>
-///    Subviews (child views) can be added to a View by calling the <see cref="Add(View)"/> method. 
-///    The container of a View can be accessed with the <see cref="SuperView"/> property.
+/// Subviews (child views) can be added to a View by calling the <see cref="Add(View)"/> method.
+/// The container of a View can be accessed with the <see cref="SuperView"/> property.
 /// </para>
 /// <para>
-///    To flag a region of the View's <see cref="Bounds"/> to be redrawn call <see cref="SetNeedsDisplay(Rect)"/>. 
-///    To flag the entire view for redraw call <see cref="SetNeedsDisplay()"/>.
+/// To flag a region of the View's <see cref="Bounds"/> to be redrawn call <see cref="SetNeedsDisplay(Rect)"/>.
+/// To flag the entire view for redraw call <see cref="SetNeedsDisplay()"/>.
 /// </para>
 /// <para>
-///    The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has
-///    changed. The default processing system will keep the size and dimensions
-///    for views that use the <see cref="LayoutStyle.Absolute"/>, and will recompute the
-///    frames for the vies that use <see cref="LayoutStyle.Computed"/>.
+/// The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has
+/// changed. The default processing system will keep the size and dimensions
+/// for views that use the <see cref="LayoutStyle.Absolute"/>, and will recompute the
+/// frames for the vies that use <see cref="LayoutStyle.Computed"/>.
 /// </para>
 /// <para>
-///    Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews
-///    should use for rendering. This ensures that the views fit in the context where
-///    they are being used, and allows for themes to be plugged in. For example, the
-///    default colors for windows and Toplevels uses a blue background, while it uses
-///    a white background for dialog boxes and a red background for errors.
+/// Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews
+/// should use for rendering. This ensures that the views fit in the context where
+/// they are being used, and allows for themes to be plugged in. For example, the
+/// default colors for windows and Toplevels uses a blue background, while it uses
+/// a white background for dialog boxes and a red background for errors.
 /// </para>
 /// <para>
-///    Subclasses should not rely on <see cref="ColorScheme"/> being
-///    set at construction time. If a <see cref="ColorScheme"/> is not set on a view, the view will inherit the
-///    value from its <see cref="SuperView"/> and the value might only be valid once a view has been
-///    added to a SuperView. 
+/// Subclasses should not rely on <see cref="ColorScheme"/> being
+/// set at construction time. If a <see cref="ColorScheme"/> is not set on a view, the view will inherit the
+/// value from its <see cref="SuperView"/> and the value might only be valid once a view has been
+/// added to a SuperView.
 /// </para>
 /// <para>
-///    By using  <see cref="ColorScheme"/> applications will work both
-///    in color as well as black and white displays.
+/// By using  <see cref="ColorScheme"/> applications will work both
+/// in color as well as black and white displays.
 /// </para>
 /// <para>
-///     Views can also opt-in to more sophisticated initialization
-///     by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
-///     <see cref="ISupportInitialize.EndInit"/> which will be called
-///     when the view is added to a <see cref="SuperView"/>. 
+/// Views can also opt-in to more sophisticated initialization
+/// by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
+/// <see cref="ISupportInitialize.EndInit"/> which will be called
+/// when the view is added to a <see cref="SuperView"/>.
 /// </para>
 /// <para>
-///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
-///     can be implemented, in which case the <see cref="ISupportInitialize"/>
-///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-///     to override base class layout code optimally by doing so only on first run,
-///     instead of on every run.
-///   </para>
+/// If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
+/// can be implemented, in which case the <see cref="ISupportInitialize"/>
+/// methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
+/// is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
+/// to override base class layout code optimally by doing so only on first run,
+/// instead of on every run.
+/// </para>
 /// <para>
-///	See <see href="../docs/keyboard.md">for an overview of View keyboard handling.</see>
-/// </para>	/// </remarks>
+/// See <see href="../docs/keyboard.md">for an overview of View keyboard handling.</see>
+/// </para>
+/// ///
+/// </remarks>
 #endregion API Docs
 
 public partial class View : Responder, ISupportInitializeNotification {
-	#region Constructors and Initialization
-	/// <summary>
-	/// Initializes a new instance of a <see cref="Terminal.Gui.LayoutStyle.Absolute"/> <see cref="View"/> class with the absolute
-	/// dimensions specified in the <paramref name="frame"/> parameter. 
-	/// </summary>
-	/// <param name="frame">The region covered by this view.</param>
-	/// <remarks>
-	/// This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Absolute"/>.
-	/// Use <see cref="View"/> to initialize a View with  <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/> 
-	/// </remarks>
-	public View (Rect frame) : this (frame, null) { }
-
-	/// <summary>
-	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
-	///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
-	///   coordinates. The initial size (<see cref="View.Frame"/>) will be 
-	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-	/// </para>
-	/// <para>
-	///   If <see cref="Height"/> is greater than one, word wrapping is provided.
-	/// </para>
-	/// <para>
-	///   This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/>. 
-	///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
-	/// </para>
-	/// </remarks>
-	public View () : this (string.Empty, TextDirection.LeftRight_TopBottom) { }
-
-	/// <summary>
-	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	///   The <see cref="View"/> will be created at the given
-	///   coordinates with the given string. The size (<see cref="View.Frame"/>) will be 
-	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-	/// </para>
-	/// <para>
-	///   No line wrapping is provided.
-	/// </para>
-	/// </remarks>
-	/// <param name="x">column to locate the View.</param>
-	/// <param name="y">row to locate the View.</param>
-	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-	public View (int x, int y, string text) : this (TextFormatter.CalcRect (x, y, text), text) { }
-
-	/// <summary>
-	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	///   The <see cref="View"/> will be created at the given
-	///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
-	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-	/// </para>
-	/// <para>
-	///   If <c>rect.Height</c> is greater than one, word wrapping is provided.
-	/// </para>
-	/// </remarks>
-	/// <param name="rect">Location.</param>
-	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-	public View (Rect rect, string text) => SetInitialProperties (text, rect, LayoutStyle.Absolute, TextDirection.LeftRight_TopBottom);
-
-	/// <summary>
-	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
-	///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
-	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-	/// </para>
-	/// <para>
-	///   If <see cref="Height"/> is greater than one, word wrapping is provided.
-	/// </para>
-	/// </remarks>
-	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-	/// <param name="direction">The text direction.</param>
-	public View (string text, TextDirection direction = TextDirection.LeftRight_TopBottom) => SetInitialProperties (text, Rect.Empty, LayoutStyle.Computed, direction);
-
-	// TODO: v2 - Remove constructors with parameters
-	/// <summary>
-	/// Private helper to set the initial properties of the View that were provided via constructors.
-	/// </summary>
-	/// <param name="text"></param>
-	/// <param name="rect"></param>
-	/// <param name="layoutStyle"></param>
-	/// <param name="direction"></param>
-	void SetInitialProperties (string text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed,
-				TextDirection direction = TextDirection.LeftRight_TopBottom)
-	{
-		TextFormatter = new TextFormatter ();
-		TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged;
-		TextDirection = direction;
-
-		CanFocus = false;
-		TabIndex = -1;
-		TabStop = false;
-
-		Text = text == null ? string.Empty : text;
-		Frame = rect.IsEmpty ? TextFormatter.CalcRect (0, 0, text, direction) : rect;
-		OnResizeNeeded ();
-
-		AddCommands ();
-
-		CreateFrames ();
-	}
-
-	/// <summary>
-	/// Get or sets if  the <see cref="View"/> has been initialized (via <see cref="ISupportInitialize.BeginInit"/> 
-	/// and <see cref="ISupportInitialize.EndInit"/>).
-	/// </summary>
-	/// <para>
-	///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification.IsInitialized"/>
-	///     can be implemented, in which case the <see cref="ISupportInitialize"/>
-	///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-	///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-	///     to override base class layout code optimally by doing so only on first run,
-	///     instead of on every run.
-	///   </para>
-	public virtual bool IsInitialized { get; set; }
-
-	/// <summary>
-	///  Signals the View that initialization is starting. See <see cref="ISupportInitialize"/>.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	///     Views can opt-in to more sophisticated initialization
-	///     by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
-	///     <see cref="ISupportInitialize.EndInit"/> which will be called
-	///     when the view is added to a <see cref="SuperView"/>. 
-	/// </para>
-	/// <para>
-	///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
-	///     can be implemented too, in which case the <see cref="ISupportInitialize"/>
-	///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-	///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-	///     to override base class layout code optimally by doing so only on first run,
-	///     instead of on every run.
-	///   </para>
-	/// </remarks>
-	public virtual void BeginInit ()
-	{
-		if (!IsInitialized) {
-			_oldCanFocus = CanFocus;
-			_oldTabIndex = _tabIndex;
-
-
-			// TODO: Figure out why ScrollView and other tests fail if this call is put here 
-			// instead of the constructor.
-			//InitializeFrames ();
-
-		} else {
-			//throw new InvalidOperationException ("The view is already initialized.");
-
-		}
-
-		if (_subviews?.Count > 0) {
-			foreach (var view in _subviews) {
-				if (!view.IsInitialized) {
-					view.BeginInit ();
-				}
-			}
-		}
-	}
-
-	/// <summary>
-	///  Signals the View that initialization is ending. See <see cref="ISupportInitialize"/>.
-	/// </summary>
-	public void EndInit ()
-	{
-		IsInitialized = true;
-		// These calls were moved from BeginInit as they access Bounds which is indeterminate until EndInit is called.
-		UpdateTextDirection (TextDirection);
-		UpdateTextFormatterText ();
-		SetHotKey ();
+	bool _oldEnabled;
 
-		OnResizeNeeded ();
-		if (_subviews != null) {
-			foreach (var view in _subviews) {
-				if (!view.IsInitialized) {
-					view.EndInit ();
-				}
-			}
-		}
-		Initialized?.Invoke (this, EventArgs.Empty);
-	}
-	#endregion Constructors and Initialization
+	string _title = string.Empty;
 
 	/// <summary>
 	/// Points to the current driver in use by the view, it is a convenience property
@@ -328,10 +152,9 @@ public partial class View : Responder, ISupportInitializeNotification {
 	/// <remarks>The id should be unique across all Views that share a SuperView.</remarks>
 	public string Id { get; set; } = "";
 
-	string _title = string.Empty;
-
 	/// <summary>
-	/// The title to be displayed for this <see cref="View"/>. The title will be displayed if <see cref="Border"/>.<see cref="Thickness.Top"/>
+	/// The title to be displayed for this <see cref="View"/>. The title will be displayed if <see cref="Border"/>.
+	/// <see cref="Thickness.Top"/>
 	/// is greater than 0.
 	/// </summary>
 	/// <value>The title.</value>
@@ -339,12 +162,12 @@ public partial class View : Responder, ISupportInitializeNotification {
 		get => _title;
 		set {
 			if (!OnTitleChanging (_title, value)) {
-				string old = _title;
+				var old = _title;
 				_title = value;
 				SetNeedsDisplay ();
 #if DEBUG
 				if (_title != null && string.IsNullOrEmpty (Id)) {
-					Id = _title.ToString ();
+					Id = _title;
 				}
 #endif // DEBUG
 				OnTitleChanged (old, _title);
@@ -352,51 +175,6 @@ public partial class View : Responder, ISupportInitializeNotification {
 		}
 	}
 
-	/// <summary>
-	/// Called before the <see cref="View.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
-	/// </summary>
-	/// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
-	/// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
-	/// <returns>`true` if an event handler canceled the Title change.</returns>
-	public virtual bool OnTitleChanging (string oldTitle, string newTitle)
-	{
-		var args = new TitleEventArgs (oldTitle, newTitle);
-		TitleChanging?.Invoke (this, args);
-		return args.Cancel;
-	}
-
-	/// <summary>
-	/// Event fired when the <see cref="View.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
-	/// `true` to cancel the Title change.
-	/// </summary>
-	public event EventHandler<TitleEventArgs> TitleChanging;
-
-	/// <summary>
-	/// Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
-	/// </summary>
-	/// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
-	/// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
-	public virtual void OnTitleChanged (string oldTitle, string newTitle)
-	{
-		var args = new TitleEventArgs (oldTitle, newTitle);
-		TitleChanged?.Invoke (this, args);
-	}
-
-	/// <summary>
-	/// Event fired after the <see cref="View.Title"/> has been changed. 
-	/// </summary>
-	public event EventHandler<TitleEventArgs> TitleChanged;
-
-	/// <summary>
-	/// Event fired when the <see cref="Enabled"/> value is being changed.
-	/// </summary>
-	public event EventHandler EnabledChanged;
-
-	/// <inheritdoc/>
-	public override void OnEnabledChanged () => EnabledChanged?.Invoke (this, EventArgs.Empty);
-
-	bool _oldEnabled;
-
 	/// <inheritdoc/>
 	public override bool Enabled {
 		get => base.Enabled;
@@ -430,20 +208,13 @@ public partial class View : Responder, ISupportInitializeNotification {
 		}
 	}
 
-	/// <summary>
-	/// Event fired when the <see cref="Visible"/> value is being changed.
-	/// </summary>
-	public event EventHandler VisibleChanged;
-
-	/// <inheritdoc/>
-	public override void OnVisibleChanged () => VisibleChanged?.Invoke (this, EventArgs.Empty);
-
 	/// <summary>
 	/// Gets or sets whether a view is cleared if the <see cref="Visible"/> property is <see langword="false"/>.
 	/// </summary>
 	public bool ClearOnVisibleFalse { get; set; } = true;
 
-	/// <inheritdoc/>>
+	/// <inheritdoc/>
+	/// >
 	public override bool Visible {
 		get => base.Visible;
 		set {
@@ -463,6 +234,58 @@ public partial class View : Responder, ISupportInitializeNotification {
 		}
 	}
 
+	/// <summary>
+	/// Called before the <see cref="View.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be
+	/// cancelled.
+	/// </summary>
+	/// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
+	/// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
+	/// <returns>`true` if an event handler canceled the Title change.</returns>
+	public virtual bool OnTitleChanging (string oldTitle, string newTitle)
+	{
+		var args = new TitleEventArgs (oldTitle, newTitle);
+		TitleChanging?.Invoke (this, args);
+		return args.Cancel;
+	}
+
+	/// <summary>
+	/// Event fired when the <see cref="View.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to
+	/// `true` to cancel the Title change.
+	/// </summary>
+	public event EventHandler<TitleEventArgs> TitleChanging;
+
+	/// <summary>
+	/// Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
+	/// </summary>
+	/// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
+	/// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
+	public virtual void OnTitleChanged (string oldTitle, string newTitle)
+	{
+		var args = new TitleEventArgs (oldTitle, newTitle);
+		TitleChanged?.Invoke (this, args);
+	}
+
+	/// <summary>
+	/// Event fired after the <see cref="View.Title"/> has been changed.
+	/// </summary>
+	public event EventHandler<TitleEventArgs> TitleChanged;
+
+	/// <summary>
+	/// Event fired when the <see cref="Enabled"/> value is being changed.
+	/// </summary>
+	public event EventHandler EnabledChanged;
+
+	/// <inheritdoc/>
+	public override void OnEnabledChanged () => EnabledChanged?.Invoke (this, EventArgs.Empty);
+
+	/// <summary>
+	/// Event fired when the <see cref="Visible"/> value is being changed.
+	/// </summary>
+	public event EventHandler VisibleChanged;
+
+	/// <inheritdoc/>
+	public override void OnVisibleChanged () => VisibleChanged?.Invoke (this, EventArgs.Empty);
+
 	bool CanBeVisible (View view)
 	{
 		if (!view.Visible) {
@@ -495,13 +318,261 @@ public partial class View : Responder, ISupportInitializeNotification {
 		Padding?.Dispose ();
 		Padding = null;
 
-		for (int i = InternalSubviews.Count - 1; i >= 0; i--) {
+		for (var i = InternalSubviews.Count - 1; i >= 0; i--) {
 			var subview = InternalSubviews [i];
 			Remove (subview);
 			subview.Dispose ();
 		}
 
 		base.Dispose (disposing);
-		System.Diagnostics.Debug.Assert (InternalSubviews.Count == 0);
+		Debug.Assert (InternalSubviews.Count == 0);
 	}
+
+	#region Constructors and Initialization
+	/// <summary>
+	/// Initializes a new instance of a <see cref="View"/> class with the absolute
+	/// dimensions specified in the <paramref name="frame"/> parameter.
+	/// </summary>
+	/// <param name="frame">The region covered by this view.</param>
+	/// <remarks>
+	///         <para>
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view.
+	///         The <see cref="View"/> will be created using <see cref="LayoutStyle.Absolute"/>
+	///         coordinates. The initial size (<see cref="View.Frame"/>) will be
+	///         adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines.
+	///         </para>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         This constructor initialize a View with a <see cref="LayoutStyle"/> of
+	///         <see cref="LayoutStyle.Absolute"/>.
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
+	///         </para>
+	/// </remarks>
+	public View (Rect frame) : this (frame, null) { }
+
+	/// <summary>
+	/// Initializes a new instance of <see cref="View"/>.
+	/// </summary>
+	/// <remarks>
+	///         <para>
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view.
+	///         The <see cref="View"/> will be created using <see cref="LayoutStyle.Absolute"/>
+	///         coordinates. The initial size (<see cref="View.Frame"/>) will be
+	///         adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines.
+	///         </para>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         This constructor initialize a View with a <see cref="LayoutStyle"/> of
+	///         <see cref="LayoutStyle.Absolute"/>.
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
+	///         </para>
+	/// </remarks>
+	public View () : this (string.Empty) { }
+
+	/// <summary>
+	/// Initializes a new instance of <see cref="View"/> in at the position specified with the
+	/// dimensions specified in the <paramref name="x"/> and <paramref name="y"/> parameters.
+	/// </summary>
+	/// <remarks>
+	///         <para>
+	///         The <see cref="View"/> will be created at the given
+	///         coordinates with the given string. The size (<see cref="View.Frame"/>) will be
+	///         adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines.
+	///         </para>
+	///         <para>
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view.
+	///         </para>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         This constructor initialize a View with a <see cref="LayoutStyle"/> of
+	///         <see cref="LayoutStyle.Absolute"/>.
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
+	///         </para>
+	/// </remarks>
+	/// <param name="x">column to locate the View.</param>
+	/// <param name="y">row to locate the View.</param>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	public View (int x, int y, string text) : this (TextFormatter.CalcRect (x, y, text), text) { }
+
+	/// <summary>
+	/// Initializes a new instance of a <see cref="View"/> class with the absolute
+	/// dimensions specified in the <paramref name="frame"/> parameter.
+	/// </summary>
+	/// <remarks>
+	///         <para>
+	///         The <see cref="View"/> will be created at the given
+	///         coordinates with the given string. The size (<see cref="View.Frame"/>) will be
+	///         adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines.
+	///         </para>
+	///         <para>
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view.
+	///         </para>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         This constructor initialize a View with a <see cref="LayoutStyle"/> of
+	///         <see cref="LayoutStyle.Absolute"/>.
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
+	///         </para>
+	/// </remarks>
+	/// <param name="rect">Location.</param>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	public View (Rect rect, string text) => SetInitialProperties (text, rect, LayoutStyle.Absolute);
+
+
+	/// <summary>
+	/// Initializes a new instance of a <see cref="View"/> class with using the given text and text styling information.
+	/// </summary>
+	/// <remarks>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         The <see cref="View"/> will be created at the given
+	///         coordinates with the given string. The size (<see cref="View.Frame"/>) will be
+	///         adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines.
+	///         </para>
+	///         <para>
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view.
+	///         </para>
+	///         <para>
+	///         If <see cref="Height"/> is greater than one, word wrapping is provided.
+	///         </para>
+	///         <para>
+	///         This constructor initialize a View with a <see cref="LayoutStyle"/> of
+	///         <see cref="LayoutStyle.Absolute"/>.
+	///         Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically
+	///         control the size and location of the view, changing it to  <see cref="LayoutStyle.Computed"/>.
+	///         </para>
+	/// </remarks>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	/// <param name="direction">The text direction.</param>
+	public View (string text, TextDirection direction = TextDirection.LeftRight_TopBottom) => SetInitialProperties (text, Rect.Empty, LayoutStyle.Computed, direction);
+
+	// TODO: v2 - Remove constructors with parameters
+
+
+	/// <summary>
+	/// Private helper to set the initial properties of the View that were provided via constructors.
+	/// </summary>
+	/// <param name="text"></param>
+	/// <param name="rect"></param>
+	/// <param name="layoutStyle"></param>
+	/// <param name="direction"></param>
+	void SetInitialProperties (string text,
+				   Rect rect,
+				   LayoutStyle layoutStyle = LayoutStyle.Computed,
+				   TextDirection direction = TextDirection.LeftRight_TopBottom)
+	{
+		TextFormatter = new TextFormatter ();
+		TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged;
+		TextDirection = direction;
+
+		CanFocus = false;
+		TabIndex = -1;
+		TabStop = false;
+
+		Text = text == null ? string.Empty : text;
+		Frame = rect.IsEmpty ? TextFormatter.CalcRect (0, 0, text, direction) : rect;
+		OnResizeNeeded ();
+
+		AddCommands ();
+
+		CreateFrames ();
+	}
+
+	/// <summary>
+	/// Get or sets if  the <see cref="View"/> has been initialized (via <see cref="ISupportInitialize.BeginInit"/>
+	/// and <see cref="ISupportInitialize.EndInit"/>).
+	/// </summary>
+	/// <para>
+	/// If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification.IsInitialized"/>
+	/// can be implemented, in which case the <see cref="ISupportInitialize"/>
+	/// methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
+	/// is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
+	/// to override base class layout code optimally by doing so only on first run,
+	/// instead of on every run.
+	/// </para>
+	public virtual bool IsInitialized { get; set; }
+
+	/// <summary>
+	/// Signals the View that initialization is starting. See <see cref="ISupportInitialize"/>.
+	/// </summary>
+	/// <remarks>
+	///         <para>
+	///         Views can opt-in to more sophisticated initialization
+	///         by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
+	///         <see cref="ISupportInitialize.EndInit"/> which will be called
+	///         when the view is added to a <see cref="SuperView"/>.
+	///         </para>
+	///         <para>
+	///         If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
+	///         can be implemented too, in which case the <see cref="ISupportInitialize"/>
+	///         methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
+	///         is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
+	///         to override base class layout code optimally by doing so only on first run,
+	///         instead of on every run.
+	///         </para>
+	/// </remarks>
+	public virtual void BeginInit ()
+	{
+		if (!IsInitialized) {
+			_oldCanFocus = CanFocus;
+			_oldTabIndex = _tabIndex;
+
+
+			// TODO: Figure out why ScrollView and other tests fail if this call is put here 
+			// instead of the constructor.
+			//InitializeFrames ();
+
+		}
+
+		//throw new InvalidOperationException ("The view is already initialized.");
+		if (_subviews?.Count > 0) {
+			foreach (var view in _subviews) {
+				if (!view.IsInitialized) {
+					view.BeginInit ();
+				}
+			}
+		}
+	}
+
+	/// <summary>
+	/// Signals the View that initialization is ending. See <see cref="ISupportInitialize"/>.
+	/// </summary>
+	public void EndInit ()
+	{
+		IsInitialized = true;
+		// These calls were moved from BeginInit as they access Bounds which is indeterminate until EndInit is called.
+		UpdateTextDirection (TextDirection);
+		UpdateTextFormatterText ();
+		SetHotKey ();
+
+		OnResizeNeeded ();
+		if (_subviews != null) {
+			foreach (var view in _subviews) {
+				if (!view.IsInitialized) {
+					view.EndInit ();
+				}
+			}
+		}
+		Initialized?.Invoke (this, EventArgs.Empty);
+	}
+	#endregion Constructors and Initialization
 }

+ 72 - 60
Terminal.Gui/View/ViewText.cs

@@ -7,24 +7,25 @@ public partial class View {
 	string _text;
 
 	/// <summary>
-	///   The text displayed by the <see cref="View"/>.
+	/// The text displayed by the <see cref="View"/>.
 	/// </summary>
 	/// <remarks>
-	/// <para>
-	///  The text will be drawn before any subviews are drawn.
-	/// </para>
-	/// <para>
-	///  The text will be drawn starting at the view origin (0, 0) and will be formatted according
-	///  to <see cref="TextAlignment"/> and <see cref="TextDirection"/>. 
-	/// </para>
-	/// <para>
-	///  The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
-	///  is 1, the text will be clipped.	
-	///  </para>
-	/// <para>
-	///  Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set <see cref="HotKeySpecifier"/> to
-	///  <c>(Rune)0xffff</c>.
-	/// </para>
+	///         <para>
+	///         The text will be drawn before any subviews are drawn.
+	///         </para>
+	///         <para>
+	///         The text will be drawn starting at the view origin (0, 0) and will be formatted according
+	///         to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
+	///         </para>
+	///         <para>
+	///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
+	///         is 1, the text will be clipped.
+	///         </para>
+	///         <para>
+	///         Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set
+	///         <see cref="HotKeySpecifier"/> to
+	///         <c>(Rune)0xffff</c>.
+	///         </para>
 	/// </remarks>
 	public virtual string Text {
 		get => _text;
@@ -48,21 +49,10 @@ public partial class View {
 	/// </summary>
 	public TextFormatter TextFormatter { get; set; }
 
-	/// <summary>
-	/// Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
-	///  different format than the default.
-	/// </summary>
-	protected virtual void UpdateTextFormatterText ()
-	{
-		if (TextFormatter != null) {
-			TextFormatter.Text = _text;
-		}
-	}
-
 	/// <summary>
 	/// Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
-	/// or not when <see cref="TextFormatter.WordWrap"/> is enabled. 
-	/// If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when 
+	/// or not when <see cref="TextFormatter.WordWrap"/> is enabled.
+	/// If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when
 	/// <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
 	/// </summary>
 	public virtual bool PreserveTrailingSpaces {
@@ -76,7 +66,8 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will redisplay the <see cref="View"/>.
+	/// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will
+	/// redisplay the <see cref="View"/>.
 	/// </summary>
 	/// <value>The text alignment.</value>
 	public virtual TextAlignment TextAlignment {
@@ -89,7 +80,8 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will redisplay the <see cref="View"/>.
+	/// Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will redisplay
+	/// the <see cref="View"/>.
 	/// </summary>
 	/// <value>The text alignment.</value>
 	public virtual VerticalTextAlignment VerticalTextAlignment {
@@ -101,7 +93,8 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the <see cref="View"/>.
+	/// Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the
+	/// <see cref="View"/>.
 	/// </summary>
 	/// <value>The text alignment.</value>
 	public virtual TextDirection TextDirection {
@@ -112,18 +105,27 @@ public partial class View {
 		}
 	}
 
+	/// <summary>
+	/// Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
+	/// different format than the default.
+	/// </summary>
+	protected virtual void UpdateTextFormatterText ()
+	{
+		if (TextFormatter != null) {
+			TextFormatter.Text = _text;
+		}
+	}
+
 	void UpdateTextDirection (TextDirection newDirection)
 	{
-		bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
-					!= TextFormatter.IsHorizontalDirection (newDirection);
+		var directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction) != TextFormatter.IsHorizontalDirection (newDirection);
 		TextFormatter.Direction = newDirection;
 
-		bool isValidOldAutoSize = AutoSize && IsValidAutoSize (out var _);
+		var isValidOldAutoSize = AutoSize && IsValidAutoSize (out var _);
 
 		UpdateTextFormatterText ();
 
-		if (!ValidatePosDim && directionChanged && AutoSize
-		|| ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize) {
+		if (!ValidatePosDim && directionChanged && AutoSize || ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize) {
 			OnResizeNeeded ();
 		} else if (directionChanged && IsAdded) {
 			ResizeBoundsToFit (Bounds.Size);
@@ -138,10 +140,13 @@ public partial class View {
 
 
 	/// <summary>
-	/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>. 
+	/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>.
 	/// </summary>
-	/// <returns><see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> == <see langword="true"/> or
-	/// <see cref="Text"/> will not fit.</returns>
+	/// <returns>
+	/// <see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> ==
+	/// <see langword="true"/> or
+	/// <see cref="Text"/> will not fit.
+	/// </returns>
 	/// <remarks>
 	/// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
 	/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
@@ -171,23 +176,23 @@ public partial class View {
 			if (!AutoSize && !string.IsNullOrEmpty (TextFormatter.Text)) {
 				switch (TextFormatter.IsVerticalDirection (TextDirection)) {
 				case true:
-					int colWidth = TextFormatter.GetSumMaxCharWidth (new List<string> { TextFormatter.Text }, 0, 1);
+					var colWidth = TextFormatter.GetSumMaxCharWidth (new List<string> { TextFormatter.Text }, 0, 1);
 					// TODO: v2 - This uses frame.Width; it should only use Bounds
 					if (_frame.Width < colWidth &&
-					(Width == null ||
-					Bounds.Width >= 0 &&
-					Width is Dim.DimAbsolute &&
-					Width.Anchor (0) >= 0 &&
-					Width.Anchor (0) < colWidth)) {
+					    (Width == null ||
+					     Bounds.Width >= 0 &&
+					     Width is Dim.DimAbsolute &&
+					     Width.Anchor (0) >= 0 &&
+					     Width.Anchor (0) < colWidth)) {
 						sizeRequired = new Size (colWidth, Bounds.Height);
 						return true;
 					}
 					break;
 				default:
 					if (_frame.Height < 1 &&
-					(Height == null ||
-					Height is Dim.DimAbsolute &&
-					Height.Anchor (0) == 0)) {
+					    (Height == null ||
+					     Height is Dim.DimAbsolute &&
+					     Height.Anchor (0) == 0)) {
 						sizeRequired = new Size (Bounds.Width, 1);
 						return true;
 					}
@@ -205,37 +210,44 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters 
+	/// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters
 	/// in the <see cref="Text"/> property.
 	/// </summary>
 	/// <remarks>
 	/// Only the first hotkey specifier found in <see cref="Text"/> is supported.
 	/// </remarks>
-	/// <param name="isWidth">If <see langword="true"/> (the default) the width required for the hotkey specifier is returned. Otherwise the height is returned.</param>
-	/// <returns>The number of characters required for the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>. If the text direction specified
-	/// by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.</returns>
+	/// <param name="isWidth">
+	/// If <see langword="true"/> (the default) the width required for the hotkey specifier is returned. Otherwise the height
+	/// is returned.
+	/// </param>
+	/// <returns>
+	/// The number of characters required for the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>. If the text
+	/// direction specified
+	/// by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.
+	/// </returns>
 	public int GetHotKeySpecifierLength (bool isWidth = true)
 	{
 		if (isWidth) {
 			return TextFormatter.IsHorizontalDirection (TextDirection) &&
-				TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
-				? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
-		} else {
-			return TextFormatter.IsVerticalDirection (TextDirection) &&
-				TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+			       TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
 				? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
 		}
+		return TextFormatter.IsVerticalDirection (TextDirection) &&
+		       TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+			? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
 	}
 
 	/// <summary>
-	/// Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>.
+	/// Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>
+	/// .
 	/// </summary>
 	/// <returns></returns>
 	public Size GetSizeNeededForTextWithoutHotKey () => new (TextFormatter.Size.Width - GetHotKeySpecifierLength (),
 		TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
 
 	/// <summary>
-	/// Gets the dimensions required for <see cref="Text"/> accounting for a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> .
+	/// Gets the dimensions required for <see cref="Text"/> accounting for a
+	/// <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> .
 	/// </summary>
 	/// <returns></returns>
 	public Size GetTextFormatterSizeNeededForTextAndHotKey ()

+ 17 - 16
Terminal.Gui/Views/Toplevel.cs

@@ -12,7 +12,7 @@ namespace Terminal.Gui;
 /// <remarks>
 ///         <para>
 ///         Toplevels can run as modal (popup) views, started by calling
-///         <see cref="Application.Run(Toplevel, System.Func{System.Exception,bool}(System.Exception))"/>.
+///         <see cref="Application.Run(Toplevel, System.Func{System.Exception,bool})"/>.
 ///         They return control to the caller when <see cref="Application.RequestStop(Toplevel)"/> has
 ///         been called (which sets the <see cref="Toplevel.Running"/> property to <c>false</c>).
 ///         </para>
@@ -22,7 +22,7 @@ namespace Terminal.Gui;
 ///         The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional
 ///         Toplevels can be created
 ///         and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and
-///         call <see cref="Application.Run(Toplevel, System.Func{System.Exception,bool}(System.Exception))"/>.
+///         call <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>.
 ///         </para>
 /// </remarks>
 public partial class Toplevel : View {
@@ -42,7 +42,8 @@ public partial class Toplevel : View {
 
 	/// <summary>
 	/// Initializes a new instance of the <see cref="Toplevel"/> class with
-	/// <see cref="LayoutStyle.Computed"/> layout, defaulting to full screen. The <see cref="View.Width"/> and <see cref="View.Height"/> properties
+	/// <see cref="LayoutStyle.Computed"/> layout, defaulting to full screen. The <see cref="View.Width"/> and
+	/// <see cref="View.Height"/> properties
 	/// will be set to the dimensions of the terminal using <see cref="Dim.Fill"/>.
 	/// </summary>
 	public Toplevel ()
@@ -250,7 +251,7 @@ public partial class Toplevel : View {
 		}
 		Unloaded?.Invoke (this, EventArgs.Empty);
 	}
-	
+
 	void SetInitialProperties ()
 	{
 		ColorScheme = Colors.TopLevel;
@@ -306,17 +307,17 @@ public partial class Toplevel : View {
 		KeyBindings.Add ((KeyCode)Application.QuitKey, Command.QuitToplevel);
 
 		KeyBindings.Add (KeyCode.CursorRight, Command.NextView);
-		KeyBindings.Add (KeyCode.CursorDown, Command.NextView);
-		KeyBindings.Add (KeyCode.CursorLeft, Command.PreviousView);
-		KeyBindings.Add (KeyCode.CursorUp, Command.PreviousView);
+		KeyBindings.Add (KeyCode.CursorDown,  Command.NextView);
+		KeyBindings.Add (KeyCode.CursorLeft,  Command.PreviousView);
+		KeyBindings.Add (KeyCode.CursorUp,    Command.PreviousView);
 
-		KeyBindings.Add (KeyCode.Tab, Command.NextView);
-		KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask, Command.PreviousView);
-		KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask, Command.NextViewOrTop);
+		KeyBindings.Add (KeyCode.Tab,                                        Command.NextView);
+		KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask,                    Command.PreviousView);
+		KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask,                     Command.NextViewOrTop);
 		KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask | KeyCode.CtrlMask, Command.PreviousViewOrTop);
 
-		KeyBindings.Add (KeyCode.F5, Command.Refresh);
-		KeyBindings.Add ((KeyCode)Application.AlternateForwardKey, Command.NextViewOrTop);     // Needed on Unix
+		KeyBindings.Add (KeyCode.F5,                                Command.Refresh);
+		KeyBindings.Add ((KeyCode)Application.AlternateForwardKey,  Command.NextViewOrTop);     // Needed on Unix
 		KeyBindings.Add ((KeyCode)Application.AlternateBackwardKey, Command.PreviousViewOrTop); // Needed on Unix
 
 #if UNIX_KEY_BINDINGS
@@ -676,16 +677,16 @@ public partial class Toplevel : View {
 	public virtual void PositionToplevel (Toplevel top)
 	{
 		var superView = GetLocationThatFits (top, top.Frame.X, top.Frame.Y,
-			out var nx, out var ny, out _, out var sb);
+			out var nx,                       out var ny,  out _, out var sb);
 		var layoutSubviews = false;
 		var maxWidth = 0;
 		if (superView.Margin != null && superView == top.SuperView) {
 			maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
 		}
-		if ((superView != top || top?.SuperView != null || top != Application.Top && top.Modal
-			|| top?.SuperView == null && top.IsOverlapped)
+		if ((superView != top || top?.SuperView != null || top != Application.Top && top.Modal || top?.SuperView == null && top.IsOverlapped)
 		    // BUGBUG: Prevously PositionToplevel required LayotuStyle.Computed
-		&& (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y) /*&& top.LayoutStyle == LayoutStyle.Computed*/) {
+		    &&
+		    (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y) /*&& top.LayoutStyle == LayoutStyle.Computed*/) {
 
 			if ((top.X == null || top.X is Pos.PosAbsolute) && top.Frame.X != nx) {
 				top.X = nx;

+ 0 - 1
UICatalog/Scenarios/AllViewsTester.cs

@@ -111,7 +111,6 @@ public class AllViewsTester : Scenario {
 		_computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 };
 		_computedCheckBox.Toggled += (s, e) => {
 			if (_curView != null) {
-				_curView.LayoutStyle = e.OldValue == true ? LayoutStyle.Absolute : LayoutStyle.Computed;
 				_hostPane.LayoutSubviews ();
 			}
 		};

+ 0 - 4
UICatalog/Scenarios/Sliders.cs

@@ -104,9 +104,7 @@ public class Sliders : Scenario {
 					s.Style.SpaceChar = new Cell { Rune = CM.Glyphs.HLine };
 
 					if (prev == null) {
-						s.LayoutStyle = LayoutStyle.Absolute;
 						s.Y = 0;
-						s.LayoutStyle = LayoutStyle.Computed;
 					} else {
 						s.Y = Pos.Bottom (prev) + 1;
 					}
@@ -119,9 +117,7 @@ public class Sliders : Scenario {
 					s.Style.SpaceChar = new Cell { Rune = CM.Glyphs.VLine };
 
 					if (prev == null) {
-						s.LayoutStyle = LayoutStyle.Absolute;
 						s.X = 0;
-						s.LayoutStyle = LayoutStyle.Computed;
 					} else {
 						s.X = Pos.Right (prev) + 2;
 					}

+ 3 - 3
UnitTests/UICatalog/ScenarioTests.cs

@@ -335,7 +335,7 @@ namespace UICatalog.Tests {
 
 			_computedCheckBox.Toggled += (s, e) => {
 				if (_curView != null) {
-					_curView.LayoutStyle = e.OldValue == true ? LayoutStyle.Absolute : LayoutStyle.Computed;
+					//_curView.LayoutStyle = e.OldValue == true ? LayoutStyle.Absolute : LayoutStyle.Computed;
 					_hostPane.LayoutSubviews ();
 				}
 			};
@@ -419,7 +419,7 @@ namespace UICatalog.Tests {
 				var layout = view.LayoutStyle;
 
 				try {
-					view.LayoutStyle = LayoutStyle.Absolute;
+					//view.LayoutStyle = LayoutStyle.Absolute;
 
 					switch (_xRadioGroup.SelectedItem) {
 					case 0:
@@ -477,7 +477,7 @@ namespace UICatalog.Tests {
 				} catch (Exception e) {
 					MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
 				} finally {
-					view.LayoutStyle = layout;
+					//view.LayoutStyle = layout;
 				}
 				UpdateTitle (view);
 			}