diff --git a/TUI.Test/StackPanelTests.cs b/TUI.Test/StackPanelTests.cs index b6d436a..b08469a 100644 --- a/TUI.Test/StackPanelTests.cs +++ b/TUI.Test/StackPanelTests.cs @@ -510,11 +510,64 @@ public void StackPanelVerticalMeasuresWidthIndependentElementsAtTheirOwnSize() FixedSizeElementBase derived = new() { Dimensions = new Dimensions(4, 3) }; Assert.AreEqual(direct.Size, ((IUIElement)direct).CalculateRequiredDimensions(1)); - Assert.AreEqual(new Dimensions(3, 2), direct.Dimensions); + // The height is the measured one; the width spans the panel (ktsu-dev/TUI#158) + Assert.AreEqual(new Dimensions(10, 2), direct.Dimensions); Assert.AreEqual(new Position(0, 2), next.Position); Assert.AreEqual(derived.CalculateRequiredDimensions(), derived.CalculateRequiredDimensions(1)); } + /// + /// A vertical stack gives each child the panel's full width, so a centered or right-aligned + /// child has room to align in (ktsu-dev/TUI#158). + /// + /// The horizontal alignment under test. + /// The column the text should be written at. + [TestMethod] + [DataRow(HorizontalAlignment.Left, 0)] + [DataRow(HorizontalAlignment.Center, 19)] + [DataRow(HorizontalAlignment.Right, 38)] + public void StackPanelVerticalChildAlignsWithinThePanelWidth(HorizontalAlignment alignment, int expectedX) + { + // Arrange + TextElement text = new("hi") { HorizontalAlignment = alignment }; + StackPanel panel = [text]; + panel.Position = Position.Origin; + panel.Dimensions = new Dimensions(40, 10); + RecordingConsoleProvider provider = new(); + + // Act + panel.ArrangeChildren(); + panel.Render(provider); + + // Assert + Assert.AreEqual(new Dimensions(40, 1), text.Dimensions); + Assert.AreEqual(expectedX, provider.WritesOf("hi").Single().Position.X); + } + + /// + /// A horizontal stack gives each child the panel's full height and keeps the measured width on + /// the stacking axis, so the stacking offsets do not change (ktsu-dev/TUI#158). + /// + [TestMethod] + public void StackPanelHorizontalChildSpansThePanelHeight() + { + // Arrange + TextElement first = new("abc"); + TextElement second = new("de"); + StackPanel panel = new(Orientation.Horizontal) { Spacing = 1 }; + panel.AddChild(first); + panel.AddChild(second); + panel.Dimensions = new Dimensions(20, 5); + + // Act + panel.ArrangeChildren(); + + // Assert + Assert.AreEqual(new Dimensions(3, 5), first.Dimensions); + Assert.AreEqual(new Dimensions(2, 5), second.Dimensions); + Assert.AreEqual(new Position(4, 0), second.Position); + } + /// /// Tests that a container that does not use the available width, such as BorderElement, measures /// the same with or without one. diff --git a/TUI.Test/UIApplicationResizeTests.cs b/TUI.Test/UIApplicationResizeTests.cs index 3e23878..e76d27f 100644 --- a/TUI.Test/UIApplicationResizeTests.cs +++ b/TUI.Test/UIApplicationResizeTests.cs @@ -90,7 +90,7 @@ public void RenderAfterAResizeRelaysOutEveryContainerBeneathTheRoot() UIApplication app = new(provider) { RootElement = root }; app.Render(); Assert.AreEqual(LaunchSize.WithoutPadding(root.Padding), panel.Dimensions, "The panel should start out filling the terminal, inside the border"); - Assert.AreEqual(WideText.Length, leaf.Dimensions.Width, "The label should start out at its full width"); + Assert.AreEqual(panel.Dimensions.Width, leaf.Dimensions.Width, "The label should start out spanning the panel"); // Act provider.Dimensions = ResizedSize; diff --git a/TUI/Elements/Layouts/StackPanel.cs b/TUI/Elements/Layouts/StackPanel.cs index d1858f8..321c565 100644 --- a/TUI/Elements/Layouts/StackPanel.cs +++ b/TUI/Elements/Layouts/StackPanel.cs @@ -99,10 +99,11 @@ protected override void OnArrangeChildren() if (Orientation == Orientation.Vertical) { - // Vertical stacking + // Vertical stacking. The child spans the panel's width rather than its own measured + // width, so it has room to apply its own horizontal alignment (ktsu-dev/TUI#158). child.Position = contentPosition.Offset(0, currentOffset); child.Dimensions = new Dimensions( - Math.Min(childDimensions.Width, contentArea.Width), + contentArea.Width, Math.Min(childDimensions.Height, contentArea.Height - currentOffset) ); @@ -116,11 +117,11 @@ protected override void OnArrangeChildren() } else { - // Horizontal stacking + // Horizontal stacking. The child spans the panel's height, matching the vertical case. child.Position = contentPosition.Offset(currentOffset, 0); child.Dimensions = new Dimensions( Math.Min(childDimensions.Width, contentArea.Width - currentOffset), - Math.Min(childDimensions.Height, contentArea.Height) + contentArea.Height ); currentOffset += child.Dimensions.Width + Spacing;