ListCtrlEx.cpp
上传用户:zslianheng
上传日期:2013-04-03
资源大小:946k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Visual C++

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