windows-nt/Source/XPSP1/NT/shell/comctl32/v5/progress.c
2020-09-26 16:20:57 +08:00

354 lines
9.1 KiB
C

/*-----------------------------------------------------------------------
**
** Progress.c
**
** A "gas gauge" type control for showing application progress.
**
**
** BUGBUG: need to implement the block style per UI style guidelines
**
**-----------------------------------------------------------------------*/
#include "ctlspriv.h"
// BUGBUG raymondc - should Process control support __int64 on Win64?
typedef struct {
HWND hwnd;
DWORD dwStyle;
int iLow, iHigh;
int iPos;
int iStep;
HFONT hfont;
COLORREF _clrBk;
COLORREF _clrBar;
} PRO_DATA, NEAR *PPRO_DATA; // ppd
LRESULT CALLBACK ProgressWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
#pragma code_seg(CODESEG_INIT)
BOOL FAR PASCAL InitProgressClass(HINSTANCE hInstance)
{
WNDCLASS wc;
if (!GetClassInfo(hInstance, s_szPROGRESS_CLASS, &wc)) {
#ifndef WIN32
extern LRESULT CALLBACK _ProgressWndProc(HWND, UINT, WPARAM, LPARAM);
wc.lpfnWndProc = _ProgressWndProc;
#else
wc.lpfnWndProc = ProgressWndProc;
#endif
wc.lpszClassName = s_szPROGRESS_CLASS;
wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hInstance; // use DLL instance if in DLL
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.cbWndExtra = sizeof(PPRO_DATA); // store a pointer
wc.cbClsExtra = 0;
if (!RegisterClass(&wc))
return FALSE;
}
return TRUE;
}
#pragma code_seg()
int NEAR PASCAL UpdatePosition(PPRO_DATA ppd, int iNewPos, BOOL bAllowWrap)
{
int iPosOrg = ppd->iPos;
UINT uRedraw = RDW_INVALIDATE | RDW_UPDATENOW;
if (ppd->iLow == ppd->iHigh)
iNewPos = ppd->iLow;
if (iNewPos < ppd->iLow) {
if (!bAllowWrap)
iNewPos = ppd->iLow;
else {
iNewPos = ppd->iHigh - ((ppd->iLow - iNewPos) % (ppd->iHigh - ppd->iLow));
// wrap, erase old stuff too
uRedraw |= RDW_ERASE;
}
}
else if (iNewPos > ppd->iHigh) {
if (!bAllowWrap)
iNewPos = ppd->iHigh;
else {
iNewPos = ppd->iLow + ((iNewPos - ppd->iHigh) % (ppd->iHigh - ppd->iLow));
// wrap, erase old stuff too
uRedraw |= RDW_ERASE;
}
}
// if moving backwards, erase old version
if (iNewPos < iPosOrg)
uRedraw |= RDW_ERASE;
if (iNewPos != ppd->iPos) {
ppd->iPos = iNewPos;
// paint, maybe erase if we wrapped
RedrawWindow(ppd->hwnd, NULL, NULL, uRedraw);
MyNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ppd->hwnd, OBJID_CLIENT, 0);
}
return iPosOrg;
}
#define HIGHBG g_clrHighlight
#define HIGHFG g_clrHighlightText
#define LOWBG g_clrBtnFace
#define LOWFG g_clrBtnText
void NEAR PASCAL ProPaint(PPRO_DATA ppd, HDC hdcIn)
{
int x, dxSpace, dxBlock, nBlocks, i;
HDC hdc;
RECT rc, rcClient;
PAINTSTRUCT ps;
int iStart, iEnd;
// RECT rcLeft, rcRight;
// TCHAR ach[40];
// int xText, yText, cText;
// HFONT hFont;
// DWORD dw;
if (hdcIn == NULL)
hdc = BeginPaint(ppd->hwnd, &ps);
else
hdc = hdcIn;
GetClientRect(ppd->hwnd, &rcClient);
// give 1 pixel around the bar
InflateRect(&rcClient, -1, -1);
rc = rcClient;
if (ppd->dwStyle & PBS_VERTICAL) {
iStart = rc.top;
iEnd = rc.bottom;
dxBlock = (rc.right - rc.left) * 2 / 3;
} else {
iStart = rc.left;
iEnd = rc.right;
dxBlock = (rc.bottom - rc.top) * 2 / 3;
}
x = MulDiv(iEnd - iStart, ppd->iPos - ppd->iLow, ppd->iHigh - ppd->iLow);
dxSpace = 2;
if (dxBlock == 0)
dxBlock = 1; // avoid div by zero
if (ppd->dwStyle & PBS_SMOOTH) {
dxBlock = 1;
dxSpace = 0;
}
nBlocks = (x + (dxBlock + dxSpace) - 1) / (dxBlock + dxSpace); // round up
for (i = 0; i < nBlocks; i++) {
if (ppd->dwStyle & PBS_VERTICAL) {
rc.top = rc.bottom - dxBlock;
// are we past the end?
if (rc.bottom <= rcClient.top)
break;
if (rc.top <= rcClient.top)
rc.top = rcClient.top + 1;
} else {
rc.right = rc.left + dxBlock;
// are we past the end?
if (rc.left >= rcClient.right)
break;
if (rc.right >= rcClient.right)
rc.right = rcClient.right - 1;
}
if (ppd->_clrBar == CLR_DEFAULT)
FillRectClr(hdc, &rc, g_clrHighlight);
else
FillRectClr(hdc, &rc, ppd->_clrBar);
if (ppd->dwStyle & PBS_VERTICAL) {
rc.bottom = rc.top - dxSpace;
} else {
rc.left = rc.right + dxSpace;
}
}
if (hdcIn == NULL)
EndPaint(ppd->hwnd, &ps);
}
LRESULT NEAR PASCAL Progress_OnCreate(HWND hWnd, LPCREATESTRUCT pcs)
{
PPRO_DATA ppd = (PPRO_DATA)LocalAlloc(LPTR, sizeof(*ppd));
if (!ppd)
return -1;
// remove ugly double 3d edge
SetWindowPtr(hWnd, 0, ppd);
ppd->hwnd = hWnd;
ppd->iHigh = 100; // default to 0-100
ppd->iStep = 10; // default to step of 10
ppd->dwStyle = pcs->style;
ppd->_clrBk = CLR_DEFAULT;
ppd->_clrBar = CLR_DEFAULT;
#ifdef DEBUG
if (GetAsyncKeyState(VK_SHIFT) < 0 &&
GetAsyncKeyState(VK_CONTROL) < 0)
ppd->dwStyle |= PBS_SMOOTH;
if (GetAsyncKeyState(VK_SHIFT) < 0 &&
GetAsyncKeyState(VK_MENU) < 0) {
ppd->dwStyle |= PBS_VERTICAL;
SetWindowPos(hWnd, NULL, 0, 0, 40, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
#endif
// hack of the 3d client edge that WM_BORDER implies in dialogs
// add the 1 pixel static edge that we really want
SetWindowLong(hWnd, GWL_EXSTYLE, (pcs->dwExStyle & ~WS_EX_CLIENTEDGE) | WS_EX_STATICEDGE);
if (!(pcs->dwExStyle & WS_EX_STATICEDGE))
SetWindowPos(hWnd, NULL, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return 0;
}
LRESULT CALLBACK ProgressWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
int x;
HFONT hFont;
PPRO_DATA ppd = (PPRO_DATA)GetWindowPtr(hWnd, 0);
switch (wMsg)
{
case WM_CREATE:
CCCreateWindow();
return Progress_OnCreate(hWnd, (LPCREATESTRUCT)lParam);
case WM_DESTROY:
CCDestroyWindow();
if (ppd)
LocalFree((HLOCAL)ppd);
break;
case WM_SYSCOLORCHANGE:
InitGlobalColors();
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_SETFONT:
hFont = ppd->hfont;
ppd->hfont = (HFONT)wParam;
return (LRESULT)(UINT_PTR)hFont;
case WM_GETFONT:
return (LRESULT)(UINT_PTR)ppd->hfont;
case PBM_GETPOS:
return ppd->iPos;
case PBM_GETRANGE:
if (lParam) {
PPBRANGE ppb = (PPBRANGE)lParam;
ppb->iLow = ppd->iLow;
ppb->iHigh = ppd->iHigh;
}
return (wParam ? ppd->iLow : ppd->iHigh);
case PBM_SETRANGE:
// win95 compat
wParam = LOWORD(lParam);
lParam = HIWORD(lParam);
// fall through
case PBM_SETRANGE32:
{
LRESULT lret = MAKELONG(ppd->iLow, ppd->iHigh);
// only repaint if something actually changed
if ((int)wParam != ppd->iLow || (int)lParam != ppd->iHigh)
{
ppd->iHigh = (int)lParam;
ppd->iLow = (int)wParam;
// force an invalidation/erase but don't redraw yet
RedrawWindow(ppd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
UpdatePosition(ppd, ppd->iPos, FALSE);
}
return lret;
}
case PBM_SETPOS:
return (LRESULT)UpdatePosition(ppd, (int) wParam, FALSE);
case PBM_SETSTEP:
x = ppd->iStep;
ppd->iStep = (int)wParam;
return (LRESULT)x;
case PBM_STEPIT:
return (LRESULT)UpdatePosition(ppd, ppd->iStep + ppd->iPos, TRUE);
case PBM_DELTAPOS:
return (LRESULT)UpdatePosition(ppd, ppd->iPos + (int)wParam, FALSE);
case PBM_SETBKCOLOR:
{
COLORREF clr = ppd->_clrBk;
ppd->_clrBk = (COLORREF)lParam;
InvalidateRect(hWnd, NULL, TRUE);
return clr;
}
case PBM_SETBARCOLOR:
{
COLORREF clr = ppd->_clrBar;
ppd->_clrBar = (COLORREF)lParam;
InvalidateRect(hWnd, NULL, TRUE);
return clr;
}
case WM_PRINTCLIENT:
case WM_PAINT:
ProPaint(ppd,(HDC)wParam);
break;
case WM_ERASEBKGND:
if (ppd) {
if (ppd->_clrBk != CLR_DEFAULT) {
RECT rc;
GetClientRect(hWnd, &rc);
FillRectClr((HDC)wParam, &rc, ppd->_clrBk);
return 1;
}
}
goto DoDefault;
case WM_GETOBJECT:
if( lParam == OBJID_QUERYCLASSNAMEIDX )
return MSAA_CLASSNAMEIDX_PROGRESS;
goto DoDefault;
DoDefault:
default:
return DefWindowProc(hWnd,wMsg,wParam,lParam);
}
return 0;
}