Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions TUI.Test/StackPanelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,43 @@ public void StackPanelVerticalDrawsEveryWrappedLineOfTextInsideABorder()
Assert.AreEqual(new Position(1, 2), Assert.ContainsSingle(provider.WritesOf("world foo")).Position);
}

/// <summary>
/// Tests that a horizontal panel does not ask for the height of a child it collapses for lack of
/// width, so a tall child that no longer fits leaves no blank rows and later siblings move up
/// (ktsu-dev/TUI#224).
/// </summary>
[TestMethod]
public void StackPanelHorizontalRequiredHeightIgnoresChildrenThatDoNotFit()
{
TextElement wide = new(new string('A', 20));
TextElement tall = new("l1\nl2\nl3\nl4\nl5");
StackPanel row = new(Orientation.Horizontal) { wide, tall };
TextElement footer = new("footer");
StackPanel root = [row, footer];
root.Dimensions = new Dimensions(20, 10);

root.ArrangeChildren();
row.ArrangeChildren();

Assert.AreEqual(new Dimensions(20, 1), row.CalculateRequiredDimensions(20));
Assert.AreEqual(Dimensions.Empty, tall.Dimensions);
Assert.AreEqual(new Dimensions(20, 1), row.Dimensions);
Assert.AreEqual(1, footer.Position.Y);
}

/// <summary>
/// Tests that a horizontal panel still measures every child when no width constrains it.
/// </summary>
[TestMethod]
public void StackPanelHorizontalUnconstrainedMeasureCountsEveryChild()
{
StackPanel row = new(Orientation.Horizontal) { Spacing = 1 };
row.Add(new TextElement(new string('A', 20)));
row.Add(new TextElement("l1\nl2\nl3\nl4\nl5"));

Assert.AreEqual(new Dimensions(23, 5), row.CalculateRequiredDimensions());
}

/// <summary>
/// Tests that a horizontal panel measures word-wrapped text against the width it has, so it
/// reports the wrapped height to a parent rather than one row (ktsu-dev/TUI#161).
Expand Down
13 changes: 12 additions & 1 deletion TUI/Elements/Layouts/StackPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,20 @@ private Dimensions CalculateRequiredDimensionsForChildren(int? availableWidth)
int maxHeight = 0;

IUIElement[] visibleChildren = [.. GetVisibleChildren()];
int totalSpacing = Math.Max(0, (visibleChildren.Length - 1) * Spacing);
int measuredChildren = 0;
int consumedWidth = 0;

foreach (IUIElement? child in visibleChildren)
{
// A horizontal child that starts where the width has run out is collapsed when arranged,
// so it adds neither width nor height, matching the arrange pass's break (ktsu-dev/TUI#224).
if (Orientation == Orientation.Horizontal && availableWidth is int limit && consumedWidth >= limit)
{
break;
}

measuredChildren++;

// A horizontal child gets the width its earlier siblings and the spacing between them
// leave, as it does when arranged (ktsu-dev/TUI#161).
Dimensions childDimensions = availableWidth switch
Expand All @@ -192,6 +201,8 @@ private Dimensions CalculateRequiredDimensionsForChildren(int? availableWidth)
}
}

int totalSpacing = Math.Max(0, (measuredChildren - 1) * Spacing);

return Orientation == Orientation.Vertical
? new Dimensions(maxWidth, totalHeight + totalSpacing)
: new Dimensions(totalWidth + totalSpacing, maxHeight);
Expand Down
Loading