Leaked source code of windows server 2003
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.

536 lines
17 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 2000
  4. *
  5. * TITLE: CHKLISTV.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 11/13/2000
  12. *
  13. * DESCRIPTION: Listview with checkmarks
  14. *
  15. *******************************************************************************/
  16. #include <windows.h>
  17. #include <windowsx.h>
  18. #include <commctrl.h>
  19. #include <simarray.h>
  20. #include <psutil.h>
  21. #include <wiadebug.h>
  22. #include "chklistv.h"
  23. CCheckedListviewHandler::CCheckedListviewHandler(void)
  24. : m_bFullImageHit(false),
  25. m_hImageList(NULL),
  26. m_nCheckedImageIndex(-1),
  27. m_nUncheckedImageIndex(-1)
  28. {
  29. ZeroMemory(&m_sizeCheck,sizeof(m_sizeCheck));
  30. CreateDefaultCheckBitmaps();
  31. }
  32. CCheckedListviewHandler::~CCheckedListviewHandler(void)
  33. {
  34. //
  35. // Free all allocated memory
  36. //
  37. DestroyImageList();
  38. }
  39. HBITMAP CCheckedListviewHandler::CreateBitmap( int nWidth, int nHeight )
  40. {
  41. //
  42. // Create a 24bit RGB DIB section of a given size
  43. //
  44. HBITMAP hBitmap = NULL;
  45. HDC hDC = GetDC( NULL );
  46. if (hDC)
  47. {
  48. BITMAPINFO BitmapInfo = {0};
  49. BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  50. BitmapInfo.bmiHeader.biWidth = nWidth;
  51. BitmapInfo.bmiHeader.biHeight = nHeight;
  52. BitmapInfo.bmiHeader.biPlanes = 1;
  53. BitmapInfo.bmiHeader.biBitCount = 24;
  54. BitmapInfo.bmiHeader.biCompression = BI_RGB;
  55. PBYTE *pBits = NULL;
  56. hBitmap = CreateDIBSection( hDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pBits, NULL, 0 );
  57. ReleaseDC( NULL, hDC );
  58. }
  59. return hBitmap;
  60. }
  61. void CCheckedListviewHandler::DestroyImageList(void)
  62. {
  63. //
  64. // Destroy the image list and initialize related variables
  65. //
  66. if (m_hImageList)
  67. {
  68. ImageList_Destroy( m_hImageList );
  69. m_hImageList = NULL;
  70. }
  71. m_nCheckedImageIndex = m_nUncheckedImageIndex = -1;
  72. m_sizeCheck.cx = m_sizeCheck.cy = 0;
  73. }
  74. bool CCheckedListviewHandler::ImagesValid(void)
  75. {
  76. //
  77. // Make sure the images in the image list are valid
  78. //
  79. return (m_hImageList && m_nCheckedImageIndex >= 0 && m_nUncheckedImageIndex >= 0 && m_sizeCheck.cx && m_sizeCheck.cy);
  80. }
  81. void CCheckedListviewHandler::Attach( HWND hWnd )
  82. {
  83. if (m_WindowList.Find(hWnd) < 0)
  84. {
  85. m_WindowList.Append(hWnd);
  86. }
  87. }
  88. void CCheckedListviewHandler::Detach( HWND hWnd )
  89. {
  90. int nIndex = m_WindowList.Find(hWnd);
  91. if (nIndex >= 0)
  92. {
  93. m_WindowList.Delete( nIndex );
  94. }
  95. }
  96. bool CCheckedListviewHandler::WindowInList( HWND hWnd )
  97. {
  98. return (m_WindowList.Find(hWnd) >= 0);
  99. }
  100. //
  101. // Private helpers
  102. //
  103. BOOL CCheckedListviewHandler::InCheckBox( HWND hwndList, int nItem, const POINT &pt )
  104. {
  105. BOOL bResult = FALSE;
  106. if (WindowInList(hwndList))
  107. {
  108. #if defined(DBG)
  109. WIA_TRACE((TEXT("nItem: %d"), nItem ));
  110. LVHITTESTINFO LvHitTestInfo = {0};
  111. LvHitTestInfo.pt = pt;
  112. ListView_SubItemHitTest( hwndList, &LvHitTestInfo );
  113. WIA_TRACE((TEXT("LvHitTestInfo.iItem: %d"), LvHitTestInfo.iItem ));
  114. #endif
  115. RECT rcItem = {0};
  116. if (ListView_GetItemRect( hwndList, nItem, &rcItem, LVIR_ICON ))
  117. {
  118. WIA_TRACE((TEXT("pt: (%d, %d)"), pt.x, pt.y ));
  119. WIA_TRACE((TEXT("rcItem: (%d, %d), (%d, %d)"), rcItem.left, rcItem.top, rcItem.right, rcItem.bottom ));
  120. rcItem.right -= c_sizeCheckMarginX;
  121. rcItem.top += c_sizeCheckMarginY;
  122. rcItem.left = rcItem.right - m_sizeCheck.cx;
  123. rcItem.bottom = rcItem.top + m_sizeCheck.cy;
  124. bResult = PtInRect( &rcItem, pt );
  125. }
  126. }
  127. return bResult;
  128. }
  129. UINT CCheckedListviewHandler::GetItemCheckState( HWND hwndList, int nIndex )
  130. {
  131. UINT nResult = LVCHECKSTATE_NOCHECK;
  132. NMGETCHECKSTATE NmGetCheckState = {0};
  133. NmGetCheckState.hdr.hwndFrom = hwndList;
  134. NmGetCheckState.hdr.idFrom = GetWindowLong( hwndList, GWL_ID );
  135. NmGetCheckState.hdr.code = NM_GETCHECKSTATE;
  136. NmGetCheckState.nItem = nIndex;
  137. nResult = static_cast<UINT>(SendMessage( reinterpret_cast<HWND>(GetWindowLongPtr(hwndList,GWLP_HWNDPARENT)), WM_NOTIFY, GetWindowLong( hwndList, GWL_ID ), reinterpret_cast<LPARAM>(&NmGetCheckState) ) );
  138. return nResult;
  139. }
  140. UINT CCheckedListviewHandler::SetItemCheckState( HWND hwndList, int nIndex, UINT nCheck )
  141. {
  142. UINT nResult = GetItemCheckState( hwndList, nIndex );
  143. NMSETCHECKSTATE NmSetCheckState = {0};
  144. NmSetCheckState.hdr.hwndFrom = hwndList;
  145. NmSetCheckState.hdr.idFrom = GetWindowLong( hwndList, GWL_ID );
  146. NmSetCheckState.hdr.code = NM_SETCHECKSTATE;
  147. NmSetCheckState.nItem = nIndex;
  148. NmSetCheckState.nCheck = nCheck;
  149. SendMessage( reinterpret_cast<HWND>(GetWindowLongPtr(hwndList,GWLP_HWNDPARENT)), WM_NOTIFY, GetWindowLong( hwndList, GWL_ID ), reinterpret_cast<LPARAM>(&NmSetCheckState) );
  150. return nResult;
  151. }
  152. int CCheckedListviewHandler::GetItemCheckBitmap( HWND hwndList, int nIndex )
  153. {
  154. int nResult = -1;
  155. if (WindowInList(hwndList))
  156. {
  157. UINT nCheck = GetItemCheckState( hwndList, nIndex );
  158. switch (nCheck)
  159. {
  160. case LVCHECKSTATE_CHECKED:
  161. nResult = m_nCheckedImageIndex;
  162. break;
  163. case LVCHECKSTATE_UNCHECKED:
  164. nResult = m_nUncheckedImageIndex;
  165. break;
  166. }
  167. }
  168. return nResult;
  169. }
  170. BOOL CCheckedListviewHandler::RealHandleListClick( WPARAM wParam, LPARAM lParam, bool bIgnoreHitArea )
  171. {
  172. BOOL bResult = FALSE;
  173. NMITEMACTIVATE *pNmItemActivate = reinterpret_cast<NMITEMACTIVATE*>(lParam);
  174. if (pNmItemActivate)
  175. {
  176. if (WindowInList(pNmItemActivate->hdr.hwndFrom))
  177. {
  178. if (bIgnoreHitArea || InCheckBox(pNmItemActivate->hdr.hwndFrom,pNmItemActivate->iItem,pNmItemActivate->ptAction))
  179. {
  180. UINT nCheck = GetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem );
  181. switch (nCheck)
  182. {
  183. case LVCHECKSTATE_UNCHECKED:
  184. SetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem, LVCHECKSTATE_CHECKED );
  185. break;
  186. case LVCHECKSTATE_CHECKED:
  187. SetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem, LVCHECKSTATE_UNCHECKED );
  188. break;
  189. }
  190. }
  191. bResult = TRUE;
  192. }
  193. }
  194. return 0;
  195. }
  196. //
  197. // Message handlers
  198. //
  199. BOOL CCheckedListviewHandler::HandleListClick( WPARAM wParam, LPARAM lParam )
  200. {
  201. return RealHandleListClick( wParam, lParam, m_bFullImageHit );
  202. }
  203. BOOL CCheckedListviewHandler::HandleListDblClk( WPARAM wParam, LPARAM lParam )
  204. {
  205. return RealHandleListClick( wParam, lParam, true );
  206. }
  207. BOOL CCheckedListviewHandler::HandleListKeyDown( WPARAM wParam, LPARAM lParam, LRESULT &lResult )
  208. {
  209. BOOL bHandled = FALSE;
  210. NMLVKEYDOWN *pNmLvKeyDown = reinterpret_cast<NMLVKEYDOWN*>(lParam);
  211. if (WindowInList(pNmLvKeyDown->hdr.hwndFrom))
  212. {
  213. lResult = 0;
  214. bool bControl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
  215. bool bShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
  216. bool bAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
  217. if (pNmLvKeyDown->wVKey == VK_SPACE && !bControl && !bShift && !bAlt)
  218. {
  219. int nFocusedItem = ListView_GetNextItem( pNmLvKeyDown->hdr.hwndFrom, -1, LVNI_FOCUSED );
  220. if (nFocusedItem >= 0)
  221. {
  222. UINT nCheckState = GetItemCheckState( pNmLvKeyDown->hdr.hwndFrom, nFocusedItem );
  223. if (LVCHECKSTATE_CHECKED == nCheckState)
  224. {
  225. nCheckState = LVCHECKSTATE_UNCHECKED;
  226. }
  227. else if (LVCHECKSTATE_UNCHECKED == nCheckState)
  228. {
  229. nCheckState = LVCHECKSTATE_CHECKED;
  230. }
  231. if (nCheckState != LVCHECKSTATE_NOCHECK)
  232. {
  233. int nCurrItem = -1;
  234. while (true)
  235. {
  236. nCurrItem = ListView_GetNextItem( pNmLvKeyDown->hdr.hwndFrom, nCurrItem, LVNI_SELECTED );
  237. if (nCurrItem < 0)
  238. {
  239. break;
  240. }
  241. SetItemCheckState( pNmLvKeyDown->hdr.hwndFrom, nCurrItem, nCheckState );
  242. }
  243. }
  244. }
  245. lResult = TRUE;
  246. bHandled = TRUE;
  247. InvalidateRect( pNmLvKeyDown->hdr.hwndFrom, NULL, FALSE );
  248. UpdateWindow( pNmLvKeyDown->hdr.hwndFrom );
  249. }
  250. }
  251. return bHandled;
  252. }
  253. BOOL CCheckedListviewHandler::HandleListCustomDraw( WPARAM wParam, LPARAM lParam, LRESULT &lResult )
  254. {
  255. BOOL bHandled = FALSE;
  256. NMLVCUSTOMDRAW *pNmCustomDraw = reinterpret_cast<NMLVCUSTOMDRAW*>(lParam);
  257. if (pNmCustomDraw)
  258. {
  259. if (WindowInList(pNmCustomDraw->nmcd.hdr.hwndFrom))
  260. {
  261. lResult = CDRF_DODEFAULT;
  262. #if defined(DUMP_NM_CUSTOMDRAW_MESSAGES)
  263. DumpCustomDraw(lParam,TEXT("SysListView32"),CDDS_ITEMPOSTPAINT);
  264. #endif
  265. if (CDDS_PREPAINT == pNmCustomDraw->nmcd.dwDrawStage)
  266. {
  267. lResult = CDRF_NOTIFYITEMDRAW;
  268. }
  269. else if (CDDS_ITEMPREPAINT == pNmCustomDraw->nmcd.dwDrawStage)
  270. {
  271. lResult = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYSUBITEMDRAW;
  272. }
  273. else if (CDDS_ITEMPOSTPAINT == pNmCustomDraw->nmcd.dwDrawStage)
  274. {
  275. int nImageListIndex = GetItemCheckBitmap( pNmCustomDraw->nmcd.hdr.hwndFrom, static_cast<int>(pNmCustomDraw->nmcd.dwItemSpec) );
  276. if (nImageListIndex >= 0)
  277. {
  278. RECT rcItem = {0};
  279. if (ListView_GetItemRect( pNmCustomDraw->nmcd.hdr.hwndFrom, pNmCustomDraw->nmcd.dwItemSpec, &rcItem, LVIR_ICON ))
  280. {
  281. ImageList_Draw( m_hImageList, nImageListIndex, pNmCustomDraw->nmcd.hdc, rcItem.right - m_sizeCheck.cx - c_sizeCheckMarginX, rcItem.top + c_sizeCheckMarginY, ILD_NORMAL );
  282. lResult = CDRF_SKIPDEFAULT;
  283. }
  284. }
  285. }
  286. bHandled = TRUE;
  287. }
  288. }
  289. return bHandled;
  290. }
  291. void CCheckedListviewHandler::Select( HWND hwndList, int nIndex, UINT nSelect )
  292. {
  293. if (WindowInList(hwndList))
  294. {
  295. //
  296. // -1 means all images
  297. //
  298. if (nIndex < 0)
  299. {
  300. for (int i=0;i<ListView_GetItemCount(hwndList);i++)
  301. {
  302. SetItemCheckState(hwndList,i,nSelect);
  303. }
  304. }
  305. else
  306. {
  307. SetItemCheckState(hwndList,nIndex,nSelect);
  308. }
  309. }
  310. }
  311. bool CCheckedListviewHandler::FullImageHit(void) const
  312. {
  313. return m_bFullImageHit;
  314. }
  315. void CCheckedListviewHandler::FullImageHit( bool bFullImageHit )
  316. {
  317. m_bFullImageHit = bFullImageHit;
  318. }
  319. bool CCheckedListviewHandler::CreateDefaultCheckBitmaps(void)
  320. {
  321. bool bResult = false;
  322. //
  323. // Get the proper size for the checkmarks
  324. //
  325. int nWidth = GetSystemMetrics( SM_CXMENUCHECK );
  326. int nHeight = GetSystemMetrics( SM_CXMENUCHECK );
  327. //
  328. // Make sure they are valid sizes
  329. //
  330. if (nWidth && nHeight)
  331. {
  332. //
  333. // Create the bitmaps and make sure they are valid
  334. //
  335. HBITMAP hBitmapChecked = CreateBitmap( nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2 );
  336. HBITMAP hBitmapUnchecked = CreateBitmap( nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2 );
  337. if (hBitmapChecked && hBitmapUnchecked)
  338. {
  339. //
  340. // Get the desktop DC
  341. //
  342. HDC hDC = GetDC( NULL );
  343. if (hDC)
  344. {
  345. //
  346. // Create a memory DC
  347. //
  348. HDC hMemDC = CreateCompatibleDC( hDC );
  349. if (hMemDC)
  350. {
  351. //
  352. // This is the rect that contains the image + the margin
  353. //
  354. RECT rcEntireBitmap = {0,0,nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2};
  355. //
  356. // This is the rect that contains only the image
  357. //
  358. RECT rcControlBitmap = {c_nCheckmarkBorder,c_nCheckmarkBorder,nWidth+c_nCheckmarkBorder, nHeight+c_nCheckmarkBorder};
  359. //
  360. // Paint the checked bitmap
  361. //
  362. HBITMAP hOldBitmap = SelectBitmap( hMemDC, hBitmapChecked );
  363. FillRect( hMemDC, &rcEntireBitmap, GetSysColorBrush( COLOR_WINDOW ) );
  364. DrawFrameControl( hMemDC, &rcControlBitmap, DFC_BUTTON, DFCS_BUTTONCHECK|DFCS_CHECKED|DFCS_FLAT );
  365. //
  366. // Paint the unchecked bitmap
  367. //
  368. SelectBitmap( hMemDC, hBitmapUnchecked );
  369. FillRect( hMemDC, &rcEntireBitmap, GetSysColorBrush( COLOR_WINDOW ) );
  370. DrawFrameControl( hMemDC, &rcControlBitmap, DFC_BUTTON, DFCS_BUTTONCHECK|DFCS_FLAT );
  371. //
  372. // Restore and delete the memory DC
  373. //
  374. SelectBitmap( hMemDC, hOldBitmap );
  375. DeleteDC( hMemDC );
  376. //
  377. // Save the images
  378. //
  379. bResult = SetCheckboxImages( hBitmapChecked, hBitmapUnchecked );
  380. //
  381. // The images are in the image list now, so discard them
  382. //
  383. DeleteBitmap(hBitmapChecked);
  384. DeleteBitmap(hBitmapUnchecked);
  385. }
  386. ReleaseDC( NULL, hDC );
  387. }
  388. }
  389. }
  390. return bResult;
  391. }
  392. bool CCheckedListviewHandler::SetCheckboxImages( HBITMAP hChecked, HBITMAP hUnchecked )
  393. {
  394. DestroyImageList();
  395. //
  396. // Find out the size of the bitmaps and make sure they are the same.
  397. //
  398. SIZE sizeChecked = {0};
  399. if (PrintScanUtil::GetBitmapSize( hChecked, sizeChecked ))
  400. {
  401. SIZE sizeUnchecked = {0};
  402. if (PrintScanUtil::GetBitmapSize( hUnchecked, sizeUnchecked ))
  403. {
  404. if (sizeChecked.cx == sizeUnchecked.cx && sizeChecked.cy == sizeUnchecked.cy)
  405. {
  406. //
  407. // Save the size
  408. //
  409. m_sizeCheck.cx = sizeChecked.cx;
  410. m_sizeCheck.cy = sizeChecked.cy;
  411. //
  412. // Create the image list to hold the checkboxes
  413. //
  414. m_hImageList = ImageList_Create( m_sizeCheck.cx, m_sizeCheck.cy, ILC_COLOR24, 2, 2 );
  415. if (m_hImageList)
  416. {
  417. //
  418. // Save the indices of the images
  419. //
  420. m_nCheckedImageIndex = ImageList_Add( m_hImageList, hChecked, NULL );
  421. m_nUncheckedImageIndex = ImageList_Add( m_hImageList, hUnchecked, NULL );
  422. }
  423. }
  424. }
  425. }
  426. //
  427. // If the images aren't valid, clean up
  428. //
  429. bool bResult = ImagesValid();
  430. if (!bResult)
  431. {
  432. DestroyImageList();
  433. }
  434. return bResult;
  435. }
  436. bool CCheckedListviewHandler::SetCheckboxImages( HICON hChecked, HICON hUnchecked )
  437. {
  438. DestroyImageList();
  439. //
  440. // Find out the size of the icons and make sure they are the same.
  441. //
  442. SIZE sizeChecked = {0};
  443. if (PrintScanUtil::GetIconSize( hChecked, sizeChecked ))
  444. {
  445. SIZE sizeUnchecked = {0};
  446. if (PrintScanUtil::GetIconSize( hUnchecked, sizeUnchecked ))
  447. {
  448. if (sizeChecked.cx == sizeUnchecked.cx && sizeChecked.cy == sizeUnchecked.cy)
  449. {
  450. //
  451. // Save the size
  452. //
  453. m_sizeCheck.cx = sizeChecked.cx;
  454. m_sizeCheck.cy = sizeChecked.cy;
  455. //
  456. // Create the image list to hold the checkboxes
  457. //
  458. m_hImageList = ImageList_Create( m_sizeCheck.cx, m_sizeCheck.cy, ILC_COLOR24|ILC_MASK, 2, 2 );
  459. if (m_hImageList)
  460. {
  461. //
  462. // Save the indices of the images
  463. //
  464. m_nCheckedImageIndex = ImageList_AddIcon( m_hImageList, hChecked );
  465. m_nUncheckedImageIndex = ImageList_AddIcon( m_hImageList, hUnchecked );
  466. }
  467. }
  468. }
  469. }
  470. //
  471. // If the images aren't valid, clean up
  472. //
  473. bool bResult = ImagesValid();
  474. if (!bResult)
  475. {
  476. DestroyImageList();
  477. }
  478. return bResult;
  479. }