From 17dcbaab9a2b967a57e3d0a31fa11a28ee5dcf52 Mon Sep 17 00:00:00 2001 From: Mpdreamz Date: Sat, 25 Aug 2018 12:40:05 +0200 Subject: [PATCH] Add FixedDurationBar subclass of ProgressBar for the cases where you want to display a progress with a well known fixed duration --- README.md | 10 +++++ .../Examples/FixedDurationExample.cs | 39 +++++++++++++++++++ src/ShellProgressBar.Example/Program.cs | 3 +- src/ShellProgressBar/FixedDurationBar.cs | 37 ++++++++++++++++++ src/ShellProgressBar/ProgressBar.cs | 7 +++- src/ShellProgressBar/ShellProgressBar.csproj | 14 +++---- 6 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 src/ShellProgressBar.Example/Examples/FixedDurationExample.cs create mode 100644 src/ShellProgressBar/FixedDurationBar.cs diff --git a/README.md b/README.md index 114e9e8..20c988f 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,16 @@ var childOptions = new ProgressBarOptions ![children_no_collapse](https://github.com/Mpdreamz/shellprogressbar/raw/master/doc/children-no-collapse-windows.gif) + +# FixedDurationBar + +`ProgressBar` is great for visualizing tasks with an unknown runtime. If you have a task that you know takes a fixed amount of time there is also a `FixedDurationBar` subclass. +`FixedDurationBar` will `Tick()` automatically but other then that all the options and usage are the same. Except it relies on the real time update feature so disabling that +will throw. + +`FixedDurationBar` exposes an `IsCompleted` and `CompletedHandle` + + ### Credits The initial implementation was inspired by this article. diff --git a/src/ShellProgressBar.Example/Examples/FixedDurationExample.cs b/src/ShellProgressBar.Example/Examples/FixedDurationExample.cs new file mode 100644 index 0000000..96669c8 --- /dev/null +++ b/src/ShellProgressBar.Example/Examples/FixedDurationExample.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading; + +namespace ShellProgressBar.Example.Examples +{ + public class FixedDurationExample : ExampleBase + { + protected override void Start() + { + var options = new ProgressBarOptions + { + ForegroundColor = ConsoleColor.Yellow, + ForegroundColorDone = ConsoleColor.DarkGreen, + BackgroundColor = ConsoleColor.DarkGray, + BackgroundCharacter = '\u2593' + }; + var wait = TimeSpan.FromSeconds(25); + using (var pbar = new FixedDurationBar(wait, "", options)) + { + var t = new Thread(()=> LongRunningTask(pbar)); + t.Start(); + + if (!pbar.CompletedHandle.WaitOne(wait)) + Console.Error.WriteLine($"{nameof(FixedDurationBar)} did not signal {nameof(FixedDurationBar.CompletedHandle)} after {wait}"); + + } + } + + private static void LongRunningTask(FixedDurationBar bar) + { + for (var i = 0; i < 1_000_000; i++) + { + bar.Message = $"{i} events"; + if (bar.IsCompleted) break; + Thread.Sleep(1); + } + } + } +} diff --git a/src/ShellProgressBar.Example/Program.cs b/src/ShellProgressBar.Example/Program.cs index fecb9a0..8dca6aa 100644 --- a/src/ShellProgressBar.Example/Program.cs +++ b/src/ShellProgressBar.Example/Program.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -14,6 +12,7 @@ class Program { private static readonly IList TestCases = new List { + new FixedDurationExample(), new DeeplyNestedProgressBarTreeExample(), new NestedProgressBarPerStepProgress(), new DrawsOnlyOnTickExample(), diff --git a/src/ShellProgressBar/FixedDurationBar.cs b/src/ShellProgressBar/FixedDurationBar.cs new file mode 100644 index 0000000..847a08d --- /dev/null +++ b/src/ShellProgressBar/FixedDurationBar.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading; + +namespace ShellProgressBar +{ + public class FixedDurationBar : ProgressBar + { + public bool IsCompleted { get; private set; } + + private readonly ManualResetEvent _completedHandle = new ManualResetEvent(false); + public WaitHandle CompletedHandle => _completedHandle; + + public FixedDurationBar(TimeSpan duration, string message, ConsoleColor color) : this(duration, message, new ProgressBarOptions {ForegroundColor = color}) { } + + public FixedDurationBar(TimeSpan duration, string message, ProgressBarOptions options = null) : base((int)Math.Ceiling(duration.TotalSeconds), message, options) + { + if (!this.Options.DisplayTimeInRealTime) + throw new ArgumentException( + $"{nameof(ProgressBarOptions)}.{nameof(ProgressBarOptions.DisplayTimeInRealTime)} has to be true for {nameof(FixedDurationBar)}", nameof(options) + ); + } + + private long _seenTicks = 0; + protected override void OnTimerTick() + { + Interlocked.Increment(ref _seenTicks); + if (_seenTicks % 2 == 0) this.Tick(); + base.OnTimerTick(); + } + + protected override void OnDone() + { + this.IsCompleted = true; + this._completedHandle.Set(); + } + } +} diff --git a/src/ShellProgressBar/ProgressBar.cs b/src/ShellProgressBar/ProgressBar.cs index c4546f6..27b1e98 100644 --- a/src/ShellProgressBar/ProgressBar.cs +++ b/src/ShellProgressBar/ProgressBar.cs @@ -40,7 +40,7 @@ public ProgressBar(int maxTicks, string message, ProgressBarOptions options = nu TaskbarProgress.SetState(TaskbarProgress.TaskbarStates.Normal); if (this.Options.DisplayTimeInRealTime) - _timer = new Timer((s) => DisplayProgress(), null, 500, 500); + _timer = new Timer((s) => OnTimerTick(), null, 500, 500); else //draw once _timer = new Timer((s) => { @@ -67,6 +67,11 @@ public ProgressBar(int maxTicks, string message, ProgressBarOptions options = nu }); } + protected virtual void OnTimerTick() + { + DisplayProgress(); + } + protected override void Grow(ProgressBarHeight direction) { switch (direction) diff --git a/src/ShellProgressBar/ShellProgressBar.csproj b/src/ShellProgressBar/ShellProgressBar.csproj index 19fdabf..829003d 100644 --- a/src/ShellProgressBar/ShellProgressBar.csproj +++ b/src/ShellProgressBar/ShellProgressBar.csproj @@ -6,13 +6,13 @@ netstandard1.3;netstandard2.0 - ShellProgressBar - Cross platform simple and complex progressbars on the command line! - Martijn Laarman - http://mpdreamz.mit-license.org/ - https://github.com/Mpdreamz/shellprogressbar - https://raw.github.com/Mpdreamz/shellprogressbar/master/src/nuget-icon.png - console;shell;terminal;progress;progressbar + ShellProgressBar + Cross platform simple and complex progressbars on the command line! + Martijn Laarman + http://mpdreamz.mit-license.org/ + https://github.com/Mpdreamz/shellprogressbar + https://raw.github.com/Mpdreamz/shellprogressbar/master/src/nuget-icon.png + console;shell;terminal;progress;progressbar