namespace Spectre.Console; /// /// Represents a renderable used to align content. /// public sealed class Align : Renderable { private readonly IRenderable _renderable; /// /// Gets or sets the horizontal alignment. /// public HorizontalAlignment Horizontal { get; set; } = HorizontalAlignment.Left; /// /// Gets or sets the vertical alignment. /// public VerticalAlignment? Vertical { get; set; } /// /// Gets or sets the width. /// public int? Width { get; set; } /// /// Gets or sets the height. /// public int? Height { get; set; } /// /// Initializes a new instance of the class. /// /// The renderable to align. /// The horizontal alignment. /// The vertical alignment, or null if none. public Align(IRenderable renderable, HorizontalAlignment horizontal, VerticalAlignment? vertical = null) { _renderable = renderable ?? throw new ArgumentNullException(nameof(renderable)); Horizontal = horizontal; Vertical = vertical; } /// /// Initializes a new instance of the class that is left aligned. /// /// The to align. /// The vertical alignment, or null if none. /// A new object. public static Align Left(IRenderable renderable, VerticalAlignment? vertical = null) { return new Align(renderable, HorizontalAlignment.Left, vertical); } /// /// Initializes a new instance of the class that is center aligned. /// /// The to align. /// The vertical alignment, or null if none. /// A new object. public static Align Center(IRenderable renderable, VerticalAlignment? vertical = null) { return new Align(renderable, HorizontalAlignment.Center, vertical); } /// /// Initializes a new instance of the class that is right aligned. /// /// The to align. /// The vertical alignment, or null if none. /// A new object. public static Align Right(IRenderable renderable, VerticalAlignment? vertical = null) { return new Align(renderable, HorizontalAlignment.Right, vertical); } /// protected override IEnumerable Render(RenderOptions options, int maxWidth) { var rendered = _renderable.Render(options with { Height = null }, maxWidth); var lines = Segment.SplitLines(rendered); var width = Math.Min(Width ?? maxWidth, maxWidth); var height = Height ?? options.Height; var blank = new SegmentLine(new[] { new Segment(new string(' ', width)) }); // Align vertically if (Vertical != null && height != null) { switch (Vertical) { case VerticalAlignment.Top: { var diff = Height - lines.Count; for (var i = 0; i < diff; i++) { lines.Add(blank); } break; } case VerticalAlignment.Middle: { var top = (height - lines.Count) / 2; var bottom = height - top - lines.Count; for (var i = 0; i < top; i++) { lines.Insert(0, blank); } for (var i = 0; i < bottom; i++) { lines.Add(blank); } break; } case VerticalAlignment.Bottom: { var diff = Height - lines.Count; for (var i = 0; i < diff; i++) { lines.Insert(0, blank); } break; } default: throw new NotSupportedException("Unknown vertical alignment"); } } // Align horizontally foreach (var line in lines) { Aligner.AlignHorizontally(line, Horizontal, width); } return new SegmentLineEnumerator(lines); } }