diff --git a/TUI.Test/BorderElementRenderTests.cs b/TUI.Test/BorderElementRenderTests.cs
index 3167c87..3f1f8cc 100644
--- a/TUI.Test/BorderElementRenderTests.cs
+++ b/TUI.Test/BorderElementRenderTests.cs
@@ -234,6 +234,32 @@ public void TitleWithALineBreakIsDrawnOnOneRow(string title)
Assert.AreEqual(0, provider.WritesOf(" ab cd ").Single().Position.Y);
}
+ ///
+ /// A border whose child is hidden measures as the bare border, so collapsing a section inside a
+ /// vertical StackPanel gives its rows back to the elements below (ktsu-dev/TUI#190).
+ ///
+ [TestMethod]
+ public void HiddenChildIsMeasuredAsAbsent()
+ {
+ // Arrange
+ BorderElement border = new() { Child = new TextElement("details line one\ndetails line two") { IsVisible = false } };
+ StackPanel panel = new(Orientation.Vertical);
+ panel.AddChild(border);
+ panel.AddChild(new TextElement("below"));
+ panel.Position = Position.Origin;
+ panel.Dimensions = new Dimensions(40, 20);
+ RecordingConsoleProvider provider = new();
+
+ // Act
+ panel.ArrangeChildren();
+ panel.Render(provider);
+
+ // Assert
+ Assert.AreEqual(new Dimensions(2, 2), border.CalculateRequiredDimensions());
+ Assert.AreEqual(new Dimensions(2, 2), border.CalculateRequiredDimensions(40));
+ Assert.AreEqual(2, provider.WritesOf("below").Single().Position.Y);
+ }
+
///
/// A border sized by a layout is measured wide enough for its title, so a title longer than
/// the content is drawn in full rather than cut short or dropped (ktsu-dev/TUI#157).
diff --git a/TUI.Test/UIContainerBaseMeasureTests.cs b/TUI.Test/UIContainerBaseMeasureTests.cs
index 70cb036..389d6ee 100644
--- a/TUI.Test/UIContainerBaseMeasureTests.cs
+++ b/TUI.Test/UIContainerBaseMeasureTests.cs
@@ -42,6 +42,20 @@ private static OriginContainer CreateContainer(Position position)
return container;
}
+ ///
+ /// A hidden child's extent is left out of the default measurement (ktsu-dev/TUI#190)
+ ///
+ [TestMethod]
+ public void DefaultMeasurementIgnoresHiddenChildren()
+ {
+ OriginContainer container = CreateContainer(Position.Origin);
+ container.AddChild(new TextElement { Text = "a much longer hidden line", IsVisible = false });
+ container.ArrangeChildren();
+
+ Assert.AreEqual(new Dimensions(5, 3), container.CalculateRequiredDimensions());
+ Assert.AreEqual(new Dimensions(5, 3), container.CalculateRequiredDimensions(80));
+ }
+
///
/// The required size is the content plus one padding, not the screen position plus two paddings
///
diff --git a/TUI/Elements/Primitives/BorderElement.cs b/TUI/Elements/Primitives/BorderElement.cs
index ca8a575..d956d1f 100644
--- a/TUI/Elements/Primitives/BorderElement.cs
+++ b/TUI/Elements/Primitives/BorderElement.cs
@@ -217,15 +217,17 @@ protected override void OnArrangeChildren()
// class adds to this result, so only the child's own size belongs here (ktsu-dev/TUI#132).
// A title is drawn as " title " between the corners, so the content area must be at least
// two wider than the title or a layout sizes the border too narrow to show it (ktsu-dev/TUI#157).
+ // A hidden child is measured as absent, so a collapsed section shrinks to the bare border
+ // (ktsu-dev/TUI#190).
protected override Dimensions OnCalculateRequiredDimensionsForChildren() =>
- WithRoomForTitle(Children.Count == 0 ? Dimensions.Empty : Children.First().CalculateRequiredDimensions());
+ WithRoomForTitle(GetVisibleChildren().FirstOrDefault()?.CalculateRequiredDimensions() ?? Dimensions.Empty);
///
// The base class has already taken the border off availableWidth, so the child is measured
// against the width it will be arranged into. Without this a word-wrapped child is measured
// unwrapped and given a single row (ktsu-dev/TUI#161).
protected override Dimensions OnCalculateRequiredDimensionsForChildren(int availableWidth) =>
- WithRoomForTitle(Children.Count == 0 ? Dimensions.Empty : Children.First().CalculateRequiredDimensions(availableWidth));
+ WithRoomForTitle(GetVisibleChildren().FirstOrDefault()?.CalculateRequiredDimensions(availableWidth) ?? Dimensions.Empty);
private Dimensions WithRoomForTitle(Dimensions childDimensions)
{
diff --git a/TUI/Elements/UIContainerBase.cs b/TUI/Elements/UIContainerBase.cs
index 15e5ba7..796690e 100644
--- a/TUI/Elements/UIContainerBase.cs
+++ b/TUI/Elements/UIContainerBase.cs
@@ -176,7 +176,8 @@ protected virtual Dimensions OnCalculateRequiredDimensionsForChildren()
int maxWidth = 0;
int maxHeight = 0;
- foreach (IUIElement child in _children)
+ // A hidden child is not drawn, so it takes no room either (ktsu-dev/TUI#190)
+ foreach (IUIElement child in GetVisibleChildren())
{
Dimensions childDimensions = child.CalculateRequiredDimensions();
int childRight = Math.Max(0, child.Position.X - origin.X + childDimensions.Width);