1 // ProgressBox.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7
8 #include "FarUtils.h"
9 #include "ProgressBox.h"
10
ClearCurState()11 void CPercentPrinterState::ClearCurState()
12 {
13 Completed = 0;
14 Total = ((UInt64)(Int64)-1);
15 Files = 0;
16 FilesTotal = 0;
17 Command.Empty();
18 FileName.Empty();
19 }
20
Init(const char * title)21 void CProgressBox::Init(const char *title)
22 {
23 _title = title;
24 _wasPrinted = false;
25 StartTick = GetTickCount();
26 _prevTick = StartTick;
27 _prevElapsedSec = 0;
28 }
29
GetPower32(UInt32 val)30 static unsigned GetPower32(UInt32 val)
31 {
32 const unsigned kStart = 32;
33 UInt32 mask = ((UInt32)1 << (kStart - 1));
34 for (unsigned i = kStart;; i--)
35 {
36 if (i == 0 || (val & mask) != 0)
37 return i;
38 mask >>= 1;
39 }
40 }
41
GetPower64(UInt64 val)42 static unsigned GetPower64(UInt64 val)
43 {
44 UInt32 high = (UInt32)(val >> 32);
45 if (high == 0)
46 return GetPower32((UInt32)val);
47 return GetPower32(high) + 32;
48 }
49
MyMultAndDiv(UInt64 mult1,UInt64 mult2,UInt64 divider)50 static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
51 {
52 unsigned pow1 = GetPower64(mult1);
53 unsigned pow2 = GetPower64(mult2);
54 while (pow1 + pow2 > 64)
55 {
56 if (pow1 > pow2) { pow1--; mult1 >>= 1; }
57 else { pow2--; mult2 >>= 1; }
58 divider >>= 1;
59 }
60 UInt64 res = mult1 * mult2;
61 if (divider != 0)
62 res /= divider;
63 return res;
64 }
65
66 #define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; }
67
GetTimeString(UInt64 timeValue,char * s)68 static void GetTimeString(UInt64 timeValue, char *s)
69 {
70 const UInt64 hours = timeValue / 3600;
71 UInt32 seconds = (UInt32)(timeValue - hours * 3600);
72 const UInt32 minutes = seconds / 60;
73 seconds %= 60;
74 if (hours > 99)
75 {
76 ConvertUInt64ToString(hours, s);
77 for (; *s != 0; s++);
78 }
79 else
80 {
81 const UInt32 hours32 = (UInt32)hours;
82 UINT_TO_STR_2(hours32)
83 }
84 *s++ = ':'; UINT_TO_STR_2(minutes)
85 *s++ = ':'; UINT_TO_STR_2(seconds)
86 *s = 0;
87 }
88
ReduceString(const UString & src,AString & dest)89 void CProgressBox::ReduceString(const UString &src, AString &dest)
90 {
91 UnicodeStringToMultiByte2(dest, src, CP_OEMCP);
92
93 if (dest.Len() <= MaxLen)
94 return;
95 unsigned len = FileName.Len();
96 for (; len != 0;)
97 {
98 unsigned delta = len / 8;
99 if (delta == 0)
100 delta = 1;
101 len -= delta;
102 _tempU = FileName;
103 _tempU.Delete(len / 2, FileName.Len() - len);
104 _tempU.Insert(len / 2, L" . ");
105 UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP);
106 if (dest.Len() <= MaxLen)
107 return;
108 }
109 dest.Empty();
110 }
111
Print_UInt64_and_String(AString & s,UInt64 val,const char * name)112 static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
113 {
114 char temp[32];
115 ConvertUInt64ToString(val, temp);
116 s += temp;
117 s.Add_Space();
118 s += name;
119 }
120
121
PrintSize_bytes_Smart(AString & s,UInt64 val)122 static void PrintSize_bytes_Smart(AString &s, UInt64 val)
123 {
124 // Print_UInt64_and_String(s, val, "bytes");
125 {
126 char temp[32];
127 ConvertUInt64ToString(val, temp);
128 s += temp;
129 }
130
131 if (val == 0)
132 return;
133
134 unsigned numBits = 10;
135 char c = 'K';
136 char temp[4] = { 'K', 'i', 'B', 0 };
137 if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
138 else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
139 temp[0] = c;
140 s += " (";
141 Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
142 s += ')';
143 }
144
145
146 static const unsigned kPercentsSize = 4;
147
Print()148 void CProgressBox::Print()
149 {
150 DWORD tick = GetTickCount();
151 DWORD elapsedTicks = tick - StartTick;
152 DWORD elapsedSec = elapsedTicks / 1000;
153
154 if (_wasPrinted)
155 {
156 if (elapsedSec == _prevElapsedSec)
157 {
158 if ((UInt32)(tick - _prevTick) < _tickStep)
159 return;
160 if (_printedState.IsEqualTo((const CPercentPrinterState &)*this))
161 return;
162 }
163 }
164
165 UInt64 cur = Completed;
166 UInt64 total = Total;
167
168 if (!UseBytesForPercents)
169 {
170 cur = Files;
171 total = FilesTotal;
172 }
173
174 {
175 _timeStr.Empty();
176 _timeStr = "Elapsed time: ";
177 char s[40];
178 GetTimeString(elapsedSec, s);
179 _timeStr += s;
180
181 if (cur != 0)
182 {
183 UInt64 remainingTime = 0;
184 if (cur < total)
185 remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur);
186 UInt64 remainingSec = remainingTime / 1000;
187 _timeStr += " Remaining time: ";
188
189 GetTimeString(remainingSec, s);
190 _timeStr += s;
191 }
192 }
193
194
195 {
196 _perc.Empty();
197 char s[32];
198 unsigned size;
199 {
200 UInt64 val = 0;
201 if (total != (UInt64)(Int64)-1 && total != 0)
202 val = cur * 100 / Total;
203
204 ConvertUInt64ToString(val, s);
205 size = (unsigned)strlen(s);
206 s[size++] = '%';
207 s[size] = 0;
208 }
209
210 unsigned len = size;
211 while (len < kPercentsSize)
212 len = kPercentsSize;
213 len++;
214
215 if (len < MaxLen)
216 {
217 unsigned numChars = MaxLen - len;
218 unsigned filled = 0;
219 if (total != (UInt64)(Int64)-1 && total != 0)
220 filled = (unsigned)(cur * numChars / total);
221 if (filled > numChars)
222 filled = numChars;
223 unsigned i = 0;
224 for (i = 0; i < filled; i++)
225 _perc += (char)(Byte)0xDB; // '=';
226 for (; i < numChars; i++)
227 _perc += (char)(Byte)0xB0; // '.';
228 }
229
230 _perc.Add_Space();
231 while (size < kPercentsSize)
232 {
233 _perc.Add_Space();
234 size++;
235 }
236 _perc += s;
237 }
238
239 _files.Empty();
240 if (Files != 0 || FilesTotal != 0)
241 {
242 _files += "Files: ";
243 char s[32];
244 // if (Files != 0)
245 {
246 ConvertUInt64ToString(Files, s);
247 _files += s;
248 }
249 if (FilesTotal != 0)
250 {
251 _files += " / ";
252 ConvertUInt64ToString(FilesTotal, s);
253 _files += s;
254 }
255 }
256
257 _sizesStr.Empty();
258 if (Total != 0)
259 {
260 _sizesStr += "Size: ";
261 PrintSize_bytes_Smart(_sizesStr, Completed);
262 if (Total != 0 && Total != (UInt64)(Int64)-1)
263 {
264 _sizesStr += " / ";
265 PrintSize_bytes_Smart(_sizesStr, Total);
266 }
267 }
268
269 _name1.Empty();
270 _name2.Empty();
271
272 if (!FileName.IsEmpty())
273 {
274 _name1U.Empty();
275 _name2U.Empty();
276
277 /*
278 if (_isDir)
279 s1 = _filePath;
280 else
281 */
282 {
283 const int slashPos = FileName.ReverseFind_PathSepar();
284 if (slashPos >= 0)
285 {
286 _name1U.SetFrom(FileName, (unsigned)(slashPos + 1));
287 _name2U = FileName.Ptr(slashPos + 1);
288 }
289 else
290 _name2U = FileName;
291 }
292 ReduceString(_name1U, _name1);
293 ReduceString(_name2U, _name2);
294 }
295
296 {
297 const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc };
298 NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0);
299 }
300
301 _wasPrinted = true;
302 _printedState = *this;
303 _prevTick = tick;
304 _prevElapsedSec = elapsedSec;
305 }
306