mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-19 10:12:50 +08:00
155 lines
4.4 KiB
C#
155 lines
4.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Spectre.Console.Internal;
|
|
using Spectre.Console.Rendering;
|
|
|
|
namespace Spectre.Console
|
|
{
|
|
/// <summary>
|
|
/// A renderable grid.
|
|
/// </summary>
|
|
public sealed class Grid : JustInTimeRenderable, IExpandable, IAlignable
|
|
{
|
|
private readonly ListWithCallback<GridColumn> _columns;
|
|
private readonly ListWithCallback<GridRow> _rows;
|
|
|
|
private bool _expand;
|
|
private Justify? _alignment;
|
|
private bool _padRightCell;
|
|
|
|
/// <summary>
|
|
/// Gets the grid columns.
|
|
/// </summary>
|
|
public IReadOnlyList<GridColumn> Columns => _columns;
|
|
|
|
/// <summary>
|
|
/// Gets the grid rows.
|
|
/// </summary>
|
|
public IReadOnlyList<GridRow> Rows => _rows;
|
|
|
|
/// <inheritdoc/>
|
|
public bool Expand
|
|
{
|
|
get => _expand;
|
|
set => MarkAsDirty(() => _expand = value);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public Justify? Alignment
|
|
{
|
|
get => _alignment;
|
|
set => MarkAsDirty(() => _alignment = value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the width of the grid.
|
|
/// </summary>
|
|
public int? Width { get; set; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Grid"/> class.
|
|
/// </summary>
|
|
public Grid()
|
|
{
|
|
_expand = false;
|
|
_alignment = null;
|
|
_columns = new ListWithCallback<GridColumn>(() => MarkAsDirty());
|
|
_rows = new ListWithCallback<GridRow>(() => MarkAsDirty());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a column to the grid.
|
|
/// </summary>
|
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
|
public Grid AddColumn()
|
|
{
|
|
AddColumn(new GridColumn());
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a column to the grid.
|
|
/// </summary>
|
|
/// <param name="column">The column to add.</param>
|
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a new row to the grid.
|
|
/// </summary>
|
|
/// <param name="columns">The columns to add.</param>
|
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override bool HasDirtyChildren()
|
|
{
|
|
return _columns.Any(c => ((IHasDirtyState)c).IsDirty);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
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;
|
|
}
|
|
}
|
|
}
|