diff --git a/Terminal.Gui/View/Layout/PosDim.cs b/Terminal.Gui/View/Layout/PosDim.cs
index 3e308d6fc..1971ee863 100644
--- a/Terminal.Gui/View/Layout/PosDim.cs
+++ b/Terminal.Gui/View/Layout/PosDim.cs
@@ -62,7 +62,7 @@ namespace Terminal.Gui;
///
///
/// -
-///
+///
///
/// Creates a object that tracks the Left (X) position of the specified .
///
@@ -450,7 +450,7 @@ public class Pos {
///
///
/// -
-///
+///
///
/// Creates a object that automatically sizes the view to fit all of the view's SubViews.
///
@@ -596,7 +596,7 @@ public class Dim {
/// The AutoSize object.
/// Specifies how will compute the dimension. The default is . NOT CURRENTLY SUPPORTED.
/// Specifies the minimum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.
- /// Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.
+ /// Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.
public static Dim Auto (DimAutoStyle style = DimAutoStyle.Subviews, Dim min = null, Dim max = null)
{
if (style == DimAutoStyle.Text) {
diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs
index decd732dd..a390d3c49 100644
--- a/Terminal.Gui/View/Layout/ViewLayout.cs
+++ b/Terminal.Gui/View/Layout/ViewLayout.cs
@@ -697,7 +697,7 @@ public partial class View {
// dimension: the current dimension (width or height)
// autosize: the size to use if autosize = true
// This mehod is recursive if d is Dim.DimCombine
- int GetNewDimension (Dim d, int location, int dimension, int autosize)
+ int GetNewDimension (Dim d, int location, int dimension, int autosize)
{
int newDimension;
switch (d) {
@@ -724,9 +724,9 @@ public partial class View {
case Dim.DimAuto auto:
var thickness = GetFramesThickness ();
- newDimension = GetNewDimension (auto._min, location, dimension, autosize);
+ //newDimension = GetNewDimension (auto._min, location, dimension, autosize);
if (width) {
- int furthestRight = Subviews.Count == 0 ? 0 : Subviews.Max (v => v.Frame.X + v.Frame.Width);
+ int furthestRight = Subviews.Count == 0 ? 0 : Subviews.Where (v => v.X is not Pos.PosAnchorEnd).Max (v => v.Frame.X + v.Frame.Width);
//Debug.Assert(superviewBounds.Width == (SuperView?.Bounds.Width ?? 0));
newDimension = int.Max (furthestRight + thickness.Left + thickness.Right, auto._min?.Anchor (superviewBounds.Width) ?? 0);
} else {
@@ -752,20 +752,11 @@ public partial class View {
// Determine new location
switch (pos) {
case Pos.PosCenter posCenter:
- if (dim == null) {
- // BUGBUG: In what situation is dim == null here? None that I can find.
- // dim == null is the same as dim == Dim.FIll (0)
- throw new ArgumentException ();
- newDimension = AutoSize ? autosizeDimension : superviewDimension;
- newLocation = posCenter.Anchor (superviewDimension - newDimension);
- } else {
- //newLocation = posCenter?.Anchor (superviewDimension) ?? 0;
- //newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
-
- newDimension = posCenter.Anchor (superviewDimension);
- newDimension = AutoSize && autosizeDimension > newDimension ? autosizeDimension : newDimension;
- newLocation = posCenter.Anchor (superviewDimension - newDimension);
- }
+ // For Center, the dimension is dependent on location, but we need to force getting the dimension first
+ // using a location of 0
+ newDimension = Math.Max (GetNewDimension (dim, 0, superviewDimension, autosizeDimension), 0);
+ newLocation = posCenter.Anchor (superviewDimension - newDimension);
+ newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
break;
case Pos.PosCombine combine:
@@ -786,7 +777,7 @@ public partial class View {
case Pos.PosFactor:
case Pos.PosFunc:
case Pos.PosView:
- default:
+ default:
newLocation = pos?.Anchor (superviewDimension) ?? 0;
newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
break;
@@ -1046,6 +1037,7 @@ public partial class View {
if (v.Width is Dim.DimAuto || v.Height is Dim.DimAuto) {
// If the view is auto-sized...
var f = v.Frame;
+ v._frame = new Rect (v.Frame.X, v.Frame.Y, 0, 0);
LayoutSubview (v, new Rect (GetBoundsOffset (), Bounds.Size));
if (v.Frame != f) {
// The subviews changed; do it again
diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs
index 48136db6e..19a9fde2c 100644
--- a/UICatalog/Scenarios/ComputedLayout.cs
+++ b/UICatalog/Scenarios/ComputedLayout.cs
@@ -163,6 +163,19 @@ namespace UICatalog.Scenarios {
};
Application.Top.Add (oddballButton);
+ oddballButton = new Button ("Center - 1") {
+ X = Pos.Center () - 1,
+ Y = Pos.Bottom (oddballButton)
+ };
+ Application.Top.Add (oddballButton);
+
+ // Won't be visible:
+ //oddballButton = new Button ("1 - Center") {
+ // X = 1 - Pos.Center (),
+ // Y = Pos.Bottom (oddballButton)
+ //};
+ //Application.Top.Add (oddballButton);
+
// This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
// The `- Pos.Percent(5)` is there so at least something is visible
oddballButton = new Button ("Center + Center - Percent(50)") {
diff --git a/UICatalog/Scenarios/DimAutoDemo.cs b/UICatalog/Scenarios/DimAutoDemo.cs
index 685447c72..b66cd6587 100644
--- a/UICatalog/Scenarios/DimAutoDemo.cs
+++ b/UICatalog/Scenarios/DimAutoDemo.cs
@@ -30,9 +30,9 @@ public class DimAutoDemo : Scenario {
var resetButton = new Button () {
Text = "P_ut Button Back",
- X = Pos.Center (),
Y = Pos.Bottom (label)
};
+ resetButton.X = Pos.AnchorEnd () - 19;
var movingButton = new Button () {
Text = "Press to make button move down.",
@@ -44,9 +44,6 @@ public class DimAutoDemo : Scenario {
movingButton.Y = movingButton.Frame.Y + 1;
};
- resetButton.Clicked += (s, e) => {
- movingButton.Y = Pos.Bottom (resetButton);
- };
var view = new FrameView () {
Title = "Type in the TextField to make View grow.",
@@ -58,6 +55,10 @@ public class DimAutoDemo : Scenario {
view.ValidatePosDim = true;
view.Add (textField, label, resetButton, movingButton);
+ resetButton.Clicked += (s, e) => {
+ movingButton.Y = Pos.Bottom (resetButton);
+ };
+
var dlgButton = new Button () {
Text = "Open Test _Dialog",
X = Pos.Right (view),
@@ -82,22 +83,31 @@ public class DimAutoDemo : Scenario {
//cancel.Clicked += (s, _) => Application.RequestStop (dlg);
//dlg.AddButton (cancel);
- var label = new Label ("This is a label (AutoSize = false; Dim.Auto(3/20). Press Esc to close.") {
+ var label = new Label ("This is a label (AutoSize = false; Dim.Auto(3/20). Press Esc to close. Even more text.") {
AutoSize = false,
- X = Pos.Center(),
+ X = Pos.Center (),
Y = 0,
Height = Dim.Auto (min: 3),
Width = Dim.Auto (min: 20),
ColorScheme = Colors.Menu
};
+ var text = new TextField () {
+ Text = "TextField... X = 1; Y = Pos.Bottom (label), Width = Dim.Fill (1); Height = Dim.Fill(1)",
+ TextFormatter = new TextFormatter () { WordWrap = true },
+ X = 20,
+ Y = Pos.Bottom (label),
+ Width = Dim.Fill (20),
+ Height = Dim.Fill (10)
+ };
var btn = new Button ("AnchorEnd") {
Y = Pos.AnchorEnd (1)
};
// TODO: We should really fix AnchorEnd to do this automatically.
btn.X = Pos.AnchorEnd () - (Pos.Right (btn) - Pos.Left (btn));
- dlg.Add (btn);
dlg.Add (label);
+ dlg.Add (text);
+ dlg.Add (btn);
Application.Run (dlg);
}
}
\ No newline at end of file
diff --git a/UnitTests/View/Layout/SetRelativeLayoutTests.cs b/UnitTests/View/Layout/SetRelativeLayoutTests.cs
index b389383d2..1f0ef550d 100644
--- a/UnitTests/View/Layout/SetRelativeLayoutTests.cs
+++ b/UnitTests/View/Layout/SetRelativeLayoutTests.cs
@@ -20,18 +20,18 @@ public class SetRelativeLayoutTests {
};
// Default layout style is Computed
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
view.BeginInit(); view.EndInit();
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
- view.SetRelativeLayout(new Rect(5, 5, 10, 10));
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ view.SetRelativeLayout (new Rect (5, 5, 10, 10));
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
@@ -50,18 +50,18 @@ public class SetRelativeLayoutTests {
};
// Default layout style is Computed
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
view.BeginInit (); view.EndInit ();
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
@@ -78,17 +78,17 @@ public class SetRelativeLayoutTests {
};
// Default layout style is Computed
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
view.BeginInit (); view.EndInit ();
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
@@ -118,17 +118,17 @@ public class SetRelativeLayoutTests {
};
// Default layout style is Computed
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
view.BeginInit (); view.EndInit ();
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
- Assert.Equal (view.LayoutStyle, LayoutStyle.Computed);
+ Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
@@ -139,6 +139,93 @@ public class SetRelativeLayoutTests {
Assert.Equal (expectedDim, view.Frame.Height);
}
+ [Fact]
+ public void Fill_Pos_Within_Bounds ()
+ {
+ var screen = new Rect (0, 0, 80, 25);
+ var view = new View () {
+ X = 1,
+ Y = 1,
+ Width = 5,
+ Height = 4
+ };
+
+ view.SetRelativeLayout (screen);
+ Assert.Equal (1, view.Frame.X);
+ Assert.Equal (1, view.Frame.Y);
+ Assert.Equal (5, view.Frame.Width);
+ Assert.Equal (4, view.Frame.Height);
+
+ view.Width = 80;
+ view.Height = 25;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (1, view.Frame.X);
+ Assert.Equal (1, view.Frame.Y);
+ Assert.Equal (80, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.Width = Dim.Fill ();
+ view.Height = Dim.Fill ();
+ view.SetRelativeLayout (screen);
+ Assert.Equal (1, view.Frame.X);
+ Assert.Equal (1, view.Frame.Y);
+ Assert.Equal (79, view.Frame.Width); // proof (80 - 1)
+ Assert.Equal (24, view.Frame.Height); // proof (25 - 1)
+
+ view.X = 79;
+ view.Width = Dim.Fill ();
+ view.Height = Dim.Fill ();
+ view.SetRelativeLayout (screen);
+ Assert.Equal (79, view.Frame.X);
+ Assert.Equal (1, view.Frame.Y);
+ Assert.Equal (1, view.Frame.Width); // proof (80 - 79)
+ Assert.Equal (24, view.Frame.Height);
+
+ view.X = 80;
+ view.Width = Dim.Fill ();
+ view.Height = Dim.Fill ();
+ view.SetRelativeLayout (screen);
+ Assert.Equal (80, view.Frame.X);
+ Assert.Equal (1, view.Frame.Y);
+ Assert.Equal (0, view.Frame.Width); // proof (80 - 80)
+ Assert.Equal (24, view.Frame.Height);
+ }
+
+ [Fact]
+ public void FIll_Pos_Outside_Bounds ()
+ {
+ var screen = new Rect (0, 0, 80, 25);
+ var view = new View () {
+ X = 90, // outside of screen +10
+ Y = -10, // outside of screen -10
+ Width = 15,
+ Height = 15
+ };
+
+ view.SetRelativeLayout (screen);
+ Assert.Equal (90, view.Frame.X);
+ Assert.Equal (-10, view.Frame.Y);
+ Assert.Equal (15, view.Frame.Width);
+ Assert.Equal (15, view.Frame.Height);
+
+ // prove Width=Height= same as screen size
+ view.Width = 80;
+ view.Height = 25;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (90, view.Frame.X);
+ Assert.Equal (-10, view.Frame.Y);
+ Assert.Equal (80, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.Width = Dim.Fill ();
+ view.Height = Dim.Fill ();
+ view.SetRelativeLayout (screen);
+ Assert.Equal (90, view.Frame.X);
+ Assert.Equal (-10, view.Frame.Y);
+ Assert.Equal (0, view.Frame.Width); // proof: 15x15 view is placed beyond right side of screen, so fill width is 0
+ Assert.Equal (35, view.Frame.Height); // proof: 15x15 view is placed beyond top of screen 10 rows, screen is 25 rows. so fill height is 25 + 10 = 35
+ }
+
[Fact]
public void PosCombine_PosCenter_Minus_Absolute ()
{
@@ -148,31 +235,114 @@ public class SetRelativeLayoutTests {
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
- X = Pos.Center () - 41, // ((80 / 2) - (5 / 2)) - 41 = (40 - 2 - 41) = -3
- Y = Pos.Center () - 13, // ((25 / 2) - (4 / 2)) - 13 = (12 - 2 - 13) = -3
- Width = 5,
- Height = 4
+ X = Pos.Center () - 41, // -2 off left edge of screen
+ Y = Pos.Center () - 13, // -1 off top edge of screen
+ Width = 1,
+ Height = 1
};
view.SetRelativeLayout (screen);
- Assert.Equal (-21, view.Frame.X); // BUGBUG: Should be -3
- Assert.Equal (-7, view.Frame.Y); // BUGBUG: Should be -3
+ Assert.Equal (-2, view.Frame.X); // proof: 1x1 view centered in 80x25 screen has x of 39, so -41 is -2
+ Assert.Equal (-1, view.Frame.Y); // proof: 1x1 view centered in 80x25 screen has y of 12, so -13 is -1
+
+ view.Width = 80;
+ view.Height = 25;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-41, view.Frame.X);
+ Assert.Equal (-13, view.Frame.Y);
+ Assert.Equal (80, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.Width = Dim.Fill ();
+ view.Height = Dim.Fill ();
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-41, view.Frame.X);
+ Assert.Equal (-13, view.Frame.Y);
+ Assert.Equal (121, view.Frame.Width); // 121 = screen.Width - (-Center - 41)
+ Assert.Equal (38, view.Frame.Height);
}
+ [Fact]
+ public void FIll_And_PosCenter ()
+ {
+ var screen = new Rect (0, 0, 80, 25);
+ var view = new View () {
+ X = Pos.Center (),
+ Y = Pos.Center (),
+ Width = Dim.Fill(),
+ Height = Dim.Fill()
+ };
+
+ view.SetRelativeLayout (screen);
+ Assert.Equal (0, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (80, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () + 1;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (1, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (79, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () + 79;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (79, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (1, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () + 80;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (80, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (0, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () - 1;
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-1, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (81, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () - 2; // Fill means all the way to right. So width will be 82. (dim gets calc'd before pos).
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-2, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (82, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () - 3; // Fill means all the way to right. So width will be 83. (dim gets calc'd before pos).
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-3, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (83, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ view.X = Pos.Center () - 41; // Fill means all the way to right. So width will be . (dim gets calc'd before pos).
+ view.SetRelativeLayout (screen);
+ Assert.Equal (-41, view.Frame.X);
+ Assert.Equal (0, view.Frame.Y);
+ Assert.Equal (121, view.Frame.Width);
+ Assert.Equal (25, view.Frame.Height);
+
+ }
[Fact]
public void PosCombine_PosCenter_Plus_Absolute ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
- X = Pos.Center () + 41, // ((80 / 2) - (5 / 2)) + 41 = (40 - 2 + 41) = 79
+ X = Pos.Center () + 41, // ((80 / 2) - (5 / 2)) + 41 = (40 - 3 + 41) = 78
Y = Pos.Center () + 13, // ((25 / 2) - (4 / 2)) + 13 = (12 - 2 + 13) = 23
Width = 5,
Height = 4
};
view.SetRelativeLayout (screen);
- Assert.Equal (79, view.Frame.X); // BUGBUG: Should be 79
- Assert.Equal (23, view.Frame.Y); // BUGBUG: Should be 23
+ Assert.Equal (78, view.Frame.X);
+ Assert.Equal (23, view.Frame.Y);
}
[Fact] [TestRespondersDisposed]
diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs
index 3d8e89c6f..c882daed2 100644
--- a/UnitTests/View/ViewTests.cs
+++ b/UnitTests/View/ViewTests.cs
@@ -547,13 +547,13 @@ namespace Terminal.Gui.ViewTests {
// This test has been moved to SetRlativeLayoutTests because it is testing
// SetRelativeLayout. In addition, the old test was bogus because it was testing the wrong thing (and
// because in v1 Pos.Center was broken in this regard!
- //view.X = Pos.Center () - 41;
- //view.Y = Pos.Center () - 13;
- //view.SetRelativeLayout (top.Bounds);
- //top.LayoutSubviews (); // BUGBUG: v2 - ??
- //view.BoundsToScreen (0, 0, out rcol, out rrow);
- //Assert.Equal (-41, rcol);
- //Assert.Equal (-13, rrow);
+ view.X = Pos.Center () - 41;
+ view.Y = Pos.Center () - 13;
+ view.SetRelativeLayout (top.Bounds);
+ top.LayoutSubviews (); // BUGBUG: v2 - ??
+ view.BoundsToScreen (0, 0, out rcol, out rrow);
+ Assert.Equal (-41, rcol);
+ Assert.Equal (-13, rrow);
Application.End (runState);
}