| // ProgressBox.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "../../../Common/IntToString.h" |
| #include "../../../Common/StringConvert.h" |
| |
| #include "FarUtils.h" |
| #include "ProgressBox.h" |
| |
| void CPercentPrinterState::ClearCurState() |
| { |
| Completed = 0; |
| Total = ((UInt64)(Int64)-1); |
| Files = 0; |
| FilesTotal = 0; |
| Command.Empty(); |
| FileName.Empty(); |
| } |
| |
| void CProgressBox::Init(const char *title) |
| { |
| _title = title; |
| _wasPrinted = false; |
| StartTick = GetTickCount(); |
| _prevTick = StartTick; |
| _prevElapsedSec = 0; |
| } |
| |
| static unsigned GetPower32(UInt32 val) |
| { |
| const unsigned kStart = 32; |
| UInt32 mask = ((UInt32)1 << (kStart - 1)); |
| for (unsigned i = kStart;; i--) |
| { |
| if (i == 0 || (val & mask) != 0) |
| return i; |
| mask >>= 1; |
| } |
| } |
| |
| static unsigned GetPower64(UInt64 val) |
| { |
| UInt32 high = (UInt32)(val >> 32); |
| if (high == 0) |
| return GetPower32((UInt32)val); |
| return GetPower32(high) + 32; |
| } |
| |
| static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider) |
| { |
| unsigned pow1 = GetPower64(mult1); |
| unsigned pow2 = GetPower64(mult2); |
| while (pow1 + pow2 > 64) |
| { |
| if (pow1 > pow2) { pow1--; mult1 >>= 1; } |
| else { pow2--; mult2 >>= 1; } |
| divider >>= 1; |
| } |
| UInt64 res = mult1 * mult2; |
| if (divider != 0) |
| res /= divider; |
| return res; |
| } |
| |
| #define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; } |
| |
| static void GetTimeString(UInt64 timeValue, char *s) |
| { |
| const UInt64 hours = timeValue / 3600; |
| UInt32 seconds = (UInt32)(timeValue - hours * 3600); |
| const UInt32 minutes = seconds / 60; |
| seconds %= 60; |
| if (hours > 99) |
| { |
| ConvertUInt64ToString(hours, s); |
| for (; *s != 0; s++); |
| } |
| else |
| { |
| const UInt32 hours32 = (UInt32)hours; |
| UINT_TO_STR_2(hours32) |
| } |
| *s++ = ':'; UINT_TO_STR_2(minutes) |
| *s++ = ':'; UINT_TO_STR_2(seconds) |
| *s = 0; |
| } |
| |
| void CProgressBox::ReduceString(const UString &src, AString &dest) |
| { |
| UnicodeStringToMultiByte2(dest, src, CP_OEMCP); |
| |
| if (dest.Len() <= MaxLen) |
| return; |
| unsigned len = FileName.Len(); |
| for (; len != 0;) |
| { |
| unsigned delta = len / 8; |
| if (delta == 0) |
| delta = 1; |
| len -= delta; |
| _tempU = FileName; |
| _tempU.Delete(len / 2, FileName.Len() - len); |
| _tempU.Insert(len / 2, L" . "); |
| UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP); |
| if (dest.Len() <= MaxLen) |
| return; |
| } |
| dest.Empty(); |
| } |
| |
| static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) |
| { |
| char temp[32]; |
| ConvertUInt64ToString(val, temp); |
| s += temp; |
| s.Add_Space(); |
| s += name; |
| } |
| |
| |
| static void PrintSize_bytes_Smart(AString &s, UInt64 val) |
| { |
| // Print_UInt64_and_String(s, val, "bytes"); |
| { |
| char temp[32]; |
| ConvertUInt64ToString(val, temp); |
| s += temp; |
| } |
| |
| if (val == 0) |
| return; |
| |
| unsigned numBits = 10; |
| char c = 'K'; |
| char temp[4] = { 'K', 'i', 'B', 0 }; |
| if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } |
| else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } |
| temp[0] = c; |
| s += " ("; |
| Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); |
| s += ')'; |
| } |
| |
| |
| static const unsigned kPercentsSize = 4; |
| |
| void CProgressBox::Print() |
| { |
| DWORD tick = GetTickCount(); |
| DWORD elapsedTicks = tick - StartTick; |
| DWORD elapsedSec = elapsedTicks / 1000; |
| |
| if (_wasPrinted) |
| { |
| if (elapsedSec == _prevElapsedSec) |
| { |
| if ((UInt32)(tick - _prevTick) < _tickStep) |
| return; |
| if (_printedState.IsEqualTo((const CPercentPrinterState &)*this)) |
| return; |
| } |
| } |
| |
| UInt64 cur = Completed; |
| UInt64 total = Total; |
| |
| if (!UseBytesForPercents) |
| { |
| cur = Files; |
| total = FilesTotal; |
| } |
| |
| { |
| _timeStr.Empty(); |
| _timeStr = "Elapsed time: "; |
| char s[40]; |
| GetTimeString(elapsedSec, s); |
| _timeStr += s; |
| |
| if (cur != 0) |
| { |
| UInt64 remainingTime = 0; |
| if (cur < total) |
| remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur); |
| UInt64 remainingSec = remainingTime / 1000; |
| _timeStr += " Remaining time: "; |
| |
| GetTimeString(remainingSec, s); |
| _timeStr += s; |
| } |
| } |
| |
| |
| { |
| _perc.Empty(); |
| char s[32]; |
| unsigned size; |
| { |
| UInt64 val = 0; |
| if (total != (UInt64)(Int64)-1 && total != 0) |
| val = cur * 100 / Total; |
| |
| ConvertUInt64ToString(val, s); |
| size = (unsigned)strlen(s); |
| s[size++] = '%'; |
| s[size] = 0; |
| } |
| |
| unsigned len = size; |
| while (len < kPercentsSize) |
| len = kPercentsSize; |
| len++; |
| |
| if (len < MaxLen) |
| { |
| unsigned numChars = MaxLen - len; |
| unsigned filled = 0; |
| if (total != (UInt64)(Int64)-1 && total != 0) |
| filled = (unsigned)(cur * numChars / total); |
| if (filled > numChars) |
| filled = numChars; |
| unsigned i = 0; |
| for (i = 0; i < filled; i++) |
| _perc += (char)(Byte)0xDB; // '='; |
| for (; i < numChars; i++) |
| _perc += (char)(Byte)0xB0; // '.'; |
| } |
| |
| _perc.Add_Space(); |
| while (size < kPercentsSize) |
| { |
| _perc.Add_Space(); |
| size++; |
| } |
| _perc += s; |
| } |
| |
| _files.Empty(); |
| if (Files != 0 || FilesTotal != 0) |
| { |
| _files += "Files: "; |
| char s[32]; |
| // if (Files != 0) |
| { |
| ConvertUInt64ToString(Files, s); |
| _files += s; |
| } |
| if (FilesTotal != 0) |
| { |
| _files += " / "; |
| ConvertUInt64ToString(FilesTotal, s); |
| _files += s; |
| } |
| } |
| |
| _sizesStr.Empty(); |
| if (Total != 0) |
| { |
| _sizesStr += "Size: "; |
| PrintSize_bytes_Smart(_sizesStr, Completed); |
| if (Total != 0 && Total != (UInt64)(Int64)-1) |
| { |
| _sizesStr += " / "; |
| PrintSize_bytes_Smart(_sizesStr, Total); |
| } |
| } |
| |
| _name1.Empty(); |
| _name2.Empty(); |
| |
| if (!FileName.IsEmpty()) |
| { |
| _name1U.Empty(); |
| _name2U.Empty(); |
| |
| /* |
| if (_isDir) |
| s1 = _filePath; |
| else |
| */ |
| { |
| const int slashPos = FileName.ReverseFind_PathSepar(); |
| if (slashPos >= 0) |
| { |
| _name1U.SetFrom(FileName, (unsigned)(slashPos + 1)); |
| _name2U = FileName.Ptr(slashPos + 1); |
| } |
| else |
| _name2U = FileName; |
| } |
| ReduceString(_name1U, _name1); |
| ReduceString(_name2U, _name2); |
| } |
| |
| { |
| const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc }; |
| NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0); |
| } |
| |
| _wasPrinted = true; |
| _printedState = *this; |
| _prevTick = tick; |
| _prevElapsedSec = elapsedSec; |
| } |