Patrik Svensson 7dccb310f3 Add support for bar charts
Closes #103
2020-12-23 10:05:08 +01:00

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;
}
}
}