소스 검색

Fixes #2503. PosCombine and DimCombine is wrongly looking into the from.InternalSubviews.

BDisp 2 년 전
부모
커밋
16a6e581d1
3개의 변경된 파일126개의 추가작업 그리고 34개의 파일을 삭제
  1. 19 23
      Terminal.Gui/View/View.cs
  2. 44 0
      UnitTests/View/Layout/DimTests.cs
  3. 63 11
      UnitTests/View/Layout/LayoutTests.cs

+ 19 - 23
Terminal.Gui/View/View.cs

@@ -1395,7 +1395,8 @@ namespace Terminal.Gui {
 		public Point ScreenToBounds (int x, int y)
 		{
 			if (SuperView == null) {
-				return new Point (x - Frame.X + GetBoundsOffset ().X, y - Frame.Y + GetBoundsOffset ().Y);
+				var boundsOffset = GetBoundsOffset ();
+				return new Point (x - Frame.X + boundsOffset.X, y - Frame.Y + boundsOffset.Y);
 			} else {
 				var parent = SuperView.ScreenToView (x, y);
 				return new Point (parent.X - frame.X, parent.Y - frame.Y);
@@ -1414,13 +1415,15 @@ namespace Terminal.Gui {
 		/// <see cref="ConsoleDriver.Rows"/>, respectively.</param>
 		public virtual void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clamped = true)
 		{
-			rcol = col + Frame.X + GetBoundsOffset ().X;
-			rrow = row + Frame.Y + GetBoundsOffset ().Y;
+			var boundsOffset = GetBoundsOffset ();
+			rcol = col + Frame.X + boundsOffset.X;
+			rrow = row + Frame.Y + boundsOffset.Y;
 
 			var super = SuperView;
 			while (super != null) {
-				rcol += super.Frame.X + super.GetBoundsOffset ().X;
-				rrow += super.Frame.Y + super.GetBoundsOffset ().Y;
+				boundsOffset = super.GetBoundsOffset ();
+				rcol += super.Frame.X + boundsOffset.X;
+				rrow += super.Frame.Y + boundsOffset.Y;
 				super = super.SuperView;
 			}
 
@@ -2577,10 +2580,8 @@ namespace Terminal.Gui {
 				}
 				return;
 			case Pos.PosCombine pc:
-				foreach (var v in from.InternalSubviews) {
-					CollectPos (pc.left, from, ref nNodes, ref nEdges);
-					CollectPos (pc.right, from, ref nNodes, ref nEdges);
-				}
+				CollectPos (pc.left, from, ref nNodes, ref nEdges);
+				CollectPos (pc.right, from, ref nNodes, ref nEdges);
 				break;
 			}
 		}
@@ -2601,10 +2602,8 @@ namespace Terminal.Gui {
 				}
 				return;
 			case Dim.DimCombine dc:
-				foreach (var v in from.InternalSubviews) {
-					CollectDim (dc.left, from, ref nNodes, ref nEdges);
-					CollectDim (dc.right, from, ref nNodes, ref nEdges);
-				}
+				CollectDim (dc.left, from, ref nNodes, ref nEdges);
+				CollectDim (dc.right, from, ref nNodes, ref nEdges);
 				break;
 			}
 		}
@@ -2658,15 +2657,11 @@ namespace Terminal.Gui {
 
 			if (edges.Any ()) {
 				(var from, var to) = edges.First ();
-				if (from != superView?.GetTopSuperView (to, from)) {
-					if (!ReferenceEquals (from, to)) {
-						if (ReferenceEquals (from.SuperView, to)) {
-							throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\").");
-						} else {
-							throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?");
-						}
+				if (from != superView?.GetTopSuperView (to, from) && !ReferenceEquals (from, to)) {
+					if (ReferenceEquals (from.SuperView, to)) {
+						throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\").");
 					} else {
-						throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": A recursive cycle was found in the relative Pos/Dim of the SubViews.");
+						throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?");
 					}
 				}
 			}
