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