ProgressWnd.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. #include "stdafx.h"
  2. #include "ProgressWnd.h"
  3. #ifdef _DEBUG
  4. #define new DEBUG_NEW
  5. #undef THIS_FILE
  6. static char THIS_FILE[] = __FILE__;
  7. #endif
  8. #define IDC_CANCEL 10
  9. #define IDC_TEXT 11
  10. #define IDC_PROGRESS 12
  11. LPCTSTR szSection = _T("Settings");
  12. LPCTSTR szEntryX = _T("X");
  13. LPCTSTR szEntryY = _T("Y");
  14. #define _CRT_NON_CONFORMING_SWPRINTFS 1
  15. /////////////////////////////////////////////////////////////////////////////
  16. // CProgressWnd
  17. CProgressWnd::CProgressWnd()
  18. {
  19. CommonConstruct();
  20. }
  21. CProgressWnd::CProgressWnd(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth /* = FALSE */)
  22. {
  23. CommonConstruct();
  24. m_strTitle = pszTitle;
  25. Create(pParent, pszTitle, bSmooth);
  26. }
  27. void CProgressWnd::CommonConstruct()
  28. {
  29. m_nNumTextLines = 4;
  30. m_nPrevPos = 0;
  31. m_nPrevPercent = 0;
  32. m_nStep = 1;
  33. m_nMinValue = 0;
  34. m_nMaxValue = 100;
  35. m_strTitle = _T("Progress");
  36. m_strCancelLabel = _T(" Cancel ");
  37. m_bCancelled = FALSE;
  38. m_bModal = FALSE;
  39. m_bPersistantPosition = TRUE; // saves and restores position automatically
  40. }
  41. CProgressWnd::~CProgressWnd()
  42. {
  43. DestroyWindow();
  44. }
  45. BOOL CProgressWnd::Create(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth /* = FALSE */)
  46. {
  47. BOOL bSuccess;
  48. m_strTitle = pszTitle;
  49. // Register window class
  50. CString csClassName = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW,
  51. ::LoadCursor(NULL, IDC_APPSTARTING),
  52. CBrush(::GetSysColor(COLOR_BTNFACE)));
  53. // Get the system window message font for use in the cancel button and text area
  54. NONCLIENTMETRICS ncm;
  55. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  56. VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
  57. m_font.CreateFontIndirect(&(ncm.lfMessageFont));
  58. // If no parent supplied then try and get a pointer to it anyway
  59. if (!pParent)
  60. pParent = AfxGetMainWnd();
  61. // Create popup window
  62. //bSuccess = CreateEx(WS_EX_DLGMODALFRAME|WS_EX_TOPMOST, // Extended style
  63. bSuccess = CreateEx(WS_EX_DLGMODALFRAME,
  64. csClassName, // Classname
  65. pszTitle, // Title
  66. WS_POPUP|WS_BORDER|WS_CAPTION, // style
  67. 0,0, // position - updated soon.
  68. 390,130, // Size - updated soon
  69. pParent->GetSafeHwnd(), // handle to parent
  70. 0, // No menu
  71. NULL);
  72. if (!bSuccess) return FALSE;
  73. // Now create the controls
  74. CRect TempRect(0,0,10,10);
  75. bSuccess = m_Text.Create(_T(""), WS_CHILD|WS_VISIBLE|SS_NOPREFIX|SS_LEFTNOWORDWRAP,
  76. TempRect, this, IDC_TEXT);
  77. if (!bSuccess) return FALSE;
  78. DWORD dwProgressStyle = WS_CHILD|WS_VISIBLE;
  79. #ifdef PBS_SMOOTH
  80. if (bSmooth)
  81. dwProgressStyle |= PBS_SMOOTH;
  82. #endif
  83. bSuccess = m_wndProgress.Create(dwProgressStyle,TempRect, this, IDC_PROGRESS);
  84. if (!bSuccess) return FALSE;
  85. bSuccess = m_CancelButton.Create(m_strCancelLabel,
  86. WS_CHILD|WS_VISIBLE|WS_TABSTOP| BS_PUSHBUTTON,
  87. TempRect, this, IDC_CANCEL);
  88. if (!bSuccess) return FALSE;
  89. m_CancelButton.SetFont(&m_font, TRUE);
  90. m_Text.SetFont(&m_font, TRUE);
  91. // Resize the whole thing according to the number of text lines, desired window
  92. // width and current font.
  93. SetWindowSize(m_nNumTextLines, 390);
  94. // Center and show window
  95. if (m_bPersistantPosition)
  96. GetPreviousSettings();
  97. else
  98. CenterWindow();
  99. Show();
  100. return TRUE;
  101. }
  102. BOOL CProgressWnd::GoModal(LPCTSTR pszTitle /*=_T("Progress")"*/, BOOL bSmooth /*=FALSE*/)
  103. {
  104. CWnd *pMainWnd = AfxGetMainWnd();
  105. if (!::IsWindow(m_hWnd) && !Create(pMainWnd, pszTitle, bSmooth))
  106. return FALSE;
  107. // Disable main window
  108. if (pMainWnd)
  109. pMainWnd->EnableWindow(FALSE);
  110. // Re-enable this window
  111. EnableWindow(TRUE);
  112. m_bModal = TRUE;
  113. return TRUE;
  114. }
  115. void CProgressWnd::SetWindowSize(int nNumTextLines, int nWindowWidth /*=390*/)
  116. {
  117. int nMargin = 10;
  118. CSize EdgeSize(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE));
  119. CRect TextRect, CancelRect, ProgressRect;
  120. CSize CancelSize;
  121. // Set up a default size for the text area in case things go wrong
  122. TextRect.SetRect(nMargin,nMargin, nWindowWidth-2*nMargin, 100+2*nMargin);
  123. // Get DrawText to tell us how tall the text area will be (while we're at
  124. // it, we'll see how big the word "Cancel" is)
  125. CDC* pDC = GetDC();
  126. if (pDC) {
  127. CFont* pOldFont = pDC->SelectObject(&m_font);
  128. CString str = _T("M");
  129. for (int i = 0; i < nNumTextLines-1; i++) str += _T("\nM");
  130. pDC->DrawText(str, TextRect, DT_CALCRECT|DT_NOCLIP|DT_NOPREFIX);
  131. TextRect.right = TextRect.left + nWindowWidth;
  132. CancelSize = pDC->GetTextExtent(m_strCancelLabel + _T(" ")) +
  133. CSize(EdgeSize.cx*4, EdgeSize.cy*3);
  134. pDC->SelectObject(pOldFont);
  135. ReleaseDC(pDC);
  136. }
  137. // Work out how big (and where) the cancel button should be
  138. CancelRect.SetRect(TextRect.right-CancelSize.cx, TextRect.bottom+nMargin,
  139. TextRect.right, TextRect.bottom+nMargin + CancelSize.cy);
  140. // Work out how big (and where) the progress control should be
  141. ProgressRect.SetRect(TextRect.left, CancelRect.top + EdgeSize.cy,
  142. CancelRect.left-nMargin, CancelRect.bottom - EdgeSize.cy);
  143. // Resize the main window to fit the controls
  144. CSize ClientSize(nMargin + TextRect.Width() + nMargin,
  145. nMargin + TextRect.Height() + nMargin + CancelRect.Height() + nMargin);
  146. CRect WndRect, ClientRect;
  147. GetWindowRect(WndRect); GetClientRect(ClientRect);
  148. WndRect.right = WndRect.left + WndRect.Width()-ClientRect.Width()+ClientSize.cx;
  149. WndRect.bottom = WndRect.top + WndRect.Height()-ClientRect.Height()+ClientSize.cy;
  150. MoveWindow(WndRect);
  151. // Now reposition the controls...
  152. m_wndProgress.MoveWindow(ProgressRect);
  153. m_CancelButton.MoveWindow(CancelRect);
  154. m_Text.MoveWindow(TextRect);
  155. }
  156. void CProgressWnd::Clear()
  157. {
  158. SetText(_T(""));
  159. SetPos(0);
  160. m_bCancelled = FALSE;
  161. m_nPrevPos = 0;
  162. if (::IsWindow(GetSafeHwnd()))
  163. UpdateWindow();
  164. }
  165. void CProgressWnd::Hide()
  166. {
  167. if (!::IsWindow(GetSafeHwnd()))
  168. return;
  169. if (IsWindowVisible())
  170. {
  171. ShowWindow(SW_HIDE);
  172. ModifyStyle(WS_VISIBLE, 0);
  173. }
  174. }
  175. void CProgressWnd::Show()
  176. {
  177. if (!::IsWindow(GetSafeHwnd()))
  178. return;
  179. if (!IsWindowVisible())
  180. {
  181. ModifyStyle(0, WS_VISIBLE);
  182. ShowWindow(SW_SHOWNA);
  183. RedrawWindow(NULL,NULL,RDW_ERASE|RDW_FRAME|RDW_INVALIDATE);
  184. }
  185. }
  186. void CProgressWnd::SetRange(int nLower, int nUpper, int nStep /* = 1 */)
  187. {
  188. if (!::IsWindow(GetSafeHwnd()))
  189. return;
  190. #ifdef PBM_SETRANGE32
  191. ASSERT(-0x7FFFFFFF <= nLower && nLower <= 0x7FFFFFFF);
  192. ASSERT(-0x7FFFFFFF <= nUpper && nUpper <= 0x7FFFFFFF);
  193. m_wndProgress.SendMessage(PBM_SETRANGE32, (WPARAM) nLower, (LPARAM) nUpper);
  194. #else
  195. ASSERT(0 <= nLower && nLower <= 65535);
  196. ASSERT(0 <= nUpper && nUpper <= 65535);
  197. m_wndProgress.SetRange(nLower, nUpper);
  198. #endif
  199. m_nMaxValue = nUpper;
  200. m_nMinValue = nLower;
  201. m_nStep = nStep;
  202. m_wndProgress.SetStep(nStep);
  203. }
  204. int CProgressWnd::OffsetPos(int nPos)
  205. {
  206. if (!::IsWindow(GetSafeHwnd()))
  207. return m_nPrevPos;
  208. Show();
  209. return SetPos(m_nPrevPos + nPos);
  210. }
  211. int CProgressWnd::StepIt()
  212. {
  213. if (!::IsWindow(GetSafeHwnd()))
  214. return m_nPrevPos;
  215. Show();
  216. return SetPos(m_nPrevPos + m_nStep);
  217. }
  218. int CProgressWnd::SetStep(int nStep)
  219. {
  220. int nOldStep = m_nStep;
  221. m_nStep = nStep;
  222. if (!::IsWindow(GetSafeHwnd()))
  223. return nOldStep;
  224. return m_wndProgress.SetStep(nStep);
  225. }
  226. int CProgressWnd::SetPos(int nPos)
  227. {
  228. #ifdef PBM_SETRANGE32
  229. ASSERT(-0x7FFFFFFF <= nPos && nPos <= 0x7FFFFFFF);
  230. #else
  231. ASSERT(0 <= nPos && nPos <= 65535);
  232. #endif
  233. if (!::IsWindow(GetSafeHwnd()))
  234. return m_nPrevPos;
  235. Show();
  236. CString strTitle;
  237. // int nPercentage;
  238. m_nPrevPos = nPos;
  239. // if (m_nMaxValue > m_nMinValue)
  240. // nPercentage = (nPos*100)/(m_nMaxValue - m_nMinValue);
  241. // else
  242. // nPercentage = 0;
  243. // if (nPercentage != m_nPrevPercent)
  244. // {
  245. // m_nPrevPercent = nPercentage;
  246. // strTitle.Format(_T("%s [%d%%]"),m_strTitle,nPercentage);
  247. strTitle.Format(_T("%s"),m_strTitle);
  248. SetWindowText(strTitle);
  249. // }
  250. return m_wndProgress.SetPos(nPos);
  251. }
  252. void CProgressWnd::SetText(LPCTSTR fmt, ...)
  253. {
  254. if (!::IsWindow(GetSafeHwnd()))
  255. return;
  256. va_list args;
  257. TCHAR buffer[512];
  258. va_start(args, fmt);
  259. _vstprintf(buffer, fmt, args);
  260. va_end(args);
  261. m_Text.SetWindowText(buffer);
  262. }
  263. BEGIN_MESSAGE_MAP(CProgressWnd, CWnd)
  264. //{{AFX_MSG_MAP(CProgressWnd)
  265. ON_WM_ERASEBKGND()
  266. //}}AFX_MSG_MAP
  267. ON_BN_CLICKED(IDC_CANCEL, OnCancel)
  268. END_MESSAGE_MAP()
  269. /////////////////////////////////////////////////////////////////////////////
  270. // CProgressWnd message handlers
  271. BOOL CProgressWnd::OnEraseBkgnd(CDC* pDC)
  272. {
  273. // Fill background with Catchment background colour
  274. CBrush backBrush(GetSysColor(COLOR_BTNFACE));
  275. CBrush* pOldBrush = pDC->SelectObject(&backBrush);
  276. CRect rect;
  277. pDC->GetClipBox(&rect); // Erase the area needed
  278. pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
  279. pDC->SelectObject(pOldBrush);
  280. return TRUE;
  281. }
  282. void CProgressWnd::OnCancel()
  283. {
  284. m_bCancelled = TRUE;
  285. Hide();
  286. if (m_bModal)
  287. SendMessage(WM_CLOSE);
  288. CWnd *pWnd = AfxGetMainWnd();
  289. if (pWnd && ::IsWindow(pWnd->m_hWnd))
  290. pWnd->SetForegroundWindow();
  291. }
  292. BOOL CProgressWnd::DestroyWindow()
  293. {
  294. if (m_bPersistantPosition)
  295. SaveCurrentSettings();
  296. if (m_bModal)
  297. {
  298. m_bModal = FALSE;
  299. CWnd *pMainWnd = AfxGetMainWnd();
  300. if (pMainWnd)
  301. pMainWnd->EnableWindow(TRUE);
  302. }
  303. return CWnd::DestroyWindow();
  304. }
  305. void CProgressWnd::PeekAndPump(BOOL bCancelOnESCkey /*= TRUE*/)
  306. {
  307. if (m_bModal && ::GetFocus() != m_hWnd)
  308. SetFocus();
  309. MSG msg;
  310. while (!m_bCancelled && ::PeekMessage(&msg, NULL,0,0,PM_NOREMOVE))
  311. {
  312. if (bCancelOnESCkey && (msg.message == WM_CHAR) && (msg.wParam == VK_ESCAPE))
  313. OnCancel();
  314. // Cancel button disabled if modal, so we fake it.
  315. if (m_bModal && (msg.message == WM_LBUTTONUP))
  316. {
  317. CRect rect;
  318. m_CancelButton.GetWindowRect(rect);
  319. if (rect.PtInRect(msg.pt))
  320. OnCancel();
  321. }
  322. if (!AfxGetApp()->PumpMessage())
  323. {
  324. ::PostQuitMessage(0);
  325. return;
  326. }
  327. }
  328. }
  329. // Retores the previous window size from the registry
  330. void CProgressWnd::GetPreviousSettings()
  331. {
  332. int x = AfxGetApp()->GetProfileInt(szSection, szEntryX, -1);
  333. int y = AfxGetApp()->GetProfileInt(szSection, szEntryY, -1);
  334. if (x >= 0 && x < GetSystemMetrics(SM_CXSCREEN) &&
  335. y >= 0 && y < GetSystemMetrics(SM_CYSCREEN))
  336. {
  337. SetWindowPos(NULL, x,y, 0,0, SWP_NOSIZE|SWP_NOZORDER);
  338. }
  339. else
  340. CenterWindow();
  341. }
  342. // Saves the current window position registry
  343. void CProgressWnd::SaveCurrentSettings()
  344. {
  345. if (!IsWindow(m_hWnd))
  346. return;
  347. CRect rect;
  348. GetWindowRect(rect);
  349. AfxGetApp()->WriteProfileInt(szSection, szEntryX, rect.left);
  350. AfxGetApp()->WriteProfileInt(szSection, szEntryY, rect.top);
  351. }
  352. void CProgressWnd::HideCancel()
  353. {
  354. m_CancelButton.ShowWindow(SW_HIDE);
  355. UpdateData(FALSE);
  356. }
  357. void CProgressWnd::ShowCancel()
  358. {
  359. m_CancelButton.ShowWindow(SW_SHOW);
  360. UpdateData(FALSE);
  361. }
  362. void CProgressWnd::SetTitleText(CString csTitle)
  363. {
  364. m_strTitle = csTitle;
  365. CString title;
  366. title.Format(_T("%s"),m_strTitle);
  367. SetWindowText(title);
  368. }