home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / general / rowlist / listvwex.cpp next >
C/C++ Source or Header  |  1998-03-26  |  11KB  |  462 lines

  1. // ListVwEx.cpp : implementation of the CListViewEx class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "ListVwEx.h"
  15.  
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CListViewEx
  24.  
  25. IMPLEMENT_DYNCREATE(CListViewEx, CListView)
  26.  
  27. BEGIN_MESSAGE_MAP(CListViewEx, CListView)
  28.     //{{AFX_MSG_MAP(CListViewEx)
  29.     ON_WM_SIZE()
  30.     ON_WM_PAINT()
  31.     ON_WM_SETFOCUS()
  32.     ON_WM_KILLFOCUS()
  33.     //}}AFX_MSG_MAP
  34.     ON_MESSAGE(LVM_SETIMAGELIST, OnSetImageList)
  35.     ON_MESSAGE(LVM_SETTEXTCOLOR, OnSetTextColor)
  36.     ON_MESSAGE(LVM_SETTEXTBKCOLOR, OnSetTextBkColor)
  37.     ON_MESSAGE(LVM_SETBKCOLOR, OnSetBkColor)
  38. END_MESSAGE_MAP()
  39.  
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CListViewEx construction/destruction
  42.  
  43. CListViewEx::CListViewEx()
  44. {
  45.     m_bFullRowSel = FALSE;
  46.     m_bClientWidthSel = TRUE;
  47.  
  48.     m_cxClient = 0;
  49.     m_cxStateImageOffset = 0;
  50.  
  51.     m_clrText = ::GetSysColor(COLOR_WINDOWTEXT);
  52.     m_clrTextBk = ::GetSysColor(COLOR_WINDOW);
  53.     m_clrBkgnd = ::GetSysColor(COLOR_WINDOW);
  54. }
  55.  
  56. CListViewEx::~CListViewEx()
  57. {
  58. }
  59.  
  60. BOOL CListViewEx::PreCreateWindow(CREATESTRUCT& cs)
  61. {
  62.     // default is report view and full row selection
  63.     cs.style &= ~LVS_TYPEMASK;
  64.     cs.style |= LVS_REPORT | LVS_OWNERDRAWFIXED;
  65.     m_bFullRowSel = TRUE;
  66.  
  67.     return(CListView::PreCreateWindow(cs));
  68. }
  69.  
  70. BOOL CListViewEx::SetFullRowSel(BOOL bFullRowSel)
  71. {
  72.     // no painting during change
  73.     LockWindowUpdate();
  74.  
  75.     m_bFullRowSel = bFullRowSel;
  76.  
  77.     BOOL bRet;
  78.  
  79.     if (m_bFullRowSel)
  80.         bRet = ModifyStyle(0L, LVS_OWNERDRAWFIXED);
  81.     else
  82.         bRet = ModifyStyle(LVS_OWNERDRAWFIXED, 0L);
  83.  
  84.     // repaint window if we are not changing view type
  85.     if (bRet && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
  86.         Invalidate();
  87.  
  88.     // repaint changes
  89.     UnlockWindowUpdate();
  90.  
  91.     return(bRet);
  92. }
  93.  
  94. BOOL CListViewEx::GetFullRowSel()
  95. {
  96.     return(m_bFullRowSel);
  97. }
  98.  
  99. /////////////////////////////////////////////////////////////////////////////
  100. // CListViewEx drawing
  101.  
  102. // offsets for first and other columns
  103. #define OFFSET_FIRST    2
  104. #define OFFSET_OTHER    6
  105.  
  106. void CListViewEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  107. {
  108.     CListCtrl& ListCtrl=GetListCtrl();
  109.     CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  110.     CRect rcItem(lpDrawItemStruct->rcItem);
  111.     UINT uiFlags = ILD_TRANSPARENT;
  112.     CImageList* pImageList;
  113.     int nItem = lpDrawItemStruct->itemID;
  114.     BOOL bFocus = (GetFocus() == this);
  115.     COLORREF clrTextSave, clrBkSave;
  116.     COLORREF clrImage = m_clrBkgnd;
  117.     static _TCHAR szBuff[MAX_PATH];
  118.     LPCTSTR pszText;
  119.  
  120. // get item data
  121.  
  122.     LV_ITEM lvi;
  123.     lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
  124.     lvi.iItem = nItem;
  125.     lvi.iSubItem = 0;
  126.     lvi.pszText = szBuff;
  127.     lvi.cchTextMax = sizeof(szBuff);
  128.     lvi.stateMask = 0xFFFF;     // get all state flags
  129.     ListCtrl.GetItem(&lvi);
  130.  
  131.     BOOL bSelected = (bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) && lvi.state & LVIS_SELECTED;
  132.     bSelected = bSelected || (lvi.state & LVIS_DROPHILITED);
  133.  
  134. // set colors if item is selected
  135.  
  136.     CRect rcAllLabels;
  137.     ListCtrl.GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
  138.  
  139.     CRect rcLabel;
  140.     ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
  141.  
  142.     rcAllLabels.left = rcLabel.left;
  143.     if (m_bClientWidthSel && rcAllLabels.right<m_cxClient)
  144.         rcAllLabels.right = m_cxClient;
  145.  
  146.     if (bSelected)
  147.     {
  148.         clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  149.         clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
  150.  
  151.         pDC->FillRect(rcAllLabels, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
  152.     }
  153.     else
  154.         pDC->FillRect(rcAllLabels, &CBrush(m_clrTextBk));
  155.  
  156. // set color and mask for the icon
  157.  
  158.     if (lvi.state & LVIS_CUT)
  159.     {
  160.         clrImage = m_clrBkgnd;
  161.         uiFlags |= ILD_BLEND50;
  162.     }
  163.     else if (bSelected)
  164.     {
  165.         clrImage = ::GetSysColor(COLOR_HIGHLIGHT);
  166.         uiFlags |= ILD_BLEND50;
  167.     }
  168.  
  169. // draw state icon
  170.  
  171.     UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
  172.     if (nStateImageMask)
  173.     {
  174.         int nImage = (nStateImageMask>>12) - 1;
  175.         pImageList = ListCtrl.GetImageList(LVSIL_STATE);
  176.         if (pImageList)
  177.         {
  178.             pImageList->Draw(pDC, nImage,
  179.                 CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
  180.         }
  181.     }
  182.  
  183. // draw normal and overlay icon
  184.  
  185.     CRect rcIcon;
  186.     ListCtrl.GetItemRect(nItem, rcIcon, LVIR_ICON);
  187.  
  188.     pImageList = ListCtrl.GetImageList(LVSIL_SMALL);
  189.     if (pImageList)
  190.     {
  191.         UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
  192.         if (rcItem.left<rcItem.right-1)
  193.         {
  194.             ImageList_DrawEx(pImageList->m_hImageList, lvi.iImage,
  195.                     pDC->m_hDC,rcIcon.left,rcIcon.top, 16, 16,
  196.                     m_clrBkgnd, clrImage, uiFlags | nOvlImageMask);
  197.         }
  198.     }
  199.  
  200. // draw item label
  201.  
  202.     ListCtrl.GetItemRect(nItem, rcItem, LVIR_LABEL);
  203.     rcItem.right -= m_cxStateImageOffset;
  204.  
  205.     pszText = MakeShortString(pDC, szBuff,
  206.                 rcItem.right-rcItem.left, 2*OFFSET_FIRST);
  207.  
  208.     rcLabel = rcItem;
  209.     rcLabel.left += OFFSET_FIRST;
  210.     rcLabel.right -= OFFSET_FIRST;
  211.  
  212.     pDC->DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  213.  
  214. // draw labels for extra columns
  215.  
  216.     LV_COLUMN lvc;
  217.     lvc.mask = LVCF_FMT | LVCF_WIDTH;
  218.  
  219.     for(int nColumn = 1; ListCtrl.GetColumn(nColumn, &lvc); nColumn++)
  220.     {
  221.         rcItem.left = rcItem.right;
  222.         rcItem.right += lvc.cx;
  223.  
  224.         int nRetLen = ListCtrl.GetItemText(nItem, nColumn,
  225.                         szBuff, sizeof(szBuff));
  226.         if (nRetLen == 0)
  227.             continue;
  228.  
  229.         pszText = MakeShortString(pDC, szBuff,
  230.             rcItem.right - rcItem.left, 2*OFFSET_OTHER);
  231.  
  232.         UINT nJustify = DT_LEFT;
  233.  
  234.         if(pszText == szBuff)
  235.         {
  236.             switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
  237.             {
  238.             case LVCFMT_RIGHT:
  239.                 nJustify = DT_RIGHT;
  240.                 break;
  241.             case LVCFMT_CENTER:
  242.                 nJustify = DT_CENTER;
  243.                 break;
  244.             default:
  245.                 break;
  246.             }
  247.         }
  248.  
  249.         rcLabel = rcItem;
  250.         rcLabel.left += OFFSET_OTHER;
  251.         rcLabel.right -= OFFSET_OTHER;
  252.  
  253.         pDC->DrawText(pszText, -1, rcLabel,
  254.             nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  255.     }
  256.  
  257. // draw focus rectangle if item has focus
  258.  
  259.     if (lvi.state & LVIS_FOCUSED && bFocus)
  260.         pDC->DrawFocusRect(rcAllLabels);
  261.  
  262. // set original colors if item was selected
  263.  
  264.     if (bSelected)
  265.     {
  266.         pDC->SetTextColor(clrTextSave);
  267.         pDC->SetBkColor(clrBkSave);
  268.     }
  269. }
  270.  
  271. LPCTSTR CListViewEx::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
  272. {
  273.     static const _TCHAR szThreeDots[] = _T("...");
  274.  
  275.     int nStringLen = lstrlen(lpszLong);
  276.  
  277.     if(nStringLen == 0 ||
  278.         (pDC->GetTextExtent(lpszLong, nStringLen).cx + nOffset) <= nColumnLen)
  279.     {
  280.         return(lpszLong);
  281.     }
  282.  
  283.     static _TCHAR szShort[MAX_PATH];
  284.  
  285.     lstrcpy(szShort,lpszLong);
  286.     int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
  287.  
  288.     for(int i = nStringLen-1; i > 0; i--)
  289.     {
  290.         szShort[i] = 0;
  291.         if((pDC->GetTextExtent(szShort, i).cx + nOffset + nAddLen)
  292.             <= nColumnLen)
  293.         {
  294.             break;
  295.         }
  296.     }
  297.  
  298.     lstrcat(szShort, szThreeDots);
  299.     return(szShort);
  300. }
  301.  
  302. void CListViewEx::RepaintSelectedItems()
  303. {
  304.     CListCtrl& ListCtrl = GetListCtrl();
  305.     CRect rcItem, rcLabel;
  306.  
  307. // invalidate focused item so it can repaint properly
  308.  
  309.     int nItem = ListCtrl.GetNextItem(-1, LVNI_FOCUSED);
  310.  
  311.     if(nItem != -1)
  312.     {
  313.         ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
  314.         ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
  315.         rcItem.left = rcLabel.left;
  316.  
  317.         InvalidateRect(rcItem, FALSE);
  318.     }
  319.  
  320. // if selected items should not be preserved, invalidate them
  321.  
  322.     if(!(GetStyle() & LVS_SHOWSELALWAYS))
  323.     {
  324.         for(nItem = ListCtrl.GetNextItem(-1, LVNI_SELECTED);
  325.             nItem != -1; nItem = ListCtrl.GetNextItem(nItem, LVNI_SELECTED))
  326.         {
  327.             ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
  328.             ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
  329.             rcItem.left = rcLabel.left;
  330.  
  331.             InvalidateRect(rcItem, FALSE);
  332.         }
  333.     }
  334.  
  335. // update changes
  336.  
  337.     UpdateWindow();
  338. }
  339.  
  340. /////////////////////////////////////////////////////////////////////////////
  341. // CListViewEx diagnostics
  342.  
  343. #ifdef _DEBUG
  344.  
  345. void CListViewEx::Dump(CDumpContext& dc) const
  346. {
  347.     CListView::Dump(dc);
  348.  
  349.     dc << "m_bFullRowSel = " << (UINT)m_bFullRowSel;
  350.     dc << "\n";
  351.     dc << "m_cxStateImageOffset = " << m_cxStateImageOffset;
  352.     dc << "\n";
  353. }
  354.  
  355. #endif //_DEBUG
  356.  
  357. /////////////////////////////////////////////////////////////////////////////
  358. // CListViewEx message handlers
  359.  
  360. LRESULT CListViewEx::OnSetImageList(WPARAM wParam, LPARAM lParam)
  361. {
  362.     // if we're running Windows 4, there's no need to offset the
  363.     // item text location
  364.  
  365.     OSVERSIONINFO info;
  366.     info.dwOSVersionInfoSize = sizeof(info);
  367.     VERIFY(::GetVersionEx(&info));
  368.  
  369.     if( (int) wParam == LVSIL_STATE && info.dwMajorVersion < 4)
  370.     {
  371.         int cx, cy;
  372.  
  373.         if(::ImageList_GetIconSize((HIMAGELIST)lParam, &cx, &cy))
  374.             m_cxStateImageOffset = cx;
  375.         else
  376.             m_cxStateImageOffset = 0;
  377.     }
  378.  
  379.     return(Default());
  380. }
  381.  
  382. LRESULT CListViewEx::OnSetTextColor(WPARAM wParam, LPARAM lParam)
  383. {
  384.     m_clrText = (COLORREF)lParam;
  385.     return(Default());
  386. }
  387.  
  388. LRESULT CListViewEx::OnSetTextBkColor(WPARAM wParam, LPARAM lParam)
  389. {
  390.     m_clrTextBk = (COLORREF)lParam;
  391.     return(Default());
  392. }
  393.  
  394. LRESULT CListViewEx::OnSetBkColor(WPARAM wParam, LPARAM lParam)
  395. {
  396.     m_clrBkgnd = (COLORREF)lParam;
  397.     return(Default());
  398. }
  399.  
  400. void CListViewEx::OnSize(UINT nType, int cx, int cy)
  401. {
  402.     m_cxClient = cx;
  403.     CListView::OnSize(nType, cx, cy);
  404. }
  405.  
  406. void CListViewEx::OnPaint()
  407. {
  408.     // in full row select mode, we need to extend the clipping region
  409.     // so we can paint a selection all the way to the right
  410.     if (m_bClientWidthSel &&
  411.         (GetStyle() & LVS_TYPEMASK) == LVS_REPORT &&
  412.         GetFullRowSel())
  413.     {
  414.         CRect rcAllLabels;
  415.         GetListCtrl().GetItemRect(0, rcAllLabels, LVIR_BOUNDS);
  416.  
  417.         if(rcAllLabels.right < m_cxClient)
  418.         {
  419.             // need to call BeginPaint (in CPaintDC c-tor)
  420.             // to get correct clipping rect
  421.             CPaintDC dc(this);
  422.  
  423.             CRect rcClip;
  424.             dc.GetClipBox(rcClip);
  425.  
  426.             rcClip.left = min(rcAllLabels.right-1, rcClip.left);
  427.             rcClip.right = m_cxClient;
  428.  
  429.             InvalidateRect(rcClip, FALSE);
  430.             // EndPaint will be called in CPaintDC d-tor
  431.         }
  432.     }
  433.  
  434.     CListView::OnPaint();
  435. }
  436.  
  437. void CListViewEx::OnSetFocus(CWnd* pOldWnd)
  438. {
  439.     CListView::OnSetFocus(pOldWnd);
  440.  
  441.     // check if we are getting focus from label edit box
  442.     if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
  443.         return;
  444.  
  445.     // repaint items that should change appearance
  446.     if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
  447.         RepaintSelectedItems();
  448. }
  449.  
  450. void CListViewEx::OnKillFocus(CWnd* pNewWnd)
  451. {
  452.     CListView::OnKillFocus(pNewWnd);
  453.  
  454.     // check if we are losing focus to label edit box
  455.     if(pNewWnd != NULL && pNewWnd->GetParent() == this)
  456.         return;
  457.  
  458.     // repaint items that should change appearance
  459.     if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
  460.         RepaintSelectedItems();
  461. }
  462.