using System; using System.Collections.Generic; using System.Linq; using Spectre.Console.Rendering; namespace Spectre.Console { /// /// A renderable grid. /// public sealed class Grid : JustInTimeRenderable, IExpandable, IAlignable { private readonly ListWithCallback _columns; private readonly ListWithCallback _rows; private bool _expand; private Justify? _alignment; private bool _padRightCell; /// /// Gets the grid columns. /// public IReadOnlyList Columns => _columns; /// /// Gets the grid rows. /// public IReadOnlyList Rows => _rows; /// public bool Expand { get => _expand; set => MarkAsDirty(() => _expand = value); } /// public Justify? Alignment { get => _alignment; set => MarkAsDirty(() => _alignment = value); } /// /// Gets or sets the width of the grid. /// public int? Width { get; set; } /// /// Initializes a new instance of the class. /// public Grid() { _expand = false; _alignment = null; _columns = new ListWithCallback(() => MarkAsDirty()); _rows = new ListWithCallback(() => MarkAsDirty()); } /// /// Adds a column to the grid. /// /// The same instance so that multiple calls can be chained. public Grid AddColumn() { AddColumn(new GridColumn()); return this; } /// /// Adds a column to the grid. /// /// The column to add. /// The same instance so that multiple calls can be chained. public Grid AddColumn(GridColumn column) { if (column is null) { throw new ArgumentNullException(nameof(column)); } if (_rows.Count > 0) { throw new InvalidOperationException("Cannot add new columns to grid with existing rows."); } // Only pad the most right cell if we've explicitly set a padding. _padRightCell = column.HasExplicitPadding; _columns.Add(column); return this; } /// /// Adds a new row to the grid. /// /// The columns to add. /// The same instance so that multiple calls can be chained. public Grid AddRow(params IRenderable[] columns) { if (columns is null) { throw new ArgumentNullException(nameof(columns)); } if (columns.Length > _columns.Count) { throw new InvalidOperationException("The number of row columns are greater than the number of grid columns."); } _rows.Add(new GridRow(columns)); return this; } /// protected override bool HasDirtyChildren() { return _columns.Any(c => ((IHasDirtyState)c).IsDirty); } /// protected override IRenderable Build() { var table = new Table { Border = TableBorder.None, ShowHeaders = false, IsGrid = true, PadRightCell = _padRightCell, Width = Width, }; foreach (var column in _columns) { table.AddColumn(new TableColumn(string.Empty) { Width = column.Width, NoWrap = column.NoWrap, Padding = column.Padding ?? new Padding(0, 0, 2, 0), Alignment = column.Alignment, }); } foreach (var row in _rows) { table.AddRow(row); } return table; } } }