BDisp 2 years ago
parent
commit
932aca89eb
2 changed files with 60 additions and 22 deletions
  1. 25 16
      Terminal.Gui/Core/View.cs
  2. 35 6
      UnitTests/Core/LayoutTests.cs

+ 25 - 16
Terminal.Gui/Core/View.cs

@@ -2435,7 +2435,7 @@ namespace Terminal.Gui {
 
 			if (edges.Any ()) {
 				(var from, var to) = edges.First ();
-				if (from != superView && from != Application.Top) {
+				if (from != superView?.GetTopSuperView (to, from)) {
 					if (!ReferenceEquals (from, to)) {
 						throw new InvalidOperationException ($"TopologicalSort (for Pos/Dim) cannot find {from} linked with {to}. Did you forget to add it to {superView}?");
 					} else {
@@ -2472,20 +2472,16 @@ namespace Terminal.Gui {
 			CollectAll (this, ref nodes, ref edges);
 			var ordered = View.TopologicalSort (SuperView, nodes, edges);
 			foreach (var v in ordered) {
-				if (v.LayoutStyle == LayoutStyle.Computed) {
-					v.SetRelativeLayout (Frame);
-				}
-
-				v.LayoutSubviews ();
-				v.LayoutNeeded = false;
+				LayoutSubview (v, Frame);
 			}
 
-			// If our SuperView is Application.Top and the layoutstyle is Computed it's a special-cass.
-			// Use SetRelativeaLayout with the Frame of the Application.Top
-			if (SuperView != null && SuperView == Application.Top && LayoutNeeded
-			    && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
-				Debug.Assert (Application.Top.Frame.Location == Point.Empty);
-				SetRelativeLayout (Application.Top.Frame);
+			// If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
+			// Use LayoutSubview with the Frame of the 'from' 
+			if (SuperView != null && GetTopSuperView () != null && LayoutNeeded
+			    && ordered.Count == 0 && edges.Count > 0 && LayoutStyle == LayoutStyle.Computed) {
+
+				(var from, var to) = edges.First ();
+				LayoutSubview (to, from.Frame);
 			}
 
 			LayoutNeeded = false;
@@ -2493,6 +2489,16 @@ namespace Terminal.Gui {
 			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 		}
 
+		private void LayoutSubview (View v, Rect hostFrame)
+		{
+			if (v.LayoutStyle == LayoutStyle.Computed) {
+				v.SetRelativeLayout (hostFrame);
+			}
+
+			v.LayoutSubviews ();
+			v.LayoutNeeded = false;
+		}
+
 		ustring text;
 
 		/// <summary>
@@ -3162,11 +3168,14 @@ namespace Terminal.Gui {
 		/// Get the top superview of a given <see cref="View"/>.
 		/// </summary>
 		/// <returns>The superview view.</returns>
-		public View GetTopSuperView ()
+		public View GetTopSuperView (View view = null, View superview = null)
 		{
-			View top = Application.Top;
-			for (var v = this?.SuperView; v != null; v = v.SuperView) {
+			View top = superview ?? Application.Top;
+			for (var v = view?.SuperView ?? (this?.SuperView); v != null; v = v.SuperView) {
 				top = v;
+				if (top == superview) {
+					break;
+				}
 			}
 
 			return top;

+ 35 - 6
UnitTests/Core/LayoutTests.cs

@@ -36,21 +36,50 @@ namespace Terminal.Gui.CoreTests {
 		}
 
 		[Fact]
-		public void TopologicalSort_Does_Not_Throws_Missing_Add ()
+		public void TopologicalSort_Does_Never_Throws_If_Root_Is_Not_Null ()
 		{
-			var root = new View ();
-			var sub1 = new View ();
-			var sub2 = new View ();
+			var root = new View () { Id = "root", Width = 20, Height = 20 };
+			var sub1 = new View () {
+				Id = "sub1",
+				X = Pos.Left (root) + 1,
+				Y = Pos.Top (root) + 1,
+				Width = Dim.Width (root) - 2,
+				Height = Dim.Height (root) - 2
+			};
+			var sub2 = new View () {
+				Id = "sub2",
+				X = Pos.Left (root) + 1,
+				Y = Pos.Top (root) + 1,
+				Width = Dim.Width (root) - 2,
+				Height = Dim.Height (root) - 2
+			};
+			var sub3 = new View () {
+				Id = "sub3",
+				X = Pos.Left (root) + 1,
+				Y = Pos.Top (root) + 1,
+				Width = Dim.Width (root) - 2,
+				Height = Dim.Height (root) - 2
+			};
+			sub2.Add (sub3);
 			sub1.Add (sub2);
 			root.Add (sub1);
-			sub2.Width = Dim.Width (root);
 
 			var exception = Record.Exception (root.LayoutSubviews);
 			Assert.Null (exception);
+			Assert.Equal (new Rect (0, 0, 20, 20), root.Frame);
+			Assert.Equal (new Rect (1, 1, 18, 18), sub1.Frame);
+			Assert.Equal (new Rect (1, 1, 18, 18), sub2.Frame);
+			Assert.Equal (new Rect (1, 1, 18, 18), sub3.Frame);
 
-			sub2.Width = Dim.Width (sub1);
+			sub2.Width = Dim.Width (root);
+			exception = Record.Exception (root.LayoutSubviews);
+			Assert.Null (exception);
+			Assert.Equal (new Rect (1, 1, 20, 18), sub2.Frame);
+
+			sub3.Width = Dim.Width (root);
 			exception = Record.Exception (root.LayoutSubviews);
 			Assert.Null (exception);
+			Assert.Equal (new Rect (1, 1, 20, 18), sub3.Frame);
 		}
 
 		[Fact]