Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

902 lines
22 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ====
  2. //
  3. // A tree of checkable items. Can have multiple root-level items. Supports drag and drop
  4. // and posts a registered Windows message to the tree's parent window when items
  5. // are checked, unchecked, dragged & dropped, and when selection changes.
  6. //
  7. //=============================================================================
  8. #include "stdafx.h"
  9. #include "treelist.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include <tier0/memdbgon.h>
  12. //
  13. // Timer IDs.
  14. //
  15. enum
  16. {
  17. TIMER_GROUP_DRAG_SCROLL = 1,
  18. };
  19. // TODO: Make these messages unique per instance so a window can contain more than one of these controls
  20. static const unsigned int g_uToggleStateMsg = ::RegisterWindowMessage(TREELIST_MSG_TOGGLE_STATE);
  21. static const unsigned int g_uLeftDragDropMsg = ::RegisterWindowMessage(TREELIST_MSG_LEFT_DRAG_DROP);
  22. static const unsigned int g_uRightDragDropMsg = ::RegisterWindowMessage(TREELIST_MSG_RIGHT_DRAG_DROP);
  23. static const unsigned int g_uSelChangeMsg = ::RegisterWindowMessage(TREELIST_MSG_SEL_CHANGE);
  24. static const unsigned int g_uKeyDownMsg = ::RegisterWindowMessage(TREELIST_MSG_KEY_DOWN);
  25. BEGIN_MESSAGE_MAP(CTreeList, CTreeCtrl)
  26. //{{AFX_MSG_MAP(CGroupList)
  27. ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
  28. ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)
  29. ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChange)
  30. ON_NOTIFY_REFLECT(TVN_KEYDOWN, OnKeyDown)
  31. ON_WM_LBUTTONDOWN()
  32. ON_WM_LBUTTONUP()
  33. ON_WM_LBUTTONDBLCLK()
  34. ON_WM_RBUTTONDOWN()
  35. ON_WM_RBUTTONUP()
  36. ON_WM_MOUSEMOVE()
  37. ON_WM_TIMER()
  38. ON_WM_CONTEXTMENU()
  39. //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41. //-----------------------------------------------------------------------------
  42. //-----------------------------------------------------------------------------
  43. CTreeList::CTreeList()
  44. {
  45. m_pDragImageList = NULL;
  46. m_hDragItem = NULL;
  47. m_bRButtonDown = false;
  48. }
  49. //-----------------------------------------------------------------------------
  50. //-----------------------------------------------------------------------------
  51. CTreeList::~CTreeList()
  52. {
  53. }
  54. //-----------------------------------------------------------------------------
  55. //-----------------------------------------------------------------------------
  56. void CTreeList::EnableChecks()
  57. {
  58. if (!m_cNormalImageList.GetSafeHandle())
  59. {
  60. // TODO: pass the image list in?
  61. #define IDB_TREELISTCHECKS 223
  62. m_cNormalImageList.Create(IDB_TREELISTCHECKS, 16, 1, RGB(255, 255, 255));
  63. m_cNormalImageList.SetOverlayImage(1, 1);
  64. m_cNormalImageList.SetOverlayImage(2, 2);
  65. }
  66. CTreeCtrl::SetImageList(&m_cNormalImageList, TVSIL_STATE);
  67. }
  68. //-----------------------------------------------------------------------------
  69. //-----------------------------------------------------------------------------
  70. void CTreeList::AddItem(void *pItem, void *pParent, const char *pText, bool bHasCheckBox )
  71. {
  72. HTREEITEM hParent = TVI_ROOT;
  73. if (pParent)
  74. {
  75. // FIXME: recursive lookup for every add is sucky
  76. hParent = FindHTreeItem(pParent);
  77. }
  78. HTREEITEM hItem = InsertItem(pText, hParent, TVI_LAST);
  79. if (hItem != NULL)
  80. {
  81. SetItemData(hItem, (DWORD)pItem);
  82. m_Items.AddToTail(pItem);
  83. if ( bHasCheckBox )
  84. {
  85. SetItemState( hItem, INDEXTOSTATEIMAGEMASK( 1 ), TVIS_STATEIMAGEMASK );
  86. }
  87. else
  88. {
  89. SetItemState( hItem, INDEXTOSTATEIMAGEMASK( 0 ), TVIS_STATEIMAGEMASK );
  90. }
  91. }
  92. }
  93. //-----------------------------------------------------------------------------
  94. //-----------------------------------------------------------------------------
  95. static void UnsetItemData_R( CTreeCtrl *pCtrl, HTREEITEM hItem )
  96. {
  97. pCtrl->SetItemData( hItem, 0 );
  98. HTREEITEM hChildItem = pCtrl->GetChildItem( hItem );
  99. while( hChildItem != NULL )
  100. {
  101. UnsetItemData_R( pCtrl, hChildItem );
  102. hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
  103. }
  104. }
  105. //-----------------------------------------------------------------------------
  106. //-----------------------------------------------------------------------------
  107. void CTreeList::DeleteAllItems()
  108. {
  109. // Un-set all item data because sometimes during a delete it'll trigger selection change notifications
  110. // which might crash things later.
  111. if ( GetSafeHwnd() && m_Items.Count() > 0 )
  112. {
  113. UnsetItemData_R( this, TVI_ROOT );
  114. }
  115. DeleteItem(TVI_ROOT);
  116. m_Items.RemoveAll();
  117. }
  118. //-----------------------------------------------------------------------------
  119. //-----------------------------------------------------------------------------
  120. void CTreeList::EnsureVisible(void *pItem)
  121. {
  122. //DBG("EnsureVisible: %s\n", pVisGroup->GetName());
  123. HTREEITEM hItem = FindHTreeItem(pItem);
  124. if (hItem)
  125. {
  126. CTreeCtrl::EnsureVisible(hItem);
  127. }
  128. }
  129. //-----------------------------------------------------------------------------
  130. //-----------------------------------------------------------------------------
  131. void CTreeList::ExpandRecursive(HTREEITEM hItem)
  132. {
  133. if (hItem)
  134. {
  135. Expand(hItem, TVE_EXPAND);
  136. if (ItemHasChildren(hItem))
  137. {
  138. HTREEITEM hChildItem = GetChildItem(hItem);
  139. while (hChildItem != NULL)
  140. {
  141. ExpandRecursive(hChildItem);
  142. hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
  143. }
  144. }
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. //-----------------------------------------------------------------------------
  149. void CTreeList::ExpandAll()
  150. {
  151. HTREEITEM hItem = GetRootItem();
  152. while (hItem)
  153. {
  154. ExpandRecursive(hItem);
  155. hItem = GetNextItem(hItem, TVGN_NEXT);
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. //-----------------------------------------------------------------------------
  160. void CTreeList::ExpandItem(void *pItem)
  161. {
  162. HTREEITEM hItem = FindHTreeItem(pItem);
  163. if (hItem)
  164. {
  165. Expand(hItem, TVE_EXPAND);
  166. }
  167. }
  168. //-----------------------------------------------------------------------------
  169. //-----------------------------------------------------------------------------
  170. void CTreeList::CollapseItem(void *pItem)
  171. {
  172. HTREEITEM hItem = FindHTreeItem(pItem);
  173. if (hItem)
  174. {
  175. Expand(hItem, TVE_COLLAPSE);
  176. }
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Returns the HTREEITEM in the given subtree associated with the given
  180. // item pointer, NULL if none.
  181. //-----------------------------------------------------------------------------
  182. HTREEITEM CTreeList::FindHTreeItemRecursive(HTREEITEM hItem, void *pItem)
  183. {
  184. if (hItem)
  185. {
  186. void *pItemCheck = (void *)GetItemData(hItem);
  187. if (pItemCheck == pItem)
  188. {
  189. return hItem;
  190. }
  191. if (ItemHasChildren(hItem))
  192. {
  193. HTREEITEM hChildItem = GetChildItem(hItem);
  194. while (hChildItem != NULL)
  195. {
  196. HTREEITEM hFoundItem = FindHTreeItemRecursive(hChildItem, pItem);
  197. if (hFoundItem)
  198. {
  199. return hFoundItem;
  200. }
  201. hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
  202. }
  203. }
  204. }
  205. return NULL;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Returns the HTREEITEM associated with the given item pointer, NULL if none.
  209. //-----------------------------------------------------------------------------
  210. HTREEITEM CTreeList::FindHTreeItem(void *pItem)
  211. {
  212. HTREEITEM hItem = GetRootItem();
  213. while (hItem)
  214. {
  215. HTREEITEM hFound = FindHTreeItemRecursive(hItem, pItem);
  216. if (hFound)
  217. {
  218. return hFound;
  219. }
  220. hItem = GetNextItem(hItem, TVGN_NEXT);
  221. }
  222. return NULL;
  223. }
  224. //-----------------------------------------------------------------------------
  225. //-----------------------------------------------------------------------------
  226. void *CTreeList::GetSelectedItem()
  227. {
  228. HTREEITEM hItem = CTreeCtrl::GetSelectedItem();
  229. if (hItem)
  230. {
  231. return (void *)GetItemData(hItem);
  232. }
  233. return NULL;
  234. }
  235. //-----------------------------------------------------------------------------
  236. //-----------------------------------------------------------------------------
  237. int CTreeList::GetSelectedIndex()
  238. {
  239. int nItem = -1;
  240. void *pItem = GetSelectedItem();
  241. if ( pItem )
  242. {
  243. for ( int i = 0; i < m_Items.Count(); i++ )
  244. {
  245. if ( m_Items[i] == pItem )
  246. {
  247. nItem = i;
  248. break;
  249. }
  250. }
  251. }
  252. return nItem;
  253. }
  254. //-----------------------------------------------------------------------------
  255. //-----------------------------------------------------------------------------
  256. void CTreeList::OnLButtonDown(UINT nFlags, CPoint point)
  257. {
  258. unsigned int uFlags;
  259. HTREEITEM hItemHit = HitTest(point, &uFlags);
  260. if (hItemHit != NULL)
  261. {
  262. if (uFlags & TVHT_ONITEMSTATEICON)
  263. {
  264. // Don't forward to the base if they clicked on the check box.
  265. // This prevents undesired expansion/collapse of tree.
  266. return;
  267. }
  268. }
  269. CTreeCtrl::OnLButtonDown(nFlags, point);
  270. }
  271. //-----------------------------------------------------------------------------
  272. //-----------------------------------------------------------------------------
  273. void CTreeList::OnLButtonUp(UINT nFlags, CPoint point)
  274. {
  275. KillTimer(TIMER_GROUP_DRAG_SCROLL);
  276. ReleaseCapture();
  277. if (!m_hDragItem)
  278. {
  279. unsigned int uFlags;
  280. HTREEITEM hItemHit = HitTest(point, &uFlags);
  281. if (hItemHit != NULL)
  282. {
  283. if (uFlags & TVHT_ONITEMSTATEICON)
  284. {
  285. //
  286. // Notify our parent window that this item's state has changed.
  287. //
  288. CWnd *pwndParent = GetParent();
  289. if (pwndParent != NULL)
  290. {
  291. // TODO: might need a way to cycle through three states: on, off, grey
  292. int nCheckState = GetCheck(hItemHit);
  293. if (!nCheckState)
  294. {
  295. nCheckState = 1;
  296. }
  297. else
  298. {
  299. nCheckState = 0;
  300. }
  301. void *pItem = (void *)GetItemData(hItemHit);
  302. pwndParent->PostMessage(g_uToggleStateMsg, (WPARAM)pItem, nCheckState);
  303. }
  304. // Don't forward to the base if they clicked on the check box.
  305. // This prevents undesired expansion/collapse of tree.
  306. return;
  307. }
  308. }
  309. CTreeCtrl::OnLButtonUp(nFlags, point);
  310. return;
  311. }
  312. Drop(DROP_LEFT, nFlags, point);
  313. }
  314. //-----------------------------------------------------------------------------
  315. //-----------------------------------------------------------------------------
  316. void CTreeList::OnLButtonDblClk(UINT nFlags, CPoint point)
  317. {
  318. unsigned int uFlags;
  319. HTREEITEM hItemHit = HitTest(point, &uFlags);
  320. if (hItemHit != NULL)
  321. {
  322. if (uFlags & TVHT_ONITEMICON)
  323. {
  324. // Don't forward to the base if they clicked on the check box.
  325. // This prevents undesired expansion/collapse of tree.
  326. return;
  327. }
  328. }
  329. CTreeCtrl::OnLButtonDblClk(nFlags, point);
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Forwards selection change notifications to our parent window.
  333. // pNMHDR -
  334. // pResult -
  335. //-----------------------------------------------------------------------------
  336. void CTreeList::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
  337. {
  338. CWnd *pwndParent = GetParent();
  339. if (pwndParent != NULL)
  340. {
  341. pwndParent->PostMessage( g_uSelChangeMsg, (WPARAM)GetDlgCtrlID(), 0 );
  342. }
  343. }
  344. //-----------------------------------------------------------------------------
  345. //-----------------------------------------------------------------------------
  346. void CTreeList::OnEndLabelEdit(NMHDR *pNMHDR, LRESULT *pResult)
  347. {
  348. NMTVDISPINFO *pInfo = (NMTVDISPINFO *)pNMHDR;
  349. if (!pInfo->item.pszText)
  350. return;
  351. void *pItem = (void *)GetItemData(pInfo->item.hItem);
  352. Assert(pItem);
  353. if (!pItem)
  354. return;
  355. OnRenameItem(pItem, pInfo->item.pszText);
  356. pResult[0] = TRUE;
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Begins dragging an item in the tree list. The drag image is
  360. // created and anchored relative to the mouse cursor.
  361. // pNMHDR -
  362. // pResult -
  363. //-----------------------------------------------------------------------------
  364. void CTreeList::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
  365. {
  366. NMTREEVIEW *ptv = (NMTREEVIEW *)pNMHDR;
  367. BeginDrag(ptv->ptDrag, ptv->itemNew.hItem);
  368. *pResult = 0;
  369. }
  370. //-----------------------------------------------------------------------------
  371. //-----------------------------------------------------------------------------
  372. void CTreeList::OnKeyDown( NMHDR *pNMHDR, LRESULT *pResult )
  373. {
  374. NMTVKEYDOWN *pKeyDown = (NMTVKEYDOWN *)pNMHDR;
  375. CWnd *pwndParent = GetParent();
  376. if (pwndParent != NULL)
  377. {
  378. pwndParent->PostMessage(g_uKeyDownMsg, (WPARAM)pKeyDown->wVKey, (LPARAM)pKeyDown->flags);
  379. }
  380. *pResult = 0;
  381. }
  382. //-----------------------------------------------------------------------------
  383. //-----------------------------------------------------------------------------
  384. void CTreeList::BeginDrag(CPoint point, HTREEITEM hItem)
  385. {
  386. m_hDragItem = hItem;
  387. if (m_hDragItem)
  388. {
  389. m_pDragImageList = CreateDragImage(m_hDragItem);
  390. if (m_pDragImageList)
  391. {
  392. CPoint ptHotSpot(0, 0);
  393. m_pDragImageList->BeginDrag(0, ptHotSpot);
  394. m_pDragImageList->DragEnter(this, point);
  395. SelectDropTarget(NULL);
  396. }
  397. // Timer handles scrolling the list control when dragging outside the window bounds.
  398. SetTimer(TIMER_GROUP_DRAG_SCROLL, 300, NULL);
  399. SetCapture();
  400. }
  401. }
  402. //-----------------------------------------------------------------------------
  403. //-----------------------------------------------------------------------------
  404. void CTreeList::OnRButtonDown(UINT nFlags, CPoint point)
  405. {
  406. m_bRButtonDown = true;
  407. m_ptRButtonDown = point;
  408. m_hDragItem = NULL;
  409. SetCapture();
  410. // Chaining to the base class causes us never to receive the button up message
  411. // for a right click without drag, so we don't do that.
  412. //CTreeCtrl::OnRButtonDown(nFlags, point);
  413. }
  414. //-----------------------------------------------------------------------------
  415. //-----------------------------------------------------------------------------
  416. void CTreeList::OnContextMenu(CWnd *pWnd, CPoint point)
  417. {
  418. KillTimer(TIMER_GROUP_DRAG_SCROLL);
  419. ReleaseCapture();
  420. m_bRButtonDown = false;
  421. if (!m_hDragItem)
  422. {
  423. // TODO: Need to invoke the correct context menu for this tree list. Currently no one uses this.
  424. CTreeCtrl::OnContextMenu(pWnd, point);
  425. return;
  426. }
  427. Drop(DROP_RIGHT, 0, point);
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose:
  431. // Input : nFlags -
  432. // point -
  433. //-----------------------------------------------------------------------------
  434. void CTreeList::OnRButtonUp(UINT nFlags, CPoint point)
  435. {
  436. KillTimer(TIMER_GROUP_DRAG_SCROLL);
  437. ReleaseCapture();
  438. m_bRButtonDown = false;
  439. if (!m_hDragItem)
  440. {
  441. CTreeCtrl::OnRButtonUp(nFlags, point);
  442. return;
  443. }
  444. Drop(DROP_RIGHT, nFlags, point);
  445. }
  446. //-----------------------------------------------------------------------------
  447. // Purpose:
  448. // Input : eDropType -
  449. // nFlags -
  450. // point -
  451. //-----------------------------------------------------------------------------
  452. void CTreeList::Drop(DropType_t eDropType, UINT nFlags, CPoint point)
  453. {
  454. SelectDropTarget(NULL);
  455. HTREEITEM hDragItem = m_hDragItem;
  456. m_hDragItem = NULL;
  457. //
  458. // We are dragging. Drop!
  459. //
  460. if (m_pDragImageList)
  461. {
  462. m_pDragImageList->DragLeave(this);
  463. m_pDragImageList->EndDrag();
  464. delete m_pDragImageList;
  465. m_pDragImageList = NULL;
  466. }
  467. //
  468. // Get the group that we were dragging.
  469. //
  470. void *pDragItem = (void *)GetItemData(hDragItem);
  471. //
  472. // Determine what group was dropped onto.
  473. //
  474. HTREEITEM hDropItem = HitTest(point);
  475. if (hDropItem == hDragItem)
  476. {
  477. return;
  478. }
  479. void *pDropItem = NULL;
  480. if (hDropItem)
  481. {
  482. pDropItem = (void *)GetItemData(hDropItem);
  483. }
  484. if (pDragItem == pDropItem)
  485. {
  486. // Shouldn't happen, but just in case.
  487. return;
  488. }
  489. CWnd *pwndParent = GetParent();
  490. if (pwndParent != NULL)
  491. {
  492. if (eDropType == DROP_LEFT)
  493. {
  494. pwndParent->PostMessage(g_uLeftDragDropMsg, (WPARAM)pDragItem, (LPARAM)pDropItem);
  495. }
  496. else
  497. {
  498. pwndParent->PostMessage(g_uRightDragDropMsg, (WPARAM)pDragItem, (LPARAM)pDropItem);
  499. }
  500. }
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose:
  504. // Input : nIDEvent -
  505. //-----------------------------------------------------------------------------
  506. void CTreeList::OnTimer(UINT nIDEvent)
  507. {
  508. //DBG("OnTimer\n");
  509. switch (nIDEvent)
  510. {
  511. case TIMER_GROUP_DRAG_SCROLL:
  512. {
  513. CPoint point;
  514. GetCursorPos(&point);
  515. CRect rect;
  516. GetWindowRect(&rect);
  517. if (!rect.PtInRect(point))
  518. {
  519. if (point.y > rect.bottom)
  520. {
  521. // scroll down
  522. int nCount = GetVisibleCount();
  523. HTREEITEM hItem = GetFirstVisibleItem();
  524. for (int i = 1; i < nCount; i++)
  525. {
  526. hItem = GetNextVisibleItem(hItem);
  527. }
  528. hItem = GetNextVisibleItem(hItem);
  529. if (hItem)
  530. {
  531. CTreeCtrl::EnsureVisible(hItem);
  532. }
  533. }
  534. else if (point.y < rect.top)
  535. {
  536. HTREEITEM hItem = GetFirstVisibleItem();
  537. HTREEITEM hPrevVisible = this->GetPrevVisibleItem(hItem);
  538. if (hPrevVisible)
  539. {
  540. // scroll up
  541. CTreeCtrl::EnsureVisible(hPrevVisible);
  542. }
  543. }
  544. }
  545. break;
  546. }
  547. default:
  548. {
  549. CTreeCtrl::OnTimer(nIDEvent);
  550. }
  551. }
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose:
  555. // Input : nFlags -
  556. // point -
  557. //-----------------------------------------------------------------------------
  558. void CTreeList::OnMouseMove(UINT nFlags, CPoint point)
  559. {
  560. CTreeCtrl::OnMouseMove(nFlags, point);
  561. if (m_bRButtonDown && !m_hDragItem && (point.x != m_ptRButtonDown.x) && (point.y != m_ptRButtonDown.y))
  562. {
  563. // First mouse move since a right button down. Start dragging.
  564. HTREEITEM hItem = HitTest(m_ptRButtonDown);
  565. BeginDrag(point, hItem);
  566. }
  567. if (!m_hDragItem)
  568. {
  569. return;
  570. }
  571. if (m_pDragImageList)
  572. {
  573. m_pDragImageList->DragMove(point);
  574. }
  575. //
  576. // Highlight the item we hit.
  577. //
  578. HTREEITEM hItem = HitTest(point);
  579. if (hItem == GetDropHilightItem())
  580. {
  581. return;
  582. }
  583. // hide image first
  584. if (m_pDragImageList)
  585. {
  586. m_pDragImageList->DragLeave(this);
  587. m_pDragImageList->DragShowNolock(FALSE);
  588. }
  589. SelectDropTarget(hItem);
  590. if (m_pDragImageList)
  591. {
  592. m_pDragImageList->DragEnter(this, point);
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Purpose:
  597. //-----------------------------------------------------------------------------
  598. void CTreeList::SelectItem(void *pItem)
  599. {
  600. //DBG("SelectTreeListItem: %s\n", pVisGroup->GetName());
  601. HTREEITEM hItem = FindHTreeItem(pItem);
  602. if (hItem)
  603. {
  604. Select(hItem, TVGN_CARET);
  605. }
  606. }
  607. //-----------------------------------------------------------------------------
  608. //-----------------------------------------------------------------------------
  609. void CTreeList::SelectNearestItem( int nItem )
  610. {
  611. if ( ( m_Items.Count() > 0 ) && ( m_Items.Count() <= nItem ) )
  612. {
  613. nItem = m_Items.Count() - 1;
  614. }
  615. if ( m_Items.IsValidIndex( nItem ) )
  616. {
  617. SelectItem( m_Items[nItem] );
  618. }
  619. }
  620. //-----------------------------------------------------------------------------
  621. //-----------------------------------------------------------------------------
  622. void CTreeList::EnsureVisible( int nItem )
  623. {
  624. if ( ( m_Items.Count() > 0 ) && ( m_Items.Count() <= nItem ) )
  625. {
  626. nItem = m_Items.Count() - 1;
  627. }
  628. if ( m_Items.IsValidIndex( nItem ) )
  629. {
  630. EnsureVisible( m_Items[nItem] );
  631. }
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Sets the check status for the given item.
  635. // pItem -
  636. // nCheckState - 0=not checked, 1=checked, -1=gray check (undefined)
  637. //-----------------------------------------------------------------------------
  638. void CTreeList::SetCheck(void *pItem, int nCheckState)
  639. {
  640. HTREEITEM hItem = FindHTreeItem(pItem);
  641. if (hItem)
  642. {
  643. UINT uState = INDEXTOSTATEIMAGEMASK(1);
  644. if (nCheckState == 1)
  645. {
  646. uState = INDEXTOSTATEIMAGEMASK(2);
  647. }
  648. else if (nCheckState != 0)
  649. {
  650. uState = INDEXTOSTATEIMAGEMASK(3);
  651. }
  652. SetItemState(hItem, uState, TVIS_STATEIMAGEMASK);
  653. }
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Returns the check state for the given item.
  657. //-----------------------------------------------------------------------------
  658. int CTreeList::GetCheck(void *pItem)
  659. {
  660. HTREEITEM hItem = FindHTreeItem(pItem);
  661. if (hItem)
  662. {
  663. return GetCheck(hItem);
  664. }
  665. return 0;
  666. }
  667. //-----------------------------------------------------------------------------
  668. //-----------------------------------------------------------------------------
  669. int CTreeList::GetCheck(HTREEITEM hItem)
  670. {
  671. UINT uState = (GetItemState(hItem, TVIS_STATEIMAGEMASK) & TVIS_STATEIMAGEMASK);
  672. if (uState == INDEXTOSTATEIMAGEMASK(2))
  673. {
  674. return 1;
  675. }
  676. else if (uState == INDEXTOSTATEIMAGEMASK(1))
  677. {
  678. return 0;
  679. }
  680. return -1;
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose: Returns the number of visgroups in the whole tree.
  684. //-----------------------------------------------------------------------------
  685. int CTreeList::GetItemCount()
  686. {
  687. return m_Items.Count();
  688. }
  689. //-----------------------------------------------------------------------------
  690. //-----------------------------------------------------------------------------
  691. void *CTreeList::GetItem(int nIndex)
  692. {
  693. return m_Items.Element(nIndex);
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Updates the tree control item text with the new group name.
  697. //-----------------------------------------------------------------------------
  698. void CTreeList::UpdateItem(void *pItem, const char *pszText)
  699. {
  700. HTREEITEM hItem = FindHTreeItem(pItem);
  701. if (hItem)
  702. {
  703. SetItemText(hItem, pszText);
  704. }
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Stores the expanded/collapsed state into a data member for retrieval later.
  708. //-----------------------------------------------------------------------------
  709. void CTreeList::SaveTreeListExpandStates()
  710. {
  711. for ( int i = 0; i < GetItemCount(); i++ )
  712. {
  713. void *pItem = GetItem(i);
  714. TreeListItemState_t newState;
  715. for ( int j = 0; j < m_ItemState.Count(); j++ )
  716. {
  717. TreeListItemState_t thisPair = m_ItemState.Element( j );
  718. if ( pItem == thisPair.pItem )
  719. {
  720. m_ItemState.Remove( j );
  721. break;
  722. }
  723. }
  724. HTREEITEM hItem = FindHTreeItem( pItem );
  725. newState.pItem = pItem;
  726. newState.bExpanded = false;
  727. if ( hItem && (GetItemState( hItem, TVIS_EXPANDED) & TVIS_EXPANDED) )
  728. {
  729. newState.bExpanded = true;
  730. }
  731. m_ItemState.AddToTail( newState );
  732. }
  733. }
  734. //-----------------------------------------------------------------------------
  735. //-----------------------------------------------------------------------------
  736. void CTreeList::RestoreTreeListExpandStates()
  737. {
  738. ExpandAll();
  739. for ( int i = 0; i < m_ItemState.Count(); i++ )
  740. {
  741. TreeListItemState_t thisPair = m_ItemState.Element( i );
  742. HTREEITEM thisItem = FindHTreeItem( thisPair.pItem );
  743. if ( thisItem )
  744. {
  745. if ( thisPair.bExpanded )
  746. {
  747. Expand(thisItem, TVE_EXPAND);
  748. }
  749. else
  750. {
  751. Expand( thisItem, TVE_COLLAPSE );
  752. }
  753. }
  754. }
  755. }