initial
This commit is contained in:
902
hammer/treelist.cpp
Normal file
902
hammer/treelist.cpp
Normal file
@@ -0,0 +1,902 @@
|
||||
//========= Copyright <20> 1996-2009, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// A tree of checkable items. Can have multiple root-level items. Supports drag and drop
|
||||
// and posts a registered Windows message to the tree's parent window when items
|
||||
// are checked, unchecked, dragged & dropped, and when selection changes.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "treelist.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
//
|
||||
// Timer IDs.
|
||||
//
|
||||
enum
|
||||
{
|
||||
TIMER_GROUP_DRAG_SCROLL = 1,
|
||||
};
|
||||
|
||||
|
||||
// TODO: Make these messages unique per instance so a window can contain more than one of these controls
|
||||
static const unsigned int g_uToggleStateMsg = ::RegisterWindowMessage(TREELIST_MSG_TOGGLE_STATE);
|
||||
static const unsigned int g_uLeftDragDropMsg = ::RegisterWindowMessage(TREELIST_MSG_LEFT_DRAG_DROP);
|
||||
static const unsigned int g_uRightDragDropMsg = ::RegisterWindowMessage(TREELIST_MSG_RIGHT_DRAG_DROP);
|
||||
static const unsigned int g_uSelChangeMsg = ::RegisterWindowMessage(TREELIST_MSG_SEL_CHANGE);
|
||||
static const unsigned int g_uKeyDownMsg = ::RegisterWindowMessage(TREELIST_MSG_KEY_DOWN);
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CTreeList, CTreeCtrl)
|
||||
//{{AFX_MSG_MAP(CGroupList)
|
||||
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
|
||||
ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)
|
||||
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChange)
|
||||
ON_NOTIFY_REFLECT(TVN_KEYDOWN, OnKeyDown)
|
||||
ON_WM_LBUTTONDOWN()
|
||||
ON_WM_LBUTTONUP()
|
||||
ON_WM_LBUTTONDBLCLK()
|
||||
ON_WM_RBUTTONDOWN()
|
||||
ON_WM_RBUTTONUP()
|
||||
ON_WM_MOUSEMOVE()
|
||||
ON_WM_TIMER()
|
||||
ON_WM_CONTEXTMENU()
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CTreeList::CTreeList()
|
||||
{
|
||||
m_pDragImageList = NULL;
|
||||
m_hDragItem = NULL;
|
||||
m_bRButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CTreeList::~CTreeList()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::EnableChecks()
|
||||
{
|
||||
if (!m_cNormalImageList.GetSafeHandle())
|
||||
{
|
||||
// TODO: pass the image list in?
|
||||
#define IDB_TREELISTCHECKS 223
|
||||
m_cNormalImageList.Create(IDB_TREELISTCHECKS, 16, 1, RGB(255, 255, 255));
|
||||
m_cNormalImageList.SetOverlayImage(1, 1);
|
||||
m_cNormalImageList.SetOverlayImage(2, 2);
|
||||
}
|
||||
|
||||
CTreeCtrl::SetImageList(&m_cNormalImageList, TVSIL_STATE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::AddItem(void *pItem, void *pParent, const char *pText, bool bHasCheckBox )
|
||||
{
|
||||
HTREEITEM hParent = TVI_ROOT;
|
||||
if (pParent)
|
||||
{
|
||||
// FIXME: recursive lookup for every add is sucky
|
||||
hParent = FindHTreeItem(pParent);
|
||||
}
|
||||
|
||||
HTREEITEM hItem = InsertItem(pText, hParent, TVI_LAST);
|
||||
if (hItem != NULL)
|
||||
{
|
||||
SetItemData(hItem, (DWORD)pItem);
|
||||
m_Items.AddToTail(pItem);
|
||||
|
||||
if ( bHasCheckBox )
|
||||
{
|
||||
SetItemState( hItem, INDEXTOSTATEIMAGEMASK( 1 ), TVIS_STATEIMAGEMASK );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetItemState( hItem, INDEXTOSTATEIMAGEMASK( 0 ), TVIS_STATEIMAGEMASK );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
static void UnsetItemData_R( CTreeCtrl *pCtrl, HTREEITEM hItem )
|
||||
{
|
||||
pCtrl->SetItemData( hItem, 0 );
|
||||
|
||||
HTREEITEM hChildItem = pCtrl->GetChildItem( hItem );
|
||||
|
||||
while( hChildItem != NULL )
|
||||
{
|
||||
UnsetItemData_R( pCtrl, hChildItem );
|
||||
hChildItem = pCtrl->GetNextItem(hChildItem, TVGN_NEXT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::DeleteAllItems()
|
||||
{
|
||||
// Un-set all item data because sometimes during a delete it'll trigger selection change notifications
|
||||
// which might crash things later.
|
||||
if ( GetSafeHwnd() && m_Items.Count() > 0 )
|
||||
{
|
||||
UnsetItemData_R( this, TVI_ROOT );
|
||||
}
|
||||
|
||||
DeleteItem(TVI_ROOT);
|
||||
m_Items.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::EnsureVisible(void *pItem)
|
||||
{
|
||||
//DBG("EnsureVisible: %s\n", pVisGroup->GetName());
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
CTreeCtrl::EnsureVisible(hItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::ExpandRecursive(HTREEITEM hItem)
|
||||
{
|
||||
if (hItem)
|
||||
{
|
||||
Expand(hItem, TVE_EXPAND);
|
||||
|
||||
if (ItemHasChildren(hItem))
|
||||
{
|
||||
HTREEITEM hChildItem = GetChildItem(hItem);
|
||||
while (hChildItem != NULL)
|
||||
{
|
||||
ExpandRecursive(hChildItem);
|
||||
hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::ExpandAll()
|
||||
{
|
||||
HTREEITEM hItem = GetRootItem();
|
||||
while (hItem)
|
||||
{
|
||||
ExpandRecursive(hItem);
|
||||
hItem = GetNextItem(hItem, TVGN_NEXT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::ExpandItem(void *pItem)
|
||||
{
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
Expand(hItem, TVE_EXPAND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::CollapseItem(void *pItem)
|
||||
{
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
Expand(hItem, TVE_COLLAPSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the HTREEITEM in the given subtree associated with the given
|
||||
// item pointer, NULL if none.
|
||||
//-----------------------------------------------------------------------------
|
||||
HTREEITEM CTreeList::FindHTreeItemRecursive(HTREEITEM hItem, void *pItem)
|
||||
{
|
||||
if (hItem)
|
||||
{
|
||||
void *pItemCheck = (void *)GetItemData(hItem);
|
||||
if (pItemCheck == pItem)
|
||||
{
|
||||
return hItem;
|
||||
}
|
||||
|
||||
if (ItemHasChildren(hItem))
|
||||
{
|
||||
HTREEITEM hChildItem = GetChildItem(hItem);
|
||||
while (hChildItem != NULL)
|
||||
{
|
||||
HTREEITEM hFoundItem = FindHTreeItemRecursive(hChildItem, pItem);
|
||||
if (hFoundItem)
|
||||
{
|
||||
return hFoundItem;
|
||||
}
|
||||
|
||||
hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the HTREEITEM associated with the given item pointer, NULL if none.
|
||||
//-----------------------------------------------------------------------------
|
||||
HTREEITEM CTreeList::FindHTreeItem(void *pItem)
|
||||
{
|
||||
HTREEITEM hItem = GetRootItem();
|
||||
while (hItem)
|
||||
{
|
||||
HTREEITEM hFound = FindHTreeItemRecursive(hItem, pItem);
|
||||
if (hFound)
|
||||
{
|
||||
return hFound;
|
||||
}
|
||||
|
||||
hItem = GetNextItem(hItem, TVGN_NEXT);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CTreeList::GetSelectedItem()
|
||||
{
|
||||
HTREEITEM hItem = CTreeCtrl::GetSelectedItem();
|
||||
if (hItem)
|
||||
{
|
||||
return (void *)GetItemData(hItem);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int CTreeList::GetSelectedIndex()
|
||||
{
|
||||
int nItem = -1;
|
||||
|
||||
void *pItem = GetSelectedItem();
|
||||
if ( pItem )
|
||||
{
|
||||
for ( int i = 0; i < m_Items.Count(); i++ )
|
||||
{
|
||||
if ( m_Items[i] == pItem )
|
||||
{
|
||||
nItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nItem;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnLButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
unsigned int uFlags;
|
||||
HTREEITEM hItemHit = HitTest(point, &uFlags);
|
||||
if (hItemHit != NULL)
|
||||
{
|
||||
if (uFlags & TVHT_ONITEMSTATEICON)
|
||||
{
|
||||
// Don't forward to the base if they clicked on the check box.
|
||||
// This prevents undesired expansion/collapse of tree.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CTreeCtrl::OnLButtonDown(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnLButtonUp(UINT nFlags, CPoint point)
|
||||
{
|
||||
KillTimer(TIMER_GROUP_DRAG_SCROLL);
|
||||
ReleaseCapture();
|
||||
|
||||
if (!m_hDragItem)
|
||||
{
|
||||
unsigned int uFlags;
|
||||
HTREEITEM hItemHit = HitTest(point, &uFlags);
|
||||
if (hItemHit != NULL)
|
||||
{
|
||||
if (uFlags & TVHT_ONITEMSTATEICON)
|
||||
{
|
||||
//
|
||||
// Notify our parent window that this item's state has changed.
|
||||
//
|
||||
CWnd *pwndParent = GetParent();
|
||||
if (pwndParent != NULL)
|
||||
{
|
||||
// TODO: might need a way to cycle through three states: on, off, grey
|
||||
int nCheckState = GetCheck(hItemHit);
|
||||
if (!nCheckState)
|
||||
{
|
||||
nCheckState = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCheckState = 0;
|
||||
}
|
||||
|
||||
void *pItem = (void *)GetItemData(hItemHit);
|
||||
pwndParent->PostMessage(g_uToggleStateMsg, (WPARAM)pItem, nCheckState);
|
||||
}
|
||||
|
||||
// Don't forward to the base if they clicked on the check box.
|
||||
// This prevents undesired expansion/collapse of tree.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CTreeCtrl::OnLButtonUp(nFlags, point);
|
||||
return;
|
||||
}
|
||||
|
||||
Drop(DROP_LEFT, nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnLButtonDblClk(UINT nFlags, CPoint point)
|
||||
{
|
||||
unsigned int uFlags;
|
||||
HTREEITEM hItemHit = HitTest(point, &uFlags);
|
||||
if (hItemHit != NULL)
|
||||
{
|
||||
if (uFlags & TVHT_ONITEMICON)
|
||||
{
|
||||
// Don't forward to the base if they clicked on the check box.
|
||||
// This prevents undesired expansion/collapse of tree.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CTreeCtrl::OnLButtonDblClk(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forwards selection change notifications to our parent window.
|
||||
// pNMHDR -
|
||||
// pResult -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
CWnd *pwndParent = GetParent();
|
||||
if (pwndParent != NULL)
|
||||
{
|
||||
pwndParent->PostMessage( g_uSelChangeMsg, (WPARAM)GetDlgCtrlID(), 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnEndLabelEdit(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
NMTVDISPINFO *pInfo = (NMTVDISPINFO *)pNMHDR;
|
||||
if (!pInfo->item.pszText)
|
||||
return;
|
||||
|
||||
void *pItem = (void *)GetItemData(pInfo->item.hItem);
|
||||
Assert(pItem);
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
OnRenameItem(pItem, pInfo->item.pszText);
|
||||
|
||||
pResult[0] = TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Begins dragging an item in the tree list. The drag image is
|
||||
// created and anchored relative to the mouse cursor.
|
||||
// pNMHDR -
|
||||
// pResult -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
{
|
||||
NMTREEVIEW *ptv = (NMTREEVIEW *)pNMHDR;
|
||||
BeginDrag(ptv->ptDrag, ptv->itemNew.hItem);
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnKeyDown( NMHDR *pNMHDR, LRESULT *pResult )
|
||||
{
|
||||
NMTVKEYDOWN *pKeyDown = (NMTVKEYDOWN *)pNMHDR;
|
||||
CWnd *pwndParent = GetParent();
|
||||
if (pwndParent != NULL)
|
||||
{
|
||||
pwndParent->PostMessage(g_uKeyDownMsg, (WPARAM)pKeyDown->wVKey, (LPARAM)pKeyDown->flags);
|
||||
}
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::BeginDrag(CPoint point, HTREEITEM hItem)
|
||||
{
|
||||
m_hDragItem = hItem;
|
||||
if (m_hDragItem)
|
||||
{
|
||||
m_pDragImageList = CreateDragImage(m_hDragItem);
|
||||
if (m_pDragImageList)
|
||||
{
|
||||
CPoint ptHotSpot(0, 0);
|
||||
m_pDragImageList->BeginDrag(0, ptHotSpot);
|
||||
m_pDragImageList->DragEnter(this, point);
|
||||
SelectDropTarget(NULL);
|
||||
}
|
||||
|
||||
// Timer handles scrolling the list control when dragging outside the window bounds.
|
||||
SetTimer(TIMER_GROUP_DRAG_SCROLL, 300, NULL);
|
||||
|
||||
SetCapture();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnRButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
m_bRButtonDown = true;
|
||||
m_ptRButtonDown = point;
|
||||
m_hDragItem = NULL;
|
||||
SetCapture();
|
||||
|
||||
// Chaining to the base class causes us never to receive the button up message
|
||||
// for a right click without drag, so we don't do that.
|
||||
//CTreeCtrl::OnRButtonDown(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnContextMenu(CWnd *pWnd, CPoint point)
|
||||
{
|
||||
KillTimer(TIMER_GROUP_DRAG_SCROLL);
|
||||
ReleaseCapture();
|
||||
|
||||
m_bRButtonDown = false;
|
||||
|
||||
if (!m_hDragItem)
|
||||
{
|
||||
// TODO: Need to invoke the correct context menu for this tree list. Currently no one uses this.
|
||||
CTreeCtrl::OnContextMenu(pWnd, point);
|
||||
return;
|
||||
}
|
||||
|
||||
Drop(DROP_RIGHT, 0, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnRButtonUp(UINT nFlags, CPoint point)
|
||||
{
|
||||
KillTimer(TIMER_GROUP_DRAG_SCROLL);
|
||||
ReleaseCapture();
|
||||
|
||||
m_bRButtonDown = false;
|
||||
|
||||
if (!m_hDragItem)
|
||||
{
|
||||
CTreeCtrl::OnRButtonUp(nFlags, point);
|
||||
return;
|
||||
}
|
||||
|
||||
Drop(DROP_RIGHT, nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : eDropType -
|
||||
// nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::Drop(DropType_t eDropType, UINT nFlags, CPoint point)
|
||||
{
|
||||
SelectDropTarget(NULL);
|
||||
|
||||
HTREEITEM hDragItem = m_hDragItem;
|
||||
m_hDragItem = NULL;
|
||||
|
||||
//
|
||||
// We are dragging. Drop!
|
||||
//
|
||||
if (m_pDragImageList)
|
||||
{
|
||||
m_pDragImageList->DragLeave(this);
|
||||
m_pDragImageList->EndDrag();
|
||||
delete m_pDragImageList;
|
||||
m_pDragImageList = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the group that we were dragging.
|
||||
//
|
||||
void *pDragItem = (void *)GetItemData(hDragItem);
|
||||
|
||||
//
|
||||
// Determine what group was dropped onto.
|
||||
//
|
||||
HTREEITEM hDropItem = HitTest(point);
|
||||
if (hDropItem == hDragItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *pDropItem = NULL;
|
||||
if (hDropItem)
|
||||
{
|
||||
pDropItem = (void *)GetItemData(hDropItem);
|
||||
}
|
||||
|
||||
if (pDragItem == pDropItem)
|
||||
{
|
||||
// Shouldn't happen, but just in case.
|
||||
return;
|
||||
}
|
||||
|
||||
CWnd *pwndParent = GetParent();
|
||||
if (pwndParent != NULL)
|
||||
{
|
||||
if (eDropType == DROP_LEFT)
|
||||
{
|
||||
pwndParent->PostMessage(g_uLeftDragDropMsg, (WPARAM)pDragItem, (LPARAM)pDropItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
pwndParent->PostMessage(g_uRightDragDropMsg, (WPARAM)pDragItem, (LPARAM)pDropItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nIDEvent -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnTimer(UINT nIDEvent)
|
||||
{
|
||||
//DBG("OnTimer\n");
|
||||
switch (nIDEvent)
|
||||
{
|
||||
case TIMER_GROUP_DRAG_SCROLL:
|
||||
{
|
||||
CPoint point;
|
||||
GetCursorPos(&point);
|
||||
|
||||
CRect rect;
|
||||
GetWindowRect(&rect);
|
||||
|
||||
if (!rect.PtInRect(point))
|
||||
{
|
||||
if (point.y > rect.bottom)
|
||||
{
|
||||
// scroll down
|
||||
int nCount = GetVisibleCount();
|
||||
HTREEITEM hItem = GetFirstVisibleItem();
|
||||
for (int i = 1; i < nCount; i++)
|
||||
{
|
||||
hItem = GetNextVisibleItem(hItem);
|
||||
}
|
||||
|
||||
hItem = GetNextVisibleItem(hItem);
|
||||
|
||||
if (hItem)
|
||||
{
|
||||
CTreeCtrl::EnsureVisible(hItem);
|
||||
}
|
||||
}
|
||||
else if (point.y < rect.top)
|
||||
{
|
||||
HTREEITEM hItem = GetFirstVisibleItem();
|
||||
HTREEITEM hPrevVisible = this->GetPrevVisibleItem(hItem);
|
||||
if (hPrevVisible)
|
||||
{
|
||||
// scroll up
|
||||
CTreeCtrl::EnsureVisible(hPrevVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
CTreeCtrl::OnTimer(nIDEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::OnMouseMove(UINT nFlags, CPoint point)
|
||||
{
|
||||
CTreeCtrl::OnMouseMove(nFlags, point);
|
||||
|
||||
if (m_bRButtonDown && !m_hDragItem && (point.x != m_ptRButtonDown.x) && (point.y != m_ptRButtonDown.y))
|
||||
{
|
||||
// First mouse move since a right button down. Start dragging.
|
||||
HTREEITEM hItem = HitTest(m_ptRButtonDown);
|
||||
BeginDrag(point, hItem);
|
||||
}
|
||||
|
||||
if (!m_hDragItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pDragImageList)
|
||||
{
|
||||
m_pDragImageList->DragMove(point);
|
||||
}
|
||||
|
||||
//
|
||||
// Highlight the item we hit.
|
||||
//
|
||||
HTREEITEM hItem = HitTest(point);
|
||||
if (hItem == GetDropHilightItem())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// hide image first
|
||||
if (m_pDragImageList)
|
||||
{
|
||||
m_pDragImageList->DragLeave(this);
|
||||
m_pDragImageList->DragShowNolock(FALSE);
|
||||
}
|
||||
|
||||
SelectDropTarget(hItem);
|
||||
|
||||
if (m_pDragImageList)
|
||||
{
|
||||
m_pDragImageList->DragEnter(this, point);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::SelectItem(void *pItem)
|
||||
{
|
||||
//DBG("SelectTreeListItem: %s\n", pVisGroup->GetName());
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
Select(hItem, TVGN_CARET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::SelectNearestItem( int nItem )
|
||||
{
|
||||
if ( ( m_Items.Count() > 0 ) && ( m_Items.Count() <= nItem ) )
|
||||
{
|
||||
nItem = m_Items.Count() - 1;
|
||||
}
|
||||
|
||||
if ( m_Items.IsValidIndex( nItem ) )
|
||||
{
|
||||
SelectItem( m_Items[nItem] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::EnsureVisible( int nItem )
|
||||
{
|
||||
if ( ( m_Items.Count() > 0 ) && ( m_Items.Count() <= nItem ) )
|
||||
{
|
||||
nItem = m_Items.Count() - 1;
|
||||
}
|
||||
|
||||
if ( m_Items.IsValidIndex( nItem ) )
|
||||
{
|
||||
EnsureVisible( m_Items[nItem] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the check status for the given item.
|
||||
// pItem -
|
||||
// nCheckState - 0=not checked, 1=checked, -1=gray check (undefined)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::SetCheck(void *pItem, int nCheckState)
|
||||
{
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
UINT uState = INDEXTOSTATEIMAGEMASK(1);
|
||||
if (nCheckState == 1)
|
||||
{
|
||||
uState = INDEXTOSTATEIMAGEMASK(2);
|
||||
}
|
||||
else if (nCheckState != 0)
|
||||
{
|
||||
uState = INDEXTOSTATEIMAGEMASK(3);
|
||||
}
|
||||
|
||||
SetItemState(hItem, uState, TVIS_STATEIMAGEMASK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the check state for the given item.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CTreeList::GetCheck(void *pItem)
|
||||
{
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
return GetCheck(hItem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int CTreeList::GetCheck(HTREEITEM hItem)
|
||||
{
|
||||
UINT uState = (GetItemState(hItem, TVIS_STATEIMAGEMASK) & TVIS_STATEIMAGEMASK);
|
||||
if (uState == INDEXTOSTATEIMAGEMASK(2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (uState == INDEXTOSTATEIMAGEMASK(1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the number of visgroups in the whole tree.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CTreeList::GetItemCount()
|
||||
{
|
||||
return m_Items.Count();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CTreeList::GetItem(int nIndex)
|
||||
{
|
||||
return m_Items.Element(nIndex);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Updates the tree control item text with the new group name.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::UpdateItem(void *pItem, const char *pszText)
|
||||
{
|
||||
HTREEITEM hItem = FindHTreeItem(pItem);
|
||||
if (hItem)
|
||||
{
|
||||
SetItemText(hItem, pszText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stores the expanded/collapsed state into a data member for retrieval later.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::SaveTreeListExpandStates()
|
||||
{
|
||||
for ( int i = 0; i < GetItemCount(); i++ )
|
||||
{
|
||||
void *pItem = GetItem(i);
|
||||
TreeListItemState_t newState;
|
||||
for ( int j = 0; j < m_ItemState.Count(); j++ )
|
||||
{
|
||||
TreeListItemState_t thisPair = m_ItemState.Element( j );
|
||||
if ( pItem == thisPair.pItem )
|
||||
{
|
||||
m_ItemState.Remove( j );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HTREEITEM hItem = FindHTreeItem( pItem );
|
||||
newState.pItem = pItem;
|
||||
newState.bExpanded = false;
|
||||
if ( hItem && (GetItemState( hItem, TVIS_EXPANDED) & TVIS_EXPANDED) )
|
||||
{
|
||||
newState.bExpanded = true;
|
||||
}
|
||||
m_ItemState.AddToTail( newState );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTreeList::RestoreTreeListExpandStates()
|
||||
{
|
||||
ExpandAll();
|
||||
for ( int i = 0; i < m_ItemState.Count(); i++ )
|
||||
{
|
||||
TreeListItemState_t thisPair = m_ItemState.Element( i );
|
||||
HTREEITEM thisItem = FindHTreeItem( thisPair.pItem );
|
||||
if ( thisItem )
|
||||
{
|
||||
if ( thisPair.bExpanded )
|
||||
{
|
||||
Expand(thisItem, TVE_EXPAND);
|
||||
}
|
||||
else
|
||||
{
|
||||
Expand( thisItem, TVE_COLLAPSE );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user