diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs
index f7be5dba3..85e69b59f 100644
--- a/Terminal.Gui/View/View.cs
+++ b/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 {
/// , respectively.
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)) {
diff --git a/UnitTests/View/Layout/DimTests.cs b/UnitTests/View/Layout/DimTests.cs
index 39ecf8b5f..07a8fb067 100644
--- a/UnitTests/View/Layout/DimTests.cs
+++ b/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 (super.LayoutSubviews);
+ }
}
}
diff --git a/UnitTests/View/Layout/LayoutTests.cs b/UnitTests/View/Layout/LayoutTests.cs
index 53554d85f..483d5940b 100644
--- a/UnitTests/View/Layout/LayoutTests.cs
+++ b/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 (() => 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);
}
}
}