ProgressBar.cs
5.6 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2017. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
#if UNITY_EDITOR
using UnityEditor;
#endif
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Leap.Unity {
/// <summary>
/// This interface describes a generic way to update the progress of an action.
/// </summary>
public interface IProgressView {
/// <summary>
/// Clears the progress view. Is called if the action has been completed
/// or canceled.
/// </summary>
void Clear();
/// <summary>
/// Updates the progress view with some title text, information, and a
/// progress percentage that ranges from 0 to 1.
/// </summary>
void DisplayProgress(string title, string info, float progress);
}
#if UNITY_EDITOR
/// <summary>
/// An example progress view that uses the simple EditorUtility methods to
/// provide a developer with progress of an editor action.
/// </summary>
public class EditorProgressView : IProgressView {
/// <summary>
/// Gets a reference to a singleton instance of the EditorProgressView.
/// This is safe because EditorProgressView is stateless.
/// </summary>
public static readonly EditorProgressView Single = new EditorProgressView();
public void Clear() {
EditorUtility.ClearProgressBar();
}
public void DisplayProgress(string title, string info, float progress) {
EditorUtility.DisplayProgressBar(title, info, progress);
}
}
#endif
/// <summary>
/// This class allows you to easily give feedback of an action as
/// it completes.
///
/// The progress bar is represented as a single 'Chunk' that is made
/// of a certain number of sections. The progress bar is hierarchical,
/// and so each section can itself be another chunk.
/// </summary>
public class ProgressBar {
private List<int> chunks = new List<int>();
private List<int> progress = new List<int>();
private List<string> titleStrings = new List<string>();
private List<string> infoStrings = new List<string>();
private Stopwatch stopwatch = new Stopwatch();
private IProgressView _view;
#if UNITY_EDITOR
/// <summary>
/// Constructs a new progress bar given a default EditorProgressView.
/// You can use this constructor whenever you want to give progress
/// feedback to a Unity developer about an editor action that might
/// take some time to complete.
/// </summary>
public ProgressBar() : this(EditorProgressView.Single) { }
#endif
/// <summary>
/// Constructs a new progress bar given a progress view object
/// that will display the progress information for this progress
/// bar.
/// </summary>
public ProgressBar(IProgressView view) {
_view = view;
}
/// <summary>
/// Begins a new chunk. If this call is made from within a chunk it
/// will generate a sub-chunk that represents a single step in the
/// parent chunk.
///
/// You must specify the number of sections this chunk contains.
/// All title and info strings will be concatenated together when
/// the progress bar is displayed.
///
/// You must specify a delegate that represents the action performed
/// by this chunk. This delegate is allowed to call both Begin and
/// StepProgress to progress through its work.
/// </summary>
public void Begin(int sections, string title, string info, Action action) {
if (!stopwatch.IsRunning) {
stopwatch.Reset();
stopwatch.Start();
}
chunks.Add(sections);
progress.Add(0);
titleStrings.Add(title);
infoStrings.Add(info);
try {
action();
} finally {
int lastIndex = chunks.Count - 1;
chunks.RemoveAt(lastIndex);
progress.RemoveAt(lastIndex);
titleStrings.RemoveAt(lastIndex);
infoStrings.RemoveAt(lastIndex);
lastIndex--;
if (lastIndex >= 0) {
progress[lastIndex]++;
}
if (chunks.Count == 0) {
_view.Clear();
stopwatch.Stop();
}
}
}
/// <summary>
/// Steps through one section of the current chunk. You can provide
/// an optional info string that will be concatenated to the current
/// info string before progress is displayed.
/// </summary>
public void Step(string infoString = "") {
progress[progress.Count - 1]++;
if (stopwatch.ElapsedMilliseconds > 17) {
displayBar(infoString);
stopwatch.Reset();
stopwatch.Start();
}
}
private void displayBar(string info = "") {
float percent = 0.0f;
float fraction = 1.0f;
string titleString = "";
string infoString = "";
for (int i = 0; i < chunks.Count; i++) {
float chunkSize = chunks[i];
float chunkProgress = progress[i];
percent += fraction * (chunkProgress / chunkSize);
fraction /= chunkSize;
titleString += titleStrings[i];
infoString += infoStrings[i];
}
infoString += info;
_view.DisplayProgress(titleString, infoString, percent);
}
}
}