ultimatepp/uppbox/WinInstaller/Progress.cpp

440 lines
10 KiB
C++

#include "Install.h"
#include <commctrl.h>
//////////////////////////////////////////////////////////////////////
ProgressMeter::ProgressMeter(int chunk, const char *text, int total, int flags, HWND parent)
: chunk(chunk)
, text(text)
, total(total)
, parent(parent)
, flags(flags)
, window(0)
, pos(0)
, cancel(false)
, caption("Working...")
, next_ticks(0)
{
}
//////////////////////////////////////////////////////////////////////
ProgressMeter::ProgressMeter(const char *title, int step, int total, int flags, HWND parent)
: chunk(step)
, text(title)
, total(total)
, parent(parent)
, flags(flags)
, window(0)
, pos(0)
, cancel(false)
, caption("Working...")
, next_ticks(0)
{
}
//////////////////////////////////////////////////////////////////////
ProgressMeter::~ProgressMeter()
{
Destroy();
}
//////////////////////////////////////////////////////////////////////
LRESULT CALLBACK ProgressMeter::StaticProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_CREATE)
{
CREATESTRUCT *pp = (CREATESTRUCT *)lParam;
ASSERT(pp -> lpCreateParams);
SetWindowLong(hwnd, GWL_USERDATA, (long)pp -> lpCreateParams);
((ProgressMeter *)pp -> lpCreateParams) -> window = hwnd;
}
ProgressMeter *pp = (ProgressMeter *)GetWindowLong(hwnd, GWL_USERDATA);
if(pp)
return pp -> Proc(message, wParam, lParam);
else
return DefWindowProc(hwnd, message, wParam, lParam);
}
//////////////////////////////////////////////////////////////////////
LRESULT ProgressMeter::Proc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
cancel = false;
break;
case WM_KEYDOWN:
if(IsAllowCancel() && wParam == VK_ESCAPE)
{
cancel = true;
Destroy();
return 0;
}
break;
case WM_COMMAND:
if(IsAllowCancel() && LOWORD(wParam) == IDCANCEL)
{
cancel = true;
Destroy();
}
return 0;
case WM_CLOSE:
if(IsAllowCancel())
{
cancel = true;
Destroy();
}
return 0;
}
return DefWindowProc(window, message, wParam, lParam);
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Caption(const char *_caption)
{
if(caption != _caption)
{
caption = _caption;
if(IsOpen())
SetWindowText(window, caption);
}
return *this;
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::Create()
{
if(window)
return true;
if(cancel)
return false;
// if(AfxGetApp())
// AfxGetApp() -> BeginWaitCursor();
HINSTANCE instance = AppGetHandle();
dword process = GetCurrentProcessId();
static const char classname[] = "Cybex_Progress";
static bool done = false;
if(!done)
{
done = true;
WNDCLASS wndclass =
{
CS_DBLCLKS | CS_SAVEBITS, // UINT style;
StaticProc, // WNDPROC lpfnWndProc;
0, // int cbClsExtra;
0, // int cbWndExtra;
instance, // HANDLE hInstance;
0, // HICON hIcon;
LoadCursor(0, IDC_WAIT), // HCURSOR hCursor;
GetSysColorBrush(COLOR_BTNFACE), // HBRUSH hbrBackground;
NULL, // LPCTSTR lpszMenuName;
classname, // LPCTSTR lpszClassName;
};
RegisterClass(&wndclass);
}
enum
{
CXWND = 240,
CYWND = 70,
CXGAP = 5,
CYGAP = 5,
XPROGRESS = CXGAP,
CXPROGRESS = CXWND - 2 * XPROGRESS,
CYPROGRESS = 10,
YPROGRESS = (CYWND - CYPROGRESS - 10) >> 1,
XTEXT = CXGAP,
YTEXT = CYGAP,
CXTEXT = CXWND - 2 * XTEXT,
CYTEXT = YPROGRESS - YTEXT,
CXBUTTON = 60,
CYBUTTON = 22,
XBUTTON = (CXWND - CXBUTTON) >> 1,
YBUTTON = CYWND - CYGAP - CYBUTTON,
STYLE = WS_OVERLAPPED | WS_DLGFRAME | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN,
};
Size screen(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
if(parent)
while(GetParent(parent))
parent = GetParent(parent);
if(!parent)
{
if(parent = GetActiveWindow())
while(GetParent(parent))
parent = GetParent(parent);
if(parent && !(IsWindowVisible(parent) && IsWindowEnabled(parent)))
parent = 0;
}
if(parent)
enable.Add(parent);
//*
for(HWND hwnd = GetWindow(GetDesktopWindow(), GW_CHILD); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT))
{
dword wprocess;
GetWindowThreadProcessId(hwnd, &wprocess);
if(wprocess == process && IsWindowVisible(hwnd) && IsWindowEnabled(hwnd))
enable.Add(hwnd);
}
if(!parent && !enable.IsEmpty())
parent = enable[0];
//*/
if(!parent)
parent = GetDesktopWindow();
Rect pane(0, 0, CXWND, CYWND);
AdjustWindowRect(pane, STYLE, false);
pane.Offset((screen >> 1) - pane.CenterPoint());
CreateWindowEx(
WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE,
classname, caption,
STYLE,
pane.left, pane.top, pane.Width(), pane.Height(),
parent, 0, instance, this);
if(!window)
return false;
SendMessage(window, WM_SETICON, ICON_BIG, 0);
SendMessage(window, WM_SETICON, ICON_SMALL, 0);
VERIFY(CreateWindow("static", NULL,
WS_CHILD | WS_VISIBLE | SS_CENTER | SS_NOPREFIX,
XTEXT, YTEXT, CXTEXT, CYTEXT,
window, (HMENU)IDOK, instance, 0));
// INITCOMMONCONTROLSEX icc;
// icc.dwSize = sizeof(icc);
// icc.dwICC = ICC_PROGRESS_CLASS;
// InitCommonControlsEx(&icc);
InitCommonControls();
VERIFY(progress = CreateWindow("msctls_progress32", NULL,
WS_CHILD | WS_DISABLED | (total ? WS_VISIBLE : 0),
XPROGRESS, YPROGRESS, CXPROGRESS, CYPROGRESS,
window, 0, instance, 0));
VERIFY(CreateWindow("button", "Cancel",
(flags & NOCANCEL ? 0 : WS_VISIBLE) | WS_CHILD | BS_PUSHBUTTON,
XBUTTON, YBUTTON, CXBUTTON, CYBUTTON,
window, (HMENU)IDCANCEL, instance, 0));
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
SendDlgItemMessage(window, IDOK, WM_SETFONT, (WPARAM)font, true);
SendDlgItemMessage(window, IDCANCEL, WM_SETFONT, (WPARAM)font, true);
ShowWindow(window, SW_SHOW);
Enable(false);
old_text = Null;
Set(pos, total);
return true;
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::SetText(const char *s, bool reset)
{
if(reset)
Reset();
text = s;
return Set(pos, total);
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Set(int apos, int atotal)
{
if(cancel && flags & THROW)
throw AbortExc();
if(atotal >= 0)
total = atotal;
if(apos >= 0)
pos = apos;
if(IgnoreStep(apos))
return *this;
next_ticks = GetTickCount() + 500;
if(!Create())
return *this;
String new_text = Format(text, pos);
if(new_text.Compare(old_text))
SetDlgItemText(window, IDOK, old_text = new_text);
atotal = total;
apos = pos;
while(atotal > 30000)
{
atotal >>= 8;
apos >>= 8;
}
ShowWindow(progress, atotal > 0 ? SW_SHOW : SW_HIDE);
if(atotal > 0)
{
SendMessage(progress, PBM_SETRANGE, 0, MAKELPARAM(0, atotal));
SendMessage(progress, PBM_SETPOS, apos, 0);
}
return *this;
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Step()
{
return Set(++pos, total);
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::SetRange(int atotal)
{
return Set(pos, atotal);
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::SetPos(int apos)
{
return Set(apos, total);
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::Cancelled()
{
Create();
MSG msg;
while(::PeekMessage(&msg, flags & FILTER ? window : 0, 0, 0, PM_REMOVE))
::DispatchMessage(&msg);
if(cancel && flags & THROW)
throw AbortExc();
return cancel;
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::StepCancelled()
{
SetPos(pos + 1);
return IgnoreStep(pos) ? cancel : Cancelled();
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::SetPosCancelled(int apos)
{
SetPos(apos);
return IgnoreStep(apos) ? cancel : Cancelled();
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::IgnoreStep(int pos) const
{
return (int)GetTickCount() < next_ticks && pos % (chunk ? chunk : 1);
}
//////////////////////////////////////////////////////////////////////
bool ProgressMeter::OnStep(int apos, int atotal)
{
if(atotal >= 0)
total = atotal;
SetPos(apos);
return IgnoreStep(apos) ? cancel : Cancelled();
}
//////////////////////////////////////////////////////////////////////
void ProgressMeter::Destroy()
{
if(window)
{
Enable(true);
if(!enable.IsEmpty())
SetActiveWindow(enable[0]);
enable.Clear();
DestroyWindow(window);
window = NULL;
progress = NULL;
// if(AfxGetApp())
// AfxGetApp() -> EndWaitCursor();
}
}
//////////////////////////////////////////////////////////////////////
void ProgressMeter::Enable(bool en)
{
for(const HWND *p = enable.Begin(), *e = enable.End(); p < e; p++)
EnableWindow(*p, en);
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Filter(bool _fm)
{
flags = _fm ? flags | FILTER : flags & ~FILTER;
return *this;
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Throw(bool _throw)
{
flags = _throw ? flags | THROW : flags & ~THROW;
return *this;
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::AllowCancel(bool _ac)
{
flags = _ac ? flags & ~NOCANCEL : flags | NOCANCEL;
if(window)
ShowWindow(GetDlgItem(window, IDCANCEL), _ac ? SW_SHOW : SW_HIDE);
return *this;
}
//////////////////////////////////////////////////////////////////////
ProgressMeter& ProgressMeter::Show(bool _show)
{
flags = _show ? flags & ~HIDDEN : flags | HIDDEN;
if(window)
ShowWindow(window, _show ? SW_SHOW : SW_HIDE);
return *this;
}
//////////////////////////////////////////////////////////////////////