diff --git a/docs/input/assets/images/barchart.png b/docs/input/assets/images/barchart.png
new file mode 100644
index 0000000..73e9d55
Binary files /dev/null and b/docs/input/assets/images/barchart.png differ
diff --git a/docs/input/widgets/barchart.md b/docs/input/widgets/barchart.md
new file mode 100644
index 0000000..6e1a993
--- /dev/null
+++ b/docs/input/widgets/barchart.md
@@ -0,0 +1,75 @@
+Title: Bar Chart
+Order: 1
+---
+
+Use `BarChart` to render bar charts to the console.
+
+
+
+# Usage
+
+## Basic usage
+
+```csharp
+AnsiConsole.Render(new BarChart()
+ .Width(60)
+ .Label("[green bold underline]Number of fruits[/]")
+ .CenterLabel()
+ .AddItem("Apple", 12, Color.Yellow)
+ .AddItem("Orange", 54, Color.Green)
+ .AddItem("Banana", 33, Color.Red));
+```
+
+## Add items with converter
+
+```csharp
+// Create a list of fruits
+var items = new List<(string Label, double Value)>
+{
+ ("Apple", 12),
+ ("Orange", 54),
+ ("Banana", 33),
+};
+
+// Render bar chart
+AnsiConsole.Render(new BarChart()
+ .Width(60)
+ .Label("[green bold underline]Number of fruits[/]")
+ .CenterLabel()
+ .AddItems(items, (item) => new BarChartItem(
+ item.Label, item.Value, Color.Yellow)));
+```
+
+## Add items implementing IBarChartItem
+
+```csharp
+public sealed class Fruit : IBarChartItem
+{
+ public string Label { get; set; }
+ public double Value { get; set; }
+ public Color? Color { get; set; }
+
+ public Fruit(string label, double value, Color? color = null)
+ {
+ Label = label;
+ Value = value;
+ Color = color;
+ }
+}
+
+// Create a list of fruits
+var items = new List
+{
+ new Fruit("Apple", 12, Color.Yellow),
+ new Fruit("Orange", 54, Color.Red),
+ new Fruit("Banana", 33, Color.Green),
+};
+
+// Render bar chart
+AnsiConsole.Render(new BarChart()
+ .Width(60)
+ .Label("[green bold underline]Number of fruits[/]")
+ .CenterLabel()
+ .AddItem(new Fruit("Mango", 3))
+ .AddItems(items));
+```
\ No newline at end of file
diff --git a/docs/input/widgets/calendar.md b/docs/input/widgets/calendar.md
index 3bf382c..3f3ad77 100644
--- a/docs/input/widgets/calendar.md
+++ b/docs/input/widgets/calendar.md
@@ -1,5 +1,5 @@
Title: Calendar
-Order: 2
+Order: 3
RedirectFrom: calendar
---
diff --git a/docs/input/widgets/canvas-image.md b/docs/input/widgets/canvas-image.md
index ae97ce5..24fd8d4 100644
--- a/docs/input/widgets/canvas-image.md
+++ b/docs/input/widgets/canvas-image.md
@@ -1,5 +1,5 @@
Title: Canvas Image
-Order: 5
+Order: 6
---
To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to
diff --git a/docs/input/widgets/canvas.md b/docs/input/widgets/canvas.md
index fc8739f..847f50e 100644
--- a/docs/input/widgets/canvas.md
+++ b/docs/input/widgets/canvas.md
@@ -1,5 +1,5 @@
Title: Canvas
-Order: 4
+Order: 5
---
`Canvas` is a widget that allows you to render arbitrary "pixels"
diff --git a/docs/input/widgets/figlet.md b/docs/input/widgets/figlet.md
index d6ecdeb..762ea0d 100644
--- a/docs/input/widgets/figlet.md
+++ b/docs/input/widgets/figlet.md
@@ -1,5 +1,5 @@
Title: Figlet
-Order: 3
+Order: 4
RedirectFrom: figlet
---
diff --git a/docs/input/widgets/rule.md b/docs/input/widgets/rule.md
index f2020cc..ff6ac55 100644
--- a/docs/input/widgets/rule.md
+++ b/docs/input/widgets/rule.md
@@ -1,5 +1,5 @@
Title: Rule
-Order: 1
+Order: 2
RedirectFrom: rule
---
diff --git a/examples/Charts/Charts.csproj b/examples/Charts/Charts.csproj
new file mode 100644
index 0000000..5b16a50
--- /dev/null
+++ b/examples/Charts/Charts.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net5.0
+ false
+ Charts
+ Demonstrates how to render charts in a console.
+
+
+
+
+
+
+
diff --git a/examples/Charts/Program.cs b/examples/Charts/Program.cs
new file mode 100644
index 0000000..08e194b
--- /dev/null
+++ b/examples/Charts/Program.cs
@@ -0,0 +1,21 @@
+using Spectre.Console;
+
+namespace InfoExample
+{
+ public static class Program
+ {
+ public static void Main()
+ {
+ var chart = new BarChart()
+ .Width(60)
+ .Label("[green bold underline]Number of fruits[/]")
+ .CenterLabel()
+ .AddItem("Apple", 12, Color.Yellow)
+ .AddItem("Orange", 54, Color.Green)
+ .AddItem("Banana", 33, Color.Red);
+
+ AnsiConsole.WriteLine();
+ AnsiConsole.Render(chart);
+ }
+ }
+}
diff --git a/src/Spectre.Console.Tests/Expectations/BarChartTests.Should_Render_Correctly.verified.txt b/src/Spectre.Console.Tests/Expectations/BarChartTests.Should_Render_Correctly.verified.txt
new file mode 100644
index 0000000..2ee8695
--- /dev/null
+++ b/src/Spectre.Console.Tests/Expectations/BarChartTests.Should_Render_Correctly.verified.txt
@@ -0,0 +1,4 @@
+ Number of fruits
+ Apple ████████ 12
+Orange █████████████████████████████████████████████████ 54
+Banana ████████████████████████████ 33
diff --git a/src/Spectre.Console.Tests/Unit/BarChartTests.cs b/src/Spectre.Console.Tests/Unit/BarChartTests.cs
new file mode 100644
index 0000000..558cf52
--- /dev/null
+++ b/src/Spectre.Console.Tests/Unit/BarChartTests.cs
@@ -0,0 +1,28 @@
+using System.Threading.Tasks;
+using VerifyXunit;
+using Xunit;
+
+namespace Spectre.Console.Tests.Unit
+{
+ [UsesVerify]
+ public sealed class BarChartTests
+ {
+ [Fact]
+ public async Task Should_Render_Correctly()
+ {
+ // Given
+ var console = new PlainConsole(width: 80);
+
+ // When
+ console.Render(new BarChart()
+ .Width(60)
+ .Label("Number of fruits")
+ .AddItem("Apple", 12)
+ .AddItem("Orange", 54)
+ .AddItem("Banana", 33));
+
+ // Then
+ await Verifier.Verify(console.Output);
+ }
+ }
+}
diff --git a/src/Spectre.Console.sln b/src/Spectre.Console.sln
index 43fdbfa..fe3d4c8 100644
--- a/src/Spectre.Console.sln
+++ b/src/Spectre.Console.sln
@@ -62,6 +62,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Progress", "..\examples\Pro
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Status", "..\examples\Status\Status.csproj", "{3716AFDF-0904-4635-8422-86E6B9356840}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Charts", "..\examples\Charts\Charts.csproj", "{0A1AFD26-86A0-4060-B277-D380172C7070}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -324,6 +326,18 @@ Global
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x64.Build.0 = Release|Any CPU
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.ActiveCfg = Release|Any CPU
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.Build.0 = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x64.Build.0 = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x86.Build.0 = Debug|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x64.ActiveCfg = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x64.Build.0 = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x86.ActiveCfg = Release|Any CPU
+ {0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -348,6 +362,7 @@ Global
{5693761A-754A-40A8-9144-36510D6A4D69} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{2B712A52-40F1-4C1C-833E-7C869ACA91F3} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{3716AFDF-0904-4635-8422-86E6B9356840} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
+ {0A1AFD26-86A0-4060-B277-D380172C7070} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
diff --git a/src/Spectre.Console/Extensions/BarGraphExtensions.cs b/src/Spectre.Console/Extensions/BarGraphExtensions.cs
new file mode 100644
index 0000000..76cbff2
--- /dev/null
+++ b/src/Spectre.Console/Extensions/BarGraphExtensions.cs
@@ -0,0 +1,234 @@
+using System;
+using System.Collections.Generic;
+
+namespace Spectre.Console
+{
+ ///
+ /// Contains extension methods for .
+ ///
+ public static class BarGraphExtensions
+ {
+ ///
+ /// Adds an item to the bar chart.
+ ///
+ /// The bar chart.
+ /// The item label.
+ /// The item value.
+ /// The item color.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart AddItem(this BarChart chart, string label, double value, Color? color = null)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.Data.Add(new BarChartItem(label, value, color));
+ return chart;
+ }
+
+ ///
+ /// Adds an item to the bar chart.
+ ///
+ /// A type that implements .
+ /// The bar chart.
+ /// The item.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart AddItem(this BarChart chart, T item)
+ where T : IBarChartItem
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.Data.Add(new BarChartItem(
+ item.Label,
+ item.Value,
+ item.Color));
+
+ return chart;
+ }
+
+ ///
+ /// Adds multiple items to the bar chart.
+ ///
+ /// A type that implements .
+ /// The bar chart.
+ /// The items.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart AddItems(this BarChart chart, IEnumerable items)
+ where T : IBarChartItem
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ if (items is null)
+ {
+ throw new ArgumentNullException(nameof(items));
+ }
+
+ foreach (var item in items)
+ {
+ AddItem(chart, item);
+ }
+
+ return chart;
+ }
+
+ ///
+ /// Adds multiple items to the bar chart.
+ ///
+ /// A type that implements .
+ /// The bar chart.
+ /// The items.
+ /// The converter that converts instances of T to .
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart AddItems(this BarChart chart, IEnumerable items, Func converter)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ if (items is null)
+ {
+ throw new ArgumentNullException(nameof(items));
+ }
+
+ if (converter is null)
+ {
+ throw new ArgumentNullException(nameof(converter));
+ }
+
+ foreach (var item in items)
+ {
+ chart.Data.Add(converter(item));
+ }
+
+ return chart;
+ }
+
+ ///
+ /// Sets the width of the bar chart.
+ ///
+ /// The bar chart.
+ /// The bar chart width.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart Width(this BarChart chart, int? width)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.Width = width;
+ return chart;
+ }
+
+ ///
+ /// Sets the label of the bar chart.
+ ///
+ /// The bar chart.
+ /// The bar chart label.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart Label(this BarChart chart, string? label)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.Label = label;
+ return chart;
+ }
+
+ ///
+ /// Shows values next to each bar in the bar chart.
+ ///
+ /// The bar chart.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart ShowValues(this BarChart chart)
+ {
+ return ShowValues(chart, true);
+ }
+
+ ///
+ /// Hides values next to each bar in the bar chart.
+ ///
+ /// The bar chart.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart HideValues(this BarChart chart)
+ {
+ return ShowValues(chart, false);
+ }
+
+ ///
+ /// Sets whether or not values should be shown
+ /// next to each bar.
+ ///
+ /// The bar chart.
+ /// Whether or not values should be shown next to each bar.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart ShowValues(this BarChart chart, bool show)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.ShowValues = show;
+ return chart;
+ }
+
+ ///
+ /// Aligns the label to the left.
+ ///
+ /// The bar chart.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart LeftAlignLabel(this BarChart chart)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.LabelAlignment = Justify.Left;
+ return chart;
+ }
+
+ ///
+ /// Centers the label.
+ ///
+ /// The bar chart.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart CenterLabel(this BarChart chart)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.LabelAlignment = Justify.Center;
+ return chart;
+ }
+
+ ///
+ /// Aligns the label to the right.
+ ///
+ /// The bar chart.
+ /// The same instance so that multiple calls can be chained.
+ public static BarChart RightAlignLabel(this BarChart chart)
+ {
+ if (chart is null)
+ {
+ throw new ArgumentNullException(nameof(chart));
+ }
+
+ chart.LabelAlignment = Justify.Right;
+ return chart;
+ }
+ }
+}
diff --git a/src/Spectre.Console/Extensions/GridExtensions.cs b/src/Spectre.Console/Extensions/GridExtensions.cs
index 078edd1..be3dbe2 100644
--- a/src/Spectre.Console/Extensions/GridExtensions.cs
+++ b/src/Spectre.Console/Extensions/GridExtensions.cs
@@ -97,5 +97,22 @@ namespace Spectre.Console
grid.AddRow(columns.Select(column => new Markup(column)).ToArray());
return grid;
}
+
+ ///
+ /// Sets the grid width.
+ ///
+ /// The grid.
+ /// The width.
+ /// The same instance so that multiple calls can be chained.
+ public static Grid Width(this Grid grid, int? width)
+ {
+ if (grid is null)
+ {
+ throw new ArgumentNullException(nameof(grid));
+ }
+
+ grid.Width = width;
+ return grid;
+ }
}
}
diff --git a/src/Spectre.Console/Extensions/TableExtensions.cs b/src/Spectre.Console/Extensions/TableExtensions.cs
index 9535b06..0ba5216 100644
--- a/src/Spectre.Console/Extensions/TableExtensions.cs
+++ b/src/Spectre.Console/Extensions/TableExtensions.cs
@@ -150,7 +150,7 @@ namespace Spectre.Console
/// The table.
/// The width.
/// The same instance so that multiple calls can be chained.
- public static Table Width(this Table table, int width)
+ public static Table Width(this Table table, int? width)
{
if (table is null)
{
diff --git a/src/Spectre.Console/Rendering/Renderable.cs b/src/Spectre.Console/Rendering/Renderable.cs
index 296af6f..35f97bb 100644
--- a/src/Spectre.Console/Rendering/Renderable.cs
+++ b/src/Spectre.Console/Rendering/Renderable.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics;
namespace Spectre.Console.Rendering
{
@@ -8,12 +9,14 @@ namespace Spectre.Console.Rendering
public abstract class Renderable : IRenderable
{
///
+ [DebuggerStepThrough]
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
{
return Measure(context, maxWidth);
}
///
+ [DebuggerStepThrough]
IEnumerable IRenderable.Render(RenderContext context, int maxWidth)
{
return Render(context, maxWidth);
diff --git a/src/Spectre.Console/Widgets/BarChart.cs b/src/Spectre.Console/Widgets/BarChart.cs
new file mode 100644
index 0000000..3541311
--- /dev/null
+++ b/src/Spectre.Console/Widgets/BarChart.cs
@@ -0,0 +1,82 @@
+using System.Collections.Generic;
+using System.Linq;
+using Spectre.Console.Rendering;
+
+namespace Spectre.Console
+{
+ ///
+ /// A renderable (horizontal) bar chart.
+ ///
+ public sealed class BarChart : Renderable
+ {
+ ///
+ /// Gets the bar chart data.
+ ///
+ public List Data { get; }
+
+ ///
+ /// Gets or sets the width of the bar chart.
+ ///
+ public int? Width { get; set; }
+
+ ///
+ /// Gets or sets the bar chart label.
+ ///
+ public string? Label { get; set; }
+
+ ///
+ /// Gets or sets the bar chart label alignment.
+ ///
+ public Justify? LabelAlignment { get; set; } = Justify.Center;
+
+ ///
+ /// Gets or sets a value indicating whether or not
+ /// values should be shown next to each bar.
+ ///
+ public bool ShowValues { get; set; } = true;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BarChart()
+ {
+ Data = new List();
+ }
+
+ ///
+ protected override IEnumerable Render(RenderContext context, int maxWidth)
+ {
+ var maxValue = Data.Max(item => item.Value);
+
+ var table = new Grid();
+ table.Collapse();
+ table.AddColumn(new GridColumn().PadRight(2).RightAligned());
+ table.AddColumn(new GridColumn().PadLeft(0));
+ table.Width = Width;
+
+ if (!string.IsNullOrWhiteSpace(Label))
+ {
+ table.AddRow(Text.Empty, new Markup(Label).Alignment(LabelAlignment));
+ }
+
+ foreach (var item in Data)
+ {
+ table.AddRow(
+ new Markup(item.Label),
+ new ProgressBar()
+ {
+ Value = item.Value,
+ MaxValue = maxValue,
+ ShowRemaining = false,
+ CompletedStyle = new Style().Foreground(item.Color ?? Color.Default),
+ FinishedStyle = new Style().Foreground(item.Color ?? Color.Default),
+ UnicodeBar = '█',
+ AsciiBar = '█',
+ ShowValue = ShowValues,
+ });
+ }
+
+ return ((IRenderable)table).Render(context, maxWidth);
+ }
+ }
+}
diff --git a/src/Spectre.Console/Widgets/BarChartItem.cs b/src/Spectre.Console/Widgets/BarChartItem.cs
new file mode 100644
index 0000000..094f036
--- /dev/null
+++ b/src/Spectre.Console/Widgets/BarChartItem.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace Spectre.Console
+{
+ ///
+ /// An item that's shown in a bar chart.
+ ///
+ public sealed class BarChartItem : IBarChartItem
+ {
+ ///
+ /// Gets the item label.
+ ///
+ public string Label { get; }
+
+ ///
+ /// Gets the item value.
+ ///
+ public double Value { get; }
+
+ ///
+ /// Gets the item color.
+ ///
+ public Color? Color { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The item label.
+ /// The item value.
+ /// The item color.
+ public BarChartItem(string label, double value, Color? color = null)
+ {
+ Label = label ?? throw new ArgumentNullException(nameof(label));
+ Value = value;
+ Color = color;
+ }
+ }
+}
diff --git a/src/Spectre.Console/Widgets/Grid.cs b/src/Spectre.Console/Widgets/Grid.cs
index 9fccaf9..7fedde1 100644
--- a/src/Spectre.Console/Widgets/Grid.cs
+++ b/src/Spectre.Console/Widgets/Grid.cs
@@ -42,6 +42,11 @@ namespace Spectre.Console
set => MarkAsDirty(() => _alignment = value);
}
+ ///
+ /// Gets or sets the width of the grid.
+ ///
+ public int? Width { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -124,6 +129,7 @@ namespace Spectre.Console
ShowHeaders = false,
IsGrid = true,
PadRightCell = _padRightCell,
+ Width = Width,
};
foreach (var column in _columns)
diff --git a/src/Spectre.Console/Widgets/IBarGraphItem.cs b/src/Spectre.Console/Widgets/IBarGraphItem.cs
new file mode 100644
index 0000000..3f8187c
--- /dev/null
+++ b/src/Spectre.Console/Widgets/IBarGraphItem.cs
@@ -0,0 +1,23 @@
+namespace Spectre.Console
+{
+ ///
+ /// Represents a bar chart item.
+ ///
+ public interface IBarChartItem
+ {
+ ///
+ /// Gets the item label.
+ ///
+ string Label { get; }
+
+ ///
+ /// Gets the item value.
+ ///
+ double Value { get; }
+
+ ///
+ /// Gets the item color.
+ ///
+ Color? Color { get; }
+ }
+}
diff --git a/src/Spectre.Console/Widgets/ProgressBar.cs b/src/Spectre.Console/Widgets/ProgressBar.cs
index 3c4e742..9fe16f4 100644
--- a/src/Spectre.Console/Widgets/ProgressBar.cs
+++ b/src/Spectre.Console/Widgets/ProgressBar.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using Spectre.Console.Rendering;
namespace Spectre.Console
@@ -10,6 +11,10 @@ namespace Spectre.Console
public double MaxValue { get; set; } = 100;
public int? Width { get; set; }
+ public bool ShowRemaining { get; set; } = true;
+ public char UnicodeBar { get; set; } = '━';
+ public char AsciiBar { get; set; } = '-';
+ public bool ShowValue { get; set; }
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow);
public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green);
@@ -26,15 +31,38 @@ namespace Spectre.Console
var width = Math.Min(Width ?? maxWidth, maxWidth);
var completed = Math.Min(MaxValue, Math.Max(0, Value));
- var token = !context.Unicode || context.LegacyConsole ? '-' : '━';
+ var token = !context.Unicode || context.LegacyConsole ? AsciiBar : UnicodeBar;
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));
+
+ var value = completed.ToString(CultureInfo.InvariantCulture);
+ if (ShowValue)
+ {
+ bars = bars - value.Length - 1;
+ }
+
yield return new Segment(new string(token, bars), style);
+ if (ShowValue)
+ {
+ yield return new Segment(" " + value, style);
+ }
+
if (bars < width)
{
- yield return new Segment(new string(token, width - bars), RemainingStyle);
+ var diff = width - bars;
+ if (ShowValue)
+ {
+ diff = diff - value.Length - 1;
+ if (diff <= 0)
+ {
+ yield break;
+ }
+ }
+
+ var remainingToken = ShowRemaining ? token : ' ';
+ yield return new Segment(new string(remainingToken, diff), RemainingStyle);
}
}
}