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.

803 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999.
  5. //
  6. // File: lview.cxx
  7. //
  8. // Contents:
  9. //
  10. // History: 15 Aug 1996 DLee Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.cxx"
  14. #pragma hdrstop
  15. //
  16. // Window procedure for ListView
  17. //
  18. LRESULT WINAPI ListViewWndProc(
  19. HWND hwnd,
  20. UINT msg,
  21. WPARAM wParam,
  22. LPARAM lParam)
  23. {
  24. CListView *pControl = (CListView *) GetWindowLongPtr(hwnd, 0);
  25. LRESULT lRet = 0;
  26. switch (msg)
  27. {
  28. case WM_CREATE :
  29. pControl = new CListView;
  30. pControl->Create (GetParent(hwnd), hwnd);
  31. SetWindowLongPtr (hwnd, 0, (LONG_PTR) pControl);
  32. break;
  33. case WM_DESTROY :
  34. delete pControl;
  35. lRet = DefWindowProc(hwnd, msg, wParam, lParam);
  36. break;
  37. case WM_SETFONT:
  38. pControl->SetFont ((HFONT)wParam);
  39. break;
  40. case WM_SETFOCUS:
  41. pControl->SetFocus();
  42. lRet = DefWindowProc(hwnd, msg, wParam, lParam);
  43. break;
  44. case wmInsertItem:
  45. pControl->InsertItem ((int)lParam);
  46. break;
  47. case wmDeleteItem:
  48. pControl->DeleteItem ((int)lParam);
  49. break;
  50. case wmUpdateItem:
  51. pControl->InvalidateItem ((int)lParam);
  52. break;
  53. case wmSetCountBefore:
  54. pControl->SetCountBefore ((int)lParam);
  55. break;
  56. case wmSetCount:
  57. pControl->SetTotalCount ((int)lParam);
  58. break;
  59. case wmResetContents:
  60. pControl->ResetContents();
  61. break;
  62. case WM_SIZE:
  63. pControl->Size (wParam, LOWORD(lParam), HIWORD(lParam));
  64. break;
  65. case WM_PAINT:
  66. {
  67. PAINTSTRUCT paint;
  68. BeginPaint ( hwnd, &paint );
  69. pControl->Paint (paint);
  70. EndPaint(hwnd, &paint );
  71. }
  72. break;
  73. case WM_LBUTTONUP:
  74. pControl->ButtonUp(HIWORD(lParam));
  75. break;
  76. case WM_LBUTTONDOWN:
  77. pControl->ButtonDown(HIWORD(lParam));
  78. break;
  79. case WM_LBUTTONDBLCLK:
  80. SendMessage (pControl->Parent(),
  81. WM_COMMAND,
  82. MAKEWPARAM(idListChild, LBN_DBLCLK),
  83. (LPARAM) hwnd);
  84. break;
  85. case WM_KEYDOWN:
  86. pControl->KeyDown ((int)wParam);
  87. break;
  88. case WM_VSCROLL:
  89. pControl->Vscroll ((int)LOWORD(wParam), (int)HIWORD(wParam));
  90. break;
  91. case WM_MOUSEWHEEL :
  92. lRet = pControl->MouseWheel( hwnd, wParam, lParam );
  93. break;
  94. case wmContextMenuHitTest:
  95. lRet = pControl->ContextMenuHitTest( wParam, lParam );
  96. break;
  97. default :
  98. lRet = DefWindowProc(hwnd, msg, wParam, lParam);
  99. break;
  100. }
  101. return lRet;
  102. } //ListViewWndProc
  103. CListView::CListView ()
  104. : _hwndParent(0),
  105. _hwnd(0),
  106. _cBefore(0),
  107. _cTotal (0),
  108. _cx(0),
  109. _cy(0),
  110. _cyLine(1),
  111. _cLines(0),
  112. _hfont(0),
  113. _iWheelRemainder(0)
  114. {}
  115. LRESULT CListView::MouseWheel(
  116. HWND hwnd,
  117. WPARAM wParam,
  118. LPARAM lParam )
  119. {
  120. // forward what we don't process
  121. if ( wParam & ( MK_SHIFT | MK_CONTROL ) )
  122. return DefWindowProc( hwnd, WM_MOUSEWHEEL, wParam, lParam );
  123. // add the current scroll to the remainder from last time
  124. int iDelta = (int) (short) HIWORD( wParam );
  125. iDelta += _iWheelRemainder;
  126. // if there isn't enough to process this time, just return
  127. if ( abs( iDelta ) < WHEEL_DELTA )
  128. {
  129. _iWheelRemainder = iDelta;
  130. return 0;
  131. }
  132. // compute the remainder and amount to scroll
  133. _iWheelRemainder = ( iDelta % WHEEL_DELTA );
  134. iDelta /= WHEEL_DELTA;
  135. BOOL fDown;
  136. if ( iDelta < 0 )
  137. {
  138. fDown = TRUE;
  139. iDelta = -iDelta;
  140. }
  141. else
  142. fDown = FALSE;
  143. // get the # of lines to scroll per WHEEL_DELTA
  144. int cLines;
  145. SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &cLines, 0 );
  146. if ( 0 == cLines )
  147. return 0;
  148. int cVisibleLines = _cLines;
  149. // if scrolling a page, do so. don't scroll more than one page
  150. if ( WHEEL_PAGESCROLL == cLines )
  151. iDelta = __max( 1, (cVisibleLines - 1) );
  152. else
  153. {
  154. iDelta *= cLines;
  155. if ( iDelta >= cVisibleLines )
  156. iDelta = __max( 1, (cVisibleLines - 1) );
  157. }
  158. // phew. do the scroll
  159. if ( 0 != iDelta )
  160. {
  161. if ( fDown )
  162. _GoDown( iDelta );
  163. else
  164. _GoUp( iDelta );
  165. }
  166. return iDelta;
  167. } //MouseWheel
  168. LRESULT CListView::ContextMenuHitTest(
  169. WPARAM wParam,
  170. LPARAM lParam )
  171. {
  172. POINT pt;
  173. // cast required to sign extend [multimon bug]
  174. pt.x = (LONG)(short)LOWORD( lParam );
  175. pt.y = (LONG)(short)HIWORD( lParam );
  176. RECT rc;
  177. GetWindowRect( _hwnd, &rc );
  178. // did they click in the window?
  179. if ( !PtInRect( &rc, pt ) )
  180. return -1;
  181. // convert y to window view coordinates
  182. int vy = pt.y - rc.top;
  183. // did they click on a line in the window?
  184. int line = vy / _cyLine;
  185. int newLine = line;
  186. if ( line >= _cLines || line >= _cTotal )
  187. return -1;
  188. // make this line the current selection
  189. ButtonDown( vy );
  190. return line;
  191. } //ContextMenuHitTest
  192. //
  193. // Create
  194. //
  195. void CListView::Create (HWND hwndParent, HWND hwnd)
  196. {
  197. _hwndParent = hwndParent;
  198. _hwnd = hwnd;
  199. MEASUREITEMSTRUCT measure;
  200. measure.CtlType = odtListView;
  201. //
  202. // Owner: Measure item!
  203. //
  204. SendMessage (_hwndParent, wmMeasureItem, 0, (LPARAM) &measure);
  205. _cyLine = measure.itemHeight;
  206. } //Create
  207. //
  208. // Key Down
  209. //
  210. void CListView::KeyDown (int nKey)
  211. {
  212. switch (nKey)
  213. {
  214. case ' ' :
  215. ButtonDown( 0 );
  216. break;
  217. case 11:
  218. case 13:
  219. // treat ENTER as a double-click
  220. //
  221. // Owner: Double click!
  222. //
  223. SendMessage (_hwndParent, WM_COMMAND, MAKEWPARAM(idListChild, LBN_DBLCLK), (LPARAM) _hwnd);
  224. break;
  225. //
  226. // Translate keystrokes into scrolling actions
  227. //
  228. case VK_HOME:
  229. SendMessage (_hwnd, WM_VSCROLL, SB_TOP, 0L);
  230. break;
  231. case VK_END:
  232. SendMessage (_hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
  233. break;
  234. case VK_PRIOR:
  235. SendMessage (_hwnd, WM_VSCROLL, SB_PAGEUP, 0L);
  236. break;
  237. case VK_NEXT:
  238. SendMessage (_hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L);
  239. break;
  240. case VK_UP:
  241. SelectUp ();
  242. break;
  243. case VK_DOWN:
  244. SelectDown ();
  245. break;
  246. }
  247. } //KeyDown
  248. void CListView::UpdateHighlight(
  249. int oldLine,
  250. int newLine )
  251. {
  252. // unhighlight
  253. if ( -1 != oldLine )
  254. RefreshRow( oldLine );
  255. // highlight
  256. if ( oldLine != newLine )
  257. RefreshRow( newLine );
  258. UpdateWindow (_hwnd);
  259. } //UpdateHighlight
  260. void CListView::SelectUp ()
  261. {
  262. int newLine;
  263. if ( SendMessage( _hwndParent, wmListNotify, listSelectUp, (LPARAM)&newLine ))
  264. UpdateHighlight( newLine + 1, newLine );
  265. } //SelectUp
  266. void CListView::SelectDown ()
  267. {
  268. int newLine;
  269. if ( SendMessage( _hwndParent, wmListNotify, listSelectDown, (LPARAM)&newLine ))
  270. UpdateHighlight( newLine - 1, newLine );
  271. } //SelectDown
  272. //
  273. // Button up (select)
  274. //
  275. void CListView::ButtonUp (int y)
  276. {
  277. }
  278. void CListView::ButtonDown (int y)
  279. {
  280. int line = y / _cyLine;
  281. int newLine = line;
  282. if (line >= _cLines)
  283. return;
  284. //
  285. // Owner: Selection made!
  286. //
  287. if (SendMessage (_hwndParent, wmListNotify, listSelect, (LPARAM)&line ))
  288. UpdateHighlight( line, newLine );
  289. ::SetFocus (_hwnd);
  290. } //ButtonDown
  291. void CListView::SetFocus()
  292. {
  293. //
  294. // Owner: Focus!
  295. //
  296. SendMessage (_hwndParent, WM_COMMAND, MAKEWPARAM(idListChild, LBN_SETFOCUS), (LPARAM) _hwnd);
  297. } //SetFocus
  298. //
  299. // Size
  300. //
  301. void CListView::Size (WPARAM flags, int cx, int cy)
  302. {
  303. int cxOld = _cx;
  304. int cyOld = _cy;
  305. _cx = cx;
  306. _cy = cy;
  307. BOOL fInvalidate = FALSE;
  308. if (cy != cyOld)
  309. {
  310. _cLines = cy / _cyLine;
  311. //
  312. // Owner: Size!
  313. //
  314. long cRows = _cLines;
  315. fInvalidate = (BOOL)SendMessage(_hwndParent, wmListNotify, listSize, (LPARAM) &cRows);
  316. }
  317. // Don't repaint the common area
  318. RECT rect;
  319. rect.top = 0;
  320. rect.left = 0;
  321. rect.bottom = min (cy, cyOld);
  322. rect.right = min (cx, cxOld);
  323. // no need -- user does this for free, and it causes repaint bugs
  324. // ValidateRect (_hwnd, &rect );
  325. if (cy != cyOld)
  326. {
  327. if ( fInvalidate )
  328. InvalidateAndUpdateScroll();
  329. else
  330. UpdateScroll();
  331. }
  332. } //Size
  333. //
  334. // Paint
  335. //
  336. void CListView::Paint (PAINTSTRUCT& paint)
  337. {
  338. RECT& rect = paint.rcPaint;
  339. int lineStart = rect.top / _cyLine;
  340. int lineEnd = (rect.bottom + _cyLine - 1) / _cyLine;
  341. DRAWITEMSTRUCT draw;
  342. draw.hwndItem = _hwnd;
  343. draw.itemAction = ODA_DRAWENTIRE;
  344. HDC hdc = paint.hdc;
  345. draw.hDC = hdc;
  346. HFONT hfontOld = (HFONT) SelectObject (hdc, _hfont);
  347. for (int i = lineStart; i < lineEnd; i++)
  348. {
  349. draw.itemState = 0;
  350. if ( GetFocus() == _hwnd )
  351. draw.itemState |= ODS_FOCUS;
  352. draw.itemID = i;
  353. draw.rcItem.top = 0;
  354. draw.rcItem.left = 0;
  355. draw.rcItem.bottom = _cyLine;
  356. draw.rcItem.right = _cx;
  357. SetViewportOrgEx( hdc, 0, i * _cyLine, 0 );
  358. //
  359. // Owner: Draw item!
  360. //
  361. SendMessage (_hwndParent, wmDrawItem, 0, (LPARAM)&draw);
  362. }
  363. SelectObject (hdc, hfontOld);
  364. } //Paint
  365. //
  366. // Set Font
  367. //
  368. void CListView::SetFont (HFONT hfontNew)
  369. {
  370. _hfont = hfontNew;
  371. MEASUREITEMSTRUCT measure;
  372. measure.CtlType = odtListView;
  373. //
  374. // Owner: Measure item
  375. //
  376. SendMessage (_hwndParent, wmMeasureItem, 0, (LPARAM) &measure);
  377. _cyLine = measure.itemHeight;
  378. long cRows = (_cy + _cyLine - 1) / _cyLine;
  379. _cLines = cRows;
  380. //
  381. // Owner: Size
  382. //
  383. SendMessage(_hwndParent, wmListNotify, listSize, (LPARAM) &cRows);
  384. InvalidateAndUpdateScroll();
  385. } //SetFont
  386. //
  387. // Scrolling
  388. //
  389. void CListView::Vscroll ( int action, int nPos)
  390. {
  391. switch (action)
  392. {
  393. case SB_LINEUP:
  394. LineUp ();
  395. break;
  396. case SB_LINEDOWN:
  397. LineDown ();
  398. break;
  399. case SB_THUMBTRACK:
  400. // don't refresh when thumb dragging
  401. // over many hits (too expensive)
  402. break;
  403. case SB_THUMBPOSITION:
  404. if (_cTotal > 65535)
  405. {
  406. SCROLLINFO si; si.cbSize = sizeof si;
  407. si.fMask = SIF_TRACKPOS;
  408. GetScrollInfo (_hwnd, SB_VERT, &si);
  409. nPos = si.nTrackPos;
  410. }
  411. ScrollPos (nPos);
  412. break;
  413. case SB_PAGEDOWN:
  414. PageDown ();
  415. break;
  416. case SB_PAGEUP:
  417. PageUp ();
  418. break;
  419. case SB_TOP:
  420. Top ();
  421. break;
  422. case SB_BOTTOM:
  423. Bottom ();
  424. break;
  425. }
  426. } //VScroll
  427. void CListView::LineUp ()
  428. {
  429. long cLine = 1;
  430. //
  431. // Owner: Line up!
  432. //
  433. SendMessage(_hwndParent, wmListNotify, listScrollLineUp, (LPARAM) &cLine);
  434. if (cLine == 1)
  435. {
  436. if (_cBefore != 0)
  437. _cBefore--;
  438. // Force scroll and redraw
  439. RECT rect;
  440. GetClientRect (_hwnd, &rect);
  441. MyScrollWindow (_hwnd, 0, _cyLine, &rect, &rect);
  442. UpdateScroll();
  443. }
  444. } //LineUp
  445. void CListView::LineDown ()
  446. {
  447. long cLine = 1;
  448. //
  449. // Owner: Line down!
  450. //
  451. SendMessage(_hwndParent, wmListNotify, listScrollLineDn, (LPARAM) &cLine);
  452. if (cLine == 1)
  453. {
  454. RECT rect;
  455. GetClientRect (_hwnd, &rect);
  456. MyScrollWindow (_hwnd, 0, -_cyLine, &rect, &rect);
  457. _cBefore++;
  458. UpdateScroll();
  459. }
  460. } //LineDown
  461. void CListView::_GoUp(
  462. long cToGo )
  463. {
  464. CWaitCursor wait;
  465. long count = cToGo;
  466. count = __min( count, _cBefore );
  467. //
  468. // Owner: Page up!
  469. //
  470. SendMessage(_hwndParent, wmListNotify, listScrollPageUp, (LPARAM) &count);
  471. // _cBefore is approximate; don't give up if it is too big
  472. if ( 0 == count )
  473. {
  474. if ( _cBefore > 0 )
  475. count = _cBefore - 1;
  476. else
  477. count = 1; // worst case; scroll up one line
  478. SendMessage( _hwndParent,
  479. wmListNotify,
  480. listScrollPageUp,
  481. (LPARAM) &count );
  482. }
  483. // gee, we're having a bad hair day
  484. if ( 0 == count )
  485. {
  486. count = 1; // worst case; scroll up one line
  487. SendMessage( _hwndParent,
  488. wmListNotify,
  489. listScrollPageUp,
  490. (LPARAM) &count );
  491. }
  492. if ( 0 != count )
  493. {
  494. // count == number of lines open at the top
  495. _cBefore -= count;
  496. if (_cBefore < 0)
  497. _cBefore = 0;
  498. InvalidateAndUpdateScroll();
  499. }
  500. } //_GoUp
  501. void CListView::PageUp ()
  502. {
  503. _GoUp( _cLines - 1 );
  504. } //PageUp
  505. void CListView::_GoDown(
  506. long cToGo )
  507. {
  508. CWaitCursor wait;
  509. long count = cToGo;
  510. //
  511. // Owner: Page Down!
  512. //
  513. SendMessage(_hwndParent, wmListNotify, listScrollPageDn, (LPARAM) &count);
  514. // count == number of lines open at the bottom
  515. if ( 0 != count )
  516. {
  517. _cBefore += count;
  518. if (_cBefore >= ( _cTotal - _cLines ) )
  519. _cBefore = ( _cTotal - _cLines );
  520. InvalidateAndUpdateScroll();
  521. }
  522. } //_GoDown
  523. void CListView::PageDown ()
  524. {
  525. _GoDown( _cLines - 1 );
  526. } //PageDown
  527. void CListView::Top ()
  528. {
  529. long count = _cLines;
  530. //
  531. // Owner: Top!
  532. //
  533. SendMessage(_hwndParent, wmListNotify, listScrollTop, (LPARAM) &count );
  534. _cBefore = 0;
  535. InvalidateAndUpdateScroll();
  536. } //Top
  537. void CListView::Bottom ()
  538. {
  539. long count = _cLines;
  540. //
  541. // Owner: Bottom!
  542. //
  543. SendMessage(_hwndParent, wmListNotify, listScrollBottom, (LPARAM) &count);
  544. // count == number of lines visible
  545. _cBefore = _cTotal - count;
  546. if (_cBefore < 0)
  547. _cBefore = 0;
  548. InvalidateAndUpdateScroll();
  549. } //Bottom
  550. void CListView::ScrollPos (int pos)
  551. {
  552. long iRow = pos;
  553. //
  554. // Owner: Scroll Position!
  555. //
  556. SendMessage(_hwndParent, wmListNotify, listScrollPos, (LPARAM) &iRow);
  557. if (iRow != -1)
  558. {
  559. _cBefore = iRow;
  560. InvalidateAndUpdateScroll();
  561. }
  562. } //ScrollPos
  563. //
  564. // Message: Reset Contents
  565. //
  566. void CListView::ResetContents()
  567. {
  568. _cBefore = 0;
  569. _cTotal = 0;
  570. UpdateScroll();
  571. RECT rect;
  572. GetClientRect (_hwnd, &rect);
  573. InvalidateRect (_hwnd, &rect, TRUE );
  574. UpdateWindow (_hwnd);
  575. } //ResetContents
  576. void CListView::InvalidateAndUpdateScroll()
  577. {
  578. RECT rect;
  579. GetClientRect (_hwnd, &rect);
  580. InvalidateRect (_hwnd, &rect, TRUE );
  581. UpdateScroll();
  582. } //InvalidateAndUpdateScroll
  583. //
  584. // Message: Insert item after iRow
  585. //
  586. void CListView::InsertItem (int iRow)
  587. {
  588. Win4Assert (iRow < _cLines );
  589. RECT rect;
  590. GetClientRect (_hwnd, &rect);
  591. rect.top = (iRow + 1) * _cyLine;
  592. MyScrollWindow( _hwnd, 0, _cyLine, &rect, &rect, FALSE );
  593. _cTotal++;
  594. UpdateWindow (_hwnd);
  595. UpdateScroll();
  596. } //InsertItem
  597. //
  598. // Message: Delete item
  599. //
  600. void CListView::DeleteItem (int iRow)
  601. {
  602. Win4Assert (iRow < _cLines );
  603. RECT rect;
  604. GetClientRect (_hwnd, &rect);
  605. rect.top = (iRow + 1) * _cyLine;
  606. MyScrollWindow( _hwnd, 0, -_cyLine, &rect, &rect, FALSE );
  607. _cTotal--;
  608. if (_cTotal < 0)
  609. _cTotal = 0;
  610. // Invalidate the area which was
  611. // scrolled up (the last row before scrolling), if visible
  612. if ( _cTotal && _cTotal < _cLines )
  613. {
  614. RefreshRow( _cTotal );
  615. }
  616. UpdateScroll();
  617. } //DeleteItem
  618. //
  619. // Message: Invalidate item
  620. //
  621. void CListView::InvalidateItem (int iRow)
  622. {
  623. Win4Assert (iRow <= _cLines );
  624. RefreshRow (iRow);
  625. UpdateWindow (_hwnd);
  626. } //InvalidateItem
  627. //
  628. // Message: Set count before
  629. //
  630. void CListView::SetCountBefore (int cBefore)
  631. {
  632. _cBefore = cBefore;
  633. SetScrollPos (_hwnd, SB_VERT, _cBefore, TRUE);
  634. } //SetCountBefore
  635. //
  636. // Message: Set total count
  637. //
  638. void CListView::SetTotalCount (int cTotal)
  639. {
  640. _cTotal = cTotal;
  641. UpdateScroll ();
  642. } //SetTotalCount
  643. //
  644. // Internal methods
  645. //
  646. void CListView::RefreshRow (int iRow)
  647. {
  648. Win4Assert ( iRow < _cLines );
  649. RECT rect;
  650. rect.top = iRow * _cyLine;
  651. rect.left = 0;
  652. rect.bottom = rect.top + _cyLine;
  653. rect.right = _cx;
  654. InvalidateRect (_hwnd, &rect, TRUE );
  655. } //RefreshRow
  656. void CListView::UpdateScroll()
  657. {
  658. if (_cTotal - _cLines >= 0)
  659. {
  660. ShowScrollBar( _hwnd, SB_VERT, TRUE );
  661. SetScrollRange (_hwnd, SB_VERT, 0, _cTotal - 1, FALSE);
  662. SetScrollPos (_hwnd, SB_VERT, _cBefore, TRUE);
  663. // proportional scroll box
  664. SCROLLINFO si;
  665. si.cbSize = sizeof(si);
  666. si.fMask = SIF_PAGE;
  667. si.nPage = _cLines;
  668. SetScrollInfo( _hwnd, SB_VERT, &si, TRUE );
  669. EnableScrollBar (_hwnd, SB_VERT, ESB_ENABLE_BOTH );
  670. }
  671. else
  672. {
  673. _cBefore = 0;
  674. ShowScrollBar( _hwnd, SB_VERT, FALSE );
  675. EnableScrollBar (_hwnd, SB_VERT, ESB_DISABLE_BOTH );
  676. }
  677. } //UpdateScroll