mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-24 04:02:50 +08:00
Add support for indeterminate progress
This commit also changes the behavior of ProgressContext.IsFinished. Only tasks that have been started will be taken into consideration, and not indeterminate tasks. Closes #329 Closes #331
This commit is contained in:
parent
6121203fee
commit
6f16081f42
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
@ -25,8 +26,12 @@ namespace ProgressExample
|
|||||||
.Start(ctx =>
|
.Start(ctx =>
|
||||||
{
|
{
|
||||||
var random = new Random(DateTime.Now.Millisecond);
|
var random = new Random(DateTime.Now.Millisecond);
|
||||||
var tasks = CreateTasks(ctx, random);
|
|
||||||
|
|
||||||
|
// Create some tasks
|
||||||
|
var tasks = CreateTasks(ctx, random);
|
||||||
|
var warpTask = ctx.AddTask("Going to warp", autoStart: false).IsIndeterminate();
|
||||||
|
|
||||||
|
// Wait for all tasks (except the indeterminate one) to complete
|
||||||
while (!ctx.IsFinished)
|
while (!ctx.IsFinished)
|
||||||
{
|
{
|
||||||
// Increment progress
|
// Increment progress
|
||||||
@ -44,13 +49,24 @@ namespace ProgressExample
|
|||||||
// Simulate some delay
|
// Simulate some delay
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now start the "warp" task
|
||||||
|
warpTask.StartTask();
|
||||||
|
warpTask.IsIndeterminate(false);
|
||||||
|
while (!ctx.IsFinished)
|
||||||
|
{
|
||||||
|
warpTask.Increment(12 * random.NextDouble());
|
||||||
|
|
||||||
|
// Simulate some delay
|
||||||
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
AnsiConsole.MarkupLine("[green]Done![/]");
|
AnsiConsole.MarkupLine("[green]Done![/]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<(ProgressTask, int)> CreateTasks(ProgressContext progress, Random random)
|
private static List<(ProgressTask Task, int Delay)> CreateTasks(ProgressContext progress, Random random)
|
||||||
{
|
{
|
||||||
var tasks = new List<(ProgressTask, int)>();
|
var tasks = new List<(ProgressTask, int)>();
|
||||||
while (tasks.Count < 5)
|
while (tasks.Count < 5)
|
||||||
|
@ -20,7 +20,7 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
public string Render()
|
public string Render()
|
||||||
{
|
{
|
||||||
var console = new FakeConsole();
|
var console = new FakeConsole();
|
||||||
var context = new RenderContext(console.Profile.Capabilities);
|
var context = new RenderContext(console.Profile.ColorSystem, console.Profile.Capabilities);
|
||||||
console.Write(Column.Render(context, Task, TimeSpan.Zero));
|
console.Write(Column.Render(context, Task, TimeSpan.Zero));
|
||||||
return console.Output;
|
return console.Output;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
|
var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Min.ShouldBe(6);
|
result.Min.ShouldBe(6);
|
||||||
@ -29,7 +29,7 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
|
var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Max.ShouldBe(11);
|
result.Max.ShouldBe(11);
|
||||||
|
@ -6,6 +6,17 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
internal static class EnumerableExtensions
|
internal static class EnumerableExtensions
|
||||||
{
|
{
|
||||||
|
public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int count)
|
||||||
|
{
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
foreach (var item in source)
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int IndexOf<T>(this IEnumerable<T> source, T item)
|
public static int IndexOf<T>(this IEnumerable<T> source, T item)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
|
@ -57,5 +57,22 @@ namespace Spectre.Console
|
|||||||
task.Value = value;
|
task.Value = value;
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether the task is considered indeterminate or not.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The task.</param>
|
||||||
|
/// <param name="indeterminate">Whether the task is considered indeterminate or not.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static ProgressTask IsIndeterminate(this ProgressTask task, bool indeterminate = true)
|
||||||
|
{
|
||||||
|
if (task is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
task.IsIndeterminate = indeterminate;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace Spectre.Console
|
|||||||
throw new ArgumentNullException(nameof(renderable));
|
throw new ArgumentNullException(nameof(renderable));
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = new RenderContext(console.Profile.Capabilities);
|
var context = new RenderContext(console.Profile.ColorSystem, console.Profile.Capabilities);
|
||||||
var renderables = console.Pipeline.Process(context, new[] { renderable });
|
var renderables = console.Pipeline.Process(context, new[] { renderable });
|
||||||
|
|
||||||
return GetSegments(console, context, renderables);
|
return GetSegments(console, context, renderables);
|
||||||
|
@ -9,7 +9,7 @@ namespace Spectre.Console.Internal
|
|||||||
{
|
{
|
||||||
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
|
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
|
||||||
{
|
{
|
||||||
var context = new RenderContext(EncoderCapabilities.Default);
|
var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default);
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n");
|
builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n");
|
||||||
|
@ -20,7 +20,7 @@ namespace Spectre.Console.Internal
|
|||||||
{
|
{
|
||||||
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
|
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
|
||||||
{
|
{
|
||||||
var context = new RenderContext(EncoderCapabilities.Default);
|
var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default);
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
foreach (var renderable in renderables)
|
foreach (var renderable in renderables)
|
||||||
|
@ -9,6 +9,11 @@ namespace Spectre.Console.Rendering
|
|||||||
{
|
{
|
||||||
private readonly IReadOnlyCapabilities _capabilities;
|
private readonly IReadOnlyCapabilities _capabilities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current color system.
|
||||||
|
/// </summary>
|
||||||
|
public ColorSystem ColorSystem { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether or not unicode is supported.
|
/// Gets a value indicating whether or not unicode is supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,17 +33,19 @@ namespace Spectre.Console.Rendering
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RenderContext"/> class.
|
/// Initializes a new instance of the <see cref="RenderContext"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="colorSystem">The color system.</param>
|
||||||
/// <param name="capabilities">The capabilities.</param>
|
/// <param name="capabilities">The capabilities.</param>
|
||||||
/// <param name="justification">The justification.</param>
|
/// <param name="justification">The justification.</param>
|
||||||
public RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null)
|
public RenderContext(ColorSystem colorSystem, IReadOnlyCapabilities capabilities, Justify? justification = null)
|
||||||
: this(capabilities, justification, false)
|
: this(colorSystem, capabilities, justification, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false)
|
private RenderContext(ColorSystem colorSystem, IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false)
|
||||||
{
|
{
|
||||||
_capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities));
|
_capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities));
|
||||||
|
|
||||||
|
ColorSystem = colorSystem;
|
||||||
Justification = justification;
|
Justification = justification;
|
||||||
SingleLine = singleLine;
|
SingleLine = singleLine;
|
||||||
}
|
}
|
||||||
@ -50,7 +57,7 @@ namespace Spectre.Console.Rendering
|
|||||||
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
|
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
|
||||||
public RenderContext WithJustification(Justify? justification)
|
public RenderContext WithJustification(Justify? justification)
|
||||||
{
|
{
|
||||||
return new RenderContext(_capabilities, justification, SingleLine);
|
return new RenderContext(ColorSystem, _capabilities, justification, SingleLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -65,7 +72,7 @@ namespace Spectre.Console.Rendering
|
|||||||
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
|
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
|
||||||
internal RenderContext WithSingleLine()
|
internal RenderContext WithSingleLine()
|
||||||
{
|
{
|
||||||
return new RenderContext(_capabilities, Justification, true);
|
return new RenderContext(ColorSystem, _capabilities, Justification, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,11 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey);
|
public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style of an indeterminate progress bar.
|
||||||
|
/// </summary>
|
||||||
|
public Style IndeterminateStyle { get; set; } = ProgressBar.DefaultPulseStyle;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
|
public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
|
||||||
{
|
{
|
||||||
@ -39,6 +44,8 @@ namespace Spectre.Console
|
|||||||
CompletedStyle = CompletedStyle,
|
CompletedStyle = CompletedStyle,
|
||||||
FinishedStyle = FinishedStyle,
|
FinishedStyle = FinishedStyle,
|
||||||
RemainingStyle = RemainingStyle,
|
RemainingStyle = RemainingStyle,
|
||||||
|
IndeterminateStyle = IndeterminateStyle,
|
||||||
|
IsIndeterminate = task.IsIndeterminate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@ namespace Spectre.Console
|
|||||||
private int _taskId;
|
private int _taskId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether or not all tasks have completed.
|
/// Gets a value indicating whether or not all started tasks have completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsFinished => _tasks.All(task => task.IsFinished);
|
public bool IsFinished => _tasks.Where(x => x.IsStarted).All(task => task.IsFinished);
|
||||||
|
|
||||||
internal ProgressContext(IAnsiConsole console, ProgressRenderer renderer)
|
internal ProgressContext(IAnsiConsole console, ProgressRenderer renderer)
|
||||||
{
|
{
|
||||||
@ -28,20 +28,41 @@ namespace Spectre.Console
|
|||||||
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="autoStart">Whether or not the task should start immediately.</param>
|
||||||
|
/// <param name="maxValue">The task's max value.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTask(string description, bool autoStart = true, double maxValue = 100)
|
||||||
|
{
|
||||||
|
return AddTask(description, new ProgressTaskSettings
|
||||||
|
{
|
||||||
|
AutoStart = autoStart,
|
||||||
|
MaxValue = maxValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a task.
|
/// Adds a task.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="description">The task description.</param>
|
/// <param name="description">The task description.</param>
|
||||||
/// <param name="settings">The task settings.</param>
|
/// <param name="settings">The task settings.</param>
|
||||||
/// <returns>The newly created task.</returns>
|
/// <returns>The newly created task.</returns>
|
||||||
public ProgressTask AddTask(string description, ProgressTaskSettings? settings = null)
|
public ProgressTask AddTask(string description, ProgressTaskSettings settings)
|
||||||
{
|
{
|
||||||
|
if (settings is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
lock (_taskLock)
|
lock (_taskLock)
|
||||||
{
|
{
|
||||||
settings ??= new ProgressTaskSettings();
|
|
||||||
var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart);
|
var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart);
|
||||||
|
|
||||||
_tasks.Add(task);
|
_tasks.Add(task);
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,12 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan? RemainingTime => GetRemainingTime();
|
public TimeSpan? RemainingTime => GetRemainingTime();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the ProgressBar shows
|
||||||
|
/// actual values or generic, continuous progress feedback.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsIndeterminate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ProgressTask"/> class.
|
/// Initializes a new instance of the <see cref="ProgressTask"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -16,5 +16,10 @@ namespace Spectre.Console
|
|||||||
/// will be auto started. Defaults to <c>true</c>.
|
/// will be auto started. Defaults to <c>true</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AutoStart { get; set; } = true;
|
public bool AutoStart { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default progress task settings.
|
||||||
|
/// </summary>
|
||||||
|
internal static ProgressTaskSettings Default { get; } = new ProgressTaskSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ namespace Spectre.Console
|
|||||||
_stopwatch.Start();
|
_stopwatch.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
var renderContext = new RenderContext(_console.Profile.Capabilities);
|
var renderContext = new RenderContext(_console.Profile.ColorSystem, _console.Profile.Capabilities);
|
||||||
|
|
||||||
var delta = _stopwatch.Elapsed - _lastUpdate;
|
var delta = _stopwatch.Elapsed - _lastUpdate;
|
||||||
_lastUpdate = _stopwatch.Elapsed;
|
_lastUpdate = _stopwatch.Elapsed;
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
{
|
{
|
||||||
internal sealed class ProgressBar : Renderable, IHasCulture
|
internal sealed class ProgressBar : Renderable, IHasCulture
|
||||||
{
|
{
|
||||||
|
private const int PULSESIZE = 20;
|
||||||
|
private const int PULSESPEED = 15;
|
||||||
|
|
||||||
public double Value { get; set; }
|
public double Value { get; set; }
|
||||||
public double MaxValue { get; set; } = 100;
|
public double MaxValue { get; set; } = 100;
|
||||||
|
|
||||||
@ -15,11 +19,15 @@ namespace Spectre.Console
|
|||||||
public char UnicodeBar { get; set; } = '━';
|
public char UnicodeBar { get; set; } = '━';
|
||||||
public char AsciiBar { get; set; } = '-';
|
public char AsciiBar { get; set; } = '-';
|
||||||
public bool ShowValue { get; set; }
|
public bool ShowValue { get; set; }
|
||||||
|
public bool IsIndeterminate { get; set; }
|
||||||
public CultureInfo? Culture { get; set; }
|
public CultureInfo? Culture { get; set; }
|
||||||
|
|
||||||
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow);
|
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow);
|
||||||
public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green);
|
public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green);
|
||||||
public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey);
|
public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey);
|
||||||
|
public Style IndeterminateStyle { get; set; } = DefaultPulseStyle;
|
||||||
|
|
||||||
|
internal static Style DefaultPulseStyle { get; } = new Style(foreground: Color.DodgerBlue1, background: Color.Grey23);
|
||||||
|
|
||||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
@ -30,43 +38,49 @@ namespace Spectre.Console
|
|||||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
var width = Math.Min(Width ?? maxWidth, maxWidth);
|
var width = Math.Min(Width ?? maxWidth, maxWidth);
|
||||||
var completed = Math.Min(MaxValue, Math.Max(0, Value));
|
var completedBarCount = Math.Min(MaxValue, Math.Max(0, Value));
|
||||||
|
var isCompleted = completedBarCount >= MaxValue;
|
||||||
|
|
||||||
var token = !context.Unicode ? AsciiBar : UnicodeBar;
|
if (IsIndeterminate && !isCompleted)
|
||||||
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
|
|
||||||
|
|
||||||
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));
|
|
||||||
|
|
||||||
var value = completed.ToString(Culture ?? CultureInfo.InvariantCulture);
|
|
||||||
if (ShowValue)
|
|
||||||
{
|
{
|
||||||
bars = bars - value.Length - 1;
|
foreach (var segment in RenderIndeterminate(context, width))
|
||||||
bars = Math.Max(0, bars);
|
{
|
||||||
|
yield return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bars < 0)
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bar = !context.Unicode ? AsciiBar : UnicodeBar;
|
||||||
|
var style = isCompleted ? FinishedStyle : CompletedStyle;
|
||||||
|
var barCount = Math.Max(0, (int)(width * (completedBarCount / MaxValue)));
|
||||||
|
|
||||||
|
// Show value?
|
||||||
|
var value = completedBarCount.ToString(Culture ?? CultureInfo.InvariantCulture);
|
||||||
|
if (ShowValue)
|
||||||
|
{
|
||||||
|
barCount = barCount - value.Length - 1;
|
||||||
|
barCount = Math.Max(0, barCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barCount < 0)
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new Segment(new string(token, bars), style);
|
yield return new Segment(new string(bar, barCount), style);
|
||||||
|
|
||||||
if (ShowValue)
|
if (ShowValue)
|
||||||
{
|
{
|
||||||
// TODO: Fix this at some point
|
yield return barCount == 0
|
||||||
if (bars == 0)
|
? new Segment(value, style)
|
||||||
{
|
: new Segment(" " + value, style);
|
||||||
yield return new Segment(value, style);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yield return new Segment(" " + value, style);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bars < width)
|
// More space available?
|
||||||
|
if (barCount < width)
|
||||||
{
|
{
|
||||||
var diff = width - bars;
|
var diff = width - barCount;
|
||||||
if (ShowValue)
|
if (ShowValue)
|
||||||
{
|
{
|
||||||
diff = diff - value.Length - 1;
|
diff = diff - value.Length - 1;
|
||||||
@ -76,9 +90,59 @@ namespace Spectre.Console
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var remainingToken = ShowRemaining ? token : ' ';
|
var legacy = context.ColorSystem == ColorSystem.NoColors || context.ColorSystem == ColorSystem.Legacy;
|
||||||
|
var remainingToken = ShowRemaining && !legacy ? bar : ' ';
|
||||||
yield return new Segment(new string(remainingToken, diff), RemainingStyle);
|
yield return new Segment(new string(remainingToken, diff), RemainingStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Segment> RenderIndeterminate(RenderContext context, int width)
|
||||||
|
{
|
||||||
|
var bar = context.Unicode ? UnicodeBar.ToString() : AsciiBar.ToString();
|
||||||
|
var style = IndeterminateStyle ?? DefaultPulseStyle;
|
||||||
|
|
||||||
|
IEnumerable<Segment> GetPulseSegments()
|
||||||
|
{
|
||||||
|
// For 1-bit and 3-bit colors, fall back to
|
||||||
|
// a simpler versions with only two colors.
|
||||||
|
if (context.ColorSystem == ColorSystem.NoColors ||
|
||||||
|
context.ColorSystem == ColorSystem.Legacy)
|
||||||
|
{
|
||||||
|
// First half of the pulse
|
||||||
|
var segments = Enumerable.Repeat(new Segment(bar, new Style(style.Foreground)), PULSESIZE / 2);
|
||||||
|
|
||||||
|
// Second half of the pulse
|
||||||
|
var legacy = context.ColorSystem == ColorSystem.NoColors || context.ColorSystem == ColorSystem.Legacy;
|
||||||
|
var bar2 = legacy ? " " : bar;
|
||||||
|
segments = segments.Concat(Enumerable.Repeat(new Segment(bar2, new Style(style.Background)), PULSESIZE - (PULSESIZE / 2)));
|
||||||
|
|
||||||
|
foreach (var segment in segments)
|
||||||
|
{
|
||||||
|
yield return segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var index = 0; index < PULSESIZE; index++)
|
||||||
|
{
|
||||||
|
var position = index / (float)PULSESIZE;
|
||||||
|
var fade = 0.5f + ((float)Math.Cos(position * Math.PI * 2) / 2.0f);
|
||||||
|
var color = style.Foreground.Blend(style.Background, fade);
|
||||||
|
|
||||||
|
yield return new Segment(bar, new Style(foreground: color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the pulse segments
|
||||||
|
var pulseSegments = GetPulseSegments();
|
||||||
|
pulseSegments = pulseSegments.Repeat((width / PULSESIZE) + 2);
|
||||||
|
|
||||||
|
// Repeat the pulse segments
|
||||||
|
var currentTime = (DateTime.Now - DateTime.Today).TotalSeconds;
|
||||||
|
var offset = (int)(currentTime * PULSESPEED) % PULSESIZE;
|
||||||
|
|
||||||
|
return pulseSegments.Skip(offset).Take(width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user