blob: ab25a104b779bacb71a2aa0fae12701f60fc1a45 [file] [log] [blame]
// 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;
}