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.

955 lines
24 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved
  3. Module Name:
  4. IeList.cpp
  5. Abstract:
  6. CIeList is a subclassed (owner-draw) list control that groups items into
  7. a 3D panel that have the same information in the indicated
  8. sortColumn.
  9. The panels are created from tiles. Each tile corresponds to one subitem
  10. in the list, and has the appropriate 3D edges so that the tiles together
  11. make up a panel.
  12. NOTE: The control must be initialized with the number of columns and the
  13. sort column. The parent dialog must implement OnMeasureItem and call
  14. GetItemHeight to set the row height for the control.
  15. Author:
  16. Art Bragg [artb] 01-DEC-1997
  17. Revision History:
  18. --*/
  19. #include "stdafx.h"
  20. #include "IeList.h"
  21. // Position of a tile in it's panel
  22. #define POS_LEFT 100
  23. #define POS_RIGHT 101
  24. #define POS_TOP 102
  25. #define POS_BOTTOM 103
  26. #define POS_MIDDLE 104
  27. #define POS_SINGLE 105
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CIeList
  30. BEGIN_MESSAGE_MAP(CIeList, CListCtrl)
  31. //{{AFX_MSG_MAP(CIeList)
  32. ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
  33. ON_WM_SETFOCUS()
  34. ON_WM_KILLFOCUS()
  35. //}}AFX_MSG_MAP
  36. ON_WM_SYSCOLORCHANGE()
  37. END_MESSAGE_MAP()
  38. CIeList::CIeList()
  39. /*++
  40. Routine Description:
  41. Sets default dimensions for the control.
  42. Arguments:
  43. none.
  44. Return Value:
  45. none.
  46. --*/
  47. {
  48. //
  49. // Initializations
  50. //
  51. m_ColCount = 0;
  52. m_SortCol = 0;
  53. m_pVertPos = NULL;
  54. //
  55. // Drawing dimensions
  56. //
  57. // If these are altered, the visual aspects of the control
  58. // should be checked (especially the focus rectangle),
  59. // as some minor adjustments may need to be made.
  60. //
  61. m_VertRaisedSpace = 1;
  62. m_BorderThickness = 2;
  63. m_VerticalTextOffsetTop = 1;
  64. // The text height will be set later (based on the font size)
  65. m_Textheight = 0;
  66. m_VerticalTextOffsetBottom = 1;
  67. // Total height will be set later
  68. m_TotalHeight = 0;
  69. m_HorzRaisedSpace = 1;
  70. m_HorzTextOffset = 3;
  71. }
  72. CIeList::~CIeList()
  73. /*++
  74. Routine Description:
  75. Cleanup.
  76. Arguments:
  77. none.
  78. Return Value:
  79. none.
  80. --*/
  81. {
  82. // Cleanup the array of vertical positions
  83. if( m_pVertPos ) free ( m_pVertPos );
  84. }
  85. /////////////////////////////////////////////////////////////////////////////
  86. // CIeList message handlers
  87. void CIeList::Initialize(
  88. IN int colCount,
  89. IN int sortCol
  90. )
  91. /*++
  92. Routine Description:
  93. Sets the number of columns (not easily available from MFC) and
  94. the sort column.
  95. Arguments:
  96. colCount - number of columns to display
  97. sortCol - column to sort on
  98. Return Value:
  99. none.
  100. --*/
  101. {
  102. m_ColCount = colCount;
  103. m_SortCol = sortCol;
  104. }
  105. void CIeList::DrawItem(
  106. IN LPDRAWITEMSTRUCT lpDrawItemStruct
  107. )
  108. /*++
  109. Routine Description:
  110. This is the callback for an owner draw control.
  111. Draws the appropriate text and/or 3D lines depending on the
  112. item number and clipping rectangle supplied by MFC in lpDrawItemStruct
  113. Arguments:
  114. lpDrawItemStruct - MFC structure that tells us what and where to draw
  115. Return Value:
  116. none.
  117. --*/
  118. {
  119. CDC dc;
  120. int saveDc;
  121. int colWidth = 0; // Width of current column
  122. int horzPos = POS_MIDDLE; // Horz position in the panel
  123. int vertPos = POS_SINGLE; // Vert position in the panel
  124. BOOL bSelected = FALSE; // Is this item selected
  125. CRect rcAllLabels; // Used to find left position of focus rectangle
  126. CRect itemRect; // Rectangle supplied in lpDrawItemStruct
  127. CRect textRect; // Rectangle for text
  128. CRect boxRect; // Rectangle for 3D box (the panel)
  129. CRect clipRect; // Current clipping rectangle
  130. LPTSTR pszText; // Text to display
  131. COLORREF clrTextSave = 0; // Save the current color
  132. COLORREF clrBkSave = 0; // Save the background color
  133. int leftStart = 0; // Left edge of where we're currently drawing
  134. BOOL bFocus = (GetFocus() == this); // Do we have focus?
  135. //
  136. // Get the current scroll position
  137. //
  138. int nHScrollPos = GetScrollPos( SB_HORZ );
  139. //
  140. // Get the item ID from the list for the item we're drawing
  141. //
  142. int itemID = lpDrawItemStruct->itemID;
  143. //
  144. // Get item data for the item we're drawing
  145. //
  146. LV_ITEM lvi;
  147. lvi.mask = LVIF_IMAGE | LVIF_STATE;
  148. lvi.iItem = itemID;
  149. lvi.iSubItem = 0;
  150. lvi.stateMask = 0xFFFF; // get all state flags
  151. GetItem(&lvi);
  152. //
  153. // Determine focus and selected states
  154. //
  155. bSelected = (bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) && lvi.state & LVIS_SELECTED;
  156. //
  157. // Get the rectangle to draw in
  158. //
  159. itemRect = lpDrawItemStruct->rcItem;
  160. dc.Attach( lpDrawItemStruct->hDC );
  161. saveDc = dc.SaveDC();
  162. //
  163. // Get the clipping rectangle - we use it's vertical edges
  164. // to optimize what we draw
  165. //
  166. dc.GetClipBox( &clipRect );
  167. boxRect = clipRect;
  168. //
  169. // For each column, paint it's text and the section of the 3D panel
  170. //
  171. for ( int col = 0; col < m_ColCount; col++ ) {
  172. colWidth = GetColumnWidth( col );
  173. //
  174. // Only paint this column if it's in the clipping rectangle
  175. //
  176. if( ( ( leftStart + colWidth ) > clipRect.left ) || ( leftStart < clipRect.right ) ) {
  177. //
  178. // Determine the horizontal position based on the column
  179. //
  180. horzPos = POS_MIDDLE;
  181. if( col == 0 ) horzPos = POS_LEFT;
  182. if( col == m_ColCount - 1 ) horzPos = POS_RIGHT;
  183. //
  184. // Calculate the rectangle for this tile
  185. //
  186. boxRect.top = itemRect.top;
  187. boxRect.bottom = itemRect.bottom;
  188. boxRect.left = itemRect.left + leftStart;
  189. boxRect.right = itemRect.left + leftStart + colWidth;
  190. //
  191. // Get the vertical position from the array. It was saved there
  192. // during SortItem for performance reasons.
  193. //
  194. if( m_pVertPos ) {
  195. vertPos = m_pVertPos[ itemID ];
  196. }
  197. //
  198. // Draw the tile for this item.
  199. //
  200. Draw3dRectx ( &dc, boxRect, horzPos, vertPos, bSelected );
  201. //
  202. // If this item is selected, change the text colors
  203. //
  204. if( bSelected ) {
  205. clrTextSave = dc.SetTextColor( m_clrHighlightText );
  206. clrBkSave = dc.SetBkColor( m_clrHighlight );
  207. }
  208. //
  209. // Calculate the text rectangle
  210. //
  211. textRect.top = itemRect.top + m_VertRaisedSpace + m_BorderThickness + m_VerticalTextOffsetTop;
  212. textRect.bottom = itemRect.bottom; // Text is top justified, no need to adjust bottom
  213. textRect.left = leftStart - nHScrollPos + m_HorzRaisedSpace + m_BorderThickness + m_HorzTextOffset;
  214. textRect.right = itemRect.right;
  215. //
  216. // Get the text and put in the "..." if we need them
  217. //
  218. CString pszLongText = GetItemText( itemID, col );
  219. pszText = NULL;
  220. MakeShortString(&dc, (LPCTSTR) pszLongText,
  221. textRect.right - textRect.left, 4, &pszText);
  222. BOOL bFree = TRUE;
  223. if (pszText == NULL) {
  224. // Failure of some kind...
  225. pszText = (LPTSTR)(LPCTSTR)pszLongText;
  226. bFree = FALSE;
  227. }
  228. //
  229. // Now draw the text using the correct color
  230. //
  231. COLORREF saveTextColor;
  232. if( bSelected ) {
  233. saveTextColor = dc.SetTextColor( m_clrHighlightText );
  234. } else {
  235. saveTextColor = dc.SetTextColor( m_clrText );
  236. }
  237. int textheight = dc.DrawText( pszText, textRect, DT_NOCLIP | DT_LEFT | DT_TOP | DT_SINGLELINE );
  238. dc.SetTextColor( saveTextColor );
  239. if (pszText && bFree) {
  240. free(pszText);
  241. }
  242. }
  243. //
  244. // Move to the next column
  245. //
  246. leftStart += colWidth;
  247. }
  248. //
  249. // draw focus rectangle if item has focus. Use LVIR_BOUNDS rectangle
  250. // to bound it.
  251. //
  252. GetItemRect(itemID, rcAllLabels, LVIR_BOUNDS);
  253. if( lvi.state & LVIS_FOCUSED && bFocus ) {
  254. CRect focusRect;
  255. focusRect.left = rcAllLabels.left + m_HorzRaisedSpace + m_BorderThickness;
  256. focusRect.right = min( rcAllLabels.right, (itemRect.right - m_HorzRaisedSpace * 2 - 3) );
  257. focusRect.top = boxRect.top + m_VertRaisedSpace + m_BorderThickness;
  258. focusRect.bottom = boxRect.top + m_TotalHeight - m_BorderThickness + 1;
  259. dc.DrawFocusRect( focusRect );
  260. }
  261. // Restore colors
  262. if( bSelected ) {
  263. dc.SetTextColor( clrTextSave );
  264. dc.SetBkColor( clrBkSave );
  265. }
  266. dc.RestoreDC( saveDc );
  267. dc.Detach();
  268. }
  269. void CIeList::MakeShortString(
  270. IN CDC* pDC,
  271. IN LPCTSTR lpszLong,
  272. IN int nColumnLen,
  273. IN int nDotOffset,
  274. OUT LPTSTR *ppszShort
  275. )
  276. /*++
  277. Routine Description:
  278. Determines it the supplied string fits in it's column. If not truncates
  279. it and adds "...". From MS sample code.
  280. Arguments:
  281. pDC - Device context
  282. lpszLong - Original String
  283. nColumnLen - Width of column
  284. nDotOffset - Space before dots
  285. Return Value:
  286. Shortened string
  287. --*/
  288. {
  289. static const _TCHAR szThreeDots[] = _T("...");
  290. int nStringLen = lstrlen(lpszLong);
  291. *ppszShort = (_TCHAR *)malloc((nStringLen + 1) * sizeof(_TCHAR) + sizeof(szThreeDots));
  292. if (*ppszShort == NULL)
  293. return;
  294. _TCHAR *szShort = *ppszShort;
  295. if(nStringLen == 0) {
  296. lstrcpy(szShort, _T(""));
  297. } else {
  298. lstrcpy(szShort, lpszLong);
  299. }
  300. if(nStringLen == 0 ||
  301. (pDC->GetTextExtent(lpszLong, nStringLen).cx + nDotOffset) <= nColumnLen)
  302. {
  303. // return long format
  304. return;
  305. }
  306. int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
  307. for(int i = nStringLen-1; i > 0; i--)
  308. {
  309. szShort[i] = 0;
  310. if((pDC->GetTextExtent(szShort, i).cx + nDotOffset + nAddLen)
  311. <= nColumnLen)
  312. {
  313. break;
  314. }
  315. }
  316. lstrcat(szShort, szThreeDots);
  317. return;
  318. }
  319. void CIeList::Draw3dRectx (
  320. IN CDC *pDc,
  321. IN CRect &rect,
  322. IN int horzPos,
  323. IN int vertPos,
  324. IN BOOL bSelected
  325. )
  326. /*++
  327. Routine Description:
  328. Draws the appropriate portion (tile) of a panel for a given cell in the
  329. list. The edges of the panel portion are determined by the horzPos
  330. and vertPos parameters.
  331. Arguments:
  332. pDc - Device context
  333. rect - Rectangle to draw the panel portion in
  334. horzPos - Where the portion is horizontally
  335. vertPos - Where the portion is vertically
  336. bSelected - Is the item selected
  337. Return Value:
  338. none.
  339. --*/
  340. {
  341. CPen *pSavePen;
  342. int topOffset = 0;
  343. int rightOffset = 0;
  344. int leftOffset = 0;
  345. //
  346. // If a given edge of the tile is to be drawn, set an offset to that
  347. // edge. If we don't draw a given edge, the offset is 0.
  348. //
  349. switch ( horzPos )
  350. {
  351. case POS_LEFT:
  352. leftOffset = m_HorzRaisedSpace;
  353. rightOffset = 0;
  354. break;
  355. case POS_MIDDLE:
  356. leftOffset = 0;
  357. rightOffset = 0;
  358. break;
  359. case POS_RIGHT:
  360. leftOffset = 0;
  361. rightOffset = m_HorzRaisedSpace + 3;
  362. break;
  363. }
  364. switch ( vertPos )
  365. {
  366. case POS_TOP:
  367. topOffset = m_VertRaisedSpace;
  368. break;
  369. case POS_MIDDLE:
  370. topOffset = 0;
  371. break;
  372. case POS_BOTTOM:
  373. topOffset = 0;
  374. break;
  375. case POS_SINGLE:
  376. topOffset = m_VertRaisedSpace;
  377. break;
  378. }
  379. //
  380. // Erase
  381. //
  382. if( !bSelected ) pDc->FillSolidRect( rect, m_clrBkgnd );
  383. //
  384. // Highlight the selected area
  385. //
  386. if (bSelected)
  387. {
  388. CRect selectRect;
  389. if (leftOffset == 0)
  390. selectRect.left = rect.left;
  391. else
  392. selectRect.left = rect.left + leftOffset + m_BorderThickness;
  393. if (rightOffset == 0)
  394. selectRect.right = rect.right;
  395. else
  396. selectRect.right = rect.right - rightOffset - m_BorderThickness + 1;
  397. selectRect.top = rect.top + m_VertRaisedSpace + m_BorderThickness;
  398. selectRect.bottom = rect.top + m_TotalHeight - m_BorderThickness + 1;
  399. pDc->FillSolidRect( selectRect, m_clrHighlight );
  400. }
  401. // Select a pen to save the original pen
  402. pSavePen = pDc->SelectObject( &m_ShadowPen );
  403. // left edge
  404. if( horzPos == POS_LEFT ) {
  405. // Outside lighter line
  406. pDc->SelectObject( &m_ShadowPen );
  407. pDc->MoveTo( rect.left + leftOffset, rect.top + topOffset );
  408. pDc->LineTo( rect.left + leftOffset, rect.top + m_TotalHeight + 1);
  409. // Inside edge - darker line
  410. pDc->SelectObject( &m_DarkShadowPen );
  411. pDc->MoveTo( rect.left + leftOffset + 1, rect.top + topOffset);
  412. pDc->LineTo( rect.left + leftOffset + 1, rect.top + m_TotalHeight + 1);
  413. }
  414. // right edge
  415. if( horzPos == POS_RIGHT ) {
  416. // Outside line
  417. pDc->SelectObject( &m_HiLightPen );
  418. pDc->MoveTo( rect.right - rightOffset, rect.top + topOffset );
  419. pDc->LineTo( rect.right - rightOffset, rect.top + m_TotalHeight + 1 );
  420. // Inside line
  421. pDc->SelectObject( &m_LightPen );// note - this is usually the same color as btnface
  422. if( vertPos == POS_TOP )
  423. pDc->MoveTo( rect.right - rightOffset - 1, rect.top + topOffset + 1 );
  424. else
  425. pDc->MoveTo( rect.right - rightOffset - 1, rect.top + topOffset );
  426. pDc->LineTo( rect.right - rightOffset - 1, rect.top + m_TotalHeight + 2 );
  427. }
  428. // top edge
  429. if( ( vertPos == POS_TOP ) || ( vertPos == POS_SINGLE ) ) {
  430. // Outside lighter
  431. pDc->SelectObject( &m_ShadowPen );
  432. pDc->MoveTo( rect.left + leftOffset, rect.top + topOffset );
  433. pDc->LineTo( rect.right - rightOffset + 1, rect.top + topOffset );
  434. // Inside edge darker
  435. pDc->SelectObject( &m_DarkShadowPen );
  436. if( horzPos == POS_LEFT )
  437. pDc->MoveTo( rect.left + leftOffset + 1, rect.top + topOffset + 1 );
  438. else
  439. pDc->MoveTo( rect.left + leftOffset - 3, rect.top + topOffset + 1 );
  440. pDc->LineTo( rect.right - rightOffset, rect.top + topOffset + 1);
  441. }
  442. // bottom edge
  443. if( ( vertPos == POS_BOTTOM ) || ( vertPos == POS_SINGLE ) ) {
  444. // Outside line
  445. pDc->SelectObject( &m_HiLightPen );
  446. if( horzPos == POS_LEFT )
  447. pDc->MoveTo( rect.left + leftOffset + 1, rect.top + m_TotalHeight );
  448. else
  449. pDc->MoveTo( rect.left + leftOffset - 1, rect.top + m_TotalHeight );
  450. pDc->LineTo( rect.right - rightOffset, rect.top + m_TotalHeight );
  451. // Inside line
  452. pDc->SelectObject( &m_LightPen );
  453. if( horzPos == POS_LEFT )
  454. pDc->MoveTo( rect.left + leftOffset + 2, rect.top + m_TotalHeight - 1 );
  455. else
  456. pDc->MoveTo( rect.left + leftOffset - 2, rect.top + m_TotalHeight - 1 );
  457. pDc->LineTo( rect.right - rightOffset - 1, rect.top + m_TotalHeight - 1 );
  458. }
  459. pDc->SelectObject( pSavePen );
  460. }
  461. void CIeList::OnClick(
  462. NMHDR* /* pNMHDR */, LRESULT* pResult
  463. )
  464. /*++
  465. Routine Description:
  466. When the list is clicked, we invalidate the
  467. rectangle for the currently selected item
  468. Arguments:
  469. pResult - ununsed
  470. Return Value:
  471. none.
  472. --*/
  473. {
  474. CRect rect;
  475. // Get the selected item
  476. int curIndex = GetNextItem( -1, LVNI_SELECTED );
  477. if( curIndex != -1 ) {
  478. GetItemRect( curIndex, &rect, LVIR_BOUNDS );
  479. InvalidateRect( rect );
  480. UpdateWindow();
  481. }
  482. *pResult = 0;
  483. }
  484. /*++
  485. Routine Description:
  486. Repaint the currently selected item if the style is LVS_SHOWSELALWAYS.
  487. Arguments:
  488. none.
  489. Return Value:
  490. none.
  491. --*/
  492. void CIeList::RepaintSelectedItems()
  493. {
  494. CRect rcItem, rcLabel;
  495. //
  496. // invalidate focused item so it can repaint properly
  497. //
  498. int nItem = GetNextItem(-1, LVNI_FOCUSED);
  499. if(nItem != -1)
  500. {
  501. GetItemRect(nItem, rcItem, LVIR_BOUNDS);
  502. GetItemRect(nItem, rcLabel, LVIR_LABEL);
  503. rcItem.left = rcLabel.left;
  504. InvalidateRect(rcItem, FALSE);
  505. }
  506. //
  507. // if selected items should not be preserved, invalidate them
  508. //
  509. if(!(GetStyle() & LVS_SHOWSELALWAYS))
  510. {
  511. for(nItem = GetNextItem(-1, LVNI_SELECTED);
  512. nItem != -1; nItem = GetNextItem(nItem, LVNI_SELECTED))
  513. {
  514. GetItemRect(nItem, rcItem, LVIR_BOUNDS);
  515. GetItemRect(nItem, rcLabel, LVIR_LABEL);
  516. rcItem.left = rcLabel.left;
  517. InvalidateRect(rcItem, FALSE);
  518. }
  519. }
  520. // update changes
  521. UpdateWindow();
  522. }
  523. int CIeList::GetItemHeight(
  524. IN LONG fontHeight
  525. )
  526. /*++
  527. Routine Description:
  528. Calculates the item height (the height of each drawing
  529. rectangle in the control) based on the supplied fontHeight. This
  530. function is used by the parent to set the item height for the
  531. control.
  532. Arguments:
  533. fontHeight - The height of the current font.
  534. Return Value:
  535. Item height.
  536. --*/
  537. {
  538. int itemHeight =
  539. m_VertRaisedSpace +
  540. m_BorderThickness +
  541. m_VerticalTextOffsetTop +
  542. fontHeight +
  543. 2 +
  544. m_VerticalTextOffsetBottom +
  545. m_BorderThickness +
  546. 1;
  547. return itemHeight;
  548. }
  549. void CIeList::OnSetFocus(
  550. CWnd* pOldWnd
  551. )
  552. /*++
  553. Routine Description:
  554. Repaint the selected item.
  555. Arguments:
  556. pOldWnd - Not used by this function
  557. Return Value:
  558. none
  559. --*/
  560. {
  561. CListCtrl::OnSetFocus(pOldWnd);
  562. // repaint items that should change appearance
  563. RepaintSelectedItems();
  564. }
  565. void CIeList::OnKillFocus(
  566. CWnd* pNewWnd
  567. )
  568. /*++
  569. Routine Description:
  570. Repaint the selected item.
  571. Arguments:
  572. pOldWnd - Not used by this function
  573. Return Value:
  574. none
  575. --*/
  576. {
  577. CListCtrl::OnKillFocus(pNewWnd);
  578. // repaint items that should change appearance
  579. RepaintSelectedItems();
  580. }
  581. void CIeList::PreSubclassWindow()
  582. /*++
  583. Routine Description:
  584. Calculate height parameters based on the font size. Set
  585. colors for the control.
  586. Arguments:
  587. none.
  588. Return Value:
  589. none
  590. --*/
  591. {
  592. CFont *pFont;
  593. LOGFONT logFont;
  594. pFont = GetFont( );
  595. pFont->GetLogFont( &logFont );
  596. LONG fontHeight = abs ( logFont.lfHeight );
  597. m_Textheight = fontHeight + 2;
  598. m_TotalHeight =
  599. m_VertRaisedSpace +
  600. m_BorderThickness +
  601. m_VerticalTextOffsetTop +
  602. m_Textheight +
  603. m_VerticalTextOffsetBottom +
  604. m_BorderThickness;
  605. SetColors();
  606. CListCtrl::PreSubclassWindow();
  607. }
  608. void CIeList::OnSysColorChange()
  609. /*++
  610. Routine Description:
  611. Set the system colors and invalidate the control.
  612. Arguments:
  613. none.
  614. Return Value:
  615. none
  616. --*/
  617. {
  618. SetColors();
  619. Invalidate();
  620. }
  621. void CIeList::SetColors()
  622. /*++
  623. Routine Description:
  624. Store the system colors and create pens.
  625. Arguments:
  626. none.
  627. Return Value:
  628. none
  629. --*/
  630. {
  631. // Text colors
  632. m_clrText = ::GetSysColor(COLOR_WINDOWTEXT);
  633. m_clrTextBk = ::GetSysColor(COLOR_BTNFACE);
  634. m_clrBkgnd = ::GetSysColor(COLOR_BTNFACE);
  635. m_clrHighlightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  636. m_clrHighlight = ::GetSysColor(COLOR_HIGHLIGHT);
  637. // Line colors
  638. m_clr3DDkShadow = ::GetSysColor( COLOR_3DDKSHADOW );
  639. m_clr3DShadow = ::GetSysColor( COLOR_3DSHADOW );
  640. m_clr3DLight = ::GetSysColor( COLOR_3DLIGHT );
  641. m_clr3DHiLight = ::GetSysColor( COLOR_3DHIGHLIGHT );
  642. SetBkColor( m_clrBkgnd );
  643. SetTextColor( m_clrText );
  644. SetTextBkColor( m_clrTextBk );
  645. // Pens for 3D rectangles
  646. if( m_DarkShadowPen.GetSafeHandle() != NULL )
  647. m_DarkShadowPen.DeleteObject();
  648. m_DarkShadowPen.CreatePen ( PS_SOLID, 1, m_clr3DDkShadow );
  649. if( m_ShadowPen.GetSafeHandle() != NULL )
  650. m_ShadowPen.DeleteObject();
  651. m_ShadowPen.CreatePen ( PS_SOLID, 1, m_clr3DShadow );
  652. if( m_LightPen.GetSafeHandle() != NULL )
  653. m_LightPen.DeleteObject();
  654. m_LightPen.CreatePen ( PS_SOLID, 1, m_clr3DLight );
  655. if( m_HiLightPen.GetSafeHandle() != NULL )
  656. m_HiLightPen.DeleteObject();
  657. m_HiLightPen.CreatePen ( PS_SOLID, 1, m_clr3DHiLight );
  658. }
  659. BOOL CIeList::SortItems(
  660. IN PFNLVCOMPARE pfnCompare,
  661. IN DWORD dwData
  662. )
  663. /*++
  664. Routine Description:
  665. Override for SortItems. Checks the text of the sortColumn
  666. for each line in the control against it's neighbors (above and
  667. below) and assigns each line a position within it's panel.
  668. Arguments:
  669. pfnCompare - sort callback function
  670. dwData - Unused
  671. Return Value:
  672. TRUE, FALSE
  673. --*/
  674. {
  675. BOOL retVal = FALSE;
  676. BOOL bEqualAbove = FALSE;
  677. BOOL bEqualBelow = FALSE;
  678. CString thisText;
  679. CString aboveText;
  680. CString belowText;
  681. int numItems = GetItemCount();
  682. //
  683. // Call the base class to sort the items
  684. //
  685. if( CListCtrl::SortItems( pfnCompare, dwData ) ) {
  686. //
  687. // Get the vertical position (position within a panel) by comparing the text
  688. // of the sort column and stash it in the array of vertical positions
  689. //
  690. if( m_pVertPos ) {
  691. free( m_pVertPos );
  692. }
  693. m_pVertPos = (int *) malloc( numItems * sizeof( int ) );
  694. if( m_pVertPos ) {
  695. retVal = TRUE;
  696. for( int itemID = 0; itemID < numItems; itemID++ ) {
  697. //
  698. // Get the text of the item and it's neighbors
  699. //
  700. thisText = GetItemText( itemID, m_SortCol );
  701. aboveText = GetItemText( itemID - 1, m_SortCol );
  702. belowText = GetItemText( itemID + 1, m_SortCol );
  703. //
  704. // Set booleans for the relationship of this item to it's
  705. // neighbors
  706. //
  707. if( ( itemID == 0) || ( thisText.CompareNoCase( aboveText ) != 0 ) ){
  708. bEqualAbove = FALSE;
  709. } else {
  710. bEqualAbove = TRUE;
  711. }
  712. if( ( itemID == GetItemCount() - 1 ) || ( thisText.CompareNoCase( belowText ) != 0 ) ) {
  713. bEqualBelow = FALSE;
  714. } else {
  715. bEqualBelow = TRUE;
  716. }
  717. //
  718. // Determine the position in the panel
  719. //
  720. if ( bEqualAbove && bEqualBelow ) m_pVertPos[ itemID ] = POS_MIDDLE;
  721. else if( bEqualAbove && !bEqualBelow ) m_pVertPos[ itemID ] = POS_BOTTOM;
  722. else if( !bEqualAbove && bEqualBelow ) m_pVertPos[ itemID ] = POS_TOP;
  723. else m_pVertPos[ itemID ] = POS_SINGLE;
  724. }
  725. }
  726. }
  727. return( retVal );
  728. }