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.

1015 lines
30 KiB

  1. /* Copyright (c) 1995, Microsoft Corporation, all rights reserved
  2. **
  3. ** lvx.c
  4. ** Listview extension routines
  5. ** Listed alphabetically
  6. **
  7. ** 11/25/95 Steve Cobb
  8. ** Some adapted from \\ftp\data\softlib\mslfiles\odlistvw.exe sample code.
  9. */
  10. #include <windows.h> // Win32 root
  11. #include <windowsx.h> // Win32 macro extensions
  12. #include <commctrl.h> // Win32 common controls
  13. #include <debug.h> // Trace and assert
  14. #include <uiutil.h> // Our public header
  15. #include <lvx.rch> // Our resource constants
  16. /* List view of check boxes state indices.
  17. */
  18. #define SI_Unchecked 1
  19. #define SI_Checked 2
  20. #define SI_DisabledUnchecked 3
  21. #define SI_DisabledChecked 4
  22. /* Text indents within a column in pixels. If you mess with the dx, you're
  23. ** asking for misalignment problems with the header labels. BTW, the first
  24. ** column doesn't line up with it's header if there are no icons. Regular
  25. ** list view has this problem, too. If you try to fix this you'll wind up
  26. ** duplicating the AUTOSIZE_USEHEADER option of ListView_SetColumnWidth.
  27. ** Should be able to change the dy without causing problems.
  28. */
  29. #define LVX_dxColText 4
  30. #define LVX_dyColText 1
  31. /* Guaranteed vertical space between icons. Should be able to mess with this
  32. ** without causing problems.
  33. */
  34. #define LVX_dyIconSpacing 1
  35. /* The atom identifying our context property suitable for use by the Windows
  36. ** XxxProp APIs. A Prop is used to associate context information (the address
  37. ** of the WNDPROC we subclassed) with a "list view of check boxes" window.
  38. */
  39. static LPCWSTR g_lvxcbContextId = NULL;
  40. /*----------------------------------------------------------------------------
  41. ** Local prototypes
  42. **----------------------------------------------------------------------------
  43. */
  44. LRESULT APIENTRY
  45. LvxcbProc(
  46. IN HWND hwnd,
  47. IN UINT unMsg,
  48. IN WPARAM wparam,
  49. IN LPARAM lparam );
  50. BOOL
  51. LvxDrawItem(
  52. IN DRAWITEMSTRUCT* pdis,
  53. IN PLVXCALLBACK pLvxCallback );
  54. BOOL
  55. LvxMeasureItem(
  56. IN HWND hwnd,
  57. IN OUT MEASUREITEMSTRUCT* pmis );
  58. /*----------------------------------------------------------------------------
  59. ** ListView of check boxes
  60. **----------------------------------------------------------------------------
  61. */
  62. BOOL
  63. ListView_GetCheck(
  64. IN HWND hwndLv,
  65. IN INT iItem )
  66. /* Returns true if the check box of item 'iItem' of listview of checkboxes
  67. ** 'hwndLv' is checked, false otherwise. This function works on disabled
  68. ** check boxes as well as enabled ones.
  69. */
  70. {
  71. UINT unState;
  72. unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
  73. return !!((unState == INDEXTOSTATEIMAGEMASK( SI_Checked )) ||
  74. (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )));
  75. }
  76. BOOL
  77. ListView_IsCheckDisabled (
  78. IN HWND hwndLv,
  79. IN INT iItem)
  80. /* Returns true if the check box of item 'iItem' of listview of checkboxes
  81. ** 'hwndLv' is disabled, false otherwise.
  82. */
  83. {
  84. UINT unState;
  85. unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
  86. if ((unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )) ||
  87. (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledUnchecked )))
  88. return TRUE;
  89. return FALSE;
  90. }
  91. VOID
  92. ListView_DisableCheck (
  93. IN HWND hwndLv,
  94. IN INT iItem)
  95. /* Disables a check box of item 'iItem' of listview of checkboxes. Once
  96. ** disabled, ListView_SetCheck will have no effect on the item until
  97. ** ListView_EnableCheck(...) is called for this item. Likewise, there is no
  98. ** way through the UI to change the check of this item until it is enabled.
  99. ** Calling this function on a disabled check has no effect.
  100. */
  101. {
  102. BOOL fCheck;
  103. fCheck = ListView_GetCheck(hwndLv, iItem);
  104. ListView_SetItemState( hwndLv, iItem,
  105. INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_DisabledChecked : SI_DisabledUnchecked),
  106. LVIS_STATEIMAGEMASK );
  107. }
  108. VOID
  109. ListView_EnableCheck (
  110. IN HWND hwndLv,
  111. IN INT iItem)
  112. /* Reverses the effect of ListView_DisableCheck.
  113. */
  114. {
  115. BOOL fCheck;
  116. fCheck = ListView_GetCheck(hwndLv, iItem);
  117. ListView_SetItemState( hwndLv, iItem,
  118. INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
  119. LVIS_STATEIMAGEMASK );
  120. }
  121. UINT
  122. ListView_GetCheckedCount(
  123. IN HWND hwndLv )
  124. /* Returns the number of checked items in 'hwndLv' regardless of whether
  125. ** they are disabled.
  126. */
  127. {
  128. UINT c = 0;
  129. INT i = -1;
  130. while ((i = ListView_GetNextItem( hwndLv, i, LVNI_ALL )) >= 0)
  131. {
  132. if (ListView_GetCheck( hwndLv, i ))
  133. ++c;
  134. }
  135. return c;
  136. }
  137. BOOL
  138. ListView_InstallChecks(
  139. IN HWND hwndLv,
  140. IN HINSTANCE hinst )
  141. /* Initialize "list of checkbox" handling for listview 'hwndLv'. 'Hinst'
  142. ** is the module instance containing the two checkbox icons. See LVX.RC.
  143. **
  144. ** Returns true if successful, false otherwise. Caller must eventually
  145. ** call 'ListView_UninstallChecks', typically in WM_DESTROY processing.
  146. */
  147. {
  148. HICON hIcon;
  149. HIMAGELIST himl;
  150. WNDPROC pOldProc;
  151. //Add this for RTL(right to left, mirrored windows version)
  152. //whistler bug 41349 gangz
  153. //
  154. BOOL fMirrored=FALSE;
  155. DWORD dwLayout;
  156. // pmay: 397395
  157. //
  158. // Prevent endless loops resulting from accidentally calling this
  159. // api twice.
  160. //
  161. pOldProc = (WNDPROC)GetWindowLongPtr(hwndLv, GWLP_WNDPROC);
  162. if (pOldProc == LvxcbProc)
  163. {
  164. return TRUE;
  165. }
  166. //get current application's layout (RTL or normal) gangz
  167. // for whistler bug 41349
  168. //There are two ways:
  169. //(1) use GetWindowLong() with GWL_EXSTYLE for WS_EX_LAYOUTRTL style if
  170. // you have a window handler available
  171. //(2) use GetProcessDefaultLayout() to get the layout for the current
  172. // process, and compare that against LAYOUT_RTL
  173. //
  174. dwLayout = GetWindowLong(hwndLv, GWL_EXSTYLE);
  175. if ( WS_EX_LAYOUTRTL & dwLayout )
  176. {
  177. fMirrored = TRUE;
  178. }
  179. /* Build checkbox image lists.
  180. */
  181. himl = ImageList_Create(
  182. GetSystemMetrics( SM_CXSMICON ),
  183. GetSystemMetrics( SM_CYSMICON ),
  184. ILC_MASK, 2, 2 );
  185. /* The order these are added is significant since it implicitly
  186. ** establishes the state indices matching SI_Unchecked and SI_Checked.
  187. */
  188. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Unchecked ) );
  189. if ( NULL != hIcon )
  190. {
  191. ImageList_AddIcon( himl, hIcon );
  192. DeleteObject( hIcon );
  193. }
  194. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_CheckedRTL : IID_Checked ) );
  195. if ( NULL != hIcon )
  196. {
  197. ImageList_AddIcon( himl, hIcon );
  198. DeleteObject( hIcon );
  199. }
  200. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledUnchecked ) );
  201. if ( NULL != hIcon )
  202. {
  203. ImageList_AddIcon( himl, hIcon );
  204. DeleteObject( hIcon );
  205. }
  206. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( fMirrored?IID_DisabledCheckedRTL : IID_DisabledChecked ) );
  207. if ( NULL != hIcon )
  208. {
  209. ImageList_AddIcon( himl, hIcon );
  210. DeleteObject( hIcon );
  211. }
  212. ListView_SetImageList( hwndLv, himl, LVSIL_STATE );
  213. /* Register atom for use in the Windows XxxProp calls which are used to
  214. ** associate the old WNDPROC with the listview window handle.
  215. */
  216. if (!g_lvxcbContextId)
  217. g_lvxcbContextId = (LPCWSTR )GlobalAddAtom( L"RASLVXCB" );
  218. if (!g_lvxcbContextId)
  219. return FALSE;
  220. /* Subclass the current window procedure.
  221. */
  222. pOldProc = (WNDPROC)SetWindowLongPtr(
  223. hwndLv, GWLP_WNDPROC, (ULONG_PTR)LvxcbProc );
  224. return SetProp( hwndLv, g_lvxcbContextId, (HANDLE )pOldProc );
  225. }
  226. VOID
  227. ListView_SetCheck(
  228. IN HWND hwndLv,
  229. IN INT iItem,
  230. IN BOOL fCheck )
  231. /* Sets the check mark on item 'iItem' of listview of checkboxes 'hwndLv'
  232. ** to checked if 'fCheck' is true or unchecked if false.
  233. */
  234. {
  235. NM_LISTVIEW nmlv;
  236. if (ListView_IsCheckDisabled(hwndLv, iItem))
  237. return;
  238. ListView_SetItemState( hwndLv, iItem,
  239. INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
  240. LVIS_STATEIMAGEMASK );
  241. nmlv.hdr.code = LVXN_SETCHECK;
  242. nmlv.hdr.hwndFrom = hwndLv;
  243. nmlv.iItem = iItem;
  244. FORWARD_WM_NOTIFY(
  245. GetParent(hwndLv), GetDlgCtrlID(hwndLv), &nmlv, SendMessage
  246. );
  247. }
  248. VOID
  249. ListView_UninstallChecks(
  250. IN HWND hwndLv )
  251. /* Uninstalls "listview of check boxes" handling from list view 'hwndLv'.
  252. */
  253. {
  254. WNDPROC pOldProc;
  255. pOldProc = (WNDPROC)GetProp( hwndLv, g_lvxcbContextId );
  256. if (pOldProc)
  257. {
  258. /* Un-subclass so it can terminate without access to the context.
  259. */
  260. SetWindowLongPtr( hwndLv, GWLP_WNDPROC, (ULONG_PTR)pOldProc );
  261. }
  262. RemoveProp( hwndLv, g_lvxcbContextId );
  263. }
  264. LRESULT APIENTRY
  265. LvxcbProc(
  266. IN HWND hwnd,
  267. IN UINT unMsg,
  268. IN WPARAM wparam,
  269. IN LPARAM lparam )
  270. /* List view subclass window procedure to trap toggle-check events.
  271. */
  272. {
  273. WNDPROC pOldProc;
  274. INT iItem;
  275. BOOL fSet;
  276. BOOL fClear;
  277. BOOL fToggle;
  278. iItem = -1;
  279. fSet = fClear = fToggle = FALSE;
  280. if (unMsg == WM_LBUTTONDOWN)
  281. {
  282. LV_HITTESTINFO info;
  283. /* Left mouse button pressed over checkbox icon toggles state.
  284. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
  285. ** want to work with our cool owner-drawn list view extensions in
  286. ** which case the control doesn't know where the icon is on the item,
  287. ** so it returns a hit anywhere on the item anyway.
  288. */
  289. ZeroMemory( &info, sizeof(info) );
  290. info.pt.x = LOWORD( lparam );
  291. info.pt.y = HIWORD( lparam );
  292. info.flags = LVHT_ONITEM;
  293. iItem = ListView_HitTest( hwnd, &info );
  294. if (iItem >= 0)
  295. {
  296. /* OK, it's over item 'iItem'. Now figure out if it's over the
  297. ** checkbox. Note this currently doesn't account for use of the
  298. ** "indent" feature on an owner-drawn item.
  299. */
  300. if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON ))
  301. iItem = -1;
  302. else
  303. fToggle = TRUE;
  304. }
  305. }
  306. else if (unMsg == WM_LBUTTONDBLCLK)
  307. {
  308. LV_HITTESTINFO info;
  309. /* Left mouse button double clicked over any area toggles state.
  310. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
  311. ** want to work with our cool owner-drawn list view extensions in
  312. ** which case the control doesn't know where the icon is on the item,
  313. ** so it returns a hit anywhere on the item anyway.
  314. */
  315. ZeroMemory( &info, sizeof(info) );
  316. info.pt.x = LOWORD( lparam );
  317. info.pt.y = HIWORD( lparam );
  318. info.flags = LVHT_ONITEM;
  319. iItem = ListView_HitTest( hwnd, &info );
  320. if (iItem >= 0)
  321. {
  322. /* OK, it's over item 'iItem'. If the click does not occur
  323. * over a checkbox, inform the parent of the double click.
  324. */
  325. if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) {
  326. NM_LISTVIEW nmlv;
  327. nmlv.hdr.code = LVXN_DBLCLK;
  328. nmlv.hdr.hwndFrom = hwnd;
  329. nmlv.iItem = iItem;
  330. FORWARD_WM_NOTIFY(
  331. GetParent(hwnd), GetDlgCtrlID(hwnd), &nmlv, SendMessage);
  332. iItem = -1;
  333. }
  334. /*
  335. * Otherwise, toggle the state.
  336. */
  337. else
  338. fToggle = TRUE;
  339. }
  340. }
  341. else if (unMsg == WM_CHAR)
  342. {
  343. /* Space bar pressed with item selected toggles check.
  344. ** Plus or Equals keys set check.
  345. ** Minus key clears check.
  346. */
  347. switch (wparam)
  348. {
  349. case TEXT(' '):
  350. fToggle = TRUE;
  351. break;
  352. case TEXT('+'):
  353. case TEXT('='):
  354. fSet = TRUE;
  355. break;
  356. case TEXT('-'):
  357. fClear = TRUE;
  358. break;
  359. }
  360. if (fToggle || fSet || fClear)
  361. iItem = ListView_GetNextItem( hwnd, -1, LVNI_SELECTED );
  362. }
  363. else if (unMsg == WM_KEYDOWN)
  364. {
  365. /* Left arrow becomes up arrow and right arrow becomes down arrow so
  366. ** the list of checkboxes behaves just like a static group of
  367. ** checkboxes.
  368. */
  369. if (wparam == VK_LEFT)
  370. wparam = VK_UP;
  371. else if (wparam == VK_RIGHT)
  372. wparam = VK_DOWN;
  373. }
  374. if (iItem >= 0)
  375. {
  376. /* If we are handling the spacebar, plus, minus, or equals,
  377. ** the change we make applies to all the selected items;
  378. ** hence the do {} while(WM_CHAR).
  379. */
  380. do {
  381. if (fToggle)
  382. {
  383. UINT unOldState;
  384. BOOL fCheck;
  385. fCheck = ListView_GetCheck( hwnd, iItem );
  386. ListView_SetCheck( hwnd, iItem, !fCheck );
  387. }
  388. else if (fSet)
  389. {
  390. if (!ListView_GetCheck( hwnd, iItem ))
  391. ListView_SetCheck( hwnd, iItem, TRUE );
  392. }
  393. else if (fClear)
  394. {
  395. if (ListView_GetCheck( hwnd, iItem ))
  396. ListView_SetCheck( hwnd, iItem, FALSE );
  397. }
  398. iItem = ListView_GetNextItem(hwnd, iItem, LVNI_SELECTED);
  399. } while(iItem >= 0 && unMsg == WM_CHAR);
  400. if (fSet || fClear) {
  401. /* Don't pass to listview to avoid beep.
  402. */
  403. return 0;
  404. }
  405. }
  406. pOldProc = (WNDPROC )GetProp( hwnd, g_lvxcbContextId );
  407. if (pOldProc)
  408. return CallWindowProc( pOldProc, hwnd, unMsg, wparam, lparam );
  409. return 0;
  410. }
  411. /*----------------------------------------------------------------------------
  412. ** Enhanced ListView
  413. **----------------------------------------------------------------------------
  414. */
  415. BOOL
  416. ListView_OwnerHandler(
  417. IN HWND hwnd,
  418. IN UINT unMsg,
  419. IN WPARAM wparam,
  420. IN LPARAM lparam,
  421. IN PLVXCALLBACK pLvxCallback )
  422. /* Handler that, when installed, turns a regular report-view-only list
  423. ** view (but with style LVS_OWNERDRAWFIXED) into an enhanced list view
  424. ** with full width selection bar and other custom column display options.
  425. ** It should appear in list view owner's dialog proc as follows:
  426. **
  427. ** BOOL
  428. ** MyDlgProc(
  429. ** IN HWND hwnd,
  430. ** IN UINT unMsg,
  431. ** IN WPARAM wparam,
  432. ** IN LPARAM lparam )
  433. ** {
  434. ** if (ListView_OwnerHandler(
  435. ** hwnd, unMsg, wParam, lParam, MyLvxCallback ))
  436. ** return TRUE;
  437. **
  438. ** <the rest of your stuff here>
  439. ** }
  440. **
  441. ** 'PLvxCallback' is caller's callback routine that provides information
  442. ** about drawing columns and other options.
  443. **
  444. ** Returns true if processed message, false otherwise.
  445. */
  446. {
  447. /* This routine executes on EVERY message thru the dialog so keep it
  448. ** efficient, please.
  449. */
  450. switch (unMsg)
  451. {
  452. case WM_DRAWITEM:
  453. return LvxDrawItem( (DRAWITEMSTRUCT* )lparam, pLvxCallback );
  454. case WM_MEASUREITEM:
  455. return LvxMeasureItem( hwnd, (MEASUREITEMSTRUCT* )lparam );
  456. }
  457. return FALSE;
  458. }
  459. BOOL
  460. LvxDrawItem(
  461. IN DRAWITEMSTRUCT* pdis,
  462. IN PLVXCALLBACK pLvxCallback )
  463. /* Respond to WM_DRAWITEM by drawing the list view item. 'Pdis' is the
  464. ** information sent by the system. 'PLvxCallback' is caller's callback to
  465. ** get information about drawing the control.
  466. **
  467. ** Returns true is processed the message, false otherwise.
  468. */
  469. {
  470. LV_ITEM item;
  471. INT i;
  472. INT dxState;
  473. INT dyState;
  474. INT dxSmall;
  475. INT dySmall;
  476. INT dxIndent;
  477. UINT uiStyleState;
  478. UINT uiStyleSmall;
  479. HIMAGELIST himlState;
  480. HIMAGELIST himlSmall;
  481. LVXDRAWINFO* pDrawInfo;
  482. RECT rc;
  483. RECT rcClient;
  484. BOOL fEnabled;
  485. BOOL fSelected;
  486. HDC hdc;
  487. HFONT hfont;
  488. TRACE3("LvxDrawItem,i=%d,a=$%X,s=$%X",
  489. pdis->itemID,pdis->itemAction,pdis->itemState);
  490. /* Make sure this is something we want to handle.
  491. */
  492. if (pdis->CtlType != ODT_LISTVIEW)
  493. return FALSE;
  494. if (pdis->itemAction != ODA_DRAWENTIRE
  495. && pdis->itemAction != ODA_SELECT
  496. && pdis->itemAction != ODA_FOCUS)
  497. {
  498. return TRUE;
  499. }
  500. /* Get item information from the list view.
  501. */
  502. ZeroMemory( &item, sizeof(item) );
  503. item.mask = LVIF_IMAGE + LVIF_STATE;
  504. item.iItem = pdis->itemID;
  505. item.stateMask = LVIS_STATEIMAGEMASK;
  506. if (!ListView_GetItem( pdis->hwndItem, &item ))
  507. {
  508. TRACE("LvxDrawItem GetItem failed");
  509. return TRUE;
  510. }
  511. /* Stash some useful stuff for reference later.
  512. */
  513. fEnabled = IsWindowEnabled( pdis->hwndItem )
  514. && !(pdis->itemState & ODS_DISABLED);
  515. fSelected = (pdis->itemState & ODS_SELECTED);
  516. GetClientRect( pdis->hwndItem, &rcClient );
  517. /* Callback owner to get drawing information.
  518. */
  519. ASSERT(pLvxCallback);
  520. pDrawInfo = pLvxCallback( pdis->hwndItem, pdis->itemID );
  521. ASSERT(pDrawInfo);
  522. /* Get image list icon sizes now, though we draw them last because their
  523. ** background is set up during first column text output.
  524. */
  525. dxState = dyState = 0;
  526. himlState = ListView_GetImageList( pdis->hwndItem, LVSIL_STATE );
  527. if (himlState)
  528. ImageList_GetIconSize( himlState, &dxState, &dyState );
  529. dxSmall = dySmall = 0;
  530. himlSmall = ListView_GetImageList( pdis->hwndItem, LVSIL_SMALL );
  531. if (himlSmall)
  532. ImageList_GetIconSize( himlSmall, &dxSmall, &dySmall );
  533. uiStyleState = uiStyleSmall = ILD_TRANSPARENT;
  534. /* Figure out the number of pixels to indent the item, if any.
  535. */
  536. if (pDrawInfo->dxIndent >= 0)
  537. dxIndent = pDrawInfo->dxIndent;
  538. else
  539. {
  540. if (dxSmall > 0)
  541. dxIndent = dxSmall;
  542. else
  543. dxIndent = GetSystemMetrics( SM_CXSMICON );
  544. }
  545. /* Get a device context for the window and set it up with the font the
  546. ** control says it's using. (Can't use the one that comes in the
  547. ** DRAWITEMSTRUCT because sometimes it has the wrong rectangle, see bug
  548. ** 13106)
  549. */
  550. hdc = GetDC( pdis->hwndItem );
  551. if(NULL == hdc)
  552. {
  553. return FALSE;
  554. }
  555. hfont = (HFONT )SendMessage( pdis->hwndItem, WM_GETFONT, 0, 0 );
  556. if (hfont)
  557. SelectObject( hdc, hfont );
  558. /* Set things up as if we'd just got done processing a column that ends
  559. ** after the icons, then loop thru each column from left to right.
  560. */
  561. rc.right = pdis->rcItem.left + dxIndent + dxState + dxSmall;
  562. rc.top = pdis->rcItem.top;
  563. rc.bottom = pdis->rcItem.bottom;
  564. for (i = 0; i < pDrawInfo->cCols; ++i)
  565. {
  566. TCHAR szText[ LVX_MaxColTchars + 1 ];
  567. TCHAR* pszText;
  568. INT dxCol;
  569. /* Get the column width, adding any index and icon width to the first
  570. ** column.
  571. */
  572. // For whistler bug 458513 39081
  573. //
  574. ZeroMemory(szText,sizeof(szText));
  575. dxCol = ListView_GetColumnWidth( pdis->hwndItem, i );
  576. if (i == 0)
  577. dxCol -= dxIndent + dxState + dxSmall;
  578. szText[ 0 ] = TEXT('\0');
  579. ListView_GetItemText( pdis->hwndItem, pdis->itemID, i, szText,
  580. LVX_MaxColTchars + 1 );
  581. /* Update rectangle to enclose just this one item's column 'i'.
  582. */
  583. rc.left = rc.right;
  584. rc.right = rc.left + dxCol;
  585. if ((pDrawInfo->dwFlags & LVXDI_DxFill)
  586. && i == pDrawInfo->cCols - 1)
  587. {
  588. INT dxWnd = pdis->rcItem.left + rcClient.right;
  589. if (rc.right < dxWnd)
  590. {
  591. /* When the last column does not fill out a full controls
  592. ** width of space, extend it to the right so it does. Note
  593. ** this does not mean the user can't scroll off to the right
  594. ** if they want.
  595. ** (Abolade-Gbadegesin 03-27-96)
  596. ** Don't subtrace rc.left when there is only one column;
  597. ** this accounts for the space needed for icons.
  598. */
  599. rc.right = pdis->rcItem.right = dxWnd;
  600. if (i == 0) {
  601. ListView_SetColumnWidth(pdis->hwndItem, i, rc.right);
  602. }
  603. else {
  604. ListView_SetColumnWidth(
  605. pdis->hwndItem, i, rc.right - rc.left );
  606. }
  607. }
  608. }
  609. /* Lop the text and append "..." if it won't fit in the column.
  610. */
  611. pszText = Ellipsisize( hdc, szText, rc.right - rc.left, LVX_dxColText );
  612. if (!pszText)
  613. continue;
  614. /* Figure out the appropriate text and background colors for the
  615. ** current item state.
  616. */
  617. if (fEnabled)
  618. {
  619. if (fSelected)
  620. {
  621. SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
  622. SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
  623. if (pDrawInfo->dwFlags & LVXDI_Blend50Sel)
  624. uiStyleSmall |= ILD_BLEND50;
  625. }
  626. else
  627. {
  628. if (pDrawInfo->adwFlags[ i ] & LVXDIA_3dFace)
  629. {
  630. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  631. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  632. }
  633. else
  634. {
  635. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  636. SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
  637. }
  638. }
  639. }
  640. else
  641. {
  642. if (pDrawInfo->adwFlags[ i ] & LVXDIA_Static)
  643. {
  644. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  645. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  646. }
  647. else
  648. {
  649. SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
  650. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  651. }
  652. if (pDrawInfo->dwFlags & LVXDI_Blend50Dis)
  653. uiStyleSmall |= ILD_BLEND50;
  654. }
  655. /* Draw the column text. In the first column the background of any
  656. ** indent and icons is erased to the text background color.
  657. */
  658. {
  659. RECT rcBg = rc;
  660. if (i == 0)
  661. rcBg.left -= dxIndent + dxState + dxSmall;
  662. ExtTextOut( hdc, rc.left + LVX_dxColText,
  663. rc.top + LVX_dyColText, ETO_CLIPPED + ETO_OPAQUE,
  664. &rcBg, pszText, lstrlen( pszText ), NULL );
  665. }
  666. Free( pszText );
  667. }
  668. /* Finally, draw the icons, if caller specified any.
  669. */
  670. if (himlState)
  671. {
  672. ImageList_Draw( himlState, (item.state >> 12) - 1, hdc,
  673. pdis->rcItem.left + dxIndent, pdis->rcItem.top, uiStyleState );
  674. }
  675. if (himlSmall)
  676. {
  677. ImageList_Draw( himlSmall, item.iImage, hdc,
  678. pdis->rcItem.left + dxIndent + dxState,
  679. pdis->rcItem.top, uiStyleSmall );
  680. }
  681. /* Draw the dotted focus rectangle around the whole item, if indicated.
  682. */
  683. //comment for bug 52688 whistler
  684. // if ((pdis->itemState & ODS_FOCUS) && GetFocus() == pdis->hwndItem)
  685. // DrawFocusRect( hdc, &pdis->rcItem );
  686. //
  687. ReleaseDC( pdis->hwndItem, hdc );
  688. return TRUE;
  689. }
  690. BOOL
  691. LvxMeasureItem(
  692. IN HWND hwnd,
  693. IN OUT MEASUREITEMSTRUCT* pmis )
  694. /* Respond to WM_MEASUREITEM message, i.e. fill in the height of an item
  695. ** in the ListView. 'Hwnd' is the owner window. 'Pmis' is the structure
  696. ** provided from Windows.
  697. **
  698. ** Returns true is processed the message, false otherwise.
  699. */
  700. {
  701. HDC hdc;
  702. HWND hwndLv;
  703. HFONT hfont;
  704. TEXTMETRIC tm;
  705. UINT dySmIcon;
  706. RECT rc;
  707. TRACE("LvxMeasureItem");
  708. if (pmis->CtlType != ODT_LISTVIEW)
  709. return FALSE;
  710. hwndLv = GetDlgItem( hwnd, pmis->CtlID );
  711. ASSERT(hwndLv);
  712. /* Get a device context for the list view control and set up the font the
  713. ** control says it's using. MSDN claims the final font may not be
  714. ** available at this point, but it sure seems to be.
  715. */
  716. hdc = GetDC( hwndLv );
  717. hfont = (HFONT )SendMessage( hwndLv, WM_GETFONT, 0, 0 );
  718. if (hfont)
  719. SelectObject( hdc, hfont );
  720. if (GetTextMetrics( hdc, &tm ))
  721. pmis->itemHeight = tm.tmHeight + 1;
  722. else
  723. pmis->itemHeight = 0;
  724. /* Make sure it's tall enough for a standard small icon.
  725. */
  726. dySmIcon = (UINT )GetSystemMetrics( SM_CYSMICON );
  727. if (pmis->itemHeight < dySmIcon + LVX_dyIconSpacing)
  728. pmis->itemHeight = dySmIcon + LVX_dyIconSpacing;
  729. /* Set the width since the docs say to, though I don't think it's used by
  730. ** list view.
  731. */
  732. GetClientRect( hwndLv, &rc );
  733. pmis->itemWidth = rc.right - rc.left - 1;
  734. ReleaseDC( hwndLv, hdc );
  735. return TRUE;
  736. }
  737. /*----------------------------------------------------------------------------
  738. ** ListView utilities
  739. **----------------------------------------------------------------------------
  740. */
  741. VOID
  742. ListView_SetDeviceImageList(
  743. IN HWND hwndLv,
  744. IN HINSTANCE hinst )
  745. /* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
  746. ** images. 'Hinst' is the module instance containing the icons IID_Modem
  747. ** and IID_Adapter. For example, see RASDLG.DLL.
  748. */
  749. {
  750. HICON hIcon;
  751. HIMAGELIST himl;
  752. himl = ImageList_Create(
  753. GetSystemMetrics( SM_CXSMICON ),
  754. GetSystemMetrics( SM_CYSMICON ),
  755. ILC_MASK, 2, 2 );
  756. /* The order these are added is significant since it implicitly
  757. ** establishes the state indices matching SI_Unchecked and SI_Checked.
  758. */
  759. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Modem ) );
  760. if ( NULL != hIcon )
  761. {
  762. ImageList_ReplaceIcon( himl, -1, hIcon );
  763. DeleteObject( hIcon );
  764. }
  765. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Adapter ) );
  766. if ( NULL != hIcon )
  767. {
  768. ImageList_ReplaceIcon( himl, -1, hIcon );
  769. DeleteObject( hIcon );
  770. }
  771. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Direct_Connect ) );
  772. if ( NULL != hIcon )
  773. {
  774. ImageList_ReplaceIcon( himl, -1, hIcon );
  775. DeleteObject( hIcon );
  776. }
  777. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_Modem ) );
  778. if ( NULL != hIcon )
  779. {
  780. ImageList_ReplaceIcon( himl, -1, hIcon );
  781. DeleteObject( hIcon );
  782. }
  783. ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
  784. }
  785. VOID
  786. ListView_SetUserImageList(
  787. IN HWND hwndLv,
  788. IN HINSTANCE hinst )
  789. /* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
  790. ** images. 'Hinst' is the module instance containing the icons IID_Modem
  791. ** and IID_Adapter. For example, see RASDLG.DLL.
  792. */
  793. {
  794. HICON hIcon;
  795. HIMAGELIST himl;
  796. himl = ImageList_Create(
  797. GetSystemMetrics( SM_CXSMICON ),
  798. GetSystemMetrics( SM_CYSMICON ),
  799. ILC_MASK, 2, 2 );
  800. /* The order these are added is significant since it implicitly
  801. ** establishes the state indices matching SI_Unchecked and SI_Checked.
  802. */
  803. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Connections_User ) );
  804. if(NULL != hIcon)
  805. {
  806. ImageList_ReplaceIcon( himl, -1, hIcon );
  807. DeleteObject( hIcon );
  808. }
  809. ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
  810. }
  811. VOID
  812. ListView_SetNetworkComponentImageList(
  813. IN HWND hwndLv,
  814. IN HINSTANCE hinst )
  815. /* Set the "small icon" image list view 'hwndLv' to be a list of DI_*
  816. ** images. 'Hinst' is the module instance containing the icons IID_Modem
  817. ** and IID_Adapter. For example, see RASDLG.DLL.
  818. */
  819. {
  820. HICON hIcon;
  821. HIMAGELIST himl;
  822. himl = ImageList_Create(
  823. GetSystemMetrics( SM_CXSMICON ),
  824. GetSystemMetrics( SM_CYSMICON ),
  825. ILC_MASK, 2, 2 );
  826. /* The order these are added is significant since it implicitly
  827. ** establishes the state indices matching SI_Unchecked and SI_Checked.
  828. */
  829. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Protocol ) );
  830. if(NULL != hIcon)
  831. {
  832. ImageList_ReplaceIcon( himl, -1, hIcon );
  833. DeleteObject( hIcon );
  834. }
  835. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Service ) );
  836. if(NULL != hIcon)
  837. {
  838. ImageList_ReplaceIcon( himl, -1, hIcon );
  839. DeleteObject( hIcon );
  840. }
  841. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Client ) );
  842. if(NULL != hIcon)
  843. {
  844. ImageList_ReplaceIcon( himl, -1, hIcon );
  845. DeleteObject( hIcon );
  846. }
  847. ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
  848. }