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.

624 lines
17 KiB

  1. // list view (small icons, multiple columns)
  2. #include "ctlspriv.h"
  3. #include "listview.h"
  4. #define COLUMN_VIEW
  5. BOOL ListView_LDrawItem(PLVDRAWITEM plvdi)
  6. {
  7. RECT rcIcon;
  8. RECT rcLabel;
  9. RECT rcBounds;
  10. RECT rcT;
  11. LV_ITEM item;
  12. TCHAR ach[CCHLABELMAX];
  13. LV* plv = plvdi->plv;
  14. int i = (int) plvdi->nmcd.nmcd.dwItemSpec;
  15. // moved here to reduce call backs in OWNERDATA case
  16. //
  17. item.iItem = i;
  18. item.iSubItem = 0;
  19. item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
  20. item.stateMask = LVIS_ALL;
  21. item.pszText = ach;
  22. item.cchTextMax = ARRAYSIZE(ach);
  23. ListView_OnGetItem(plv, &item);
  24. ListView_LGetRects(plv, i, &rcIcon, &rcLabel, &rcBounds, NULL);
  25. if (!plvdi->prcClip || IntersectRect(&rcT, &rcBounds, plvdi->prcClip))
  26. {
  27. UINT fText;
  28. if (plvdi->lpptOrg)
  29. {
  30. OffsetRect(&rcIcon, plvdi->lpptOrg->x - rcBounds.left,
  31. plvdi->lpptOrg->y - rcBounds.top);
  32. OffsetRect(&rcLabel, plvdi->lpptOrg->x - rcBounds.left,
  33. plvdi->lpptOrg->y - rcBounds.top);
  34. }
  35. fText = ListView_DrawImage(plv, &item, plvdi->nmcd.nmcd.hdc,
  36. rcIcon.left, rcIcon.top, plvdi->flags) | SHDT_ELLIPSES;
  37. // Don't draw the label if it is being edited.
  38. if (plv->iEdit != i)
  39. {
  40. int ItemCxSingleLabel;
  41. UINT ItemState;
  42. if (ListView_IsOwnerData( plv ))
  43. {
  44. LISTITEM listitem;
  45. // calculate lable sizes from iItem
  46. listitem.pszText = ach;
  47. ListView_RecomputeLabelSize( plv, &listitem, i, plvdi->nmcd.nmcd.hdc, TRUE );
  48. ItemCxSingleLabel = listitem.cxSingleLabel;
  49. ItemState = item.state;
  50. }
  51. else
  52. {
  53. ItemCxSingleLabel = plvdi->pitem->cxSingleLabel;
  54. ItemState = plvdi->pitem->state;
  55. }
  56. if (plvdi->flags & LVDI_TRANSTEXT)
  57. fText |= SHDT_TRANSPARENT;
  58. if (ItemCxSingleLabel == SRECOMPUTE) {
  59. ListView_RecomputeLabelSize(plv, plvdi->pitem, i, plvdi->nmcd.nmcd.hdc, FALSE);
  60. ItemCxSingleLabel = plvdi->pitem->cxSingleLabel;
  61. }
  62. if (ItemCxSingleLabel < rcLabel.right - rcLabel.left)
  63. rcLabel.right = rcLabel.left + ItemCxSingleLabel;
  64. if ((fText & SHDT_SELECTED) && (plvdi->flags & LVDI_HOTSELECTED))
  65. fText |= SHDT_HOTSELECTED;
  66. if( plv->dwExStyle & WS_EX_RTLREADING)
  67. {
  68. fText |= SHDT_RTLREADING;
  69. }
  70. SHDrawText(plvdi->nmcd.nmcd.hdc, item.pszText, &rcLabel, LVCFMT_LEFT, fText,
  71. plv->cyLabelChar, plv->cxEllipses,
  72. plvdi->nmcd.clrText, plvdi->nmcd.clrTextBk);
  73. if ((plvdi->flags & LVDI_FOCUS) && (ItemState & LVIS_FOCUSED)
  74. && !(CCGetUIState(&(plvdi->plv->ci)) & UISF_HIDEFOCUS)
  75. )
  76. DrawFocusRect(plvdi->nmcd.nmcd.hdc, &rcLabel);
  77. }
  78. }
  79. return TRUE;
  80. }
  81. DWORD ListView_LApproximateViewRect(LV* plv, int iCount, int iWidth, int iHeight)
  82. {
  83. int cxItem = plv->cxItem;
  84. int cyItem = plv->cyItem;
  85. int cCols;
  86. int cRows;
  87. cRows = iHeight / cyItem;
  88. cRows = min(cRows, iCount);
  89. if (cRows == 0)
  90. cRows = 1;
  91. cCols = (iCount + cRows - 1) / cRows;
  92. iWidth = cCols * cxItem;
  93. iHeight = cRows * cyItem;
  94. return MAKELONG(iWidth + g_cxEdge, iHeight + g_cyEdge);
  95. }
  96. int NEAR ListView_LItemHitTest(LV* plv, int x, int y, UINT FAR* pflags, int *piSubItem)
  97. {
  98. int iHit;
  99. int i;
  100. int iCol;
  101. int xItem; //where is the x in relation to the item
  102. UINT flags;
  103. LISTITEM FAR* pitem;
  104. if (piSubItem)
  105. *piSubItem = 0;
  106. flags = LVHT_NOWHERE;
  107. iHit = -1;
  108. #ifdef COLUMN_VIEW
  109. i = y / plv->cyItem;
  110. if (i >= 0 && i < plv->cItemCol)
  111. {
  112. iCol = (x + plv->xOrigin) / plv->cxItem;
  113. i += iCol * plv->cItemCol;
  114. if (i >= 0 && i < ListView_Count(plv))
  115. {
  116. iHit = i;
  117. xItem = x + plv->xOrigin - iCol * plv->cxItem;
  118. if (xItem < plv->cxState) {
  119. flags = LVHT_ONITEMSTATEICON;
  120. } else if (xItem < (plv->cxState + plv->cxSmIcon)) {
  121. flags = LVHT_ONITEMICON;
  122. }
  123. else
  124. {
  125. int ItemCxSingleLabel;
  126. if (ListView_IsOwnerData( plv ))
  127. {
  128. LISTITEM item;
  129. // calculate lable sizes from iItem
  130. ListView_RecomputeLabelSize( plv, &item, i, NULL, FALSE );
  131. ItemCxSingleLabel = item.cxSingleLabel;
  132. }
  133. else
  134. {
  135. pitem = ListView_FastGetItemPtr(plv, i);
  136. if (pitem->cxSingleLabel == SRECOMPUTE)
  137. {
  138. ListView_RecomputeLabelSize(plv, pitem, i, NULL, FALSE);
  139. }
  140. ItemCxSingleLabel = pitem->cxSingleLabel;
  141. }
  142. if (xItem < (plv->cxSmIcon + plv->cxState + ItemCxSingleLabel))
  143. flags = LVHT_ONITEMLABEL;
  144. }
  145. }
  146. }
  147. #else
  148. i = x / plv->cxItem;
  149. if (i < plv->cItemCol)
  150. {
  151. i += ((y + plv->xOrigin) / plv->cyItem) * plv->cItemCol;
  152. if (i < ListView_Count(plv))
  153. {
  154. iHit = i;
  155. flags = LVHT_ONITEMICON;
  156. }
  157. }
  158. #endif
  159. *pflags = flags;
  160. return iHit;
  161. }
  162. void NEAR ListView_LGetRects(LV* plv, int i, RECT FAR* prcIcon,
  163. RECT FAR* prcLabel, RECT FAR *prcBounds, RECT FAR* prcSelectBounds)
  164. {
  165. RECT rcIcon;
  166. RECT rcLabel;
  167. int x, y;
  168. int cItemCol = plv->cItemCol;
  169. if (cItemCol == 0)
  170. {
  171. // Called before other data has been initialized so call
  172. // update scrollbars which should make sure that that
  173. // we have valid data...
  174. ListView_UpdateScrollBars(plv);
  175. // but it's possible that updatescrollbars did nothing because of
  176. // LVS_NOSCROLL or redraw
  177. // BUGBUG raymondc v6.0: Get it right even if no redraw. Fix for v6.
  178. if (plv->cItemCol == 0)
  179. cItemCol = 1;
  180. else
  181. cItemCol = plv->cItemCol;
  182. }
  183. #ifdef COLUMN_VIEW
  184. x = (i / cItemCol) * plv->cxItem;
  185. y = (i % cItemCol) * plv->cyItem;
  186. rcIcon.left = x - plv->xOrigin + plv->cxState;
  187. rcIcon.top = y;
  188. #else
  189. x = (i % cItemCol) * plv->cxItem;
  190. y = (i / cItemCol) * plv->cyItem;
  191. rcIcon.left = x;
  192. rcIcon.top = y - plv->xOrigin;
  193. #endif
  194. rcIcon.right = rcIcon.left + plv->cxSmIcon;
  195. rcIcon.bottom = rcIcon.top + plv->cyItem;
  196. if (prcIcon)
  197. *prcIcon = rcIcon;
  198. rcLabel.left = rcIcon.right;
  199. rcLabel.right = rcIcon.left + plv->cxItem - plv->cxState;
  200. rcLabel.top = rcIcon.top;
  201. rcLabel.bottom = rcIcon.bottom;
  202. if (prcLabel)
  203. *prcLabel = rcLabel;
  204. if (prcBounds)
  205. {
  206. *prcBounds = rcLabel;
  207. prcBounds->left = rcIcon.left - plv->cxState;
  208. }
  209. if (prcSelectBounds)
  210. {
  211. *prcSelectBounds = rcLabel;
  212. prcSelectBounds->left = rcIcon.left;
  213. }
  214. }
  215. void NEAR ListView_LUpdateScrollBars(LV* plv)
  216. {
  217. RECT rcClient;
  218. int cItemCol;
  219. int cCol;
  220. int cColVis;
  221. SCROLLINFO si;
  222. ASSERT(plv);
  223. ListView_GetClientRect(plv, &rcClient, FALSE, NULL);
  224. #ifdef COLUMN_VIEW
  225. cColVis = (rcClient.right - rcClient.left) / plv->cxItem;
  226. cItemCol = max(1, (rcClient.bottom - rcClient.top) / plv->cyItem);
  227. #else
  228. cColVis = (rcClient.bottom - rcClient.top) / plv->cyItem;
  229. cItemCol = max(1, (rcClient.right - rcClient.left) / plv->cxItem);
  230. #endif
  231. cCol = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  232. // Make the client area smaller as appropriate, and
  233. // recompute cCol to reflect scroll bar.
  234. //
  235. si.cbSize = sizeof(SCROLLINFO);
  236. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  237. si.nPage = cColVis;
  238. si.nMin = 0;
  239. #ifdef COLUMN_VIEW
  240. rcClient.bottom -= ListView_GetCyScrollbar(plv);
  241. cItemCol = max(1, (rcClient.bottom - rcClient.top) / plv->cyItem);
  242. cCol = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  243. si.nPos = plv->xOrigin / plv->cxItem;
  244. si.nMax = cCol - 1;
  245. ListView_SetScrollInfo(plv, SB_HORZ, &si, TRUE);
  246. #else
  247. rcClient.right -= ListView_GetCxScrollbar(plv);
  248. cItemCol = max(1, (rcClient.right - rcClient.left) / plv->cxItem);
  249. cCol = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  250. si.nPos = plv->xOrigin / plv->cyItem;
  251. si.nMax = cCol - 1;
  252. ListView_SetScrollInfo(plv, SB_VERT, &si, TRUE);
  253. #endif
  254. // Update number of visible lines...
  255. //
  256. if (plv->cItemCol != cItemCol)
  257. {
  258. plv->cItemCol = cItemCol;
  259. InvalidateRect(plv->ci.hwnd, NULL, TRUE);
  260. }
  261. // make sure our position and page doesn't hang over max
  262. if ((si.nPos + (LONG)si.nPage - 1 > si.nMax) && si.nPos > 0) {
  263. int iNewPos, iDelta;
  264. iNewPos = (int)si.nMax - (int)si.nPage + 1;
  265. if (iNewPos < 0) iNewPos = 0;
  266. if (iNewPos != si.nPos) {
  267. iDelta = iNewPos - (int)si.nPos;
  268. #ifdef COLUMN_VIEW
  269. ListView_LScroll2(plv, iDelta, 0, 0);
  270. #else
  271. ListView_LScroll2(plv, 0, iDelta, 0);
  272. #endif
  273. ListView_LUpdateScrollBars(plv);
  274. }
  275. }
  276. // never have the other scrollbar
  277. #ifdef COLUMN_VIEW
  278. ListView_SetScrollRange(plv, SB_VERT, 0, 0, TRUE);
  279. #else
  280. ListView_SetScrollRange(plv, SB_HORZ, 0, 0, TRUE);
  281. #endif
  282. }
  283. //
  284. // We need a smoothscroll callback so our background image draws
  285. // at the correct origin. If we don't have a background image,
  286. // then this work is superfluous but not harmful either.
  287. //
  288. int CALLBACK ListView_LScroll2_SmoothScroll(
  289. HWND hwnd,
  290. int dx,
  291. int dy,
  292. CONST RECT *prcScroll,
  293. CONST RECT *prcClip,
  294. HRGN hrgnUpdate,
  295. LPRECT prcUpdate,
  296. UINT flags)
  297. {
  298. LV* plv = ListView_GetPtr(hwnd);
  299. if (plv)
  300. {
  301. #ifdef COLUMN_VIEW
  302. plv->xOrigin -= dx;
  303. #else
  304. plv->xOrigin -= dy;
  305. #endif
  306. }
  307. // Now do what SmoothScrollWindow would've done if we weren't
  308. // a callback
  309. return ScrollWindowEx(hwnd, dx, dy, prcScroll, prcClip, hrgnUpdate, prcUpdate, flags);
  310. }
  311. void FAR PASCAL ListView_LScroll2(LV* plv, int dx, int dy, UINT uSmooth)
  312. {
  313. #ifdef COLUMN_VIEW
  314. if (dx)
  315. {
  316. dx *= plv->cxItem;
  317. {
  318. SMOOTHSCROLLINFO si;
  319. si.cbSize = sizeof(si);
  320. si.fMask = SSIF_SCROLLPROC;
  321. si.hwnd =plv->ci.hwnd ;
  322. si.dx =-dx ;
  323. si.dy = 0;
  324. si.lprcSrc = NULL;
  325. si.lprcClip = NULL;
  326. si.hrgnUpdate = NULL;
  327. si.lprcUpdate = NULL;
  328. si.fuScroll = SW_INVALIDATE | SW_ERASE;
  329. si.pfnScrollProc = ListView_LScroll2_SmoothScroll;
  330. SmoothScrollWindow(&si);
  331. }
  332. UpdateWindow(plv->ci.hwnd);
  333. }
  334. #else
  335. if (dy)
  336. {
  337. dy *= plv->cyItem;
  338. {
  339. SMOOTHSCROLLINFO si;
  340. si.cbSize = sizeof(si);
  341. si.fMask = SSIF_SCROLLPROC;
  342. si.hwnd = plv->ci.hwnd;
  343. si.dx = 0;
  344. si.dy = -dy;
  345. si.lprcSrc = NULL;
  346. si.lprcClip = NULL;
  347. si.hrgnUpdate = NULL;
  348. si.lprcUpdate = NULL;
  349. si.fuScroll = SW_INVALIDATE | SW_ERASE;
  350. si.pfnScrollProc = ListView_LScroll2_SmoothScroll;
  351. SmoothScrollWindow(&si);
  352. }
  353. UpdateWindow(plv->ci.hwnd);
  354. }
  355. #endif
  356. }
  357. void NEAR ListView_LOnScroll(LV* plv, UINT code, int posNew, UINT sb)
  358. {
  359. RECT rcClient;
  360. int cPage;
  361. if (plv->hwndEdit)
  362. ListView_DismissEdit(plv, FALSE);
  363. ListView_GetClientRect(plv, &rcClient, TRUE, NULL);
  364. #ifdef COLUMN_VIEW
  365. cPage = (rcClient.right - rcClient.left) / plv->cxItem;
  366. ListView_ComOnScroll(plv, code, posNew, SB_HORZ, 1,
  367. cPage ? cPage : 1);
  368. #else
  369. cPage = (rcClient.bottom - rcClient.top) / plv->cyItem;
  370. ListView_ComOnScroll(plv, code, posNew, SB_VERT, 1,
  371. cPage ? cPage : 1);
  372. #endif
  373. }
  374. int NEAR ListView_LGetScrollUnitsPerLine(LV* plv, UINT sb)
  375. {
  376. return 1;
  377. }
  378. //------------------------------------------------------------------------------
  379. //
  380. // Function: ListView_LCalcViewItem
  381. //
  382. // Summary: This function will calculate which item slot is at the x, y location
  383. //
  384. // Arguments:
  385. // plv [in] - The list View to work with
  386. // x [in] - The x location
  387. // y [in] - The y location
  388. //
  389. // Returns: the valid slot the point was within.
  390. //
  391. // Notes:
  392. //
  393. // History:
  394. // Nov-3-94 MikeMi Created
  395. //
  396. //------------------------------------------------------------------------------
  397. int ListView_LCalcViewItem( LV* plv, int x, int y )
  398. {
  399. int iItem;
  400. int iRow = 0;
  401. int iCol = 0;
  402. ASSERT( plv );
  403. #ifdef COLUMN_VIEW
  404. iRow = y / plv->cyItem;
  405. iRow = max( iRow, 0 );
  406. iRow = min( iRow, plv->cItemCol - 1 );
  407. iCol = (x + plv->xOrigin) / plv->cxItem;
  408. iItem = iRow + iCol * plv->cItemCol;
  409. #else
  410. iCol = x / plv->cxItem;
  411. iCol = max( iCol, 0 );
  412. iCol = min( iCol, plv->cItemCol - 1 );
  413. iRow = (y + plv->xOrigin) / plv->cyItem;
  414. iItem = iCol + iRow * plv->cItemCol;
  415. #endif
  416. iItem = max( iItem, 0 );
  417. iItem = min( iItem, ListView_Count(plv) - 1);
  418. return( iItem );
  419. }
  420. int LV_GetNewColWidth(LV* plv, int iFirst, int iLast)
  421. {
  422. int cxMaxLabel = 0;
  423. // Don't do anything if there are no items to measure
  424. if (iFirst <= iLast)
  425. {
  426. LVFAKEDRAW lvfd;
  427. LV_ITEM lvitem;
  428. LISTITEM item;
  429. if (ListView_IsOwnerData( plv ))
  430. {
  431. int iViewFirst;
  432. int iViewLast;
  433. iViewFirst = ListView_LCalcViewItem( plv, 1, 1 );
  434. iViewLast = ListView_LCalcViewItem( plv,
  435. plv->sizeClient.cx - 1,
  436. plv->sizeClient.cy - 1 );
  437. if ((iLast - iFirst) > (iViewLast - iViewFirst))
  438. {
  439. iFirst = max( iFirst, iViewFirst );
  440. iLast = min( iLast, iViewLast );
  441. }
  442. iLast = min( ListView_Count( plv ), iLast );
  443. iFirst = max( 0, iFirst );
  444. iLast = max( iLast, iFirst );
  445. ListView_NotifyCacheHint( plv, iFirst, iLast );
  446. }
  447. ListView_BeginFakeCustomDraw(plv, &lvfd, &lvitem);
  448. lvitem.iSubItem = 0;
  449. lvitem.mask = LVIF_PARAM;
  450. item.lParam = 0;
  451. while (iFirst <= iLast)
  452. {
  453. LISTITEM FAR* pitem;
  454. if (ListView_IsOwnerData( plv ))
  455. {
  456. pitem = &item;
  457. pitem->cxSingleLabel = SRECOMPUTE;
  458. }
  459. else
  460. {
  461. pitem = ListView_FastGetItemPtr(plv, iFirst);
  462. }
  463. if (pitem->cxSingleLabel == SRECOMPUTE)
  464. {
  465. lvitem.iItem = iFirst;
  466. lvitem.lParam = pitem->lParam;
  467. ListView_BeginFakeItemDraw(&lvfd);
  468. ListView_RecomputeLabelSize(plv, pitem, iFirst, lvfd.nmcd.nmcd.hdc, FALSE);
  469. ListView_EndFakeItemDraw(&lvfd);
  470. }
  471. if (pitem->cxSingleLabel > cxMaxLabel)
  472. cxMaxLabel = pitem->cxSingleLabel;
  473. iFirst++;
  474. }
  475. ListView_EndFakeCustomDraw(&lvfd);
  476. }
  477. // We have the max label width, see if this plus the rest of the slop will
  478. // cause us to want to resize.
  479. //
  480. cxMaxLabel += plv->cxSmIcon + g_cxIconMargin + plv->cxState;
  481. if (cxMaxLabel > g_cxScreen)
  482. cxMaxLabel = g_cxScreen;
  483. return cxMaxLabel;
  484. }
  485. //------------------------------------------------------------------------------
  486. // This function will see if the size of column should be changed for the listview
  487. // It will check to see if the items between first and last exceed the current width
  488. // and if so will see if the columns are currently big enough. This wont happen
  489. // if we are not currently in listview or if the caller has set an explicit size.
  490. //
  491. // OWNERDATA CHANGE
  492. // This function is normally called with the complete list range,
  493. // This will has been changed to be called only with currently visible
  494. // to the user when in OWNERDATA mode. This will be much more effiencent.
  495. //
  496. BOOL FAR PASCAL ListView_MaybeResizeListColumns(LV* plv, int iFirst, int iLast)
  497. {
  498. HDC hdc = NULL;
  499. int cxMaxLabel;
  500. if (!ListView_IsListView(plv) || (plv->flags & LVF_COLSIZESET))
  501. return(FALSE);
  502. cxMaxLabel = LV_GetNewColWidth(plv, iFirst, iLast);
  503. // Now see if we should resize the columns...
  504. if (cxMaxLabel > plv->cxItem)
  505. {
  506. int iScroll = plv->xOrigin / plv->cxItem;
  507. TraceMsg(TF_LISTVIEW, "LV Resize Columns: %d", cxMaxLabel);
  508. ListView_ISetColumnWidth(plv, 0, cxMaxLabel, FALSE);
  509. plv->xOrigin = iScroll * plv->cxItem;
  510. return(TRUE);
  511. }
  512. return(FALSE);
  513. }