mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 17:02:51 +08:00
Add row and column accessors for tables and grids
This commit is contained in:
parent
3e5e22d6c2
commit
e7f497050c
@ -140,6 +140,11 @@
|
|||||||
|
|
||||||
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible())
|
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible())
|
||||||
{
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(document.GetTitle()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
|
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
|
||||||
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)">
|
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)">
|
||||||
@if(document.ShowLink())
|
@if(document.ShowLink())
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Title: Calendar
|
Title: Calendar
|
||||||
Order: 4
|
Order: 4
|
||||||
RedirectFrom: calendar
|
RedirectFrom: calendar
|
||||||
---
|
---
|
||||||
@ -58,7 +58,7 @@ You can hide the calendar header.
|
|||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var calendar = new Calendar(2020,10);
|
var calendar = new Calendar(2020,10);
|
||||||
calendar.ShowHeader = false;
|
calendar.ShowHeader();
|
||||||
AnsiConsole.Render(calendar);
|
AnsiConsole.Render(calendar);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -91,33 +91,33 @@ table.Width(50);
|
|||||||
## Alignment
|
## Alignment
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
column.Alignment(Justify.Right);
|
table.Columns[0].Alignment(Justify.Right);
|
||||||
column.LeftAligned();
|
table.Columns[0].LeftAligned();
|
||||||
column.Centered();
|
table.Columns[0].Centered();
|
||||||
column.RightAligned();
|
table.Columns[0].RightAligned();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Padding
|
## Padding
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// Set left and right padding
|
// Set left and right padding
|
||||||
column.Padding(left: 3, right: 5);
|
table.Columns[0].Padding(left: 3, right: 5);
|
||||||
|
|
||||||
// Set padding individually.
|
// Set padding individually
|
||||||
column.PadLeft(3);
|
table.Columns[0].PadLeft(3);
|
||||||
column.PadRight(5);
|
table.Columns[0].PadRight(5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disable column wrapping
|
## Disable column wrapping
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// Disable column wrapping
|
// Disable column wrapping
|
||||||
column.NoWrap();
|
table.Columns[0].NoWrap();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Set column width
|
## Set column width
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// Set the column width (no fluent extension method for this yet)
|
// Set the column width
|
||||||
column.Width = 15;
|
table.Columns[0].Width(15);
|
||||||
```
|
```
|
@ -1,4 +1,3 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
grid.AddRow("Foo");
|
grid.AddRow("Foo");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
grid.RowCount.ShouldBe(1);
|
grid.Rows.Count.ShouldBe(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -98,7 +98,7 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
table.AddRow("Foo");
|
table.AddRow("Foo");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
table.RowCount.ShouldBe(1);
|
table.Rows.Count.ShouldBe(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -96,5 +96,37 @@ namespace Spectre.Console
|
|||||||
calendar.HeaderStyle = style ?? Style.Plain;
|
calendar.HeaderStyle = style ?? Style.Plain;
|
||||||
return calendar;
|
return calendar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the calendar header.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="calendar">The calendar.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Calendar ShowHeader(this Calendar calendar)
|
||||||
|
{
|
||||||
|
if (calendar is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(calendar));
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar.ShowHeader = true;
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hides the calendar header.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="calendar">The calendar.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Calendar HideHeader(this Calendar calendar)
|
||||||
|
{
|
||||||
|
if (calendar is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(calendar));
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar.ShowHeader = false;
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,5 +24,24 @@ namespace Spectre.Console
|
|||||||
obj.NoWrap = true;
|
obj.NoWrap = true;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the width of the column.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">An object implementing <see cref="IColumn"/>.</typeparam>
|
||||||
|
/// <param name="obj">The column.</param>
|
||||||
|
/// <param name="width">The column width.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static T Width<T>(this T obj, int? width)
|
||||||
|
where T : class, IColumn
|
||||||
|
{
|
||||||
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Width = width;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(grid));
|
throw new ArgumentNullException(nameof(grid));
|
||||||
}
|
}
|
||||||
|
|
||||||
var columns = new IRenderable[grid.ColumnCount];
|
var columns = new IRenderable[grid.Columns.Count];
|
||||||
Enumerable.Range(0, grid.ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
Enumerable.Range(0, grid.Columns.Count).ForEach(index => columns[index] = Text.Empty);
|
||||||
grid.AddRow(columns);
|
grid.AddRow(columns);
|
||||||
|
|
||||||
return grid;
|
return grid;
|
||||||
|
@ -22,7 +22,7 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(obj, new Padding(left, obj.Padding.Top, obj.Padding.Right, obj.Padding.Bottom));
|
return Padding(obj, new Padding(left, obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,7 +40,7 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(obj, new Padding(obj.Padding.Left, top, obj.Padding.Right, obj.Padding.Bottom));
|
return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), top, obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -58,7 +58,7 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, right, obj.Padding.Bottom));
|
return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), right, obj.Padding.GetBottomSafe()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -76,7 +76,7 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, obj.Padding.Right, bottom));
|
return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
48
src/Spectre.Console/Extensions/PaddingExtensions.cs
Normal file
48
src/Spectre.Console/Extensions/PaddingExtensions.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains extension methods for <see cref="Padding"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class PaddingExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the left padding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="padding">The padding.</param>
|
||||||
|
/// <returns>The left padding or zero if <c>padding</c> is null.</returns>
|
||||||
|
public static int GetLeftSafe(this Padding? padding)
|
||||||
|
{
|
||||||
|
return padding?.Left ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the right padding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="padding">The padding.</param>
|
||||||
|
/// <returns>The right padding or zero if <c>padding</c> is null.</returns>
|
||||||
|
public static int GetRightSafe(this Padding? padding)
|
||||||
|
{
|
||||||
|
return padding?.Right ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the top padding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="padding">The padding.</param>
|
||||||
|
/// <returns>The top padding or zero if <c>padding</c> is null.</returns>
|
||||||
|
public static int GetTopSafe(this Padding? padding)
|
||||||
|
{
|
||||||
|
return padding?.Top ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bottom padding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="padding">The padding.</param>
|
||||||
|
/// <returns>The bottom padding or zero if <c>padding</c> is null.</returns>
|
||||||
|
public static int GetBottomSafe(this Padding? padding)
|
||||||
|
{
|
||||||
|
return padding?.Bottom ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,22 @@ namespace Spectre.Console
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a row to the table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table to add the row to.</param>
|
||||||
|
/// <param name="columns">The row columns to add.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Table AddRow(this Table table, params IRenderable[] columns)
|
||||||
|
{
|
||||||
|
if (table is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(table));
|
||||||
|
}
|
||||||
|
|
||||||
|
return table.AddRow(columns);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an empty row to the table.
|
/// Adds an empty row to the table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -48,8 +64,8 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(table));
|
throw new ArgumentNullException(nameof(table));
|
||||||
}
|
}
|
||||||
|
|
||||||
var columns = new IRenderable[table.ColumnCount];
|
var columns = new IRenderable[table.Columns.Count];
|
||||||
Enumerable.Range(0, table.ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
Enumerable.Range(0, table.Columns.Count).ForEach(index => columns[index] = Text.Empty);
|
||||||
table.AddRow(columns);
|
table.AddRow(columns);
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,10 @@ namespace Spectre.Console
|
|||||||
/// or not wrapping should be prevented.
|
/// or not wrapping should be prevented.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool NoWrap { get; set; }
|
bool NoWrap { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of the column.
|
||||||
|
/// </summary>
|
||||||
|
int? Width { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@ namespace Spectre.Console
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the padding.
|
/// Gets or sets the padding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Padding Padding { get; set; }
|
public Padding? Padding { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Spectre.Console.Internal.Collections
|
namespace Spectre.Console.Internal.Collections
|
||||||
{
|
{
|
||||||
internal sealed class ListWithCallback<T> : IList<T>
|
internal sealed class ListWithCallback<T> : IList<T>, IReadOnlyList<T>
|
||||||
{
|
{
|
||||||
private readonly List<T> _list;
|
private readonly List<T> _list;
|
||||||
private readonly Action _callback;
|
private readonly Action _callback;
|
||||||
|
@ -6,6 +6,21 @@ namespace Spectre.Console.Internal
|
|||||||
{
|
{
|
||||||
internal static class EnumerableExtensions
|
internal static class EnumerableExtensions
|
||||||
{
|
{
|
||||||
|
public static int GetCount<T>(this IEnumerable<T> source)
|
||||||
|
{
|
||||||
|
if (source is IList<T> list)
|
||||||
|
{
|
||||||
|
return list.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source is T[] array)
|
||||||
|
{
|
||||||
|
return array.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.Count();
|
||||||
|
}
|
||||||
|
|
||||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||||
{
|
{
|
||||||
foreach (var item in source)
|
foreach (var item in source)
|
||||||
|
@ -63,10 +63,10 @@ namespace Spectre.Console.Rendering
|
|||||||
{
|
{
|
||||||
var padding = columns[columnIndex].Padding;
|
var padding = columns[columnIndex].Padding;
|
||||||
|
|
||||||
if (padding.Left > 0)
|
if (padding != null && padding.Value.Left > 0)
|
||||||
{
|
{
|
||||||
// Left padding
|
// Left padding
|
||||||
builder.Append(" ".Repeat(padding.Left));
|
builder.Append(" ".Repeat(padding.Value.Left));
|
||||||
}
|
}
|
||||||
|
|
||||||
var justification = columns[columnIndex].Alignment;
|
var justification = columns[columnIndex].Alignment;
|
||||||
@ -96,9 +96,9 @@ namespace Spectre.Console.Rendering
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Right padding
|
// Right padding
|
||||||
if (padding.Right > 0)
|
if (padding != null && padding.Value.Right > 0)
|
||||||
{
|
{
|
||||||
builder.Append(" ".Repeat(padding.Right));
|
builder.Append(" ".Repeat(padding.Value.Right));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastColumn)
|
if (!lastColumn)
|
||||||
|
13
src/Spectre.Console/Rendering/IHasDirtyState.cs
Normal file
13
src/Spectre.Console/Rendering/IHasDirtyState.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Spectre.Console.Rendering
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents something that can be dirty.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasDirtyState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the object is dirty.
|
||||||
|
/// </summary>
|
||||||
|
bool IsDirty { get; }
|
||||||
|
}
|
||||||
|
}
|
79
src/Spectre.Console/Rendering/JustInTimeRenderable.cs
Normal file
79
src/Spectre.Console/Rendering/JustInTimeRenderable.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Spectre.Console.Rendering
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents something renderable that's reconstructed
|
||||||
|
/// when it's state change in any way.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class JustInTimeRenderable : Renderable
|
||||||
|
{
|
||||||
|
private bool _dirty;
|
||||||
|
private IRenderable? _rendered;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected sealed override Measurement Measure(RenderContext context, int maxWidth)
|
||||||
|
{
|
||||||
|
return GetInner().Measure(context, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected sealed override IEnumerable<Segment> Render(RenderContext context, int width)
|
||||||
|
{
|
||||||
|
return GetInner().Render(context, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the inner renderable.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new inner renderable.</returns>
|
||||||
|
protected abstract IRenderable Build();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if there are any children that has changed.
|
||||||
|
/// If so, the underlying renderable needs rebuilding.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c> if the object needs rebuilding, otherwise <c>false</c>.</returns>
|
||||||
|
protected virtual bool HasDirtyChildren()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks this instance as dirty.
|
||||||
|
/// </summary>
|
||||||
|
protected void MarkAsDirty()
|
||||||
|
{
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks this instance as dirty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">
|
||||||
|
/// The action to execute before marking the instance as dirty.
|
||||||
|
/// </param>
|
||||||
|
protected void MarkAsDirty(Action action)
|
||||||
|
{
|
||||||
|
if (action is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
action();
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRenderable GetInner()
|
||||||
|
{
|
||||||
|
if (_dirty || HasDirtyChildren() || _rendered == null)
|
||||||
|
{
|
||||||
|
_rendered = Build();
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _rendered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -55,7 +55,7 @@ namespace Spectre.Console
|
|||||||
foreach (var (columnIndex, _, lastColumn, columnWidth) in widths.Enumerate())
|
foreach (var (columnIndex, _, lastColumn, columnWidth) in widths.Enumerate())
|
||||||
{
|
{
|
||||||
var padding = columns[columnIndex].Padding;
|
var padding = columns[columnIndex].Padding;
|
||||||
var centerWidth = padding.Left + columnWidth + padding.Right;
|
var centerWidth = padding.GetLeftSafe() + columnWidth + padding.GetRightSafe();
|
||||||
builder.Append(center.Repeat(centerWidth));
|
builder.Append(center.Repeat(centerWidth));
|
||||||
|
|
||||||
if (!lastColumn)
|
if (!lastColumn)
|
||||||
|
@ -11,7 +11,7 @@ namespace Spectre.Console
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A renderable calendar.
|
/// A renderable calendar.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Calendar : Renderable, IHasCulture, IHasTableBorder, IAlignable
|
public sealed class Calendar : JustInTimeRenderable, IHasCulture, IHasTableBorder, IAlignable
|
||||||
{
|
{
|
||||||
private const int NumberOfWeekDays = 7;
|
private const int NumberOfWeekDays = 7;
|
||||||
private const int ExpectedRowCount = 6;
|
private const int ExpectedRowCount = 6;
|
||||||
@ -21,11 +21,9 @@ namespace Spectre.Console
|
|||||||
private int _year;
|
private int _year;
|
||||||
private int _month;
|
private int _month;
|
||||||
private int _day;
|
private int _day;
|
||||||
private IRenderable? _table;
|
|
||||||
private TableBorder _border;
|
private TableBorder _border;
|
||||||
private bool _useSafeBorder;
|
private bool _useSafeBorder;
|
||||||
private Style? _borderStyle;
|
private Style? _borderStyle;
|
||||||
private bool _dirty;
|
|
||||||
private CultureInfo _culture;
|
private CultureInfo _culture;
|
||||||
private Style _highlightStyle;
|
private Style _highlightStyle;
|
||||||
private bool _showHeader;
|
private bool _showHeader;
|
||||||
@ -158,43 +156,17 @@ namespace Spectre.Console
|
|||||||
_year = year;
|
_year = year;
|
||||||
_month = month;
|
_month = month;
|
||||||
_day = day;
|
_day = day;
|
||||||
_table = null;
|
|
||||||
_border = TableBorder.Square;
|
_border = TableBorder.Square;
|
||||||
_useSafeBorder = true;
|
_useSafeBorder = true;
|
||||||
_borderStyle = null;
|
_borderStyle = null;
|
||||||
_dirty = true;
|
|
||||||
_culture = CultureInfo.InvariantCulture;
|
_culture = CultureInfo.InvariantCulture;
|
||||||
_highlightStyle = new Style(foreground: Color.Blue);
|
_highlightStyle = new Style(foreground: Color.Blue);
|
||||||
_showHeader = true;
|
_showHeader = true;
|
||||||
_calendarEvents = new ListWithCallback<CalendarEvent>(() => _dirty = true);
|
_calendarEvents = new ListWithCallback<CalendarEvent>(() => MarkAsDirty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
protected override IRenderable Build()
|
||||||
{
|
|
||||||
var table = GetTable();
|
|
||||||
return table.Measure(context, maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
|
||||||
{
|
|
||||||
return GetTable().Render(context, maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRenderable GetTable()
|
|
||||||
{
|
|
||||||
// Table needs to be built?
|
|
||||||
if (_dirty || _table == null)
|
|
||||||
{
|
|
||||||
_table = BuildTable();
|
|
||||||
_dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _table;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRenderable BuildTable()
|
|
||||||
{
|
{
|
||||||
var culture = Culture ?? CultureInfo.InvariantCulture;
|
var culture = Culture ?? CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
@ -264,9 +236,9 @@ namespace Spectre.Console
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We want all calendars to have the same height.
|
// We want all calendars to have the same height.
|
||||||
if (table.RowCount < ExpectedRowCount)
|
if (table.Rows.Count < ExpectedRowCount)
|
||||||
{
|
{
|
||||||
var diff = Math.Max(0, ExpectedRowCount - table.RowCount);
|
var diff = Math.Max(0, ExpectedRowCount - table.Rows.Count);
|
||||||
for (var i = 0; i < diff; i++)
|
for (var i = 0; i < diff; i++)
|
||||||
{
|
{
|
||||||
table.AddEmptyRow();
|
table.AddEmptyRow();
|
||||||
@ -276,12 +248,6 @@ namespace Spectre.Console
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MarkAsDirty(Action action)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DayOfWeek[] GetWeekdays()
|
private DayOfWeek[] GetWeekdays()
|
||||||
{
|
{
|
||||||
var culture = Culture ?? CultureInfo.InvariantCulture;
|
var culture = Culture ?? CultureInfo.InvariantCulture;
|
||||||
|
@ -13,7 +13,7 @@ namespace Spectre.Console
|
|||||||
private readonly List<IRenderable> _items;
|
private readonly List<IRenderable> _items;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Padding Padding { get; set; } = new Padding(0, 0, 1, 0);
|
public Padding? Padding { get; set; } = new Padding(0, 0, 1, 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not the columns should
|
/// Gets or sets a value indicating whether or not the columns should
|
||||||
@ -62,7 +62,7 @@ namespace Spectre.Console
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
var maxPadding = Math.Max(Padding.Left, Padding.Right);
|
var maxPadding = Math.Max(Padding.GetLeftSafe(), Padding.GetRightSafe());
|
||||||
|
|
||||||
var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
|
var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
|
||||||
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
|
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
|
||||||
@ -90,7 +90,7 @@ namespace Spectre.Console
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
var maxPadding = Math.Max(Padding.Left, Padding.Right);
|
var maxPadding = Math.Max(Padding.GetLeftSafe(), Padding.GetRightSafe());
|
||||||
|
|
||||||
var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
|
var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
|
||||||
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
|
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Spectre.Console.Internal.Collections;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
@ -7,32 +9,37 @@ namespace Spectre.Console
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A renderable grid.
|
/// A renderable grid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Grid : Renderable, IExpandable, IAlignable
|
public sealed class Grid : JustInTimeRenderable, IExpandable, IAlignable
|
||||||
{
|
{
|
||||||
private readonly Table _table;
|
private readonly ListWithCallback<GridColumn> _columns;
|
||||||
|
private readonly ListWithCallback<GridRow> _rows;
|
||||||
|
|
||||||
|
private bool _expand;
|
||||||
|
private Justify? _alignment;
|
||||||
|
private bool _padRightCell;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of columns in the table.
|
/// Gets the grid columns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ColumnCount => _table.ColumnCount;
|
public IReadOnlyList<GridColumn> Columns => _columns;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of rows in the table.
|
/// Gets the grid rows.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int RowCount => _table.RowCount;
|
public IReadOnlyList<GridRow> Rows => _rows;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool Expand
|
public bool Expand
|
||||||
{
|
{
|
||||||
get => _table.Expand;
|
get => _expand;
|
||||||
set => _table.Expand = value;
|
set => MarkAsDirty(() => _expand = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Justify? Alignment
|
public Justify? Alignment
|
||||||
{
|
{
|
||||||
get => _table.Alignment;
|
get => _alignment;
|
||||||
set => _table.Alignment = value;
|
set => MarkAsDirty(() => _alignment = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,25 +47,10 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Grid()
|
public Grid()
|
||||||
{
|
{
|
||||||
_table = new Table
|
_expand = false;
|
||||||
{
|
_alignment = null;
|
||||||
Border = TableBorder.None,
|
_columns = new ListWithCallback<GridColumn>(() => MarkAsDirty());
|
||||||
ShowHeaders = false,
|
_rows = new ListWithCallback<GridRow>(() => MarkAsDirty());
|
||||||
IsGrid = true,
|
|
||||||
PadRightCell = false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
|
||||||
{
|
|
||||||
return ((IRenderable)_table).Measure(context, maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override IEnumerable<Segment> Render(RenderContext context, int width)
|
|
||||||
{
|
|
||||||
return ((IRenderable)_table).Render(context, width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -83,21 +75,15 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(column));
|
throw new ArgumentNullException(nameof(column));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_table.RowCount > 0)
|
if (_rows.Count > 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Cannot add new columns to grid with existing rows.");
|
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.
|
// Only pad the most right cell if we've explicitly set a padding.
|
||||||
_table.PadRightCell = column.HasExplicitPadding;
|
_padRightCell = column.HasExplicitPadding;
|
||||||
|
|
||||||
_table.AddColumn(new TableColumn(string.Empty)
|
_columns.Add(column);
|
||||||
{
|
|
||||||
Width = column.Width,
|
|
||||||
NoWrap = column.NoWrap,
|
|
||||||
Padding = column.Padding,
|
|
||||||
Alignment = column.Alignment,
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -114,13 +100,49 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(columns));
|
throw new ArgumentNullException(nameof(columns));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columns.Length > _table.ColumnCount)
|
if (columns.Length > _columns.Count)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("The number of row columns are greater than the number of grid columns.");
|
throw new InvalidOperationException("The number of row columns are greater than the number of grid columns.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_table.AddRow(columns);
|
_rows.Add(new GridRow(columns));
|
||||||
return this;
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a grid column.
|
/// Represents a grid column.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class GridColumn : IColumn
|
public sealed class GridColumn : IColumn, IHasDirtyState
|
||||||
{
|
{
|
||||||
private Padding _padding;
|
private bool _isDirty;
|
||||||
|
private int? _width;
|
||||||
|
private bool _noWrap;
|
||||||
|
private Padding? _padding;
|
||||||
|
private Justify? _alignment;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
bool IHasDirtyState.IsDirty => _isDirty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the width of the column.
|
/// Gets or sets the width of the column.
|
||||||
/// If <c>null</c>, the column will adapt to it's contents.
|
/// If <c>null</c>, the column will adapt to it's contents.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? Width { get; set; }
|
public int? Width
|
||||||
|
{
|
||||||
|
get => _width;
|
||||||
|
set => MarkAsDirty(() => _width = value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether wrapping of
|
/// Gets or sets a value indicating whether wrapping of
|
||||||
/// text within the column should be prevented.
|
/// text within the column should be prevented.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool NoWrap { get; set; }
|
public bool NoWrap
|
||||||
|
{
|
||||||
|
get => _noWrap;
|
||||||
|
set => MarkAsDirty(() => _noWrap = value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the padding of the column.
|
/// Gets or sets the padding of the column.
|
||||||
/// Vertical padding (top and bottom) is ignored.
|
/// Vertical padding (top and bottom) is ignored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Padding Padding
|
public Padding? Padding
|
||||||
{
|
{
|
||||||
get => _padding;
|
get => _padding;
|
||||||
set
|
set => MarkAsDirty(() => _padding = value);
|
||||||
{
|
|
||||||
HasExplicitPadding = true;
|
|
||||||
_padding = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the alignment of the column.
|
/// Gets or sets the alignment of the column.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Justify? Alignment { get; set; }
|
public Justify? Alignment
|
||||||
|
{
|
||||||
|
get => _alignment;
|
||||||
|
set => MarkAsDirty(() => _alignment = value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the user
|
/// Gets a value indicating whether the user
|
||||||
/// has set an explicit padding for this column.
|
/// has set an explicit padding for this column.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool HasExplicitPadding { get; private set; }
|
internal bool HasExplicitPadding => Padding != null;
|
||||||
|
|
||||||
/// <summary>
|
private void MarkAsDirty(Action action)
|
||||||
/// Initializes a new instance of the <see cref="GridColumn"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public GridColumn()
|
|
||||||
{
|
{
|
||||||
_padding = new Padding(0, 0, 2, 0);
|
action();
|
||||||
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
src/Spectre.Console/Widgets/GridRow.cs
Normal file
56
src/Spectre.Console/Widgets/GridRow.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a grid row.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GridRow : IEnumerable<IRenderable>
|
||||||
|
{
|
||||||
|
private readonly List<IRenderable> _items;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a row item at the specified grid column index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The grid column index.</param>
|
||||||
|
/// <returns>The row item at the specified grid column index.</returns>
|
||||||
|
public IRenderable this[int index]
|
||||||
|
{
|
||||||
|
get => _items[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GridRow"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The row items.</param>
|
||||||
|
public GridRow(IEnumerable<IRenderable> items)
|
||||||
|
{
|
||||||
|
_items = new List<IRenderable>(items ?? Array.Empty<IRenderable>());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Add(IRenderable item)
|
||||||
|
{
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
_items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerator<IRenderable> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _items.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ namespace Spectre.Console
|
|||||||
private readonly IRenderable _child;
|
private readonly IRenderable _child;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Padding Padding { get; set; } = new Padding(1, 1, 1, 1);
|
public Padding? Padding { get; set; } = new Padding(1, 1, 1, 1);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not the padding should
|
/// Gets or sets a value indicating whether or not the padding should
|
||||||
@ -35,7 +35,7 @@ namespace Spectre.Console
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
var paddingWidth = Padding.GetWidth();
|
var paddingWidth = Padding?.GetWidth() ?? 0;
|
||||||
var measurement = _child.Measure(context, maxWidth - paddingWidth);
|
var measurement = _child.Measure(context, maxWidth - paddingWidth);
|
||||||
|
|
||||||
return new Measurement(
|
return new Measurement(
|
||||||
@ -46,7 +46,7 @@ namespace Spectre.Console
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
var paddingWidth = Padding.GetWidth();
|
var paddingWidth = Padding?.GetWidth() ?? 0;
|
||||||
var childWidth = maxWidth - paddingWidth;
|
var childWidth = maxWidth - paddingWidth;
|
||||||
|
|
||||||
if (!Expand)
|
if (!Expand)
|
||||||
@ -59,7 +59,7 @@ namespace Spectre.Console
|
|||||||
var result = new List<Segment>();
|
var result = new List<Segment>();
|
||||||
|
|
||||||
// Top padding
|
// Top padding
|
||||||
for (var i = 0; i < Padding.Top; i++)
|
for (var i = 0; i < Padding.GetTopSafe(); i++)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', width)));
|
result.Add(new Segment(new string(' ', width)));
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
@ -69,22 +69,22 @@ namespace Spectre.Console
|
|||||||
foreach (var (_, _, _, line) in Segment.SplitLines(context, child).Enumerate())
|
foreach (var (_, _, _, line) in Segment.SplitLines(context, child).Enumerate())
|
||||||
{
|
{
|
||||||
// Left padding
|
// Left padding
|
||||||
if (Padding.Left != 0)
|
if (Padding.GetLeftSafe() != 0)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', Padding.Left)));
|
result.Add(new Segment(new string(' ', Padding.GetLeftSafe())));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.AddRange(line);
|
result.AddRange(line);
|
||||||
|
|
||||||
// Right padding
|
// Right padding
|
||||||
if (Padding.Right != 0)
|
if (Padding.GetRightSafe() != 0)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', Padding.Right)));
|
result.Add(new Segment(new string(' ', Padding.GetRightSafe())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Missing space on right side?
|
// Missing space on right side?
|
||||||
var lineWidth = line.CellCount(context);
|
var lineWidth = line.CellCount(context);
|
||||||
var diff = width - lineWidth - Padding.Left - Padding.Right;
|
var diff = width - lineWidth - Padding.GetLeftSafe() - Padding.GetRightSafe();
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', diff)));
|
result.Add(new Segment(new string(' ', diff)));
|
||||||
@ -94,7 +94,7 @@ namespace Spectre.Console
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bottom padding
|
// Bottom padding
|
||||||
for (var i = 0; i < Padding.Bottom; i++)
|
for (var i = 0; i < Padding.GetBottomSafe(); i++)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', width)));
|
result.Add(new Segment(new string(' ', width)));
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
|
@ -34,7 +34,7 @@ namespace Spectre.Console
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the padding.
|
/// Gets or sets the padding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Padding Padding { get; set; } = new Padding(1, 0, 1, 0);
|
public Padding? Padding { get; set; } = new Padding(1, 0, 1, 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the header.
|
/// Gets or sets the header.
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Spectre.Console.Internal;
|
using Spectre.Console.Internal;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
using Spectre.Console.Widgets;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
{
|
{
|
||||||
@ -14,20 +15,20 @@ namespace Spectre.Console
|
|||||||
private const int EdgeCount = 2;
|
private const int EdgeCount = 2;
|
||||||
|
|
||||||
private readonly List<TableColumn> _columns;
|
private readonly List<TableColumn> _columns;
|
||||||
private readonly List<List<IRenderable>> _rows;
|
private readonly List<TableRow> _rows;
|
||||||
|
|
||||||
private static Style _defaultHeadingStyle = new Style(Color.Silver);
|
private static Style _defaultHeadingStyle = new Style(Color.Silver);
|
||||||
private static Style _defaultCaptionStyle = new Style(Color.Grey);
|
private static Style _defaultCaptionStyle = new Style(Color.Grey);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of columns in the table.
|
/// Gets the table columns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ColumnCount => _columns.Count;
|
public IReadOnlyList<TableColumn> Columns => _columns;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of rows in the table.
|
/// Gets the table rows.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int RowCount => _rows.Count;
|
public IReadOnlyList<TableRow> Rows => _rows;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public TableBorder Border { get; set; } = TableBorder.Square;
|
public TableBorder Border { get; set; } = TableBorder.Square;
|
||||||
@ -87,7 +88,7 @@ namespace Spectre.Console
|
|||||||
public Table()
|
public Table()
|
||||||
{
|
{
|
||||||
_columns = new List<TableColumn>();
|
_columns = new List<TableColumn>();
|
||||||
_rows = new List<List<IRenderable>>();
|
_rows = new List<TableRow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -116,24 +117,25 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="columns">The row columns to add.</param>
|
/// <param name="columns">The row columns to add.</param>
|
||||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
public Table AddRow(params IRenderable[] columns)
|
public Table AddRow(IEnumerable<IRenderable> columns)
|
||||||
{
|
{
|
||||||
if (columns is null)
|
if (columns is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(columns));
|
throw new ArgumentNullException(nameof(columns));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columns.Length > _columns.Count)
|
var rowColumnCount = columns.GetCount();
|
||||||
|
if (rowColumnCount > _columns.Count)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_rows.Add(columns.ToList());
|
_rows.Add(new TableRow(columns));
|
||||||
|
|
||||||
// Need to add missing columns?
|
// Need to add missing columns?
|
||||||
if (columns.Length < _columns.Count)
|
if (rowColumnCount < _columns.Count)
|
||||||
{
|
{
|
||||||
var diff = _columns.Count - columns.Length;
|
var diff = _columns.Count - rowColumnCount;
|
||||||
Enumerable.Range(0, diff).ForEach(_ => _rows.Last().Add(Text.Empty));
|
Enumerable.Range(0, diff).ForEach(_ => _rows.Last().Add(Text.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +200,11 @@ namespace Spectre.Console
|
|||||||
return new List<Segment>(new[] { new Segment("…", BorderStyle ?? Style.Plain) });
|
return new List<Segment>(new[] { new Segment("…", BorderStyle ?? Style.Plain) });
|
||||||
}
|
}
|
||||||
|
|
||||||
var rows = new List<List<IRenderable>>();
|
var rows = new List<TableRow>();
|
||||||
if (ShowHeaders)
|
if (ShowHeaders)
|
||||||
{
|
{
|
||||||
// Add columns to top of rows
|
// Add columns to top of rows
|
||||||
rows.Add(new List<IRenderable>(_columns.Select(c => c.Header)));
|
rows.Add(new TableRow(new List<IRenderable>(_columns.Select(c => c.Header))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add rows.
|
// Add rows.
|
||||||
@ -210,7 +212,7 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
if (hasFooters)
|
if (hasFooters)
|
||||||
{
|
{
|
||||||
rows.Add(new List<IRenderable>(_columns.Select(c => c.Footer ?? Text.Empty)));
|
rows.Add(new TableRow(new List<IRenderable>(_columns.Select(c => c.Footer ?? Text.Empty))));
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<Segment>();
|
var result = new List<Segment>();
|
||||||
@ -273,7 +275,7 @@ namespace Spectre.Console
|
|||||||
// Pad column on left side.
|
// Pad column on left side.
|
||||||
if (showBorder || IsGrid)
|
if (showBorder || IsGrid)
|
||||||
{
|
{
|
||||||
var leftPadding = _columns[cellIndex].Padding.Left;
|
var leftPadding = _columns[cellIndex].Padding.GetLeftSafe();
|
||||||
if (leftPadding > 0)
|
if (leftPadding > 0)
|
||||||
{
|
{
|
||||||
rowResult.Add(new Segment(new string(' ', leftPadding)));
|
rowResult.Add(new Segment(new string(' ', leftPadding)));
|
||||||
@ -293,7 +295,7 @@ namespace Spectre.Console
|
|||||||
// Pad column on the right side
|
// Pad column on the right side
|
||||||
if (showBorder || (hideBorder && !lastCell) || (hideBorder && lastCell && IsGrid && PadRightCell))
|
if (showBorder || (hideBorder && !lastCell) || (hideBorder && lastCell && IsGrid && PadRightCell))
|
||||||
{
|
{
|
||||||
var rightPadding = _columns[cellIndex].Padding.Right;
|
var rightPadding = _columns[cellIndex].Padding.GetRightSafe();
|
||||||
if (rightPadding > 0)
|
if (rightPadding > 0)
|
||||||
{
|
{
|
||||||
rowResult.Add(new Segment(new string(' ', rightPadding)));
|
rowResult.Add(new Segment(new string(' ', rightPadding)));
|
||||||
@ -446,7 +448,7 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
private (int Min, int Max) MeasureColumn(TableColumn column, RenderContext options, int maxWidth)
|
private (int Min, int Max) MeasureColumn(TableColumn column, RenderContext options, int maxWidth)
|
||||||
{
|
{
|
||||||
var padding = column.Padding.GetWidth();
|
var padding = column.Padding?.GetWidth() ?? 0;
|
||||||
|
|
||||||
// Predetermined width?
|
// Predetermined width?
|
||||||
if (column.Width != null)
|
if (column.Width != null)
|
||||||
@ -482,11 +484,11 @@ namespace Spectre.Console
|
|||||||
var hideBorder = !Border.Visible;
|
var hideBorder = !Border.Visible;
|
||||||
var separators = hideBorder ? 0 : _columns.Count - 1;
|
var separators = hideBorder ? 0 : _columns.Count - 1;
|
||||||
var edges = hideBorder ? 0 : EdgeCount;
|
var edges = hideBorder ? 0 : EdgeCount;
|
||||||
var padding = includePadding ? _columns.Select(x => x.Padding.GetWidth()).Sum() : 0;
|
var padding = includePadding ? _columns.Select(x => x.Padding?.GetWidth() ?? 0).Sum() : 0;
|
||||||
|
|
||||||
if (!PadRightCell)
|
if (!PadRightCell)
|
||||||
{
|
{
|
||||||
padding -= _columns.Last().Padding.Right;
|
padding -= _columns.Last().Padding.GetRightSafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
return separators + edges + padding;
|
return separators + edges + padding;
|
||||||
|
@ -28,7 +28,7 @@ namespace Spectre.Console
|
|||||||
/// Gets or sets the padding of the column.
|
/// Gets or sets the padding of the column.
|
||||||
/// Vertical padding (top and bottom) is ignored.
|
/// Vertical padding (top and bottom) is ignored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Padding Padding { get; set; }
|
public Padding? Padding { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether wrapping of
|
/// Gets or sets a value indicating whether wrapping of
|
||||||
|
56
src/Spectre.Console/Widgets/TableRow.cs
Normal file
56
src/Spectre.Console/Widgets/TableRow.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
|
namespace Spectre.Console.Widgets
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a table row.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TableRow : IEnumerable<IRenderable>
|
||||||
|
{
|
||||||
|
private readonly List<IRenderable> _items;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a row item at the specified table column index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The table column index.</param>
|
||||||
|
/// <returns>The row item at the specified table column index.</returns>
|
||||||
|
public IRenderable this[int index]
|
||||||
|
{
|
||||||
|
get => _items[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TableRow"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The row items.</param>
|
||||||
|
public TableRow(IEnumerable<IRenderable> items)
|
||||||
|
{
|
||||||
|
_items = new List<IRenderable>(items ?? Array.Empty<IRenderable>());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Add(IRenderable item)
|
||||||
|
{
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
_items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerator<IRenderable> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _items.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user