XListCtrl.cpp
上传用户:dfzycw
上传日期:2010-01-10
资源大小:66k
文件大小:56k
源码类别:

进程与线程

开发平台:

Visual C++

  1. // XListCtrl.cpp  Version 1.3
  2. //
  3. // Author:  Hans Dietrich
  4. //          hdietrich2@hotmail.com
  5. //
  6. // This code is based on "Neat Stuff to do in List Controls Using Custom Draw"
  7. // by Michael Dunn. See http://www.codeproject.com/listctrl/lvcustomdraw.asp
  8. //
  9. // Thanks to David Patrick for pointing out how to subclass header control
  10. // if CXListCtrl is created via Create() instead of via dialog template.
  11. //
  12. // This software is released into the public domain.
  13. // You are free to use it in any way you like.
  14. //
  15. // This software is provided "as is" with no expressed
  16. // or implied warranty.  I accept no liability for any
  17. // damage or loss of business that this software may cause.
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "XListCtrl.h"
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. UINT NEAR WM_XLISTCTRL_COMBO_SELECTION  = ::RegisterWindowMessage(_T("WM_XLISTCTRL_COMBO_SELECTION"));
  28. UINT NEAR WM_XLISTCTRL_CHECKBOX_CLICKED = ::RegisterWindowMessage(_T("WM_XLISTCTRL_CHECKBOX_CLICKED"));
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CXListCtrl
  31. BEGIN_MESSAGE_MAP(CXListCtrl, CListCtrl)
  32. //{{AFX_MSG_MAP(CXListCtrl)
  33. ON_NOTIFY_REFLECT_EX(NM_CLICK, OnClick)
  34. ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnColumnClick)
  35. ON_WM_CREATE()
  36. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
  37. ON_WM_DESTROY()
  38. ON_WM_LBUTTONDOWN()
  39. ON_WM_PAINT()
  40. ON_WM_SYSCOLORCHANGE()
  41. //}}AFX_MSG_MAP
  42. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  43. ON_WM_TIMER()
  44. ON_REGISTERED_MESSAGE(WM_XCOMBOLIST_VK_ESCAPE, OnComboEscape)
  45. ON_REGISTERED_MESSAGE(WM_XCOMBOLIST_VK_RETURN, OnComboReturn)
  46. ON_REGISTERED_MESSAGE(WM_XCOMBOLIST_KEYDOWN, OnComboKeydown)
  47. ON_REGISTERED_MESSAGE(WM_XCOMBOLIST_LBUTTONUP, OnComboLButtonUp)
  48. #endif
  49. #ifndef NO_XLISTCTRL_TOOL_TIPS
  50. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  51. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  52. #endif
  53. END_MESSAGE_MAP()
  54. ///////////////////////////////////////////////////////////////////////////////
  55. // ctor
  56. CXListCtrl::CXListCtrl()
  57. {
  58. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  59. m_bComboIsClicked       = FALSE;
  60. m_nComboItem            = 0;
  61. m_nComboSubItem         = 0;
  62. m_pListBox              = NULL;
  63. m_bFontIsCreated        = FALSE;
  64. m_strInitialComboString = _T("");
  65. #endif
  66. m_dwExtendedStyleX      = 0;
  67. m_bHeaderIsSubclassed   = FALSE;
  68. m_cr3DFace              = ::GetSysColor(COLOR_3DFACE);
  69. m_cr3DHighLight         = ::GetSysColor(COLOR_3DHIGHLIGHT);
  70. m_cr3DShadow            = ::GetSysColor(COLOR_3DSHADOW);
  71. m_crBtnFace             = ::GetSysColor(COLOR_BTNFACE);
  72. m_crBtnShadow           = ::GetSysColor(COLOR_BTNSHADOW);
  73. m_crBtnText             = ::GetSysColor(COLOR_BTNTEXT);
  74. m_crGrayText            = ::GetSysColor(COLOR_GRAYTEXT);
  75. m_crHighLight           = ::GetSysColor(COLOR_HIGHLIGHT);
  76. m_crHighLightText       = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  77. m_crWindow              = ::GetSysColor(COLOR_WINDOW);
  78. m_crWindowText          = ::GetSysColor(COLOR_WINDOWTEXT);
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////
  81. // dtor
  82. CXListCtrl::~CXListCtrl()
  83. {
  84. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  85. if (m_pListBox)
  86. delete m_pListBox;
  87. #endif
  88. }
  89. ///////////////////////////////////////////////////////////////////////////////
  90. // PreSubclassWindow
  91. void CXListCtrl::PreSubclassWindow()
  92. {
  93. CListCtrl::PreSubclassWindow();
  94. // for Dialog based applications, this is a good place
  95. // to subclass the header control because the OnCreate()
  96. // function does not get called.
  97. SubclassHeaderControl();
  98. }
  99. ///////////////////////////////////////////////////////////////////////////////
  100. // OnCreate
  101. int CXListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
  102. {
  103. if (CListCtrl::OnCreate(lpCreateStruct) == -1)
  104. {
  105. ASSERT(FALSE);
  106. return -1;
  107. }
  108. // When the CXListCtrl object is created via a call to Create(), instead
  109. // of via a dialog box template, we must subclass the header control
  110. // window here because it does not exist when the PreSubclassWindow()
  111. // function is called.
  112. SubclassHeaderControl();
  113. return 0;
  114. }
  115. ///////////////////////////////////////////////////////////////////////////////
  116. // SubclassHeaderControl
  117. void CXListCtrl::SubclassHeaderControl()
  118. {
  119. if (m_bHeaderIsSubclassed)
  120. return;
  121. // if the list control has a header control window, then
  122. // subclass it
  123. // Thanks to Alberto Gattegno and Alon Peleg牋and their article
  124. // "A Multiline Header Control Inside a CListCtrl" for easy way
  125. // to determine if the header control exists.
  126. CHeaderCtrl* pHeader = GetHeaderCtrl();
  127. if (pHeader)
  128. {
  129. VERIFY(m_HeaderCtrl.SubclassWindow(pHeader->m_hWnd));
  130. m_bHeaderIsSubclassed = TRUE;
  131. }
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////
  134. // OnClick
  135. BOOL CXListCtrl::OnClick(NMHDR*, LRESULT* pResult)
  136. {
  137. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  138. UnpressComboButton();
  139. #endif
  140. *pResult = 0;
  141. return FALSE; // return FALSE to send message to parent also -
  142. // NOTE:  MSDN documentation is incorrect
  143. }
  144. ///////////////////////////////////////////////////////////////////////////////
  145. // OnCustomDraw
  146. void CXListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
  147. {
  148. NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
  149. // Take the default processing unless we set this to something else below.
  150. *pResult = CDRF_DODEFAULT;
  151. // First thing - check the draw stage. If it's the control's prepaint
  152. // stage, then tell Windows we want messages for every item.
  153. if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT)
  154. {
  155. *pResult = CDRF_NOTIFYITEMDRAW;
  156. }
  157. else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
  158. {
  159. // This is the notification message for an item.  We'll request
  160. // notifications before each subitem's prepaint stage.
  161. *pResult = CDRF_NOTIFYSUBITEMDRAW;
  162. }
  163. else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
  164. {
  165. // This is the prepaint stage for a subitem. Here's where we set the
  166. // item's text and background colors. Our return value will tell
  167. // Windows to draw the subitem itself, but it will use the new colors
  168. // we set here.
  169. int nItem = static_cast<int> (pLVCD->nmcd.dwItemSpec);
  170. int nSubItem = pLVCD->iSubItem;
  171. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) pLVCD->nmcd.lItemlParam;
  172. ASSERT(pXLCD);
  173. COLORREF crText  = m_crWindowText;
  174. COLORREF crBkgnd = m_crWindow;
  175. if (pXLCD)
  176. {
  177. crText  = pXLCD[nSubItem].crText;
  178. crBkgnd = pXLCD[nSubItem].crBackground;
  179. if (!pXLCD[0].bEnabled)
  180. crText = m_crGrayText;
  181. }
  182. // store the colors back in the NMLVCUSTOMDRAW struct
  183. pLVCD->clrText = crText;
  184. pLVCD->clrTextBk = crBkgnd;
  185. CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
  186. CRect rect;
  187. GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
  188. if (pXLCD && (pXLCD[nSubItem].bShowProgress))
  189. {
  190. DrawProgress(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  191. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  192. }
  193. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  194. else if (pXLCD && (pXLCD[nSubItem].bCombo))
  195. {
  196. if (GetItemState(nItem, LVIS_SELECTED))
  197. DrawComboBox(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  198. else
  199. DrawText(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  200. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  201. }
  202. #endif
  203. else if (pXLCD && (pXLCD[nSubItem].nCheckedState != -1))
  204. {
  205. DrawCheckbox(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  206. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  207. }
  208. else
  209. {
  210. rect.left += DrawImage(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  211. DrawText(nItem, nSubItem, pDC, crText, crBkgnd, rect, pXLCD);
  212. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  213. }
  214. }
  215. }
  216. ///////////////////////////////////////////////////////////////////////////////
  217. // DrawProgress
  218. void CXListCtrl::DrawProgress(int nItem,
  219.   int nSubItem,
  220.   CDC *pDC,
  221.   COLORREF crText,
  222.   COLORREF crBkgnd,
  223.   CRect& rect,
  224.   XLISTCTRLDATA *pXLCD)
  225. {
  226. UNUSED_ALWAYS(nItem);
  227. ASSERT(pDC);
  228. ASSERT(pXLCD);
  229. rect.bottom -= 1;
  230. rect.left += 1; // leave margin in case row is highlighted
  231. rect.right -= 2;
  232. // draw border
  233. CPen graypen(PS_SOLID, 1, m_crBtnShadow);
  234. CPen *pOldPen = pDC->SelectObject(&graypen);
  235. pDC->MoveTo(rect.left, rect.bottom);
  236. pDC->LineTo(rect.right+1, rect.bottom);
  237. pDC->MoveTo(rect.left, rect.top);
  238. pDC->LineTo(rect.right, rect.top);
  239. pDC->MoveTo(rect.left, rect.top);
  240. pDC->LineTo(rect.left, rect.bottom);
  241. pDC->MoveTo(rect.right, rect.top);
  242. pDC->LineTo(rect.right, rect.bottom);
  243. // fill interior with light gray
  244. CRect InteriorRect;
  245. InteriorRect = rect;
  246. InteriorRect.left += 1;
  247. InteriorRect.top += 1;
  248. pDC->FillSolidRect(InteriorRect, RGB(224,224,224));
  249. // finish drawing border
  250. CPen blackpen(PS_SOLID, 1, RGB(0,0,0));
  251. pDC->SelectObject(&blackpen);
  252. pDC->MoveTo(rect.left+1, rect.top+1);
  253. pDC->LineTo(rect.right, rect.top+1);
  254. pDC->MoveTo(rect.left+1, rect.top+1);
  255. pDC->LineTo(rect.left+1, rect.bottom);
  256. pDC->SelectObject(pOldPen);
  257. if (pXLCD[nSubItem].nProgressPercent > 0)
  258. {
  259. // draw progress bar and text
  260. CRect LeftRect, RightRect;
  261. LeftRect = rect;
  262. LeftRect.left += 2;
  263. LeftRect.top += 2;
  264. RightRect = LeftRect;
  265. int w = (LeftRect.Width() * pXLCD[nSubItem].nProgressPercent) / 100;
  266. LeftRect.right = LeftRect.left + w;
  267. RightRect.left = LeftRect.right + 1;
  268. pDC->FillSolidRect(LeftRect, m_crHighLight);
  269. if (pXLCD[nSubItem].bShowProgressMessage)
  270. {
  271. CString str, format;
  272. format = pXLCD[nSubItem].strProgressMessage;
  273. if (format.IsEmpty())
  274. str.Format(_T("%d%%"), pXLCD[nSubItem].nProgressPercent);
  275. else
  276. str.Format(format, pXLCD[nSubItem].nProgressPercent);
  277. pDC->SetBkMode(TRANSPARENT);
  278. CRect TextRect;
  279. TextRect = rect;
  280. TextRect.DeflateRect(1, 1);
  281. TextRect.top += 1;
  282. CRgn rgn;
  283. rgn.CreateRectRgn(LeftRect.left, LeftRect.top, LeftRect.right, LeftRect.bottom);
  284. pDC->SelectClipRgn(&rgn);
  285. pDC->SetTextColor(crBkgnd);
  286. pDC->DrawText(str, &TextRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  287. rgn.DeleteObject();
  288. rgn.CreateRectRgn(RightRect.left, RightRect.top, RightRect.right, RightRect.bottom);
  289. pDC->SelectClipRgn(&rgn);
  290. pDC->SetTextColor(crText);
  291. pDC->DrawText(str, &TextRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  292. rgn.DeleteObject();
  293. pDC->SelectClipRgn(NULL);
  294. }
  295. }
  296. }
  297. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  298. ///////////////////////////////////////////////////////////////////////////////
  299. // DrawComboBox
  300. void CXListCtrl::DrawComboBox(int nItem,
  301.   int nSubItem,
  302.   CDC *pDC,
  303.   COLORREF crText,
  304.   COLORREF crBkgnd,
  305.   CRect& rect,
  306.   XLISTCTRLDATA *pXLCD)
  307. {
  308. UNUSED_ALWAYS(crText);
  309. UNUSED_ALWAYS(crBkgnd);
  310. ASSERT(pDC);
  311. ASSERT(pXLCD);
  312. #ifdef _DEBUG
  313. DWORD dwExStyle = GetExtendedStyle();
  314. if ((dwExStyle & LVS_EX_FULLROWSELECT) == 0)
  315. {
  316. TRACE(_T("XListCtrl: combo boxes require LVS_EX_FULLROWSELECT stylen"));
  317. ASSERT(FALSE);
  318. }
  319. #endif
  320. rect.bottom += 1; // bottom edge is white, so this doesn't matter
  321. rect.left += 1; // leave margin in case row is highlighted
  322. rect.right -= 2;
  323. // draw border
  324. CPen pen(PS_SOLID, 1, m_crBtnShadow);
  325. CPen *pOldPen = pDC->SelectObject(&pen);
  326. pDC->MoveTo(rect.left, rect.bottom-2);
  327. pDC->LineTo(rect.right, rect.bottom-2);
  328. pDC->MoveTo(rect.left, rect.top);
  329. pDC->LineTo(rect.right, rect.top);
  330. pDC->MoveTo(rect.left, rect.top);
  331. pDC->LineTo(rect.left, rect.bottom-2);
  332. pDC->MoveTo(rect.right, rect.top);
  333. pDC->LineTo(rect.right, rect.bottom-1);
  334. CPen blackpen(PS_SOLID, 1, RGB(0,0,0));
  335. pDC->SelectObject(&blackpen);
  336. // fill interior with white
  337. CRect InteriorRect;
  338. InteriorRect = rect;
  339. InteriorRect.DeflateRect(2, 2);
  340. pDC->FillSolidRect(InteriorRect, RGB(255,255,255));
  341. // set arrow rect
  342. CRect ArrowRect;
  343. ArrowRect = rect;
  344. ArrowRect.right += 1;
  345. ArrowRect.left = ArrowRect.right - ArrowRect.Height();
  346. ArrowRect.DeflateRect(2, 2);
  347. CString str;
  348. str = GetItemText(nItem, nSubItem);
  349. if (str.IsEmpty())
  350. {
  351. // subitem text is empty, try to get from listbox strings
  352. if (pXLCD[nSubItem].psa)
  353. {
  354. int index = 0;
  355. if ((pXLCD[nSubItem].nInitialComboSel >= 0) &&
  356. (pXLCD[nSubItem].psa->GetSize() > pXLCD[nSubItem].nInitialComboSel))
  357. {
  358. index = pXLCD[nSubItem].nInitialComboSel;
  359. str = pXLCD[nSubItem].psa->GetAt(index);
  360. SetItemText(nItem, nSubItem, str);
  361. }
  362. }
  363. }
  364. if (!str.IsEmpty())
  365. {
  366. // draw text
  367. CRect TextRect;
  368. TextRect = rect;
  369. TextRect.top -= 1;
  370. TextRect.left += 2;
  371. TextRect.right = ArrowRect.left - 1;
  372. pDC->SetBkMode(TRANSPARENT);
  373. COLORREF cr = m_crWindowText;
  374. if (!pXLCD[0].bEnabled)
  375. cr = m_crGrayText;
  376. pDC->SetTextColor(cr);
  377. pDC->SetBkColor(m_crWindow);
  378. UINT nFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
  379. pDC->DrawText(str, &TextRect, nFormat);
  380. }
  381. if (!pXLCD[nSubItem].bComboIsClicked)
  382. {
  383. // draw depressed combobox
  384. pDC->DrawEdge(&ArrowRect, EDGE_RAISED, BF_RECT);
  385. ArrowRect.DeflateRect(2, 2);
  386. pDC->FillSolidRect(ArrowRect, m_crBtnFace);
  387. // draw the downarrow using blackpen
  388. int x = ArrowRect.left + 1;
  389. int y = ArrowRect.top + 2;
  390. int k = 5;
  391. for (int i = 0; i < 3; i++)
  392. {
  393. pDC->MoveTo(x, y);
  394. pDC->LineTo(x+k, y);
  395. x++;
  396. y++;
  397. k -= 2;
  398. }
  399. }
  400. else
  401. {
  402. // draw normal combobox
  403. m_rectComboButton = ArrowRect;
  404. CBrush brush(m_cr3DShadow);
  405. pDC->FrameRect(&ArrowRect, &brush);
  406. ArrowRect.DeflateRect(1, 1);
  407. pDC->FillSolidRect(ArrowRect, m_crBtnFace);
  408. // draw the downarrow using blackpen
  409. int x = ArrowRect.left + 3;
  410. int y = ArrowRect.top + 4;
  411. int k = 5;
  412. for (int i = 0; i < 3; i++)
  413. {
  414. pDC->MoveTo(x, y);
  415. pDC->LineTo(x+k, y);
  416. x++;
  417. y++;
  418. k -= 2;
  419. }
  420. // show listbox if not already shown
  421. if (!m_pListBox)
  422. {
  423. // create and populate the combo's listbox
  424. m_pListBox = new CXComboList(this);
  425. ASSERT(m_pListBox);
  426. if (m_pListBox)
  427. {
  428. m_nComboItem = nItem;
  429. m_nComboSubItem = nSubItem;
  430. m_rectComboList = rect;
  431. m_rectComboList.right -= 1;
  432. m_rectComboList.top += rect.Height() - 1;
  433. m_rectComboList.bottom = m_rectComboList.top +
  434. (pXLCD[nSubItem].nComboListHeight) * (rect.Height() - 2);
  435. ClientToScreen(&m_rectComboList);
  436. CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS,
  437.   LoadCursor(NULL, IDC_ARROW));
  438. BOOL bSuccess = m_pListBox->CreateEx(0, szClassName, _T(""),
  439. WS_POPUP | WS_VISIBLE /*| WS_VSCROLL*/ | WS_BORDER,
  440. m_rectComboList,
  441. this, 0, NULL);
  442. if (!bSuccess)
  443. {
  444. }
  445. else
  446. {
  447. m_strInitialComboString = _T("");
  448. if (!m_bFontIsCreated)
  449. {
  450. // use font from list control
  451. CFont *font = pDC->GetCurrentFont();
  452. if (font)
  453. {
  454. LOGFONT lf;
  455. font->GetLogFont(&lf);
  456. m_ListboxFont.CreateFontIndirect(&lf);
  457. m_bFontIsCreated = TRUE;
  458. }
  459. }
  460. if (m_bFontIsCreated)
  461. m_pListBox->SetFont(&m_ListboxFont, FALSE);
  462. if (pXLCD[nSubItem].psa)
  463. {
  464. CString s;
  465. for (int i = 0; i < pXLCD[nSubItem].psa->GetSize(); i++)
  466. {
  467. s = pXLCD[nSubItem].psa->GetAt(i);
  468. if (!s.IsEmpty())
  469. m_pListBox->AddString(s);
  470. }
  471. }
  472. int index = 0;
  473. if (str.IsEmpty())
  474. {
  475. // str is empty, try to get from first listbox string
  476. if (m_pListBox->GetCount() > 0)
  477. m_pListBox->GetText(0, str);
  478. SetItemText(nItem, nSubItem, str);
  479. }
  480. else
  481. {
  482. // set listbox selection from subitem text
  483. index = m_pListBox->FindStringExact(-1, str);
  484. if (index == LB_ERR)
  485. index = 0;
  486. }
  487. m_pListBox->SetCurSel(index);
  488. m_pListBox->GetText(index, m_strInitialComboString);
  489. m_pListBox->SetActive(11);
  490. }
  491. }
  492. }
  493. }
  494. pDC->SelectObject(pOldPen);
  495. }
  496. #endif
  497. ///////////////////////////////////////////////////////////////////////////////
  498. // DrawCheckbox
  499. void CXListCtrl::DrawCheckbox(int nItem,
  500.   int nSubItem,
  501.   CDC *pDC,
  502.   COLORREF crText,
  503.   COLORREF crBkgnd,
  504.   CRect& rect,
  505.   XLISTCTRLDATA *pXLCD)
  506. {
  507. ASSERT(pDC);
  508. ASSERT(pXLCD);
  509. GetDrawColors(nItem, nSubItem, crText, crBkgnd);
  510. pDC->FillSolidRect(&rect, crBkgnd);
  511. CRect chkboxrect;
  512. chkboxrect = rect;
  513. chkboxrect.bottom -= 1;
  514. chkboxrect.left += 9; // line up checkbox with header checkbox
  515. chkboxrect.right = chkboxrect.left + chkboxrect.Height(); // width = height
  516. CString str;
  517. str = GetItemText(nItem, nSubItem);
  518. if (str.IsEmpty())
  519. {
  520. // center the checkbox
  521. chkboxrect.left = rect.left + rect.Width()/2 - chkboxrect.Height()/2 - 1;
  522. chkboxrect.right = chkboxrect.left + chkboxrect.Height();
  523. }
  524. // fill rect around checkbox with white
  525. pDC->FillSolidRect(&chkboxrect, m_crWindow);
  526. chkboxrect.left += 1;
  527. // draw border
  528. pDC->DrawEdge(&chkboxrect, EDGE_SUNKEN, BF_RECT);
  529. if (pXLCD[nSubItem].nCheckedState == 1)
  530. {
  531. CPen *pOldPen = NULL;
  532. CPen graypen(PS_SOLID, 1, m_crGrayText);
  533. CPen blackpen(PS_SOLID, 1, RGB(0,0,0));
  534. if (pXLCD[0].bEnabled)
  535. pOldPen = pDC->SelectObject(&blackpen);
  536. else
  537. pOldPen = pDC->SelectObject(&graypen);
  538. // draw the checkmark
  539. int x = chkboxrect.left + 9;
  540. ASSERT(x < chkboxrect.right);
  541. int y = chkboxrect.top + 3;
  542. int i;
  543. for (i = 0; i < 4; i++)
  544. {
  545. pDC->MoveTo(x, y);
  546. pDC->LineTo(x, y+3);
  547. x--;
  548. y++;
  549. }
  550. for (i = 0; i < 3; i++)
  551. {
  552. pDC->MoveTo(x, y);
  553. pDC->LineTo(x, y+3);
  554. x--;
  555. y--;
  556. }
  557. if (pOldPen)
  558. pDC->SelectObject(pOldPen);
  559. }
  560. if (!str.IsEmpty())
  561. {
  562. pDC->SetBkMode(TRANSPARENT);
  563. pDC->SetTextColor(crText);
  564. pDC->SetBkColor(crBkgnd);
  565. CRect textrect;
  566. textrect = rect;
  567. textrect.left = chkboxrect.right + 4;
  568. pDC->DrawText(str, &textrect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
  569. }
  570. }
  571. ///////////////////////////////////////////////////////////////////////////////
  572. // GetDrawColors
  573. void CXListCtrl::GetDrawColors(int nItem,
  574.    int nSubItem,
  575.    COLORREF& colorText,
  576.    COLORREF& colorBkgnd)
  577. {
  578. DWORD dwStyle    = GetStyle();
  579. DWORD dwExStyle  = GetExtendedStyle();
  580. COLORREF crText  = colorText;
  581. COLORREF crBkgnd = colorBkgnd;
  582. if (GetItemState(nItem, LVIS_SELECTED))
  583. {
  584. if (dwExStyle & LVS_EX_FULLROWSELECT)
  585. {
  586. // selected?  if so, draw highlight background
  587. crText  = m_crHighLightText;
  588. crBkgnd = m_crHighLight;
  589. // has focus?  if not, draw gray background
  590. if (m_hWnd != ::GetFocus())
  591. {
  592. if (dwStyle & LVS_SHOWSELALWAYS)
  593. {
  594. crText  = m_crWindowText;
  595. crBkgnd = m_crBtnFace;
  596. }
  597. else
  598. {
  599. crText  = colorText;
  600. crBkgnd = colorBkgnd;
  601. }
  602. }
  603. }
  604. else // not full row select
  605. {
  606. if (nSubItem == 0)
  607. {
  608. // selected?  if so, draw highlight background
  609. crText  = m_crHighLightText;
  610. crBkgnd = m_crHighLight;
  611. // has focus?  if not, draw gray background
  612. if (m_hWnd != ::GetFocus())
  613. {
  614. if (dwStyle & LVS_SHOWSELALWAYS)
  615. {
  616. crText  = m_crWindowText;
  617. crBkgnd = m_crBtnFace;
  618. }
  619. else
  620. {
  621. crText  = colorText;
  622. crBkgnd = colorBkgnd;
  623. }
  624. }
  625. }
  626. }
  627. }
  628. colorText = crText;
  629. colorBkgnd = crBkgnd;
  630. }
  631. ///////////////////////////////////////////////////////////////////////////////
  632. // DrawImage
  633. int CXListCtrl::DrawImage(int nItem,
  634.   int nSubItem,
  635.   CDC* pDC,
  636.   COLORREF crText,
  637.   COLORREF crBkgnd,
  638.   CRect rect,
  639.      XLISTCTRLDATA *pXLCD)
  640. {
  641. GetDrawColors(nItem, nSubItem, crText, crBkgnd);
  642. pDC->FillSolidRect(&rect, crBkgnd);
  643. int nWidth = 0;
  644. rect.left += m_HeaderCtrl.GetSpacing();
  645. CImageList* pImageList = GetImageList(LVSIL_SMALL);
  646. if (pImageList)
  647. {
  648. SIZE sizeImage;
  649. sizeImage.cx = sizeImage.cy = 0;
  650. IMAGEINFO info;
  651. int nImage = -1;
  652. if (pXLCD)
  653. nImage = pXLCD[nSubItem].nImage;
  654. if (nImage == -1)
  655. return 0;
  656. if (pImageList->GetImageInfo(nImage, &info))
  657. {
  658. sizeImage.cx = info.rcImage.right - info.rcImage.left;
  659. sizeImage.cy = info.rcImage.bottom - info.rcImage.top;
  660. }
  661. if (nImage >= 0)
  662. {
  663. if (rect.Width() > 0)
  664. {
  665. POINT point;
  666. point.y = rect.CenterPoint().y - (sizeImage.cy >> 1);
  667. point.x = rect.left;
  668. SIZE size;
  669. size.cx = rect.Width() < sizeImage.cx ? rect.Width() : sizeImage.cx;
  670. size.cy = rect.Height() < sizeImage.cy ? rect.Height() : sizeImage.cy;
  671. // save image list background color
  672. COLORREF rgb = pImageList->GetBkColor();
  673. // set image list background color
  674. pImageList->SetBkColor(crBkgnd);
  675. pImageList->DrawIndirect(pDC, nImage, point, size, CPoint(0, 0));
  676. pImageList->SetBkColor(rgb);
  677. nWidth = sizeImage.cx + m_HeaderCtrl.GetSpacing();
  678. }
  679. }
  680. }
  681. return nWidth;
  682. }
  683. ///////////////////////////////////////////////////////////////////////////////
  684. // DrawText
  685. void CXListCtrl::DrawText(int nItem,
  686.   int nSubItem,
  687.   CDC *pDC,
  688.   COLORREF crText,
  689.   COLORREF crBkgnd,
  690.   CRect& rect,
  691.   XLISTCTRLDATA *pXLCD)
  692. {
  693. ASSERT(pDC);
  694. ASSERT(pXLCD);
  695. GetDrawColors(nItem, nSubItem, crText, crBkgnd);
  696. pDC->FillSolidRect(&rect, crBkgnd);
  697. CString str;
  698. str = GetItemText(nItem, nSubItem);
  699. if (!str.IsEmpty())
  700. {
  701. // get text justification
  702. HDITEM hditem;
  703. hditem.mask = HDI_FORMAT;
  704. m_HeaderCtrl.GetItem(nSubItem, &hditem);
  705. int nFmt = hditem.fmt & HDF_JUSTIFYMASK;
  706. UINT nFormat = DT_VCENTER | DT_SINGLELINE;
  707. if (nFmt == HDF_CENTER)
  708. nFormat |= DT_CENTER;
  709. else if (nFmt == HDF_LEFT)
  710. nFormat |= DT_LEFT;
  711. else
  712. nFormat |= DT_RIGHT;
  713. CFont *pOldFont = NULL;
  714. CFont boldfont;
  715. // check if bold specified for subitem
  716. if (pXLCD && pXLCD[nSubItem].bBold)
  717. {
  718. CFont *font = pDC->GetCurrentFont();
  719. if (font)
  720. {
  721. LOGFONT lf;
  722. font->GetLogFont(&lf);
  723. lf.lfWeight = FW_BOLD;
  724. boldfont.CreateFontIndirect(&lf);
  725. pOldFont = pDC->SelectObject(&boldfont);
  726. }
  727. }
  728. pDC->SetBkMode(TRANSPARENT);
  729. pDC->SetTextColor(crText);
  730. pDC->SetBkColor(crBkgnd);
  731. pDC->DrawText(str, &rect, nFormat);
  732. if (pOldFont)
  733. pDC->SelectObject(pOldFont);
  734. }
  735. }
  736. ///////////////////////////////////////////////////////////////////////////////
  737. // GetSubItemRect
  738. BOOL CXListCtrl::GetSubItemRect(int nItem,
  739. int nSubItem,
  740. int nArea,
  741. CRect& rect)
  742. {
  743. ASSERT(nItem >= 0);
  744. ASSERT(nItem < GetItemCount());
  745. if ((nItem < 0) || nItem >= GetItemCount())
  746. return FALSE;
  747. ASSERT(nSubItem >= 0);
  748. ASSERT(nSubItem < GetColumns());
  749. if ((nSubItem < 0) || nSubItem >= GetColumns())
  750. return FALSE;
  751. BOOL bRC = CListCtrl::GetSubItemRect(nItem, nSubItem, nArea, rect);
  752. // if nSubItem == 0, the rect returned by CListCtrl::GetSubItemRect
  753. // is the entire row, so use left edge of second subitem
  754. if (nSubItem == 0)
  755. {
  756. if (GetColumns() > 1)
  757. {
  758. CRect rect1;
  759. bRC = GetSubItemRect(nItem, 1, LVIR_BOUNDS, rect1);
  760. rect.right = rect1.left;
  761. }
  762. }
  763. return bRC;
  764. }
  765. ///////////////////////////////////////////////////////////////////////////////
  766. // OnLButtonDown
  767. void CXListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  768. {
  769. TRACE(_T("in CXListCtrl::OnLButtonDownn"));
  770. int nItem = -1;
  771. CRect rect;
  772. int i;
  773. for (i = 0; i < GetItemCount(); i++)
  774. {
  775. if (CListCtrl::GetItemRect(i, &rect, LVIR_BOUNDS))
  776. {
  777. if (rect.PtInRect(point))
  778. {
  779. nItem = i;
  780. break;
  781. }
  782. }
  783. }
  784. if (nItem == -1)
  785. {
  786. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  787. if (m_pListBox)
  788. OnComboEscape(0, 0);
  789. #endif
  790. }
  791. else
  792. {
  793. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  794. if (!pXLCD)
  795. {
  796. return;
  797. }
  798. if (!pXLCD[0].bEnabled)
  799. return;
  800. CRect rect;
  801. int nSubItem = -1;
  802. // check if a subitem checkbox was clicked
  803. for (i = 0; i < GetColumns(); i++)
  804. {
  805. GetSubItemRect(nItem, i, LVIR_BOUNDS, rect);
  806. if (rect.PtInRect(point))
  807. {
  808. nSubItem = i;
  809. break;
  810. }
  811. }
  812. if (nSubItem == -1)
  813. {
  814. // -1 = no checkbox for this subitem
  815. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  816. if (m_pListBox)
  817. {
  818. OnComboEscape(0, 0);
  819. }
  820. #endif
  821. }
  822. else
  823. {
  824. if (pXLCD[nSubItem].nCheckedState >= 0)
  825. {
  826. int nChecked = pXLCD[nSubItem].nCheckedState;
  827. nChecked = (nChecked == 0) ? 1 : 0;
  828. pXLCD[nSubItem].nCheckedState = nChecked;
  829. UpdateSubItem(nItem, nSubItem);
  830. CWnd *pWnd = GetParent();
  831. if (!pWnd)
  832. pWnd = GetOwner();
  833. if (pWnd && ::IsWindow(pWnd->m_hWnd))
  834. pWnd->SendMessage(WM_XLISTCTRL_CHECKBOX_CLICKED, 
  835. nItem, nSubItem);
  836. // now update checkbox in header
  837. // -1 = no checkbox in column header
  838. if (GetHeaderCheckedState(nSubItem) != XHEADERCTRL_NO_IMAGE)
  839. {
  840. int nCheckedCount = CountCheckedItems(nSubItem);
  841. if (nCheckedCount == GetItemCount())
  842. SetHeaderCheckedState(nSubItem, XHEADERCTRL_CHECKED_IMAGE);
  843. else
  844. SetHeaderCheckedState(nSubItem, XHEADERCTRL_UNCHECKED_IMAGE);
  845. }
  846. }
  847. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  848. else if (pXLCD[nSubItem].bCombo)
  849. {
  850. if (m_pListBox)
  851. {
  852. m_pListBox->DestroyWindow();
  853. delete m_pListBox;
  854. m_pListBox = NULL;
  855. }
  856. rect.left = rect.right - rect.Height();
  857. if (point.x >= rect.left && point.y <= rect.right)
  858. {
  859. pXLCD[nSubItem].bComboIsClicked = TRUE;
  860. m_bComboIsClicked = TRUE;
  861. m_nComboItem = nItem;
  862. m_nComboSubItem = nSubItem;
  863. UpdateSubItem(nItem, nSubItem);
  864. SetTimer(1, 100, NULL);
  865. }
  866. }
  867. else if (m_pListBox)
  868. {
  869. OnComboEscape(0, 0);
  870. }
  871. #endif
  872. }
  873. }
  874. CListCtrl::OnLButtonDown(nFlags, point);
  875. }
  876. ///////////////////////////////////////////////////////////////////////////////
  877. // OnPaint
  878. void CXListCtrl::OnPaint()
  879. {
  880.     Default();
  881. if (GetItemCount() <= 0)
  882. {
  883. CDC* pDC = GetDC();
  884. int nSavedDC = pDC->SaveDC();
  885. CRect rc;
  886. GetWindowRect(&rc);
  887. ScreenToClient(&rc);
  888. CHeaderCtrl* pHC = GetHeaderCtrl();
  889. if (pHC != NULL)
  890. {
  891. CRect rcH;
  892. pHC->GetItemRect(0, &rcH);
  893. rc.top += rcH.bottom;
  894. }
  895. rc.top += 10;
  896. CString strText;
  897. strText = _T("There are no items to show in this view.");
  898. COLORREF crText = m_crWindowText;
  899. COLORREF crBkgnd = m_crWindow;
  900. CBrush brush(crBkgnd);
  901. pDC->FillRect(rc, &brush);
  902. pDC->SetTextColor(crText);
  903. pDC->SetBkColor(crBkgnd);
  904. pDC->SelectStockObject(ANSI_VAR_FONT);
  905. pDC->DrawText(strText, -1, rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);
  906. pDC->RestoreDC(nSavedDC);
  907. ReleaseDC(pDC);
  908. }
  909. }
  910. ///////////////////////////////////////////////////////////////////////////////
  911. // InsertItem
  912. int CXListCtrl::InsertItem(const LVITEM* pItem)
  913. {
  914. ASSERT(pItem->iItem >= 0);
  915. if (pItem->iItem < 0)
  916. return -1;
  917. int index = CListCtrl::InsertItem(pItem);
  918. if (index < 0)
  919. return index;
  920. XLISTCTRLDATA *pXLCD = new XLISTCTRLDATA [GetColumns()];
  921. ASSERT(pXLCD);
  922. if (!pXLCD)
  923. return -1;
  924. pXLCD[0].crText       = m_crWindowText;
  925. pXLCD[0].crBackground = m_crWindow;
  926. pXLCD[0].nImage       = pItem->iImage;
  927. CListCtrl::SetItemData(index, (DWORD) pXLCD);
  928. return index;
  929. }
  930. ///////////////////////////////////////////////////////////////////////////////
  931. // InsertItem
  932. int CXListCtrl::InsertItem(int nItem, LPCTSTR lpszItem)
  933. {
  934. ASSERT(nItem >= 0);
  935. if (nItem < 0)
  936. return -1;
  937. return InsertItem(nItem,
  938.   lpszItem,
  939.   m_crWindowText,
  940.   m_crWindow);
  941. }
  942. ///////////////////////////////////////////////////////////////////////////////
  943. // InsertItem
  944. int CXListCtrl::InsertItem(int nItem,
  945.    LPCTSTR lpszItem,
  946.    COLORREF crText,
  947.    COLORREF crBackground)
  948. {
  949. ASSERT(nItem >= 0);
  950. if (nItem < 0)
  951. return -1;
  952. int index = CListCtrl::InsertItem(nItem, lpszItem);
  953. if (index < 0)
  954. return index;
  955. XLISTCTRLDATA *pXLCD = new XLISTCTRLDATA [GetColumns()];
  956. ASSERT(pXLCD);
  957. if (!pXLCD)
  958. return -1;
  959. pXLCD[0].crText       = crText;
  960. pXLCD[0].crBackground = crBackground;
  961. pXLCD[0].nImage       = -1;
  962. CListCtrl::SetItemData(index, (DWORD) pXLCD);
  963. return index;
  964. }
  965. ///////////////////////////////////////////////////////////////////////////////
  966. // SetItem
  967. int CXListCtrl::SetItem(const LVITEM* pItem)
  968. {
  969. ASSERT(pItem->iItem >= 0);
  970. if (pItem->iItem < 0)
  971. return -1;
  972. BOOL rc = CListCtrl::SetItem(pItem);
  973. if (!rc)
  974. return FALSE;
  975. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(pItem->iItem);
  976. if (pXLCD)
  977. {
  978. pXLCD[pItem->iSubItem].nImage = pItem->iImage;
  979. UpdateSubItem(pItem->iItem, pItem->iSubItem);
  980. rc = TRUE;
  981. }
  982. else
  983. {
  984. rc = FALSE;
  985. }
  986. return rc;
  987. }
  988. ///////////////////////////////////////////////////////////////////////////////
  989. // SetItemImage
  990. BOOL CXListCtrl::SetItemImage(int nItem, int nSubItem, int nImage)
  991. {
  992. ASSERT(nItem >= 0);
  993. ASSERT(nItem < GetItemCount());
  994. if ((nItem < 0) || nItem >= GetItemCount())
  995. return FALSE;
  996. ASSERT(nSubItem >= 0);
  997. ASSERT(nSubItem < GetColumns());
  998. if ((nSubItem < 0) || nSubItem >= GetColumns())
  999. return FALSE;
  1000. BOOL rc = TRUE;
  1001. if (nItem < 0)
  1002. return FALSE;
  1003. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1004. if (pXLCD)
  1005. {
  1006. pXLCD[nSubItem].nImage = nImage;
  1007. }
  1008. UpdateSubItem(nItem, nSubItem);
  1009. return rc;
  1010. }
  1011. ///////////////////////////////////////////////////////////////////////////////
  1012. // SetItemText
  1013. BOOL CXListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)
  1014. {
  1015. ASSERT(nItem >= 0);
  1016. ASSERT(nItem < GetItemCount());
  1017. if ((nItem < 0) || nItem >= GetItemCount())
  1018. return FALSE;
  1019. ASSERT(nSubItem >= 0);
  1020. ASSERT(nSubItem < GetColumns());
  1021. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1022. return FALSE;
  1023. BOOL rc = CListCtrl::SetItemText(nItem, nSubItem, lpszText);
  1024. UpdateSubItem(nItem, nSubItem);
  1025. return rc;
  1026. }
  1027. ///////////////////////////////////////////////////////////////////////////////
  1028. // SetItemText
  1029. //
  1030. // This function will set the text and colors for a subitem.  If lpszText
  1031. // is NULL, only the colors will be set.  If a color value is -1, the display
  1032. // color will be set to the default Windows color.
  1033. //
  1034. BOOL CXListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText,
  1035. COLORREF crText, COLORREF crBackground)
  1036. {
  1037. ASSERT(nItem >= 0);
  1038. ASSERT(nItem < GetItemCount());
  1039. if ((nItem < 0) || nItem >= GetItemCount())
  1040. return FALSE;
  1041. ASSERT(nSubItem >= 0);
  1042. ASSERT(nSubItem < GetColumns());
  1043. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1044. return FALSE;
  1045. BOOL rc = TRUE;
  1046. if (nItem < 0)
  1047. return FALSE;
  1048. if (lpszText)
  1049. rc = CListCtrl::SetItemText(nItem, nSubItem, lpszText);
  1050. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1051. if (pXLCD)
  1052. {
  1053. pXLCD[nSubItem].crText       = (crText == -1) ? m_crWindowText : crText;
  1054. pXLCD[nSubItem].crBackground = (crBackground == -1) ? m_crWindow : crBackground;
  1055. }
  1056. UpdateSubItem(nItem, nSubItem);
  1057. return rc;
  1058. }
  1059. ///////////////////////////////////////////////////////////////////////////////
  1060. // DeleteItem
  1061. BOOL CXListCtrl::DeleteItem(int nItem)
  1062. {
  1063. ASSERT(nItem >= 0);
  1064. ASSERT(nItem < GetItemCount());
  1065. if ((nItem < 0) || nItem >= GetItemCount())
  1066. return FALSE;
  1067. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1068. if (pXLCD)
  1069. delete [] pXLCD;
  1070. CListCtrl::SetItemData(nItem, 0);
  1071. return CListCtrl::DeleteItem(nItem);
  1072. }
  1073. ///////////////////////////////////////////////////////////////////////////////
  1074. // DeleteAllItems
  1075. BOOL CXListCtrl::DeleteAllItems()
  1076. {
  1077. int n = GetItemCount();
  1078. for (int i = 0; i < n; i++)
  1079. {
  1080. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(i);
  1081. if (pXLCD)
  1082. delete [] pXLCD;
  1083. CListCtrl::SetItemData(i, 0);
  1084. }
  1085. return CListCtrl::DeleteAllItems();
  1086. }
  1087. ///////////////////////////////////////////////////////////////////////////////
  1088. // OnDestroy
  1089. void CXListCtrl::OnDestroy()
  1090. {
  1091. int n = GetItemCount();
  1092. for (int i = 0; i < n; i++)
  1093. {
  1094. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(i);
  1095. if (pXLCD)
  1096. delete [] pXLCD;
  1097. CListCtrl::SetItemData(i, 0);
  1098. }
  1099. CListCtrl::OnDestroy();
  1100. }
  1101. ///////////////////////////////////////////////////////////////////////////////
  1102. // SetProgress
  1103. //
  1104. // This function creates a progress bar in the specified subitem.  The
  1105. // UpdateProgress function may then be called to update the progress
  1106. // percent.  If bShowProgressText is TRUE, either the default text
  1107. // of "n%" or the custom percent text (lpszProgressText) will be
  1108. // displayed.  If bShowProgressText is FALSE, only the progress bar
  1109. // will be displayed, with no text.
  1110. //
  1111. // Note that the lpszProgressText string should include the format
  1112. // specifier "%d":  e.g., "Pct %d%%"
  1113. //
  1114. BOOL CXListCtrl::SetProgress(int nItem,
  1115.  int nSubItem,
  1116.  BOOL bShowProgressText /*= TRUE*/,
  1117.  LPCTSTR lpszProgressText /*= NULL*/)
  1118. {
  1119. ASSERT(nItem >= 0);
  1120. ASSERT(nItem < GetItemCount());
  1121. if ((nItem < 0) || nItem >= GetItemCount())
  1122. return FALSE;
  1123. ASSERT(nSubItem >= 0);
  1124. ASSERT(nSubItem < GetColumns());
  1125. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1126. return FALSE;
  1127. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1128. if (!pXLCD)
  1129. {
  1130. return FALSE;
  1131. }
  1132. pXLCD[nSubItem].bShowProgress        = TRUE;
  1133. pXLCD[nSubItem].nProgressPercent     = 0;
  1134. pXLCD[nSubItem].bShowProgressMessage = bShowProgressText;
  1135. pXLCD[nSubItem].strProgressMessage   = lpszProgressText;
  1136. UpdateSubItem(nItem, nSubItem);
  1137. return TRUE;
  1138. }
  1139. ///////////////////////////////////////////////////////////////////////////////
  1140. // DeleteProgress
  1141. void CXListCtrl::DeleteProgress(int nItem, int nSubItem)
  1142. {
  1143. ASSERT(nItem >= 0);
  1144. ASSERT(nItem < GetItemCount());
  1145. if ((nItem < 0) || nItem >= GetItemCount())
  1146. return;
  1147. ASSERT(nSubItem >= 0);
  1148. ASSERT(nSubItem < GetColumns());
  1149. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1150. return;
  1151. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1152. if (!pXLCD)
  1153. {
  1154. return;
  1155. }
  1156. pXLCD[nSubItem].bShowProgress = FALSE;
  1157. pXLCD[nSubItem].nProgressPercent = 0;
  1158. UpdateSubItem(nItem, nSubItem);
  1159. }
  1160. ///////////////////////////////////////////////////////////////////////////////
  1161. // UpdateProgress
  1162. void CXListCtrl::UpdateProgress(int nItem, int nSubItem, int nPercent)
  1163. {
  1164. ASSERT(nItem >= 0);
  1165. ASSERT(nItem < GetItemCount());
  1166. if ((nItem < 0) || nItem >= GetItemCount())
  1167. return;
  1168. ASSERT(nSubItem >= 0);
  1169. ASSERT(nSubItem < GetColumns());
  1170. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1171. return;
  1172. ASSERT(nPercent >= 0 && nPercent <= 100);
  1173. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1174. if (!pXLCD)
  1175. {
  1176. return;
  1177. }
  1178. pXLCD[nSubItem].nProgressPercent = nPercent;
  1179. UpdateSubItem(nItem, nSubItem);
  1180. }
  1181. ///////////////////////////////////////////////////////////////////////////////
  1182. // SetCheckbox
  1183. BOOL CXListCtrl::SetCheckbox(int nItem, int nSubItem, int nCheckedState)
  1184. {
  1185. ASSERT(nItem >= 0);
  1186. ASSERT(nItem < GetItemCount());
  1187. if ((nItem < 0) || nItem >= GetItemCount())
  1188. return FALSE;
  1189. ASSERT(nSubItem >= 0);
  1190. ASSERT(nSubItem < GetColumns());
  1191. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1192. return FALSE;
  1193. ASSERT(nCheckedState == 0 || nCheckedState == 1 || nCheckedState == -1);
  1194. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1195. if (!pXLCD)
  1196. {
  1197. return FALSE;
  1198. }
  1199. // update checkbox in subitem
  1200. pXLCD[nSubItem].nCheckedState = nCheckedState;
  1201. UpdateSubItem(nItem, nSubItem);
  1202. // now update checkbox in column header
  1203. // -1 = no checkbox in column header
  1204. if (GetHeaderCheckedState(nSubItem) != XHEADERCTRL_NO_IMAGE)
  1205. {
  1206. int nCheckedCount = CountCheckedItems(nSubItem);
  1207. if (nCheckedCount == GetItemCount())
  1208. SetHeaderCheckedState(nSubItem, XHEADERCTRL_CHECKED_IMAGE);
  1209. else
  1210. SetHeaderCheckedState(nSubItem, XHEADERCTRL_UNCHECKED_IMAGE);
  1211. }
  1212. return TRUE;
  1213. }
  1214. ///////////////////////////////////////////////////////////////////////////////
  1215. // GetCheckbox
  1216. int CXListCtrl::GetCheckbox(int nItem, int nSubItem)
  1217. {
  1218. ASSERT(nItem >= 0);
  1219. ASSERT(nItem < GetItemCount());
  1220. if ((nItem < 0) || nItem >= GetItemCount())
  1221. return -1;
  1222. ASSERT(nSubItem >= 0);
  1223. ASSERT(nSubItem < GetColumns());
  1224. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1225. return -1;
  1226. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1227. if (!pXLCD)
  1228. {
  1229. return -1;
  1230. }
  1231. return pXLCD[nSubItem].nCheckedState;
  1232. }
  1233. ///////////////////////////////////////////////////////////////////////////////
  1234. // GetEnabled
  1235. //
  1236. // Note that GetEnabled and SetEnabled only Get/Set the enabled flag from
  1237. // subitem 0, since this is a per-row flag.
  1238. //
  1239. BOOL CXListCtrl::GetEnabled(int nItem)
  1240. {
  1241. ASSERT(nItem >= 0);
  1242. ASSERT(nItem < GetItemCount());
  1243. if ((nItem < 0) || nItem >= GetItemCount())
  1244. return FALSE;
  1245. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1246. if (!pXLCD)
  1247. {
  1248. return FALSE;
  1249. }
  1250. return pXLCD[0].bEnabled;
  1251. }
  1252. ///////////////////////////////////////////////////////////////////////////////
  1253. // SetEnabled
  1254. BOOL CXListCtrl::SetEnabled(int nItem, BOOL bEnable)
  1255. {
  1256. ASSERT(nItem >= 0);
  1257. ASSERT(nItem < GetItemCount());
  1258. if ((nItem < 0) || nItem >= GetItemCount())
  1259. return FALSE;
  1260. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1261. if (!pXLCD)
  1262. {
  1263. return FALSE;
  1264. }
  1265. pXLCD[0].bEnabled = bEnable;
  1266. CRect rect;
  1267. GetItemRect(nItem, &rect, LVIR_BOUNDS);
  1268. InvalidateRect(&rect);
  1269. UpdateWindow();
  1270. return TRUE;
  1271. }
  1272. ///////////////////////////////////////////////////////////////////////////////
  1273. // SetBold
  1274. BOOL CXListCtrl::SetBold(int nItem, int nSubItem, BOOL bBold)
  1275. {
  1276. ASSERT(nItem >= 0);
  1277. ASSERT(nItem < GetItemCount());
  1278. if ((nItem < 0) || nItem >= GetItemCount())
  1279. return FALSE;
  1280. ASSERT(nSubItem >= 0);
  1281. ASSERT(nSubItem < GetColumns());
  1282. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1283. return FALSE;
  1284. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1285. if (!pXLCD)
  1286. {
  1287. return FALSE;
  1288. }
  1289. // update bold flag
  1290. pXLCD[nSubItem].bBold = bBold;
  1291. UpdateSubItem(nItem, nSubItem);
  1292. return TRUE;
  1293. }
  1294. ///////////////////////////////////////////////////////////////////////////////
  1295. // GetBold
  1296. BOOL CXListCtrl::GetBold(int nItem, int nSubItem)
  1297. {
  1298. ASSERT(nItem >= 0);
  1299. ASSERT(nItem < GetItemCount());
  1300. if ((nItem < 0) || nItem >= GetItemCount())
  1301. return FALSE;
  1302. ASSERT(nSubItem >= 0);
  1303. ASSERT(nSubItem < GetColumns());
  1304. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1305. return FALSE;
  1306. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1307. if (!pXLCD)
  1308. {
  1309. return FALSE;
  1310. }
  1311. // update bold flag
  1312. return pXLCD[nSubItem].bBold;
  1313. }
  1314. ///////////////////////////////////////////////////////////////////////////////
  1315. // SetComboBox
  1316. //
  1317. // Note:  SetItemText may also be used to set the initial combo selection.
  1318. //
  1319. BOOL CXListCtrl::SetComboBox(int nItem,
  1320.  int nSubItem,
  1321.  BOOL bEnableCombo,
  1322.  CStringArray *psa,
  1323.  int nComboListHeight,
  1324.  int nInitialComboSel)
  1325. {
  1326. ASSERT(nItem >= 0);
  1327. ASSERT(nItem < GetItemCount());
  1328. if ((nItem < 0) || nItem >= GetItemCount())
  1329. return FALSE;
  1330. ASSERT(nSubItem >= 0);
  1331. ASSERT(nSubItem < GetColumns());
  1332. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1333. return FALSE;
  1334. ASSERT(psa);
  1335. if (!psa)
  1336. return FALSE;
  1337. ASSERT(nComboListHeight > 0);
  1338. ASSERT(nInitialComboSel >= 0 && nInitialComboSel < psa->GetSize());
  1339. if ((nInitialComboSel < 0) || (nInitialComboSel >= psa->GetSize()))
  1340. nInitialComboSel = 0;
  1341. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1342. if (!pXLCD)
  1343. {
  1344. return FALSE;
  1345. }
  1346. // update flag
  1347. pXLCD[nSubItem].bCombo = bEnableCombo;
  1348. if (bEnableCombo)
  1349. {
  1350. pXLCD[nSubItem].psa = psa;
  1351. pXLCD[nSubItem].nComboListHeight = nComboListHeight;
  1352. pXLCD[nSubItem].nInitialComboSel = nInitialComboSel;
  1353. if (pXLCD[nSubItem].psa)
  1354. {
  1355. int index = 0;
  1356. if ((pXLCD[nSubItem].nInitialComboSel >= 0) &&
  1357. (pXLCD[nSubItem].psa->GetSize() > pXLCD[nSubItem].nInitialComboSel))
  1358. {
  1359. index = pXLCD[nSubItem].nInitialComboSel;
  1360. CString str;
  1361. str = pXLCD[nSubItem].psa->GetAt(index);
  1362. SetItemText(nItem, nSubItem, str);
  1363. }
  1364. }
  1365. }
  1366. UpdateSubItem(nItem, nSubItem);
  1367. return TRUE;
  1368. }
  1369. ///////////////////////////////////////////////////////////////////////////////
  1370. // GetComboText
  1371. //
  1372. // Actually this does nothing more than GetItemText()
  1373. //
  1374. CString CXListCtrl::GetComboText(int nItem, int nSubItem)
  1375. {
  1376. ASSERT(nItem >= 0);
  1377. ASSERT(nItem < GetItemCount());
  1378. if ((nItem < 0) || nItem >= GetItemCount())
  1379. return _T("");
  1380. ASSERT(nSubItem >= 0);
  1381. ASSERT(nSubItem < GetColumns());
  1382. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1383. return _T("");
  1384. CString str;
  1385. str = _T("");
  1386. str = GetItemText(nItem, nSubItem);
  1387. return str;
  1388. }
  1389. ///////////////////////////////////////////////////////////////////////////////
  1390. // SetCurSel
  1391. BOOL CXListCtrl::SetCurSel(int nItem)
  1392. {
  1393. return SetItemState(nItem, LVIS_FOCUSED | LVIS_SELECTED,
  1394. LVIS_FOCUSED | LVIS_SELECTED);
  1395. }
  1396. ///////////////////////////////////////////////////////////////////////////////
  1397. // GetCurSel - returns selected item number, or -1 if no item selected
  1398. //
  1399. // Note:  for single-selection lists only
  1400. //
  1401. int CXListCtrl::GetCurSel()
  1402. {
  1403. POSITION pos = GetFirstSelectedItemPosition();
  1404. int nSelectedItem = -1;
  1405. if (pos != NULL)
  1406. nSelectedItem = GetNextSelectedItem(pos);
  1407. return nSelectedItem;
  1408. }
  1409. ///////////////////////////////////////////////////////////////////////////////
  1410. // UpdateSubItem
  1411. void CXListCtrl::UpdateSubItem(int nItem, int nSubItem)
  1412. {
  1413. ASSERT(nItem >= 0);
  1414. ASSERT(nItem < GetItemCount());
  1415. if ((nItem < 0) || nItem >= GetItemCount())
  1416. return;
  1417. ASSERT(nSubItem >= 0);
  1418. ASSERT(nSubItem < GetColumns());
  1419. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1420. return;
  1421. CRect rect;
  1422. if (nSubItem == -1)
  1423. {
  1424. GetItemRect(nItem, &rect, LVIR_BOUNDS);
  1425. }
  1426. else
  1427. {
  1428. GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
  1429. }
  1430. InvalidateRect(&rect);
  1431. UpdateWindow();
  1432. }
  1433. ///////////////////////////////////////////////////////////////////////////////
  1434. // GetColumns
  1435. int CXListCtrl::GetColumns()
  1436. {
  1437. return GetHeaderCtrl()->GetItemCount();
  1438. }
  1439. ///////////////////////////////////////////////////////////////////////////////
  1440. // GetItemData
  1441. //
  1442. // The GetItemData and SetItemData functions allow for app-specific data
  1443. // to be stored, by using an extra field in the XLISTCTRLDATA struct.
  1444. //
  1445. DWORD CXListCtrl::GetItemData(int nItem)
  1446. {
  1447. ASSERT(nItem >= 0);
  1448. ASSERT(nItem < GetItemCount());
  1449. if ((nItem < 0) || nItem >= GetItemCount())
  1450. return 0;
  1451. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1452. if (!pXLCD)
  1453. {
  1454. return 0;
  1455. }
  1456. return pXLCD->dwItemData;
  1457. }
  1458. ///////////////////////////////////////////////////////////////////////////////
  1459. // SetItemData
  1460. BOOL CXListCtrl::SetItemData(int nItem, DWORD dwData)
  1461. {
  1462. ASSERT(nItem >= 0);
  1463. ASSERT(nItem < GetItemCount());
  1464. if ((nItem < 0) || nItem >= GetItemCount())
  1465. return FALSE;
  1466. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1467. if (!pXLCD)
  1468. {
  1469. return FALSE;
  1470. }
  1471. pXLCD->dwItemData = dwData;
  1472. return TRUE;
  1473. }
  1474. ///////////////////////////////////////////////////////////////////////////////
  1475. // GetHeaderCheckedState
  1476. //
  1477. // The GetHeaderCheckedState and SetHeaderCheckedState may be used to toggle
  1478. // the checkbox in a column header.
  1479. //     0 = no checkbox
  1480. //     1 = unchecked
  1481. //     2 = checked
  1482. //
  1483. int CXListCtrl::GetHeaderCheckedState(int nSubItem)
  1484. {
  1485. ASSERT(nSubItem >= 0);
  1486. ASSERT(nSubItem < GetColumns());
  1487. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1488. return -1;
  1489. HDITEM hditem;
  1490. // use the image index (0 or 1) to indicate the checked status
  1491. hditem.mask = HDI_IMAGE;
  1492. m_HeaderCtrl.GetItem(nSubItem, &hditem);
  1493. return hditem.iImage;
  1494. }
  1495. ///////////////////////////////////////////////////////////////////////////////
  1496. // SetHeaderCheckedState
  1497. BOOL CXListCtrl::SetHeaderCheckedState(int nSubItem, int nCheckedState)
  1498. {
  1499. ASSERT(nSubItem >= 0);
  1500. ASSERT(nSubItem < GetColumns());
  1501. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1502. return FALSE;
  1503. ASSERT(nCheckedState == 0 || nCheckedState == 1 || nCheckedState == 2);
  1504. HDITEM hditem;
  1505. hditem.mask = HDI_IMAGE;
  1506. hditem.iImage = nCheckedState;
  1507. m_HeaderCtrl.SetItem(nSubItem, &hditem);
  1508. return TRUE;
  1509. }
  1510. ///////////////////////////////////////////////////////////////////////////////
  1511. // OnColumnClick
  1512. BOOL CXListCtrl::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult)
  1513. {
  1514. NMLISTVIEW* pnmlv = (NMLISTVIEW*)pNMHDR;
  1515. int nSubItem = pnmlv->iSubItem;
  1516. int nCheckedState = GetHeaderCheckedState(nSubItem);
  1517. // 0 = no checkbox
  1518. if (nCheckedState != XHEADERCTRL_NO_IMAGE)
  1519. {
  1520. nCheckedState = (nCheckedState == 1) ? 2 : 1;
  1521. SetHeaderCheckedState(nSubItem, nCheckedState);
  1522. m_HeaderCtrl.UpdateWindow();
  1523. for (int nItem = 0; nItem < GetItemCount(); nItem++)
  1524. {
  1525. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1526. if (!pXLCD)
  1527. {
  1528. continue;
  1529. }
  1530. if (pXLCD[nSubItem].nCheckedState != -1)
  1531. {
  1532. pXLCD[nSubItem].nCheckedState = nCheckedState - 1;
  1533. UpdateSubItem(nItem, nSubItem);
  1534. }
  1535. }
  1536. }
  1537. *pResult = 0;
  1538. return FALSE; // return FALSE to send message to parent also -
  1539. // NOTE:  MSDN documentation is incorrect
  1540. }
  1541. ///////////////////////////////////////////////////////////////////////////////
  1542. // CountCheckedItems
  1543. int CXListCtrl::CountCheckedItems(int nSubItem)
  1544. {
  1545. ASSERT(nSubItem >= 0);
  1546. ASSERT(nSubItem < GetColumns());
  1547. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1548. return 0;
  1549. int nCount = 0;
  1550. for (int nItem = 0; nItem < GetItemCount(); nItem++)
  1551. {
  1552. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1553. if (!pXLCD)
  1554. {
  1555. continue;
  1556. }
  1557. if (pXLCD[nSubItem].nCheckedState == 1)
  1558. nCount++;
  1559. }
  1560. return nCount;
  1561. }
  1562. ///////////////////////////////////////////////////////////////////////////////
  1563. // OnSysColorChange
  1564. void CXListCtrl::OnSysColorChange()
  1565. {
  1566. TRACE(_T("in CXListCtrl::OnSysColorChangen"));
  1567. CListCtrl::OnSysColorChange();
  1568. m_cr3DFace        = ::GetSysColor(COLOR_3DFACE);
  1569. m_cr3DHighLight   = ::GetSysColor(COLOR_3DHIGHLIGHT);
  1570. m_cr3DShadow      = ::GetSysColor(COLOR_3DSHADOW);
  1571. m_crBtnFace       = ::GetSysColor(COLOR_BTNFACE);
  1572. m_crBtnShadow     = ::GetSysColor(COLOR_BTNSHADOW);
  1573. m_crBtnText       = ::GetSysColor(COLOR_BTNTEXT);
  1574. m_crGrayText      = ::GetSysColor(COLOR_GRAYTEXT);
  1575. m_crHighLight     = ::GetSysColor(COLOR_HIGHLIGHT);
  1576. m_crHighLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  1577. m_crWindow        = ::GetSysColor(COLOR_WINDOW);
  1578. m_crWindowText    = ::GetSysColor(COLOR_WINDOWTEXT);
  1579. }
  1580. #ifndef DO_NOT_INCLUDE_XCOMBOLIST
  1581. ///////////////////////////////////////////////////////////////////////////////
  1582. // UnpressComboButton
  1583. void CXListCtrl::UnpressComboButton()
  1584. {
  1585. static BOOL bFlag = FALSE;
  1586. if (bFlag)
  1587. return;
  1588. bFlag = TRUE;
  1589. if (m_bComboIsClicked)
  1590. {
  1591. if (m_nComboItem >= 0 && m_nComboItem < GetItemCount())
  1592. {
  1593. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(m_nComboItem);
  1594. if (pXLCD)
  1595. {
  1596. if (m_nComboSubItem >= 0 && m_nComboSubItem < GetColumns())
  1597. {
  1598. pXLCD[m_nComboSubItem].bComboIsClicked = FALSE;
  1599. UpdateSubItem(m_nComboItem, m_nComboSubItem);
  1600. }
  1601. }
  1602. }
  1603. }
  1604. m_bComboIsClicked = FALSE;
  1605. bFlag = FALSE;
  1606. }
  1607. ///////////////////////////////////////////////////////////////////////////////
  1608. // OnTimer
  1609. //
  1610. // Timer usage:
  1611. //    1 - used to check if combo button needs to be unpressed,set in
  1612. //        OnLButtonDown (when combo button is clicked)
  1613. //    2 - used to close combo listbox, set in OnComboEscape (user hits Escape
  1614. //        or listbox loses focus)
  1615. //    3 - used to get combo listbox selection, then close combo listbox,
  1616. //        set in OnComboReturn and OnComboLButtonUp (user hits Enter
  1617. //        or clicks on item in listbox)
  1618. //    4 - used to get combo listbox selection, set in OnComboKeydown (for
  1619. //        example, user hits arrow key in listbox)
  1620. //
  1621. void CXListCtrl::OnTimer(UINT nIDEvent)
  1622. {
  1623. if (nIDEvent == 1) // timer set when combo button is clicked
  1624. {
  1625. if (m_bComboIsClicked)
  1626. {
  1627. POINT point;
  1628. ::GetCursorPos(&point);
  1629. ScreenToClient(&point);
  1630. if (!m_rectComboButton.PtInRect(point))
  1631. {
  1632. UnpressComboButton();
  1633. }
  1634. }
  1635. else if (m_pListBox)
  1636. {
  1637. m_pListBox->SetActive(11);
  1638. }
  1639. else
  1640. {
  1641. KillTimer(nIDEvent);
  1642. }
  1643. }
  1644. else if (nIDEvent == 2) // close combo listbox
  1645. {
  1646. KillTimer(nIDEvent);
  1647. if (m_pListBox)
  1648. {
  1649. m_pListBox->DestroyWindow();
  1650. delete m_pListBox;
  1651. }
  1652. m_pListBox = NULL;
  1653. }
  1654. else if (nIDEvent == 3) // get combo listbox selection, then close combo listbox
  1655. {
  1656. KillTimer(nIDEvent);
  1657. if (m_pListBox)
  1658. {
  1659. CString str;
  1660. int i = m_pListBox->GetCurSel();
  1661. if (i != LB_ERR)
  1662. {
  1663. m_pListBox->GetText(i, str);
  1664. if ((m_nComboItem >= 0 && m_nComboItem < GetItemCount()) &&
  1665. (m_nComboSubItem >= 0 && m_nComboSubItem < GetColumns()))
  1666. {
  1667. SetItemText(m_nComboItem, m_nComboSubItem, str);
  1668. UpdateSubItem(m_nComboItem, m_nComboSubItem);
  1669. CWnd *pWnd = GetParent();
  1670. if (!pWnd)
  1671. pWnd = GetOwner();
  1672. if (pWnd && ::IsWindow(pWnd->m_hWnd))
  1673. pWnd->SendMessage(WM_XLISTCTRL_COMBO_SELECTION, 
  1674. m_nComboItem, m_nComboSubItem);
  1675. }
  1676. }
  1677. m_pListBox->DestroyWindow();
  1678. delete m_pListBox;
  1679. }
  1680. m_pListBox = NULL;
  1681. }
  1682. else if (nIDEvent == 4) // get combo listbox selection
  1683. {
  1684. KillTimer(nIDEvent);
  1685. if (m_pListBox)
  1686. {
  1687. CString str;
  1688. int i = m_pListBox->GetCurSel();
  1689. if (i != LB_ERR)
  1690. {
  1691. m_pListBox->GetText(i, str);
  1692. if ((m_nComboItem >= 0 && m_nComboItem < GetItemCount()) &&
  1693. (m_nComboSubItem >= 0 && m_nComboSubItem < GetColumns()))
  1694. {
  1695. SetItemText(m_nComboItem, m_nComboSubItem, str);
  1696. UpdateSubItem(m_nComboItem, m_nComboSubItem);
  1697. }
  1698. }
  1699. }
  1700. }
  1701. }
  1702. ///////////////////////////////////////////////////////////////////////////////
  1703. // OnComboEscape
  1704. LRESULT CXListCtrl::OnComboEscape(WPARAM, LPARAM)
  1705. {
  1706. KillTimer(1);
  1707. SetTimer(2, 50, NULL);
  1708. // restore original string
  1709. SetItemText(m_nComboItem, m_nComboSubItem, m_strInitialComboString);
  1710. UpdateSubItem(m_nComboItem, m_nComboSubItem);
  1711. return 0;
  1712. }
  1713. ///////////////////////////////////////////////////////////////////////////////
  1714. // OnComboReturn
  1715. LRESULT CXListCtrl::OnComboReturn(WPARAM, LPARAM)
  1716. {
  1717. TRACE(_T("in CXListCtrl::OnComboReturnn"));
  1718. KillTimer(1);
  1719. SetTimer(3, 50, NULL);
  1720. return 0;
  1721. }
  1722. ///////////////////////////////////////////////////////////////////////////////
  1723. // OnComboLButtonUp
  1724. LRESULT CXListCtrl::OnComboLButtonUp(WPARAM, LPARAM)
  1725. {
  1726. TRACE(_T("in CXListCtrl::OnComboLButtonUpn"));
  1727. KillTimer(1);
  1728. SetTimer(3, 50, NULL);
  1729. return 0;
  1730. }
  1731. ///////////////////////////////////////////////////////////////////////////////
  1732. // OnComboKeydown
  1733. LRESULT CXListCtrl::OnComboKeydown(WPARAM, LPARAM)
  1734. {
  1735. SetTimer(4, 50, NULL);
  1736. return 0;
  1737. }
  1738. #endif
  1739. #ifndef NO_XLISTCTRL_TOOL_TIPS
  1740. ///////////////////////////////////////////////////////////////////////////////
  1741. // OnToolHitTest
  1742. int CXListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
  1743. {
  1744. LVHITTESTINFO lvhitTestInfo;
  1745. lvhitTestInfo.pt = point;
  1746. int nItem = ListView_SubItemHitTest(this->m_hWnd, &lvhitTestInfo);
  1747. int nSubItem = lvhitTestInfo.iSubItem;
  1748. TRACE(_T("in CToolTipListCtrl::OnToolHitTest: %d,%dn"), nItem, nSubItem);
  1749. UINT nFlags = lvhitTestInfo.flags;
  1750. // nFlags is 0 if the SubItemHitTest fails
  1751. // Therefore, 0 & <anything> will equal false
  1752. if (nFlags & LVHT_ONITEMLABEL)
  1753. {
  1754. // If it did fall on a list item,
  1755. // and it was also hit one of the
  1756. // item specific subitems we wish to show tool tips for
  1757. // get the client (area occupied by this control
  1758. RECT rcClient;
  1759. GetClientRect(&rcClient);
  1760. // fill in the TOOLINFO structure
  1761. pTI->hwnd = m_hWnd;
  1762. pTI->uId = (UINT) (nItem * 1000 + nSubItem + 1);
  1763. pTI->lpszText = LPSTR_TEXTCALLBACK;
  1764. pTI->rect = rcClient;
  1765. return pTI->uId; // By returning a unique value per listItem,
  1766. // we ensure that when the mouse moves over another
  1767. // list item, the tooltip will change
  1768. }
  1769. else
  1770. {
  1771. //Otherwise, we aren't interested, so let the message propagate
  1772. return -1;
  1773. }
  1774. }
  1775. ///////////////////////////////////////////////////////////////////////////////
  1776. // OnToolTipText
  1777. BOOL CXListCtrl::OnToolTipText(UINT /*id*/, NMHDR * pNMHDR, LRESULT * pResult)
  1778. {
  1779. UINT nID = pNMHDR->idFrom;
  1780. TRACE(_T("in CXListCtrl::OnToolTipText: id=%dn"), nID);
  1781. // check if this is the automatic tooltip of the control
  1782. if (nID == 0) 
  1783. return TRUE; // do not allow display of automatic tooltip,
  1784. // or our tooltip will disappear
  1785. // handle both ANSI and UNICODE versions of the message
  1786. TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  1787. TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  1788. *pResult = 0;
  1789. // get the mouse position
  1790. const MSG* pMessage;
  1791. pMessage = GetCurrentMessage();
  1792. ASSERT(pMessage);
  1793. CPoint pt;
  1794. pt = pMessage->pt; // get the point from the message
  1795. ScreenToClient(&pt); // convert the point's coords to be relative to this control
  1796. // see if the point falls onto a list item
  1797. LVHITTESTINFO lvhitTestInfo;
  1798. lvhitTestInfo.pt = pt;
  1799. int nItem = SubItemHitTest(&lvhitTestInfo);
  1800. int nSubItem = lvhitTestInfo.iSubItem;
  1801. UINT nFlags = lvhitTestInfo.flags;
  1802. // nFlags is 0 if the SubItemHitTest fails
  1803. // Therefore, 0 & <anything> will equal false
  1804. if (nFlags & LVHT_ONITEMLABEL)
  1805. {
  1806. // If it did fall on a list item,
  1807. // and it was also hit one of the
  1808. // item specific subitems we wish to show tooltips for
  1809. CString strToolTip;
  1810. strToolTip = _T("");
  1811. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1812. if (pXLCD)
  1813. {
  1814. strToolTip = pXLCD[nSubItem].strToolTip;
  1815. }
  1816. if (!strToolTip.IsEmpty())
  1817. {
  1818. // If there was a CString associated with the list item,
  1819. // copy it's text (up to 80 characters worth, limitation 
  1820. // of the TOOLTIPTEXT structure) into the TOOLTIPTEXT 
  1821. // structure's szText member
  1822. #ifndef _UNICODE
  1823. if (pNMHDR->code == TTN_NEEDTEXTA)
  1824. lstrcpyn(pTTTA->szText, strToolTip, 80);
  1825. else
  1826. _mbstowcsz(pTTTW->szText, strToolTip, 80);
  1827. #else
  1828. if (pNMHDR->code == TTN_NEEDTEXTA)
  1829. _wcstombsz(pTTTA->szText, strToolTip, 80);
  1830. else
  1831. lstrcpyn(pTTTW->szText, strToolTip, 80);
  1832. #endif
  1833. return FALSE;  // we found a tool tip,
  1834. }
  1835. }
  1836. return FALSE; // we didn't handle the message, let the 
  1837. // framework continue propagating the message
  1838. }
  1839. ///////////////////////////////////////////////////////////////////////////////
  1840. // SetItemToolTipText
  1841. BOOL CXListCtrl::SetItemToolTipText(int nItem, int nSubItem, LPCTSTR lpszToolTipText)
  1842. {
  1843. ASSERT(nItem >= 0);
  1844. ASSERT(nItem < GetItemCount());
  1845. if ((nItem < 0) || nItem >= GetItemCount())
  1846. return FALSE;
  1847. ASSERT(nSubItem >= 0);
  1848. ASSERT(nSubItem < GetColumns());
  1849. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1850. return FALSE;
  1851. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1852. if (!pXLCD)
  1853. {
  1854. return FALSE;
  1855. }
  1856. pXLCD[nSubItem].strToolTip = lpszToolTipText;
  1857. return TRUE;
  1858. }
  1859. ///////////////////////////////////////////////////////////////////////////////
  1860. // GetItemToolTipText
  1861. CString CXListCtrl::GetItemToolTipText(int nItem, int nSubItem)
  1862. {
  1863. CString strToolTip;
  1864. strToolTip = _T("");
  1865. ASSERT(nItem >= 0);
  1866. ASSERT(nItem < GetItemCount());
  1867. if ((nItem < 0) || nItem >= GetItemCount())
  1868. return strToolTip;
  1869. ASSERT(nSubItem >= 0);
  1870. ASSERT(nSubItem < GetColumns());
  1871. if ((nSubItem < 0) || nSubItem >= GetColumns())
  1872. return strToolTip;
  1873. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1874. if (pXLCD)
  1875. {
  1876. strToolTip = pXLCD[nSubItem].strToolTip;
  1877. }
  1878. return strToolTip;
  1879. }
  1880. ///////////////////////////////////////////////////////////////////////////////
  1881. // DeleteAllToolTips
  1882. void CXListCtrl::DeleteAllToolTips()
  1883. {
  1884. int nRow = GetItemCount();
  1885. int nCol = GetColumns();
  1886. for (int nItem = 0; nItem < nRow; nItem++)
  1887. {
  1888. XLISTCTRLDATA *pXLCD = (XLISTCTRLDATA *) CListCtrl::GetItemData(nItem);
  1889. if (pXLCD)
  1890. for (int nSubItem = 0; nSubItem < nCol; nSubItem++)
  1891. pXLCD[nSubItem].strToolTip = _T("");
  1892. }
  1893. }
  1894. #endif