Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
9.1 KiB

  1. /*-----------------------------------------------------------------------
  2. **
  3. ** Progress.c
  4. **
  5. ** A "gas gauge" type control for showing application progress.
  6. **
  7. **
  8. ** BUGBUG: need to implement the block style per UI style guidelines
  9. **
  10. **-----------------------------------------------------------------------*/
  11. #include "ctlspriv.h"
  12. // BUGBUG raymondc - should Process control support __int64 on Win64?
  13. typedef struct {
  14. HWND hwnd;
  15. DWORD dwStyle;
  16. int iLow, iHigh;
  17. int iPos;
  18. int iStep;
  19. HFONT hfont;
  20. COLORREF _clrBk;
  21. COLORREF _clrBar;
  22. } PRO_DATA, NEAR *PPRO_DATA; // ppd
  23. LRESULT CALLBACK ProgressWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  24. #pragma code_seg(CODESEG_INIT)
  25. BOOL FAR PASCAL InitProgressClass(HINSTANCE hInstance)
  26. {
  27. WNDCLASS wc;
  28. if (!GetClassInfo(hInstance, s_szPROGRESS_CLASS, &wc)) {
  29. #ifndef WIN32
  30. extern LRESULT CALLBACK _ProgressWndProc(HWND, UINT, WPARAM, LPARAM);
  31. wc.lpfnWndProc = _ProgressWndProc;
  32. #else
  33. wc.lpfnWndProc = ProgressWndProc;
  34. #endif
  35. wc.lpszClassName = s_szPROGRESS_CLASS;
  36. wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
  37. wc.hInstance = hInstance; // use DLL instance if in DLL
  38. wc.hIcon = NULL;
  39. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  40. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  41. wc.lpszMenuName = NULL;
  42. wc.cbWndExtra = sizeof(PPRO_DATA); // store a pointer
  43. wc.cbClsExtra = 0;
  44. if (!RegisterClass(&wc))
  45. return FALSE;
  46. }
  47. return TRUE;
  48. }
  49. #pragma code_seg()
  50. int NEAR PASCAL UpdatePosition(PPRO_DATA ppd, int iNewPos, BOOL bAllowWrap)
  51. {
  52. int iPosOrg = ppd->iPos;
  53. UINT uRedraw = RDW_INVALIDATE | RDW_UPDATENOW;
  54. if (ppd->iLow == ppd->iHigh)
  55. iNewPos = ppd->iLow;
  56. if (iNewPos < ppd->iLow) {
  57. if (!bAllowWrap)
  58. iNewPos = ppd->iLow;
  59. else {
  60. iNewPos = ppd->iHigh - ((ppd->iLow - iNewPos) % (ppd->iHigh - ppd->iLow));
  61. // wrap, erase old stuff too
  62. uRedraw |= RDW_ERASE;
  63. }
  64. }
  65. else if (iNewPos > ppd->iHigh) {
  66. if (!bAllowWrap)
  67. iNewPos = ppd->iHigh;
  68. else {
  69. iNewPos = ppd->iLow + ((iNewPos - ppd->iHigh) % (ppd->iHigh - ppd->iLow));
  70. // wrap, erase old stuff too
  71. uRedraw |= RDW_ERASE;
  72. }
  73. }
  74. // if moving backwards, erase old version
  75. if (iNewPos < iPosOrg)
  76. uRedraw |= RDW_ERASE;
  77. if (iNewPos != ppd->iPos) {
  78. ppd->iPos = iNewPos;
  79. // paint, maybe erase if we wrapped
  80. RedrawWindow(ppd->hwnd, NULL, NULL, uRedraw);
  81. MyNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ppd->hwnd, OBJID_CLIENT, 0);
  82. }
  83. return iPosOrg;
  84. }
  85. #define HIGHBG g_clrHighlight
  86. #define HIGHFG g_clrHighlightText
  87. #define LOWBG g_clrBtnFace
  88. #define LOWFG g_clrBtnText
  89. void NEAR PASCAL ProPaint(PPRO_DATA ppd, HDC hdcIn)
  90. {
  91. int x, dxSpace, dxBlock, nBlocks, i;
  92. HDC hdc;
  93. RECT rc, rcClient;
  94. PAINTSTRUCT ps;
  95. int iStart, iEnd;
  96. // RECT rcLeft, rcRight;
  97. // TCHAR ach[40];
  98. // int xText, yText, cText;
  99. // HFONT hFont;
  100. // DWORD dw;
  101. if (hdcIn == NULL)
  102. hdc = BeginPaint(ppd->hwnd, &ps);
  103. else
  104. hdc = hdcIn;
  105. GetClientRect(ppd->hwnd, &rcClient);
  106. // give 1 pixel around the bar
  107. InflateRect(&rcClient, -1, -1);
  108. rc = rcClient;
  109. if (ppd->dwStyle & PBS_VERTICAL) {
  110. iStart = rc.top;
  111. iEnd = rc.bottom;
  112. dxBlock = (rc.right - rc.left) * 2 / 3;
  113. } else {
  114. iStart = rc.left;
  115. iEnd = rc.right;
  116. dxBlock = (rc.bottom - rc.top) * 2 / 3;
  117. }
  118. x = MulDiv(iEnd - iStart, ppd->iPos - ppd->iLow, ppd->iHigh - ppd->iLow);
  119. dxSpace = 2;
  120. if (dxBlock == 0)
  121. dxBlock = 1; // avoid div by zero
  122. if (ppd->dwStyle & PBS_SMOOTH) {
  123. dxBlock = 1;
  124. dxSpace = 0;
  125. }
  126. nBlocks = (x + (dxBlock + dxSpace) - 1) / (dxBlock + dxSpace); // round up
  127. for (i = 0; i < nBlocks; i++) {
  128. if (ppd->dwStyle & PBS_VERTICAL) {
  129. rc.top = rc.bottom - dxBlock;
  130. // are we past the end?
  131. if (rc.bottom <= rcClient.top)
  132. break;
  133. if (rc.top <= rcClient.top)
  134. rc.top = rcClient.top + 1;
  135. } else {
  136. rc.right = rc.left + dxBlock;
  137. // are we past the end?
  138. if (rc.left >= rcClient.right)
  139. break;
  140. if (rc.right >= rcClient.right)
  141. rc.right = rcClient.right - 1;
  142. }
  143. if (ppd->_clrBar == CLR_DEFAULT)
  144. FillRectClr(hdc, &rc, g_clrHighlight);
  145. else
  146. FillRectClr(hdc, &rc, ppd->_clrBar);
  147. if (ppd->dwStyle & PBS_VERTICAL) {
  148. rc.bottom = rc.top - dxSpace;
  149. } else {
  150. rc.left = rc.right + dxSpace;
  151. }
  152. }
  153. if (hdcIn == NULL)
  154. EndPaint(ppd->hwnd, &ps);
  155. }
  156. LRESULT NEAR PASCAL Progress_OnCreate(HWND hWnd, LPCREATESTRUCT pcs)
  157. {
  158. PPRO_DATA ppd = (PPRO_DATA)LocalAlloc(LPTR, sizeof(*ppd));
  159. if (!ppd)
  160. return -1;
  161. // remove ugly double 3d edge
  162. SetWindowPtr(hWnd, 0, ppd);
  163. ppd->hwnd = hWnd;
  164. ppd->iHigh = 100; // default to 0-100
  165. ppd->iStep = 10; // default to step of 10
  166. ppd->dwStyle = pcs->style;
  167. ppd->_clrBk = CLR_DEFAULT;
  168. ppd->_clrBar = CLR_DEFAULT;
  169. #ifdef DEBUG
  170. if (GetAsyncKeyState(VK_SHIFT) < 0 &&
  171. GetAsyncKeyState(VK_CONTROL) < 0)
  172. ppd->dwStyle |= PBS_SMOOTH;
  173. if (GetAsyncKeyState(VK_SHIFT) < 0 &&
  174. GetAsyncKeyState(VK_MENU) < 0) {
  175. ppd->dwStyle |= PBS_VERTICAL;
  176. SetWindowPos(hWnd, NULL, 0, 0, 40, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  177. }
  178. #endif
  179. // hack of the 3d client edge that WM_BORDER implies in dialogs
  180. // add the 1 pixel static edge that we really want
  181. SetWindowLong(hWnd, GWL_EXSTYLE, (pcs->dwExStyle & ~WS_EX_CLIENTEDGE) | WS_EX_STATICEDGE);
  182. if (!(pcs->dwExStyle & WS_EX_STATICEDGE))
  183. SetWindowPos(hWnd, NULL, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  184. return 0;
  185. }
  186. LRESULT CALLBACK ProgressWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  187. {
  188. int x;
  189. HFONT hFont;
  190. PPRO_DATA ppd = (PPRO_DATA)GetWindowPtr(hWnd, 0);
  191. switch (wMsg)
  192. {
  193. case WM_CREATE:
  194. CCCreateWindow();
  195. return Progress_OnCreate(hWnd, (LPCREATESTRUCT)lParam);
  196. case WM_DESTROY:
  197. CCDestroyWindow();
  198. if (ppd)
  199. LocalFree((HLOCAL)ppd);
  200. break;
  201. case WM_SYSCOLORCHANGE:
  202. InitGlobalColors();
  203. InvalidateRect(hWnd, NULL, TRUE);
  204. break;
  205. case WM_SETFONT:
  206. hFont = ppd->hfont;
  207. ppd->hfont = (HFONT)wParam;
  208. return (LRESULT)(UINT_PTR)hFont;
  209. case WM_GETFONT:
  210. return (LRESULT)(UINT_PTR)ppd->hfont;
  211. case PBM_GETPOS:
  212. return ppd->iPos;
  213. case PBM_GETRANGE:
  214. if (lParam) {
  215. PPBRANGE ppb = (PPBRANGE)lParam;
  216. ppb->iLow = ppd->iLow;
  217. ppb->iHigh = ppd->iHigh;
  218. }
  219. return (wParam ? ppd->iLow : ppd->iHigh);
  220. case PBM_SETRANGE:
  221. // win95 compat
  222. wParam = LOWORD(lParam);
  223. lParam = HIWORD(lParam);
  224. // fall through
  225. case PBM_SETRANGE32:
  226. {
  227. LRESULT lret = MAKELONG(ppd->iLow, ppd->iHigh);
  228. // only repaint if something actually changed
  229. if ((int)wParam != ppd->iLow || (int)lParam != ppd->iHigh)
  230. {
  231. ppd->iHigh = (int)lParam;
  232. ppd->iLow = (int)wParam;
  233. // force an invalidation/erase but don't redraw yet
  234. RedrawWindow(ppd->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
  235. UpdatePosition(ppd, ppd->iPos, FALSE);
  236. }
  237. return lret;
  238. }
  239. case PBM_SETPOS:
  240. return (LRESULT)UpdatePosition(ppd, (int) wParam, FALSE);
  241. case PBM_SETSTEP:
  242. x = ppd->iStep;
  243. ppd->iStep = (int)wParam;
  244. return (LRESULT)x;
  245. case PBM_STEPIT:
  246. return (LRESULT)UpdatePosition(ppd, ppd->iStep + ppd->iPos, TRUE);
  247. case PBM_DELTAPOS:
  248. return (LRESULT)UpdatePosition(ppd, ppd->iPos + (int)wParam, FALSE);
  249. case PBM_SETBKCOLOR:
  250. {
  251. COLORREF clr = ppd->_clrBk;
  252. ppd->_clrBk = (COLORREF)lParam;
  253. InvalidateRect(hWnd, NULL, TRUE);
  254. return clr;
  255. }
  256. case PBM_SETBARCOLOR:
  257. {
  258. COLORREF clr = ppd->_clrBar;
  259. ppd->_clrBar = (COLORREF)lParam;
  260. InvalidateRect(hWnd, NULL, TRUE);
  261. return clr;
  262. }
  263. case WM_PRINTCLIENT:
  264. case WM_PAINT:
  265. ProPaint(ppd,(HDC)wParam);
  266. break;
  267. case WM_ERASEBKGND:
  268. if (ppd) {
  269. if (ppd->_clrBk != CLR_DEFAULT) {
  270. RECT rc;
  271. GetClientRect(hWnd, &rc);
  272. FillRectClr((HDC)wParam, &rc, ppd->_clrBk);
  273. return 1;
  274. }
  275. }
  276. goto DoDefault;
  277. case WM_GETOBJECT:
  278. if( lParam == OBJID_QUERYCLASSNAMEIDX )
  279. return MSAA_CLASSNAMEIDX_PROGRESS;
  280. goto DoDefault;
  281. DoDefault:
  282. default:
  283. return DefWindowProc(hWnd,wMsg,wParam,lParam);
  284. }
  285. return 0;
  286. }