@@ -3508,8 +3503,9 @@ namespace Terminal.Gui {
 			if (start.InternalSubviews != null) {
 				int count = start.InternalSubviews.Count;
 				if (count > 0) {
-					var rx = x - (startFrame.X + start.GetBoundsOffset ().X);
-					var ry = y - (startFrame.Y + start.GetBoundsOffset ().Y);
+					var boundsOffset = start.GetBoundsOffset ();
+					var rx = x - (startFrame.X + boundsOffset.X);
+					var ry = y - (startFrame.Y + boundsOffset.Y);
 					for (int i = count - 1; i >= 0; i--) {
 						View v = start.InternalSubviews [i];
 						if (v.Visible && v.Frame.Contains (rx, ry)) {

+ 44 - 0
UnitTests/View/Layout/DimTests.cs

@@ -1266,5 +1266,49 @@ namespace Terminal.Gui.ViewTests {
 				Assert.Equal (51, label.Frame.Height);
 			}
 		}
+
+		[Fact]
+		public void Dim_Referencing_SuperView_Throws ()
+		{
+			var super = new View ("super") {
+				Width = 10,
+				Height = 10
+			};
+			var view = new View ("view") {
+				Width = Dim.Width (super),      // this is allowed
+				Height = Dim.Height (super),    // this is allowed
+			};
+
+			super.Add (view);
+			super.BeginInit ();
+			super.EndInit ();
+
+			var exception = Record.Exception (super.LayoutSubviews);
+			Assert.Null (exception);
+		}
+
+		[Fact]
+		public void Dim_SyperView_Referencing_SubView_Does_Not_Throws ()
+		{
+			var super = new View ("super") {
+				Width = 10,
+				Height = 10
+			};
+			var view2 = new View ("view2") {
+				Width = 10,
+				Height = 10,
+			};
+			var view = new View ("view") {
+				Width = Dim.Width (view2),      // this is not allowed
+				Height = Dim.Height (view2),    // this is not allowed
+			};
+
+			view.Add (view2);
+			super.Add (view);
+			super.BeginInit ();
+			super.EndInit ();
+
+			Assert.Throws<InvalidOperationException> (super.LayoutSubviews);
+		}
 	}
 }

+ 63 - 11
UnitTests/View/Layout/LayoutTests.cs

@@ -43,7 +43,9 @@ namespace Terminal.Gui.ViewTests {
 			var sub2 = new View ();
 			root.Add (sub2);
 			sub2.Width = Dim.Width (sub2);
-			Assert.Throws<InvalidOperationException> (() => root.LayoutSubviews ());
+
+			var exception = Record.Exception (root.LayoutSubviews);
+			Assert.Null (exception);
 		}
 
 		[Fact]
@@ -1693,7 +1695,7 @@ Y
 
 			switch (width) {
 			case 1:
-				//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 0, 4), subview.Frame);
 				expected = @"
@@ -1704,7 +1706,7 @@ Y
 │";
 				break;
 			case 2:
-				//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 0, 4), subview.Frame);
 				expected = @"
 ┌┐
 ││
@@ -1715,7 +1717,7 @@ Y
 └┘";
 				break;
 			case 3:
-				//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 0, 4), subview.Frame);
 				expected = @"
 ┌─┐
 │ │
@@ -1727,7 +1729,7 @@ Y
 ";
 				break;
 			case 4:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 1, 4), subview.Frame);
 				expected = @"
 ┌──┐
 ││ │
@@ -1738,7 +1740,7 @@ Y
 └──┘";
 				break;
 			case 5:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 2, 4), subview.Frame);
 				expected = @"
 ┌───┐
 │┌┐ │
@@ -1749,7 +1751,7 @@ Y
 └───┘";
 				break;
 			case 6:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 3, 4), subview.Frame);
 				expected = @"
 ┌────┐
 │┌─┐ │
@@ -1760,7 +1762,7 @@ Y
 └────┘";
 				break;
 			case 7:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 4, 4), subview.Frame);
 				expected = @"
 ┌─────┐
 │┌──┐ │
@@ -1771,7 +1773,7 @@ Y
 └─────┘";
 				break;
 			case 8:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (0, 0, 5, 4), subview.Frame);
 				expected = @"
 ┌──────┐
 │┌───┐ │
@@ -1782,7 +1784,7 @@ Y
 └──────┘";
 				break;
 			case 9:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (1, 0, 5, 4), subview.Frame);
 				expected = @"
 ┌───────┐
 │ ┌───┐ │
@@ -1793,7 +1795,7 @@ Y
 └───────┘";
 				break;
 			case 10:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+				Assert.Equal (new Rect (1, 0, 6, 4), subview.Frame);
 				expected = @"
 ┌────────┐
 │ ┌────┐ │
@@ -1805,7 +1807,57 @@ Y
 				break;
 			}
 			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void PosConbine_DimCombine_View_With_SubViews ()
+		{
+			var clicked = false;
+			var top = Application.Top;
+			var win1 = new Window () { Id = "win1", Width = 20, Height = 10 };
+			var btn = new Button ("ok");
+			var win2 = new Window () { Id = "win2", Y = Pos.Bottom (btn) + 1, Width = 10, Height = 3 };
+			var view1 = new View () { Id = "view1", Width = Dim.Fill (), Height = 1, CanFocus = true };
+			view1.MouseClick += (sender, e) => clicked = true;
+			var view2 = new View () { Id = "view2", Width = Dim.Fill (1), Height = 1, CanFocus = true };
+
+			view1.Add (view2);
+			win2.Add (view1);
+			win1.Add (btn, win2);
+			top.Add (win1);
 
+			var rs = Application.Begin (top);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌──────────────────┐
+│[ ok ]            │
+│                  │
+│┌────────┐        │
+││        │        │
+│└────────┘        │
+│                  │
+│                  │
+│                  │
+└──────────────────┘", output);
+			Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
+			Assert.Equal (new Rect (0, 0, 6, 1), btn.Frame);
+			Assert.Equal (new Rect (0, 0, 20, 10), win1.Frame);
+			Assert.Equal (new Rect (0, 2, 10, 3), win2.Frame);
+			Assert.Equal (new Rect (0, 0, 8, 1), view1.Frame);
+			Assert.Equal (new Rect (0, 0, 7, 1), view2.Frame);
+			var foundView = View.FindDeepestView (top, 9, 4, out int rx, out int ry);
+			Assert.Equal (foundView, view1);
+			ReflectionTools.InvokePrivate (
+				typeof (Application),
+				"ProcessMouseEvent",
+				new MouseEvent () {
+					X = 9,
+					Y = 4,
+					Flags = MouseFlags.Button1Clicked
+				});
+			Assert.True (clicked);
+
+			Application.End (rs);
 		}
 	}
 }