Skip to content
Merged
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
41 changes: 41 additions & 0 deletions TUI.Test/BorderElementRenderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ktsu.TUI.Test;

using ktsu.TUI.Core.Elements.Layouts;
using ktsu.TUI.Core.Elements.Primitives;
using ktsu.TUI.Core.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -230,4 +231,44 @@ public void TitleWithALineBreakIsDrawnOnOneRow(string title)
Assert.IsFalse(provider.Writes.Any(w => w.Text.Contains('\r') || w.Text.Contains('\n')), "A write carried a line break");
Assert.AreEqual(0, provider.WritesOf(" ab cd ").Single().Position.Y);
}

/// <summary>
/// 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).
/// </summary>
[TestMethod]
public void TitleLongerThanTheContentIsDrawnInFullInsideAStackPanel()
{
// Arrange
StackPanel panel = new(Orientation.Horizontal) { Spacing = 1 };
panel.AddChild(new BorderElement { Title = "Single", Child = new TextElement { Text = "Content" } });
panel.AddChild(new BorderElement { Title = "Status", Child = new TextElement { Text = "OK" } });
panel.Position = Position.Origin;
panel.Dimensions = new Dimensions(80, 24);
RecordingConsoleProvider provider = new();

// Act
panel.ArrangeChildren();
panel.Render(provider);

// Assert
Assert.ContainsSingle(provider.WritesOf(" Single "));
Assert.ContainsSingle(provider.WritesOf(" Status "));
}

/// <summary>
/// The measure reserves room for the title only when a title is drawn: an untitled border, and a
/// <see cref="BorderStyle.None"/> border, are still exactly as wide as their content.
/// </summary>
[TestMethod]
public void MeasuredWidthMakesRoomForTheTitleOnlyWhenOneIsDrawn()
{
BorderElement titled = new() { Title = "Status", Child = new TextElement { Text = "OK" } };
BorderElement untitled = new() { Child = new TextElement { Text = "OK" } };
BorderElement borderless = new(BorderStyle.None) { Title = "Status", Child = new TextElement { Text = "OK" } };

Assert.AreEqual(" Status ".Length + 2, titled.CalculateRequiredDimensions().Width);
Assert.AreEqual("OK".Length + 2, untitled.CalculateRequiredDimensions().Width);
Assert.AreEqual("OK".Length + 2, borderless.CalculateRequiredDimensions().Width);
}
}
25 changes: 19 additions & 6 deletions TUI/Elements/Primitives/BorderElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,7 @@ protected override void OnRender(IConsoleProvider provider)
{
int maxTitleWidth = dimensions.Width - 4; // Leave space for border and padding

// A line break written to the terminal would move the rest of the title off the top
// border row and over the left edge, so each break becomes a space (ktsu-dev/TUI#151).
string singleLineTitle = Title.Replace("\r\n", " ", StringComparison.Ordinal).Replace('\r', ' ').Replace('\n', ' ');
string singleLineTitle = GetSingleLineTitle();
string displayTitle = singleLineTitle.Length > maxTitleWidth ? singleLineTitle[..maxTitleWidth] : singleLineTitle;
string titleWithPadding = $" {displayTitle} ";

Expand Down Expand Up @@ -186,9 +184,24 @@ protected override void OnArrangeChildren()

/// <inheritdoc />
// The border itself is reserved by the Padding(1) set in the constructor, which the base
// class adds to this result, so only the child's own size belongs here (ktsu-dev/TUI#132)
protected override Dimensions OnCalculateRequiredDimensionsForChildren() =>
Children.Count == 0 ? Dimensions.Empty : Children.First().CalculateRequiredDimensions();
// 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).
protected override Dimensions OnCalculateRequiredDimensionsForChildren()
{
Dimensions childDimensions = Children.Count == 0 ? Dimensions.Empty : Children.First().CalculateRequiredDimensions();
if (BorderStyle == BorderStyle.None || string.IsNullOrEmpty(Title))
{
return childDimensions;
}

return new Dimensions(Math.Max(childDimensions.Width, GetSingleLineTitle().Length + 2), childDimensions.Height);
}

// A line break written to the terminal would move the rest of the title off the top
// border row and over the left edge, so each break becomes a space (ktsu-dev/TUI#151).
private string GetSingleLineTitle() =>
Title.Replace("\r\n", " ", StringComparison.Ordinal).Replace('\r', ' ').Replace('\n', ' ');

private static BorderCharacters GetBorderCharacters(BorderStyle style)
{
Expand Down
Loading