-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProgressBar.cs
More file actions
99 lines (82 loc) · 2.82 KB
/
ProgressBar.cs
File metadata and controls
99 lines (82 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Confirmator
{
public class ProgressBar : IDisposable, IProgress<double>
{
private const int blockCount = 10;
private readonly TimeSpan animationInterval = TimeSpan.FromSeconds(1.0 / 8);
private const string animation = @"┐┘└┌";
private readonly Timer timer;
private double currentProgress = 0;
private string currentText = string.Empty;
private bool disposed = false;
private int animationIndex = 0;
private string customLabel = null;
public ProgressBar() {
timer = new Timer( TimerHandler );
// A progress bar is only for temporary display in a console window.
// If the console output is redirected to a file, draw nothing.
// Otherwise, we'll end up with a lot of garbage in the target file.
if ( !Console.IsOutputRedirected ) {
ResetTimer();
}
}
public void Report( double value ) {
// Make sure value is in [0..1] range
value = Math.Max( 0, Math.Min( 1, value ) );
Interlocked.Exchange( ref currentProgress, value );
}
private void TimerHandler( object state ) {
lock ( timer ) {
if ( disposed ) return;
int progressBlockCount = (int) (currentProgress * blockCount);
int percent = (int) (currentProgress * 100);
string text = string.Format("[{0}{1}] "+(customLabel == null ?"{2,3}%":"{3}")+" {4}",
new string('▓', progressBlockCount), new string('░', blockCount - progressBlockCount),
percent,
customLabel,
animation[animationIndex++ % animation.Length]);
UpdateText( text );
ResetTimer();
}
}
public void setCustomLabel(string text) {
customLabel = text;
}
private void UpdateText( string text ) {
// Get length of common portion
int commonPrefixLength = 0;
int commonLength = Math.Min(currentText.Length, text.Length);
while ( commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength] ) {
commonPrefixLength++;
}
// Backtrack to the first differing character
StringBuilder outputBuilder = new StringBuilder();
outputBuilder.Append( '\b', currentText.Length - commonPrefixLength );
// Output new suffix
outputBuilder.Append( text.Substring( commonPrefixLength ) );
// If the new text is shorter than the old one: delete overlapping characters
int overlapCount = currentText.Length - text.Length;
if ( overlapCount > 0 ) {
outputBuilder.Append( ' ', overlapCount );
outputBuilder.Append( '\b', overlapCount );
}
Console.Write( outputBuilder );
currentText = text;
}
private void ResetTimer() {
timer.Change( animationInterval, TimeSpan.FromMilliseconds( -1 ) );
}
public void Dispose() {
lock ( timer ) {
disposed = true;
UpdateText( string.Empty );
}
}
}
}