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.

560 lines
16 KiB

  1. // Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved.
  2. #include "header.h"
  3. #include "cdlg.h"
  4. #include "strtable.h"
  5. #include "cpaldc.h"
  6. // CLockOut for disabling the outer level windows.
  7. #include "lockout.h"
  8. #ifndef IDBMP_CHECK
  9. #include "resource.h"
  10. #endif
  11. static BOOL WINAPI EnumFontProc(HWND hwnd, LPARAM lval);
  12. static BOOL WINAPI EnumBidiSettings(HWND hwnd, LPARAM lval);
  13. CDlg::CDlg(HWND hwndParent, UINT idTemplate)
  14. {
  15. ZERO_INIT_CLASS(CDlg);
  16. m_hwndParent = hwndParent;
  17. if(g_bWinNT5)
  18. m_lpDialogTemplate = (char *)MAKEINTRESOURCEW(idTemplate);
  19. else
  20. m_lpDialogTemplate = MAKEINTRESOURCE(idTemplate);
  21. m_fCenterWindow = TRUE;
  22. m_phhCtrl = NULL;
  23. m_fUnicode = g_bWinNT5;
  24. }
  25. CDlg::CDlg(CHtmlHelpControl* phhCtrl, UINT idTemplate)
  26. {
  27. ZERO_INIT_CLASS(CDlg);
  28. ASSERT(phhCtrl);
  29. m_hwndParent = phhCtrl->m_hwnd;
  30. if(g_bWinNT5)
  31. m_lpDialogTemplate = (char *)MAKEINTRESOURCEW(idTemplate);
  32. else
  33. m_lpDialogTemplate = MAKEINTRESOURCE(idTemplate);
  34. m_fCenterWindow = TRUE;
  35. m_phhCtrl = phhCtrl;
  36. m_fUnicode = g_bWinNT5;
  37. }
  38. int CDlg::DoModal(void)
  39. {
  40. if (m_phhCtrl)
  41. m_phhCtrl->ModalDialog(TRUE);
  42. else
  43. m_LockOut.LockOut(m_hwndParent) ;
  44. int result = -1;
  45. if (m_fUnicode || g_bWinNT5)
  46. {
  47. result = (int)::DialogBoxParamW(_Module.GetResourceInstance(), (LPCWSTR)m_lpDialogTemplate,
  48. m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
  49. // Docs say this returns -1 for failure, but returns 0 on
  50. // Win95 like other unimplemented APIs.
  51. if (0 == result)
  52. {
  53. if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError())
  54. {
  55. m_fUnicode = FALSE;
  56. goto _Ansi;
  57. }
  58. }
  59. }
  60. else
  61. {
  62. _Ansi: result = (int)::DialogBoxParamA(_Module.GetResourceInstance(), m_lpDialogTemplate,
  63. m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
  64. }
  65. if (m_phhCtrl)
  66. m_phhCtrl->ModalDialog(FALSE);
  67. return result;
  68. }
  69. CDlg::~CDlg()
  70. {
  71. if (m_fModeLess && IsValidWindow(m_hWnd))
  72. DestroyWindow(m_hWnd);
  73. if (m_pCheckBox)
  74. delete m_pCheckBox;
  75. }
  76. void STDCALL CenterWindow(HWND hwndParent, HWND hwnd)
  77. {
  78. RECT rcParent, rc;
  79. //BUGBUG: This is broken in the multiple monitor case.
  80. if (!hwndParent)
  81. hwndParent = GetDesktopWindow();
  82. GetWindowRect(hwndParent, &rcParent);
  83. GetWindowRect(hwnd, &rc);
  84. int cx = RECT_WIDTH(rc);
  85. int cy = RECT_HEIGHT(rc);
  86. int left = rcParent.left + (RECT_WIDTH(rcParent) - cx) / 2;
  87. int top = rcParent.top + (RECT_HEIGHT(rcParent) - cy) / 2;
  88. // Make certain we don't cover the tray
  89. // Also make sure that the dialog box is completely visible.
  90. // If its not visible, then let the default happen.
  91. SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
  92. if (left < rc.left)
  93. left = rc.left;
  94. if (top < rc.top)
  95. top = rc.top;
  96. // BUG 2426: Make sure that the window is visible.
  97. if (left+cx > rc.right)
  98. left = rc.right - cx ;
  99. if (top+cy > rc.bottom)
  100. top = rc.bottom - cy ;
  101. // Make sure that the dialog still fits.
  102. ASSERT(left >= rc.left && top >= rc.top);
  103. // Make sure that the window is completely visible before doing the move:
  104. MoveWindow(hwnd, left, top, cx, cy, TRUE);
  105. }
  106. BOOL CALLBACK CDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  107. {
  108. CDlg* pThis = (CDlg*) GetWindowLongPtr(hdlg, GWLP_USERDATA);
  109. switch (msg) {
  110. case WM_INITDIALOG:
  111. // Save this pointer in the window data area
  112. pThis = (CDlg*) lParam;
  113. SetWindowLongPtr(hdlg, GWLP_USERDATA, lParam);
  114. pThis->m_hWnd = hdlg;
  115. pThis->m_fInitializing = TRUE; // reset when IDOK processed
  116. if (pThis->m_fCenterWindow)
  117. CenterWindow(pThis->m_hwndParent, pThis->m_hWnd);
  118. if (pThis->m_pBeginOrEnd)
  119. pThis->m_pBeginOrEnd(pThis);
  120. else
  121. pThis->OnBeginOrEnd();
  122. // set the correct font
  123. //
  124. if(g_bWinNT5)
  125. EnumChildWindows(hdlg, (WNDENUMPROC) EnumFontProc, 0);
  126. if (g_fBiDi) {
  127. // If BiDi, make adjustments to list and combo boxes
  128. EnumChildWindows(hdlg, (WNDENUMPROC) EnumBidiSettings, 0);
  129. }
  130. if (pThis->m_aHelpIds)
  131. SetWindowLong(hdlg, GWL_EXSTYLE,
  132. GetWindowLong(hdlg, GWL_EXSTYLE) | WS_EX_CONTEXTHELP);
  133. // If we're threaded, we may be behind our caller
  134. SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0,
  135. SWP_NOMOVE | SWP_NOSIZE);
  136. //BUG 2035: Return TRUE to tell windows to set the keyboard focus.
  137. // m_fFocusChanged is FALSE if the derived class hasn't changed it.
  138. return !pThis->m_fFocusChanged;
  139. case WM_COMMAND:
  140. {
  141. pThis = (CDlg*) GetWindowLongPtr(hdlg, GWLP_USERDATA);
  142. if (!pThis || pThis->m_fShuttingDown)
  143. return FALSE; // pThis == NULL if a spin control is being initialized
  144. switch (HIWORD(wParam)) {
  145. case BN_CLICKED:
  146. pThis->OnButton(LOWORD(wParam));
  147. break;
  148. case LBN_SELCHANGE: // same value as CBN_SELCHANGE
  149. pThis->OnSelChange(LOWORD(wParam));
  150. break;
  151. case LBN_DBLCLK: // same value as CBN_DBLCLK
  152. pThis->OnDoubleClick(LOWORD(wParam));
  153. break;
  154. case EN_CHANGE:
  155. pThis->OnEditChange(LOWORD(wParam));
  156. break;
  157. }
  158. // If m_pmsglist is set, OnCommand will call OnMsg
  159. if (!pThis->OnCommand(wParam, lParam))
  160. return FALSE;
  161. BOOL fResult;
  162. switch (LOWORD(wParam)) {
  163. case IDOK:
  164. pThis->m_fInitializing = FALSE;
  165. fResult = -1;
  166. if (pThis->m_pBeginOrEnd)
  167. fResult = pThis->m_pBeginOrEnd(pThis);
  168. else
  169. fResult = pThis->OnBeginOrEnd();
  170. if (!fResult)
  171. break;
  172. if (pThis->m_fModeLess) {
  173. pThis->m_fShuttingDown = TRUE;
  174. PostMessage(hdlg, WM_CLOSE, 0, 0);
  175. }
  176. else
  177. pThis->m_LockOut.Unlock();
  178. EndDialog(hdlg, TRUE);
  179. break;
  180. case IDCANCEL:
  181. if (pThis->m_fModeLess) {
  182. pThis->m_fShuttingDown = TRUE;
  183. PostMessage(hdlg, WM_CLOSE, 0, 0);
  184. }
  185. else
  186. pThis->m_LockOut.Unlock();
  187. EndDialog(hdlg, FALSE);
  188. break;
  189. case IDNO:
  190. if (pThis->m_fModeLess) {
  191. pThis->m_fShuttingDown = TRUE;
  192. PostMessage(hdlg, WM_CLOSE, 0, 0);
  193. }
  194. else
  195. pThis->m_LockOut.Unlock();
  196. EndDialog(hdlg, IDNO);
  197. break;
  198. case IDRETRY:
  199. if (pThis->m_fModeLess) {
  200. pThis->m_fShuttingDown = TRUE;
  201. PostMessage(hdlg, WM_CLOSE, 0, 0);
  202. }
  203. else
  204. pThis->m_LockOut.Unlock();
  205. EndDialog(hdlg, IDRETRY);
  206. break;
  207. default:
  208. break;
  209. }
  210. }
  211. break;
  212. case WM_HELP:
  213. pThis->OnHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle);
  214. break;
  215. case WM_CONTEXTMENU:
  216. pThis->OnContextMenu((HWND) wParam);
  217. break;
  218. case WM_DRAWITEM:
  219. if (!pThis)
  220. return FALSE;
  221. if (pThis->m_pCheckBox &&
  222. GetDlgItem(hdlg, (int)wParam) == pThis->m_pCheckBox->m_hWnd) {
  223. ASSERT(IsValidWindow(pThis->m_pCheckBox->m_hWnd));
  224. pThis->m_pCheckBox->DrawItem((DRAWITEMSTRUCT*) lParam);
  225. return TRUE;
  226. }
  227. else
  228. return (int)pThis->OnDlgMsg(msg, wParam, lParam);
  229. case WM_VKEYTOITEM:
  230. if (pThis && pThis->m_pCheckBox && (HWND) lParam == pThis->m_pCheckBox->m_hWnd) {
  231. if (LOWORD(wParam) == VK_SPACE) {
  232. int cursel = (int)pThis->m_pCheckBox->GetCurSel();
  233. if (cursel != LB_ERR)
  234. pThis->m_pCheckBox->ToggleItem(cursel);
  235. }
  236. return -1; // always perform default action
  237. }
  238. else
  239. return (int)pThis->OnDlgMsg(msg, wParam, lParam);
  240. default:
  241. if (pThis)
  242. return (int)pThis->OnDlgMsg(msg, wParam, lParam);
  243. else
  244. return FALSE;
  245. }
  246. return FALSE;
  247. }
  248. /***************************************************************************
  249. FUNCTION: CDlg::OnMsg
  250. PURPOSE: Parse an array of messages and ids. If the message is
  251. intended for an id, call the associated function.
  252. PARAMETERS:
  253. wParam
  254. RETURNS: TRUE if no message was processed (i.e., continue processing).
  255. FALSE if message processed
  256. COMMENTS:
  257. MODIFICATION DATES:
  258. 16-Apr-1997 [ralphw]
  259. ***************************************************************************/
  260. BOOL CDlg::OnMsg(WPARAM wParam)
  261. {
  262. if (!m_pmsglist)
  263. return TRUE;
  264. UINT msg = HIWORD(wParam);
  265. UINT id = LOWORD(wParam);
  266. const CDLG_MESSAGE_LIST* pmsglist = m_pmsglist;
  267. for (;pmsglist->idControl; pmsglist++) {
  268. if (msg == pmsglist->idMessage && id == pmsglist->idControl) {
  269. (this->*pmsglist->pfunc)();
  270. return FALSE;
  271. }
  272. }
  273. return TRUE; // continue processing
  274. }
  275. HWND CDlg::DoModeless(void)
  276. {
  277. HWND hwnd = NULL;
  278. m_fModeLess = TRUE;
  279. if (m_fUnicode)
  280. {
  281. hwnd = ::CreateDialogParamW(_Module.GetResourceInstance(), (LPCWSTR)m_lpDialogTemplate,
  282. m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
  283. if (NULL == hwnd)
  284. {
  285. if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError())
  286. {
  287. m_fUnicode = FALSE;
  288. goto _Ansi;
  289. }
  290. }
  291. }
  292. else
  293. {
  294. _Ansi: hwnd = ::CreateDialogParamA(_Module.GetResourceInstance(), m_lpDialogTemplate, m_hwndParent,
  295. (DLGPROC) CDlgProc, (LPARAM) this);
  296. }
  297. ASSERT(IsValidWindow(m_hWnd) && hwnd == m_hWnd);
  298. ::ShowWindow(m_hWnd, SW_SHOW);
  299. return m_hWnd;
  300. }
  301. LRESULT CDlg::OnContextMenu(HWND hwnd)
  302. {
  303. if (m_aHelpIds)
  304. WinHelp(hwnd, m_pszHelpFile,
  305. HELP_CONTEXTMENU, (DWORD_PTR) (LPVOID) m_aHelpIds);
  306. return 0;
  307. }
  308. LRESULT CDlg::OnHelp(HWND hwnd)
  309. {
  310. if (m_aHelpIds)
  311. WinHelp(hwnd, m_pszHelpFile,
  312. HELP_WM_HELP, (DWORD_PTR) (LPVOID) m_aHelpIds);
  313. return 0;
  314. }
  315. static BOOL WINAPI EnumFontProc(HWND hwnd, LPARAM lval)
  316. {
  317. SendMessage(hwnd, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
  318. return TRUE;
  319. }
  320. static BOOL WINAPI EnumBidiSettings(HWND hwnd, LPARAM lval)
  321. {
  322. char szClass[MAX_PATH];
  323. VERIFY(GetClassName(hwnd, szClass, sizeof(szClass)));
  324. // In BiDi, flip the scroll bars to the left side
  325. if (IsSamePrefix(szClass, "LISTBOX", -2) ||
  326. IsSamePrefix(szClass, "COMBOBOX", -2)) {
  327. ::SetWindowLong(hwnd, GWL_EXSTYLE,
  328. WS_EX_LEFTSCROLLBAR | ::GetWindowLong(hwnd, GWL_EXSTYLE));
  329. }
  330. return TRUE;
  331. }
  332. void CDlgListBox::RemoveListItem()
  333. {
  334. int cursel;
  335. if ((cursel = (int)GetCurSel()) != LB_ERR) {
  336. // Delete current selection, and select the item below it
  337. DeleteString(cursel);
  338. if (cursel < GetCount())
  339. SetCurSel(cursel);
  340. else if (cursel > 0)
  341. SetCurSel(--cursel);
  342. else if (GetCount())
  343. SetCurSel(0);
  344. }
  345. }
  346. void CDlg::MakeCheckedList(int idLB)
  347. {
  348. if (!m_pCheckBox)
  349. m_pCheckBox = new CDlgCheckListBox;
  350. m_pCheckBox->Initialize(*this, idLB);
  351. }
  352. CDlgCheckListBox::CDlgCheckListBox()
  353. {
  354. m_xMargin = GetSystemMetrics(SM_CXBORDER);
  355. m_yMargin = GetSystemMetrics(SM_CYBORDER);
  356. m_cxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME);
  357. m_hbmpCheck = LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_CHECK));
  358. ASSERT(m_hbmpCheck);
  359. BITMAP bmp;
  360. GetObject(m_hbmpCheck, sizeof(BITMAP), &bmp);
  361. m_cxCheck = bmp.bmWidth / 3;
  362. m_cyCheck = bmp.bmHeight;
  363. m_iLastSel = LB_ERR;
  364. }
  365. CDlgCheckListBox::~CDlgCheckListBox()
  366. {
  367. DeleteObject(m_hbmpCheck);
  368. }
  369. BOOL CDlgCheckListBox::IsItemChecked (int nIndex) const
  370. {
  371. return (BOOL) GetItemData(nIndex);
  372. }
  373. void CDlgCheckListBox::CheckItem(int nIndex, BOOL fChecked /*= TRUE*/)
  374. {
  375. SetItemData(nIndex, fChecked);
  376. InvalidateItem(nIndex);
  377. }
  378. void CDlgCheckListBox::ToggleItem (int nIndex)
  379. {
  380. CheckItem(nIndex, IsItemChecked(nIndex) ? FALSE : TRUE);
  381. }
  382. int CDlgCheckListBox::ItemHeight(void)
  383. {
  384. HDC hdc = GetDC(m_hWnd);
  385. SIZE size;
  386. VERIFY(GetTextExtentPoint(hdc, "M", 1, &size));
  387. ReleaseDC(m_hWnd, hdc);
  388. return size.cy; // + GetSystemMetrics (SM_CYBORDER);
  389. }
  390. void CDlgCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  391. {
  392. ASSERT (lpDrawItemStruct != NULL);
  393. // Ignore if not redrawing 1
  394. if (lpDrawItemStruct->itemID != LB_ERR &&
  395. (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) {
  396. CStr cszText;
  397. int cbText = (int)GetTextLength(lpDrawItemStruct->itemID);
  398. cszText.psz = (PSTR) lcMalloc(cbText + 1);
  399. GetText(cszText.psz, cbText + 1, lpDrawItemStruct->itemID);
  400. SetTextColor(lpDrawItemStruct->hDC,
  401. GetSysColor((lpDrawItemStruct->itemState & ODS_SELECTED) ?
  402. COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
  403. SetBkColor(lpDrawItemStruct->hDC,
  404. GetSysColor((lpDrawItemStruct->itemState & ODS_SELECTED) ?
  405. COLOR_HIGHLIGHT : COLOR_WINDOW));
  406. RECT rcItem;
  407. RECT rcCheck;
  408. GetItemRect(&rcItem, lpDrawItemStruct->itemID);
  409. GetCheckRect(lpDrawItemStruct->itemID, &rcCheck);
  410. int yTextOffset = max(0, (RECT_HEIGHT(rcItem) - ItemHeight()) / 2);
  411. int xTextOffset = 2 * m_cxDlgFrame + RECT_WIDTH(rcCheck);
  412. ExtTextOut(lpDrawItemStruct->hDC,
  413. rcItem.left + xTextOffset, rcItem.top + yTextOffset,
  414. ETO_OPAQUE, &rcItem, cszText, cbText, NULL);
  415. DrawCheck(lpDrawItemStruct->hDC, &rcCheck, IsItemChecked(lpDrawItemStruct->itemID));
  416. }
  417. }
  418. void CDlgCheckListBox::InvalidateItem(int nIndex, BOOL fRedraw /*= FALSE*/)
  419. {
  420. RECT rc;
  421. if (GetItemRect(&rc, nIndex) != LB_ERR)
  422. InvalidateRect(m_hWnd, &rc, fRedraw);
  423. }
  424. void CDlgCheckListBox::DrawCheck(HDC hdc, RECT* prc, BOOL fChecked)
  425. {
  426. CPalDC dcBmp(m_hbmpCheck);
  427. BitBlt(hdc, prc->left, prc->top,
  428. m_cxCheck, m_cyCheck, dcBmp,
  429. m_cyCheck * (fChecked ? 1 : 0), 0, SRCCOPY);
  430. }
  431. const int CHECK_MARGIN = 2;
  432. int CDlgCheckListBox::GetCheckRect(int nIndex, RECT* prc)
  433. {
  434. if (GetItemRect(prc, nIndex) == LB_ERR)
  435. return LB_ERR;
  436. prc->left += CHECK_MARGIN;
  437. prc->right = prc->left + m_cxCheck;
  438. if (RECT_HEIGHT(prc) > m_cyCheck) {
  439. int diff = (RECT_HEIGHT(prc) - m_cyCheck) / 2;
  440. prc->top += diff;
  441. }
  442. return 0;
  443. }
  444. void CDlgCheckListBox::OnSelChange(void)
  445. {
  446. int pos = (int)GetCurSel();
  447. if (pos != LB_ERR) {
  448. POINT pt;
  449. GetCursorPos(&pt);
  450. ScreenToClient(*this, &pt);
  451. RECT rc;
  452. GetCheckRect(pos, &rc);
  453. if (PtInRect(&rc, pt))
  454. ToggleItem(pos);
  455. else if (pos == m_iLastSel)
  456. ToggleItem(pos);
  457. }
  458. m_iLastSel = pos;
  459. }