ProgressWnd.cpp 12 KB

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