From a4a98d82e580bc0cb5e6105503475b43ee14aaf2 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 21 Oct 2023 00:12:44 +0100 Subject: [PATCH] Update to match latest Spectre Console code --- .../Extensions/BreakdownChartExtensions.cs | 19 ++++++- .../Extensions/Progress/ProgressExtensions.cs | 17 ++++++ .../Extensions/TableExtensions.cs | 34 ++++++++++- .../Spectre.Console/Live/Progress/Progress.cs | 7 ++- .../Renderers/DefaultProgressRenderer.cs | 13 ++++- .../Rendering/Borders/TableBorderPart.cs | 22 ++++++- .../Borders/Tables/Ascii2TableBorder.cs | 4 ++ .../Tables/AsciiDoubleHeadTableBorder.cs | 6 +- .../Borders/Tables/AsciiTableBorder.cs | 6 +- .../Borders/Tables/DoubleEdgeTableBorder.cs | 6 +- .../Borders/Tables/DoubleTableBorder.cs | 6 +- .../Borders/Tables/HeavyEdgeTableBorder.cs | 6 +- .../Borders/Tables/HeavyHeadTableBorder.cs | 6 +- .../Borders/Tables/HeavyTableBorder.cs | 6 +- .../Borders/Tables/HorizontalTableBorder.cs | 6 +- .../Borders/Tables/MarkdownTableBorder.cs | 13 ++++- .../Tables/MinimalDoubleHeadTableBorder.cs | 6 +- .../Tables/MinimalHeavyHeadTableBorder.cs | 6 +- .../Borders/Tables/MinimalTableBorder.cs | 6 +- .../Rendering/Borders/Tables/NoTableBorder.cs | 5 +- .../Borders/Tables/RoundedTableBorder.cs | 6 +- .../Borders/Tables/SimpleHeavyTableBorder.cs | 6 +- .../Borders/Tables/SimpleTableBorder.cs | 6 +- .../Borders/Tables/SquareTableBorder.cs | 6 +- .../Spectre.Console/Rendering/TablePart.cs | 7 ++- .../Spectre.Console/TableBorder.cs | 7 ++- .../Widgets/Charts/BreakdownChart.cs | 6 ++ .../Widgets/Charts/BreakdownTags.cs | 9 ++- .../Spectre.Console/Widgets/ControlCode.cs | 32 +++++++++-- .../Widgets/Figlet/FigletText.cs | 4 +- .../Spectre.Console/Widgets/Panel.cs | 9 +++ .../Spectre.Console/Widgets/Rows.cs | 11 ++-- .../Spectre.Console/Widgets/Table/Table.cs | 5 ++ .../Widgets/Table/TableRenderer.cs | 57 +++++++++++++++---- .../Widgets/Table/TableRendererContext.cs | 2 + .../Spectre.Console/Widgets/TextPath.cs | 9 +-- 36 files changed, 322 insertions(+), 60 deletions(-) diff --git a/src/Spectre.Console.Rx/Spectre.Console/Extensions/BreakdownChartExtensions.cs b/src/Spectre.Console.Rx/Spectre.Console/Extensions/BreakdownChartExtensions.cs index b35f643..ad797f5 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Extensions/BreakdownChartExtensions.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Extensions/BreakdownChartExtensions.cs @@ -282,4 +282,21 @@ public static BreakdownChart Compact(this BreakdownChart chart, bool compact) chart.Compact = compact; return chart; } -} \ No newline at end of file + + /// + /// Sets the . + /// + /// The breakdown chart. + /// The to set. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart WithValueColor(this BreakdownChart chart, Color color) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueColor = color; + return chart; + } +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Extensions/Progress/ProgressExtensions.cs b/src/Spectre.Console.Rx/Spectre.Console/Extensions/Progress/ProgressExtensions.cs index 0ff9af2..d356b58 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Extensions/Progress/ProgressExtensions.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Extensions/Progress/ProgressExtensions.cs @@ -37,6 +37,23 @@ public static Progress Columns(this Progress progress, params ProgressColumn[] c return progress; } + /// + /// Sets an optional hook to intercept rendering. + /// + /// The instance. + /// The custom render function. + /// The same instance so that multiple calls can be chained. + public static Progress UseRenderHook(this Progress progress, Func, IRenderable> renderHook) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.RenderHook = renderHook; + return progress; + } + /// /// Sets whether or not auto refresh is enabled. /// If disabled, you will manually have to refresh the progress. diff --git a/src/Spectre.Console.Rx/Spectre.Console/Extensions/TableExtensions.cs b/src/Spectre.Console.Rx/Spectre.Console/Extensions/TableExtensions.cs index 981c499..0cbe0e1 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Extensions/TableExtensions.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Extensions/TableExtensions.cs @@ -337,6 +337,38 @@ public static Table HideHeaders(this Table table) return table; } + /// + /// Shows row separators. + /// + /// The table. + /// The same instance so that multiple calls can be chained. + public static Table ShowRowSeparators(this Table table) + { + if (table is null) + { + throw new ArgumentNullException(nameof(table)); + } + + table.ShowRowSeparators = true; + return table; + } + + /// + /// Hides row separators. + /// + /// The table. + /// The same instance so that multiple calls can be chained. + public static Table HideRowSeparators(this Table table) + { + if (table is null) + { + throw new ArgumentNullException(nameof(table)); + } + + table.ShowRowSeparators = false; + return table; + } + /// /// Shows table footers. /// @@ -446,4 +478,4 @@ public static Table Caption(this Table table, TableTitle caption) table.Caption = caption; return table; } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Progress.cs b/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Progress.cs index ec53469..4586772 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Progress.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Progress.cs @@ -27,6 +27,11 @@ public Progress(IAnsiConsole console) }; } + /// + /// Gets or sets a optional custom render function. + /// + public Func, IRenderable> RenderHook { get; set; } = (renderable, _) => renderable; + /// /// Gets or sets a value indicating whether or not task list should auto refresh. /// Defaults to true. @@ -162,7 +167,7 @@ private ProgressRenderer CreateRenderer() if (interactive) { var columns = new List(Columns); - return new DefaultProgressRenderer(_console, columns, RefreshRate, HideCompleted); + return new DefaultProgressRenderer(_console, columns, RefreshRate, HideCompleted, RenderHook); } return FallbackRenderer ?? new FallbackProgressRenderer(); diff --git a/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs b/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs index 69297c7..916b88e 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Live/Progress/Renderers/DefaultProgressRenderer.cs @@ -3,7 +3,7 @@ namespace Spectre.Console.Rx; -internal sealed class DefaultProgressRenderer(IAnsiConsole console, List columns, TimeSpan refreshRate, bool hideCompleted) : ProgressRenderer +internal sealed class DefaultProgressRenderer(IAnsiConsole console, List columns, TimeSpan refreshRate, bool hideCompleted, Func, IRenderable> renderHook) : ProgressRenderer { private readonly IAnsiConsole _console = console ?? throw new ArgumentNullException(nameof(console)); private readonly List _columns = columns ?? throw new ArgumentNullException(nameof(columns)); @@ -81,13 +81,20 @@ public override void Update(ProgressContext context) } // Add rows - foreach (var task in context.GetTasks().Where(tsk => !(hideCompleted && tsk.IsFinished))) + var tasks = context.GetTasks(); + + var layout = new Grid(); + layout.AddColumn(); + + foreach (var task in tasks.Where(tsk => !(hideCompleted && tsk.IsFinished))) { var columns = _columns.Select(column => column.Render(renderContext, task, delta)); grid.AddRow(columns.ToArray()); } - _live.SetRenderable(new Padder(grid, new Padding(0, 1))); + layout.AddRow(grid); + + _live.SetRenderable(new Padder(renderHook(layout, tasks), new Padding(0, 1))); } } diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/TableBorderPart.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/TableBorderPart.cs index b6d6e2e..11cb284 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/TableBorderPart.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/TableBorderPart.cs @@ -117,4 +117,24 @@ public enum TableBorderPart /// The bottom right part of a footer. /// FooterBottomRight, -} \ No newline at end of file + + /// + /// The left part of a row. + /// + RowLeft, + + /// + /// The center part of a row. + /// + RowCenter, + + /// + /// The separator part of a row. + /// + RowSeparator, + + /// + /// The right part of a row. + /// + RowRight, +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs index 70492de..6498653 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs @@ -33,6 +33,10 @@ public sealed class Ascii2TableBorder : TableBorder TableBorderPart.FooterBottom => "-", TableBorderPart.FooterBottomSeparator => "+", TableBorderPart.FooterBottomRight => "+", + TableBorderPart.RowLeft => "|", + TableBorderPart.RowCenter => "-", + TableBorderPart.RowSeparator => "+", + TableBorderPart.RowRight => "|", _ => throw new InvalidOperationException("Unknown border part."), }; } diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs index 67a0a34..809e77b 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs @@ -33,6 +33,10 @@ public sealed class AsciiDoubleHeadTableBorder : TableBorder TableBorderPart.FooterBottom => "-", TableBorderPart.FooterBottomSeparator => "+", TableBorderPart.FooterBottomRight => "+", + TableBorderPart.RowLeft => "|", + TableBorderPart.RowCenter => "-", + TableBorderPart.RowSeparator => "+", + TableBorderPart.RowRight => "|", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs index 2a88b92..0b7255d 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs @@ -33,6 +33,10 @@ public sealed class AsciiTableBorder : TableBorder TableBorderPart.FooterBottom => "-", TableBorderPart.FooterBottomSeparator => "-", TableBorderPart.FooterBottomRight => "+", + TableBorderPart.RowLeft => "|", + TableBorderPart.RowCenter => "-", + TableBorderPart.RowSeparator => "+", + TableBorderPart.RowRight => "|", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs index df1e663..a1b5af9 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs @@ -33,6 +33,10 @@ public sealed class DoubleEdgeTableBorder : TableBorder TableBorderPart.FooterBottom => "═", TableBorderPart.FooterBottomSeparator => "╧", TableBorderPart.FooterBottomRight => "╝", + TableBorderPart.RowLeft => "╟", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => "╢", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs index 531cd0b..bb30049 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs @@ -33,6 +33,10 @@ public sealed class DoubleTableBorder : TableBorder TableBorderPart.FooterBottom => "═", TableBorderPart.FooterBottomSeparator => "╩", TableBorderPart.FooterBottomRight => "╝", + TableBorderPart.RowLeft => "╠", + TableBorderPart.RowCenter => "═", + TableBorderPart.RowSeparator => "╬", + TableBorderPart.RowRight => "╣", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs index 99160a9..e21d25b 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs @@ -36,6 +36,10 @@ public sealed class HeavyEdgeTableBorder : TableBorder TableBorderPart.FooterBottom => "━", TableBorderPart.FooterBottomSeparator => "┷", TableBorderPart.FooterBottomRight => "┛", + TableBorderPart.RowLeft => "┠", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => "┨", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs index a5d95d8..4c8ea6f 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs @@ -36,6 +36,10 @@ public sealed class HeavyHeadTableBorder : TableBorder TableBorderPart.FooterBottom => "─", TableBorderPart.FooterBottomSeparator => "┴", TableBorderPart.FooterBottomRight => "┘", + TableBorderPart.RowLeft => "├", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => "┤", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs index e58f6bb..42a7b78 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs @@ -36,6 +36,10 @@ public sealed class HeavyTableBorder : TableBorder TableBorderPart.FooterBottom => "━", TableBorderPart.FooterBottomSeparator => "┻", TableBorderPart.FooterBottomRight => "┛", + TableBorderPart.RowLeft => "┣", + TableBorderPart.RowCenter => "━", + TableBorderPart.RowSeparator => "╋", + TableBorderPart.RowRight => "┫", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs index 9c4592f..a4cfbb3 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs @@ -33,6 +33,10 @@ public sealed class HorizontalTableBorder : TableBorder TableBorderPart.FooterBottom => "─", TableBorderPart.FooterBottomSeparator => "─", TableBorderPart.FooterBottomRight => "─", + TableBorderPart.RowLeft => "─", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "─", + TableBorderPart.RowRight => "─", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs index 66ae490..2f2cc13 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs @@ -8,6 +8,9 @@ namespace Spectre.Console.Rx.Rendering; /// public sealed class MarkdownTableBorder : TableBorder { + /// + public override bool SupportsRowSeparator => false; + /// public override string GetPart(TableBorderPart part) => part switch { @@ -33,6 +36,10 @@ public sealed class MarkdownTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => " ", + TableBorderPart.RowCenter => " ", + TableBorderPart.RowSeparator => " ", + TableBorderPart.RowRight => " ", _ => throw new InvalidOperationException("Unknown border part."), }; @@ -58,7 +65,7 @@ public override string GetColumnRow(TablePart part, IReadOnlyList widths, I { var padding = columns[columnIndex].Padding; - if (padding != null && padding.Value.Left > 0) + if (padding?.Left > 0) { // Left padding builder.Append(" ".Repeat(padding.Value.Left)); @@ -91,7 +98,7 @@ public override string GetColumnRow(TablePart part, IReadOnlyList widths, I } // Right padding - if (padding != null && padding.Value.Right > 0) + if (padding?.Right > 0) { builder.Append(" ".Repeat(padding.Value.Right)); } @@ -105,4 +112,4 @@ public override string GetColumnRow(TablePart part, IReadOnlyList widths, I builder.Append(right); return builder.ToString(); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs index d3f6e42..898b429 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs @@ -33,6 +33,10 @@ public sealed class MinimalDoubleHeadTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => " ", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => " ", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs index b5afb86..48c2fb8 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs @@ -36,6 +36,10 @@ public sealed class MinimalHeavyHeadTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => " ", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => " ", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs index f53ac10..27df2f6 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs @@ -33,6 +33,10 @@ public sealed class MinimalTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => " ", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => " ", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs index ee5f6b0..63fbd1a 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs @@ -11,6 +11,9 @@ public sealed class NoTableBorder : TableBorder /// public override bool Visible => false; + /// + public override bool SupportsRowSeparator => false; + /// public override string GetPart(TableBorderPart part) => " "; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs index 5b04df1..9385f16 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs @@ -36,6 +36,10 @@ public sealed class RoundedTableBorder : TableBorder TableBorderPart.FooterBottom => "─", TableBorderPart.FooterBottomSeparator => "┴", TableBorderPart.FooterBottomRight => "╯", + TableBorderPart.RowLeft => "├", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => "┤", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs index a87c01d..e6f7ddf 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs @@ -36,6 +36,10 @@ public sealed class SimpleHeavyTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => "─", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "─", + TableBorderPart.RowRight => "─", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs index 709abf8..d3c926e 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs @@ -33,6 +33,10 @@ public sealed class SimpleTableBorder : TableBorder TableBorderPart.FooterBottom => " ", TableBorderPart.FooterBottomSeparator => " ", TableBorderPart.FooterBottomRight => " ", + TableBorderPart.RowLeft => "─", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "─", + TableBorderPart.RowRight => "─", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs index 886509f..f963e4e 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs @@ -33,6 +33,10 @@ public sealed class SquareTableBorder : TableBorder TableBorderPart.FooterBottom => "─", TableBorderPart.FooterBottomSeparator => "┴", TableBorderPart.FooterBottomRight => "┘", + TableBorderPart.RowLeft => "├", + TableBorderPart.RowCenter => "─", + TableBorderPart.RowSeparator => "┼", + TableBorderPart.RowRight => "┤", _ => throw new InvalidOperationException("Unknown border part."), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Rendering/TablePart.cs b/src/Spectre.Console.Rx/Spectre.Console/Rendering/TablePart.cs index 4b31474..5514f52 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Rendering/TablePart.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Rendering/TablePart.cs @@ -18,6 +18,11 @@ public enum TablePart /// HeaderSeparator, + /// + /// The separator between the rows. + /// + RowSeparator, + /// /// The separator between the footer and the cells. /// @@ -27,4 +32,4 @@ public enum TablePart /// The bottom of a table. /// Bottom, -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/TableBorder.cs b/src/Spectre.Console.Rx/Spectre.Console/TableBorder.cs index f40a121..e831e71 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/TableBorder.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/TableBorder.cs @@ -18,6 +18,11 @@ public abstract partial class TableBorder /// public virtual TableBorder? SafeBorder { get; } + /// + /// Gets a value indicating whether the border supports row separators or not. + /// + public virtual bool SupportsRowSeparator { get; } = true; + /// /// Gets the string representation of a specified table border part. /// @@ -95,4 +100,4 @@ public virtual string GetColumnRow(TablePart part, IReadOnlyList widths, IR // Unknown _ => throw new NotSupportedException("Unknown column row part"), }; -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownChart.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownChart.cs index 80527a0..7270064 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownChart.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownChart.cs @@ -22,6 +22,11 @@ public BreakdownChart() /// public List Data { get; } + /// + /// Gets or sets the Color in which the values will be shown. + /// + public Color ValueColor { get; set; } = Color.Grey; + /// /// Gets or sets the width of the breakdown chart. /// @@ -97,6 +102,7 @@ protected override IEnumerable Render(RenderOptions options, int maxWid Culture = Culture, ShowTagValues = ShowTagValues, ValueFormatter = ValueFormatter, + ValueColor = ValueColor, }); } diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownTags.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownTags.cs index 7586d49..4795d04 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownTags.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Charts/BreakdownTags.cs @@ -9,6 +9,8 @@ internal sealed class BreakdownTags(List data) : Renderable public int? Width { get; set; } + public Color ValueColor { get; set; } = Color.Grey; + public CultureInfo? Culture { get; set; } public bool ShowTagValues { get; set; } = true; @@ -55,7 +57,12 @@ private string FormatValue(IBreakdownChartItem item, CultureInfo culture) if (ShowTagValues) { - return string.Format(culture, "{0} [grey]{1}[/]", item.Label.EscapeMarkup(), formatter(item.Value, culture)); + return string.Format( + culture, + "{0} [{1}]{2}[/]", + item.Label.EscapeMarkup(), + ValueColor.ToMarkup(), + formatter(item.Value, culture)); } return item.Label.EscapeMarkup(); diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/ControlCode.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/ControlCode.cs index 5540712..84a7d4a 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/ControlCode.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/ControlCode.cs @@ -3,14 +3,36 @@ namespace Spectre.Console.Rx; -internal sealed class ControlCode : Renderable +/// +/// ControlCode. +/// +/// +/// +/// Initializes a new instance of the class. +/// +/// The control. +public sealed class ControlCode(string control) : Renderable { - private readonly Segment _segment; - - public ControlCode(string control) => _segment = Segment.Control(control); + private readonly Segment _segment = Segment.Control(control); + /// + /// Measures the renderable object. + /// + /// The render options. + /// The maximum allowed width. + /// + /// The minimum and maximum width of the object. + /// protected override Measurement Measure(RenderOptions options, int maxWidth) => new(0, 0); + /// + /// Renders the object. + /// + /// The render options. + /// The maximum allowed width. + /// + /// A collection of segments. + /// protected override IEnumerable Render(RenderOptions options, int maxWidth) { if (options.Ansi) @@ -18,4 +40,4 @@ protected override IEnumerable Render(RenderOptions options, int maxWid yield return _segment; } } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Figlet/FigletText.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Figlet/FigletText.cs index 0029240..c3b5314 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Figlet/FigletText.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Figlet/FigletText.cs @@ -64,8 +64,8 @@ protected override IEnumerable Render(RenderOptions options, int maxWid } else if (alignment == Rx.Justify.Center) { - var left = (maxWidth - lineWidth) / 2; - var right = left + ((maxWidth - lineWidth) % 2); + var left = Math.Max(0, maxWidth - lineWidth) / 2; + var right = left + (Math.Max(0, maxWidth - lineWidth) % 2); yield return Segment.Padding(left); yield return line; diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Panel.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Panel.cs index 4af92b2..4371cbb 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Panel.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Panel.cs @@ -109,6 +109,15 @@ protected override IEnumerable Render(RenderOptions options, int maxWid { AddTopBorder(result, options, border, borderStyle, panelWidth); } + else + { + // Not showing border, but we have a header text? + // Use a invisible border to draw the top border + if (Header?.Text != null) + { + AddTopBorder(result, options, BoxBorder.None, borderStyle, panelWidth); + } + } // Split the child segments into lines. var childSegments = ((IRenderable)child).Render(options with { Height = height }, innerWidth); diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Rows.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Rows.cs index 816a7e9..4e2b528 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Rows.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Rows.cs @@ -38,8 +38,8 @@ protected override Measurement Measure(RenderOptions options, int maxWidth) if (measurements.Length > 0) { return new Measurement( - measurements.Min(c => c.Min), - measurements.Min(c => c.Max)); + measurements.Max(c => c.Min), + measurements.Max(c => c.Max)); } return new Measurement(0, 0); @@ -57,12 +57,9 @@ protected override IEnumerable Render(RenderOptions options, int maxWid { result.Add(segment); - if (last) + if (last && !segment.IsLineBreak && child is not ControlCode) { - if (!segment.IsLineBreak) - { - result.Add(Segment.LineBreak); - } + result.Add(Segment.LineBreak); } } } diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/Table.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/Table.cs index 6b37fe9..a259266 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/Table.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/Table.cs @@ -32,6 +32,11 @@ public Table() /// public TableBorder Border { get; set; } = TableBorder.Square; + /// + /// Gets or sets a value indicating whether or not row separators should be shown. + /// + public bool ShowRowSeparators { get; set; } + /// public Style? BorderStyle { get; set; } diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRenderer.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRenderer.cs index 12deae3..5b6a957 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRenderer.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRenderer.cs @@ -11,7 +11,7 @@ internal static class TableRenderer public static List Render(TableRendererContext context, List columnWidths) { // Can't render the table? - if (context.TableWidth <= 0 || context.TableWidth > context.MaxWidth || columnWidths.Any(c => c <= 0)) + if (context.TableWidth <= 0 || context.TableWidth > context.MaxWidth || columnWidths.Any(c => c < 0)) { return new List(new[] { new Segment("…", context.BorderStyle ?? Style.Plain) }); } @@ -26,12 +26,12 @@ public static List Render(TableRendererContext context, List colum // Get the list of cells for the row and calculate the cell height var cells = new List>(); - foreach (var (columnIndex, _, _, (rowWidth, cell)) in columnWidths.Zip(row).Enumerate()) + foreach (var (columnIndex, _, _, (columnWidth, cell)) in columnWidths.Zip(row).Enumerate()) { var justification = context.Columns[columnIndex].Alignment; var childContext = context.Options with { Justification = justification }; - var lines = Segment.SplitLines(cell.Render(childContext, rowWidth)); + var lines = Segment.SplitLines(cell.Render(childContext, columnWidth)); cellHeight = Math.Max(cellHeight, lines.Count); cells.Add(lines); } @@ -39,7 +39,10 @@ public static List Render(TableRendererContext context, List colum // Show top of header? if (isFirstRow && context.ShowBorder) { - var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth); + var separator = Aligner.Align( + context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), + context.Alignment, + context.MaxWidth); result.Add(new Segment(separator, context.BorderStyle)); result.Add(Segment.LineBreak); } @@ -69,7 +72,9 @@ public static List Render(TableRendererContext context, List colum if (isFirstCell && context.ShowBorder) { // Show left column edge - var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft; + var part = isFirstRow && context.ShowHeaders + ? TableBorderPart.HeaderLeft + : TableBorderPart.CellLeft; rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle)); } @@ -94,7 +99,8 @@ public static List Render(TableRendererContext context, List colum } // Pad column on the right side - if (context.ShowBorder || (context.HideBorder && !isLastCell) || (context.HideBorder && isLastCell && context.IsGrid && context.PadRightCell)) + if (context.ShowBorder || (context.HideBorder && !isLastCell) || + (context.HideBorder && isLastCell && context.IsGrid && context.PadRightCell)) { var rightPadding = context.Columns[cellIndex].Padding.GetRightSafe(); if (rightPadding > 0) @@ -106,13 +112,17 @@ public static List Render(TableRendererContext context, List colum if (isLastCell && context.ShowBorder) { // Add right column edge - var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight; + var part = isFirstRow && context.ShowHeaders + ? TableBorderPart.HeaderRight + : TableBorderPart.CellRight; rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle)); } else if (context.ShowBorder) { // Add column separator - var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator; + var part = isFirstRow && context.ShowHeaders + ? TableBorderPart.HeaderSeparator + : TableBorderPart.CellSeparator; rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle)); } } @@ -136,15 +146,40 @@ public static List Render(TableRendererContext context, List colum // Show header separator? if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows) { - var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth); + var separator = + Aligner.Align( + context.Border.GetColumnRow( + TablePart.HeaderSeparator, + columnWidths, + context.Columns), + context.Alignment, + context.MaxWidth); result.Add(new Segment(separator, context.BorderStyle)); result.Add(Segment.LineBreak); } + // Show row separator? + if (context.Border.SupportsRowSeparator && context.ShowRowSeparators && !isFirstRow && !isLastRow) + { + var hasVisibleFootes = context is { ShowFooters: true, HasFooters: true }; + var isNextLastLine = index == context.Rows.Count - 2; + + var isRenderingFooter = hasVisibleFootes && isNextLastLine; + if (!isRenderingFooter) + { + var separator = + Aligner.Align( + context.Border.GetColumnRow(TablePart.RowSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth); + result.Add(new Segment(separator, context.BorderStyle)); + result.Add(Segment.LineBreak); + } + } + // Show bottom of footer? if (isLastRow && context.ShowBorder) { - var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth); + var separator = + Aligner.Align(context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth); result.Add(new Segment(separator, context.BorderStyle)); result.Add(Segment.LineBreak); } @@ -175,4 +210,4 @@ private static IEnumerable RenderAnnotation(TableRendererContext contex segments.Add(Segment.LineBreak); return segments; } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRendererContext.cs b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRendererContext.cs index 9eb43e1..45be7f2 100644 --- a/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRendererContext.cs +++ b/src/Spectre.Console.Rx/Spectre.Console/Widgets/Table/TableRendererContext.cs @@ -32,6 +32,8 @@ public TableRendererContext(Table table, RenderOptions options, IEnumerable @@ -129,9 +129,6 @@ public IEnumerable Render(RenderOptions options, int maxWidth) // Align the result Aligner.Align(parts, Justification, maxWidth); - // Insert a line break - parts.Add(Segment.LineBreak); - return parts; } @@ -144,7 +141,7 @@ private string[] Fit(RenderOptions options, int maxWidth) } // Will it fit as is? - if (_parts.Sum(p => Cell.GetCellLength(p)) + (_parts.Length - 1) < maxWidth) + if (_parts.Sum(Cell.GetCellLength) + (_parts.Length - 1) <= maxWidth) { return _parts; } @@ -169,7 +166,7 @@ private string[] Fit(RenderOptions options, int maxWidth) var queueWidth = rootLength // Root (if rooted) + ellipsisLength // Ellipsis - + queue.Sum(p => Cell.GetCellLength(p)) // Middle + + queue.Sum(Cell.GetCellLength) // Middle + Cell.GetCellLength(_parts.Last()) // Last + queue.Count + separatorCount; // Separators