diff --git a/Terminal.Gui/Core/PosDim.cs b/Terminal.Gui/Core/PosDim.cs
index 7ce92f9f15..1169fa0493 100644
--- a/Terminal.Gui/Core/PosDim.cs
+++ b/Terminal.Gui/Core/PosDim.cs
@@ -593,7 +593,7 @@ public static Dim Sized (int n)
internal class DimCombine : Dim {
internal Dim left, right;
- bool add;
+ internal bool add;
public DimCombine (bool add, Dim left, Dim right)
{
this.left = left;
diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 8548be267c..0fcd73b077 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -348,7 +348,7 @@ public override bool CanFocus {
}
if (base.CanFocus != value) {
base.CanFocus = value;
-
+
switch (value) {
case false when tabIndex > -1:
TabIndex = -1;
@@ -357,7 +357,7 @@ public override bool CanFocus {
SuperView.CanFocus = true;
break;
}
-
+
if (value && tabIndex == -1) {
TabIndex = SuperView != null ? SuperView.tabIndexes.IndexOf (this) : -1;
}
@@ -881,10 +881,10 @@ public void SetNeedsDisplay (Rect region)
NeedDisplay = new Rect (x, y, w, h);
}
container?.SetChildNeedsDisplay ();
-
+
if (subviews == null)
return;
-
+
foreach (var view in subviews)
if (view.Frame.IntersectsWith (region)) {
var childRegion = Rect.Intersect (view.Frame, region);
@@ -1132,7 +1132,7 @@ internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool c
// Computes the real row, col relative to the screen.
rrow = row + frame.Y;
rcol = col + frame.X;
-
+
var curContainer = container;
while (curContainer != null) {
rrow += curContainer.frame.Y;
@@ -1303,7 +1303,7 @@ public virtual void PositionCursor ()
}
bool hasFocus;
-
+
///
public override bool HasFocus => hasFocus;
@@ -1694,7 +1694,7 @@ public override bool ProcessKey (KeyEvent keyEvent)
if (args.Handled)
return true;
}
-
+
return Focused?.Enabled == true && Focused?.ProcessKey (keyEvent) == true;
}
@@ -1870,7 +1870,7 @@ public override bool ProcessHotKey (KeyEvent keyEvent)
return true;
if (subviews == null || subviews.Count == 0)
return false;
-
+
foreach (var view in subviews)
if (view.Enabled && view.ProcessHotKey (keyEvent))
return true;
@@ -1897,7 +1897,7 @@ public override bool ProcessColdKey (KeyEvent keyEvent)
return true;
if (subviews == null || subviews.Count == 0)
return false;
-
+
foreach (var view in subviews)
if (view.Enabled && view.ProcessColdKey (keyEvent))
return true;
@@ -2043,7 +2043,7 @@ public bool FocusPrev ()
FocusLast ();
return focused != null;
}
-
+
var focusedIdx = -1;
for (var i = tabIndexes.Count; i > 0;) {
i--;
@@ -2153,20 +2153,8 @@ internal void SetRelativeLayout (Rect hostFrame)
actX = x.Anchor (hostFrame.Width - actW);
} else {
actX = x?.Anchor (hostFrame.Width) ?? 0;
-
- switch (width) {
- case null:
- actW = AutoSize ? s.Width : hostFrame.Width;
- break;
- case Dim.DimFactor factor when !factor.IsFromRemaining ():
- actW = width.Anchor (hostFrame.Width);
- actW = AutoSize && s.Width > actW ? s.Width : actW;
- break;
- default:
- actW = Math.Max (width.Anchor (hostFrame.Width - actX), 0);
- actW = AutoSize && s.Width > actW ? s.Width : actW;
- break;
- }
+
+ actW = Math.Max (CalculateActualWidth (width, hostFrame, actX, s), 0);
}
if (y is Pos.PosCenter) {
@@ -2179,30 +2167,78 @@ internal void SetRelativeLayout (Rect hostFrame)
actY = y.Anchor (hostFrame.Height - actH);
} else {
actY = y?.Anchor (hostFrame.Height) ?? 0;
-
- switch (height) {
- case null:
- actH = AutoSize ? s.Height : hostFrame.Height;
- break;
- case Dim.DimFactor factor when !factor.IsFromRemaining ():
- actH = height.Anchor (hostFrame.Height);
- actH = AutoSize && s.Height > actH ? s.Height : actH;
- break;
- default:
- actH = Math.Max (height.Anchor (hostFrame.Height - actY), 0);
- actH = AutoSize && s.Height > actH ? s.Height : actH;
- break;
- }
+
+ actH = Math.Max (CalculateActualHight (height, hostFrame, actY, s), 0);
}
-
+
var r = new Rect (actX, actY, actW, actH);
if (Frame != r) {
- Frame = new Rect (actX, actY, actW, actH);
+ Frame = r;
if (!SetMinWidthHeight ())
TextFormatter.Size = GetBoundsTextFormatterSize ();
}
}
+ private int CalculateActualWidth (Dim width, Rect hostFrame, int actX, Size s)
+ {
+ int actW;
+ switch (width) {
+ case null:
+ actW = AutoSize ? s.Width : hostFrame.Width;
+ break;
+ case Dim.DimCombine combine:
+ int leftActW = CalculateActualWidth (combine.left, hostFrame, actX, s);
+ int rightActW = CalculateActualWidth (combine.right, hostFrame, actX, s);
+ if (combine.add) {
+ actW = leftActW + rightActW;
+ } else {
+ actW = leftActW - rightActW;
+ }
+ actW = AutoSize && s.Width > actW ? s.Width : actW;
+ break;
+ case Dim.DimFactor factor when !factor.IsFromRemaining ():
+ actW = width.Anchor (hostFrame.Width);
+ actW = AutoSize && s.Width > actW ? s.Width : actW;
+ break;
+ default:
+ actW = Math.Max (width.Anchor (hostFrame.Width - actX), 0);
+ actW = AutoSize && s.Width > actW ? s.Width : actW;
+ break;
+ }
+
+ return actW;
+ }
+
+ private int CalculateActualHight (Dim height, Rect hostFrame, int actY, Size s)
+ {
+ int actH;
+ switch (height) {
+ case null:
+ actH = AutoSize ? s.Height : hostFrame.Height;
+ break;
+ case Dim.DimCombine combine:
+ int leftActH = CalculateActualHight (combine.left, hostFrame, actY, s);
+ int rightActH = CalculateActualHight (combine.right, hostFrame, actY, s);
+ if (combine.add) {
+ actH = leftActH + rightActH;
+ } else {
+ actH = leftActH - rightActH;
+ }
+ actH = AutoSize && s.Height > actH ? s.Height : actH;
+ break;
+ case Dim.DimFactor factor when !factor.IsFromRemaining ():
+ actH = height.Anchor (hostFrame.Height);
+ actH = AutoSize && s.Height > actH ? s.Height : actH;
+ break;
+ default:
+ actH = Math.Max (height.Anchor (hostFrame.Height - actY), 0);
+ actH = AutoSize && s.Height > actH ? s.Height : actH;
+ break;
+ }
+
+ return actH;
+ }
+
// https://en.wikipedia.org/wiki/Topological_sorting
List TopologicalSort (IEnumerable nodes, ICollection<(View From, View To)> edges)
{
@@ -2326,7 +2362,6 @@ void CollectPos (Pos pos, View from, ref HashSet nNodes, ref HashSet<(View
{
switch (pos) {
case Pos.PosView pv:
- {
if (pv.Target != this) {
nEdges.Add ((pv.Target, from));
}
@@ -2334,23 +2369,19 @@ void CollectPos (Pos pos, View from, ref HashSet nNodes, ref HashSet<(View
CollectAll (v, ref nNodes, ref nEdges);
}
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);
}
break;
}
- }
}
void CollectDim (Dim dim, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
{
switch (dim) {
case Dim.DimView dv:
- {
if (dv.Target != this) {
nEdges.Add ((dv.Target, from));
}
@@ -2358,16 +2389,13 @@ void CollectDim (Dim dim, View from, ref HashSet nNodes, ref HashSet<(View
CollectAll (v, ref nNodes, ref nEdges);
}
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);
}
break;
}
- }
}
void CollectAll (View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
@@ -2759,14 +2787,14 @@ public class MouseEventArgs : EventArgs {
/// The for the event.
///
public MouseEvent MouseEvent { get; set; }
-
+
///
/// Indicates if the current mouse event has already been processed and the driver should stop notifying any other event subscriber.
/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
///
/// This property forwards to the property and is provided as a convenience and for
/// backwards compatibility
- public bool Handled {
+ public bool Handled {
get => MouseEvent.Handled;
set => MouseEvent.Handled = value;
}
@@ -2785,7 +2813,7 @@ public override bool OnMouseEnter (MouseEvent mouseEvent)
var args = new MouseEventArgs (mouseEvent);
MouseEnter?.Invoke (args);
-
+
return args.Handled || base.OnMouseEnter (mouseEvent);
}
@@ -2802,7 +2830,7 @@ public override bool OnMouseLeave (MouseEvent mouseEvent)
var args = new MouseEventArgs (mouseEvent);
MouseLeave?.Invoke (args);
-
+
return args.Handled || base.OnMouseLeave (mouseEvent);
}
@@ -2956,7 +2984,6 @@ bool CanSetHeight (int desiredHeight, out int resultHeight)
canSetHeight = !ForceValidatePosDim;
break;
case Dim.DimFactor factor:
- {
// Tries to get the SuperView height otherwise the view height.
var sh = SuperView != null ? SuperView.Frame.Height : h;
if (factor.IsFromRemaining ()) {
@@ -2965,7 +2992,6 @@ bool CanSetHeight (int desiredHeight, out int resultHeight)
h = Height.Anchor (sh);
canSetHeight = !ForceValidatePosDim;
break;
- }
default:
canSetHeight = true;
break;
diff --git a/UnitTests/DimTests.cs b/UnitTests/DimTests.cs
index 7148d8e68f..9bdd8d9b97 100644
--- a/UnitTests/DimTests.cs
+++ b/UnitTests/DimTests.cs
@@ -1246,5 +1246,42 @@ public void Function_Equal ()
dim2 = Dim.Function (f2);
Assert.NotEqual (dim1, dim2);
}
+
+ [Theory, AutoInitShutdown]
+ [InlineData (0, true)]
+ [InlineData (0, false)]
+ [InlineData (50, true)]
+ [InlineData (50, false)]
+
+ public void DimPercentPlusOne (int startingDistance, bool testHorizontal)
+ {
+ var container = new View {
+ Width = 100,
+ Height = 100,
+ };
+
+ var label = new Label {
+ X = testHorizontal ? startingDistance : 0,
+ Y = testHorizontal ? 0 : startingDistance,
+ Width = testHorizontal ? Dim.Percent (50) + 1 : 1,
+ Height = testHorizontal ? 1 : Dim.Percent (50) + 1,
+ };
+
+ container.Add (label);
+ Application.Top.Add (container);
+ Application.Top.LayoutSubviews ();
+
+
+ Assert.Equal (100, container.Frame.Width);
+ Assert.Equal (100, container.Frame.Height);
+
+ if (testHorizontal) {
+ Assert.Equal (51, label.Frame.Width);
+ Assert.Equal (1, label.Frame.Height);
+ } else {
+ Assert.Equal (1, label.Frame.Width);
+ Assert.Equal (51, label.Frame.Height);
+ }
+ }
}
}
diff --git a/UnitTests/PosTests.cs b/UnitTests/PosTests.cs
index 259bb106c5..ee10488624 100644
--- a/UnitTests/PosTests.cs
+++ b/UnitTests/PosTests.cs
@@ -1032,5 +1032,40 @@ public void Function_Equal ()
pos2 = Pos.Function (f2);
Assert.NotEqual (pos1, pos2);
}
+
+ [Theory, AutoInitShutdown]
+ [InlineData (true)]
+ [InlineData (false)]
+
+ public void PosPercentPlusOne (bool testHorizontal)
+ {
+ var container = new View {
+ Width = 100,
+ Height = 100,
+ };
+
+ var label = new Label {
+ X = testHorizontal ? Pos.Percent (50) + Pos.Percent (10) + 1 : 1,
+ Y = testHorizontal ? 1 : Pos.Percent (50) + Pos.Percent (10) + 1,
+ Width = 10,
+ Height = 10,
+ };
+
+ container.Add (label);
+ Application.Top.Add (container);
+ Application.Top.LayoutSubviews ();
+
+
+ Assert.Equal (100, container.Frame.Width);
+ Assert.Equal (100, container.Frame.Height);
+
+ if (testHorizontal) {
+ Assert.Equal (61, label.Frame.X);
+ Assert.Equal (1, label.Frame.Y);
+ } else {
+ Assert.Equal (1, label.Frame.X);
+ Assert.Equal (61, label.Frame.Y);
+ }
+ }
}
}