// TreeCtrlEx.cpp : implementation file
//
#include "stdafx.h"
#include "exile.h"
#include "typedefs.h"
#include "messagebox.h"
#include "TreeCtrlEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTreeCtrlEx
CTreeCtrlEx::CTreeCtrlEx()
{
m_hDragging = 0;
m_pimgDrag = 0;
m_bDragging = FALSE;
}
CTreeCtrlEx::~CTreeCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CTreeCtrlEx, CTreeCtrl)
//{{AFX_MSG_MAP(CTreeCtrlEx)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTreeCtrlEx message handlers
void CTreeCtrlEx::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
// First off, do nothing if a root item is being dragged
if(0 == GetParentItem(hItem))
return;
// Creating drag image
m_pimgDrag = CreateDragImage(hItem);
if(0 == m_pimgDrag)
return;
// Item Hot-Spot - the location of the
// cursor relative to the upper-left corner of the item rectangle
CRect rc;
GetItemRect(hItem, rc, TRUE);
CPoint pt(pNMTreeView->ptDrag.x, pNMTreeView->ptDrag.y);
CPoint ptHotSpot(pt);
ptHotSpot.x -= rc.left;
ptHotSpot.y -= rc.top;
CPoint ptClient(0, 0);
ClientToScreen(&ptClient);
GetWindowRect(rc);
pt.x += ptClient.x - rc.left;
pt.y += ptClient.y - rc.top;
// Begin drag
SetCapture();
m_pimgDrag->BeginDrag(0, ptHotSpot);
m_pimgDrag->DragEnter(this, pt);
m_bDragging = TRUE;
m_hDragging = hItem;
// Dragged item
*pResult = 0;
}
void CTreeCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
CTreeCtrl::OnMouseMove(nFlags, point);
if((m_bDragging) && (m_pimgDrag))
{
m_pimgDrag->DragMove(point);
HTREEITEM hItem = GetDropTarget(point);
// Some visual feedback
::SetCursor(hItem ? (HCURSOR)::GetClassLong(m_hWnd, GCL_HCURSOR) :
LoadCursor(0, IDC_NO));
} // if
}
HTREEITEM CTreeCtrlEx::GetDropTarget(CPoint pt)
{
UINT uFlags;
HTREEITEM hItem = HitTest(pt, &uFlags);
// If this item is a drop target...
TV_ITEM tvi;
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
tvi.hItem = hItem;
if(GetItem(&tvi))
{
if(!IsDropTarget(tvi.lParam))
return (HTREEITEM)0;
m_pimgDrag->DragShowNolock(FALSE);
SelectDropTarget(hItem);
m_pimgDrag->DragShowNolock(TRUE);
return hItem;
} // if
return (HTREEITEM)0;
}
void CTreeCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
CTreeCtrl::OnLButtonUp(nFlags, point);
if((m_bDragging) && (m_pimgDrag))
{
// Release mouse and terminate dragging operation
m_pimgDrag->DragLeave(this);
m_pimgDrag->EndDrag();
::ReleaseCapture();
m_bDragging = FALSE;
SelectDropTarget(0);
// Cleanup
m_pimgDrag->DeleteImageList();
delete m_pimgDrag;
m_pimgDrag = 0;
// Get item handle
UINT uFlags;
HTREEITEM hItem = HitTest(point, &uFlags);
if(!hItem)
return;
// Some vaildation...
if(m_hDragging == hItem)
{
MessageBoxEx(GetSafeHwnd(), IDS_CANTDROPTOITSELF, IDS_TITLE);
return;
} // if
if(GetParentItem(m_hDragging) == hItem)
{
MessageBoxEx(GetSafeHwnd(), IDS_CANTDROPONPARENT, IDS_TITLE);
return;
} // if
if(IsChildOf(hItem, m_hDragging))
{
MessageBoxEx(GetSafeHwnd(), IDS_CANTDROPONCHILDREN, IDS_TITLE);
return;
} // if
MoveTree(hItem, m_hDragging);
m_hDragging = 0;
// Notifying parent about a successful (hopefully)
// drag operation
::SendMessage(GetParent()->GetSafeHwnd(), TCEX_ITEMDRAGGED, 0, 0);
} // if
}
BOOL CTreeCtrlEx::IsChildOf(const HTREEITEM hItem1, const HTREEITEM hItem2)
{
HTREEITEM hParent = hItem1;
hParent = GetParentItem(hParent);
while(hParent)
{
if(hItem2 == hParent)
return TRUE;
hParent = GetParentItem(hParent);
} // while
return FALSE;
}
void CTreeCtrlEx::MoveTree(HTREEITEM hDest, HTREEITEM hSrc)
{
CopyTree(hDest, hSrc);
DeleteItem(hSrc);
}
void CTreeCtrlEx::CopyTree(HTREEITEM hDest, HTREEITEM hSrc)
{
// Just transferring TV_ITEM
TV_ITEM tvi;
TV_INSERTSTRUCT tvIns;
TCHAR szBuffer[nNameLength];
tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_IMAGE | TVIF_HANDLE;
tvi.hItem = m_hDragging;
tvi.pszText = szBuffer;
tvi.cchTextMax = nNameLength;
if(!GetItem(&tvi))
return;
tvIns.hParent = hDest;
tvIns.hInsertAfter = TVI_LAST;
tvIns.item = tvi;
HTREEITEM hNew = InsertItem(&tvIns);
// Copy children if there are any
if(ItemHasChildren(hSrc))
{
CopyChildren(hNew, hSrc);
} // if
SelectItem(hNew);
}
void CTreeCtrlEx::CopyChildren(HTREEITEM hDest, HTREEITEM hSrc)
{
// Get first item
HTREEITEM hItem = GetChildItem(hSrc);
// Just transferring TV_ITEM
TV_ITEM tvi;
TV_INSERTSTRUCT tvIns;
TCHAR szBuffer[nNameLength];
tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_IMAGE | TVIF_HANDLE;
tvi.hItem = hItem;
tvi.pszText = szBuffer;
tvi.cchTextMax = nNameLength;
if(!GetItem(&tvi))
return;
tvIns.hParent = hDest;
tvIns.hInsertAfter = TVI_LAST;
tvIns.item = tvi;
HTREEITEM hNew = InsertItem(&tvIns);
// Copy all subitems (if there are any)
if(ItemHasChildren(hItem))
CopyChildren(hNew, hItem);
// Process all siblings
hItem = GetNextSiblingItem(hItem);
while(hItem)
{
tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_IMAGE | TVIF_HANDLE;
tvi.hItem = hItem;
tvi.pszText = szBuffer;
tvi.cchTextMax = nNameLength;
if(!GetItem(&tvi))
return;
tvIns.hParent = hDest;
tvIns.hInsertAfter = TVI_LAST;
tvIns.item = tvi;
hNew = InsertItem(&tvIns);
// Copy all subitems (if there are any)
if(ItemHasChildren(hItem))
CopyChildren(hNew, hItem);
hItem = GetNextSiblingItem(hItem);
} // while
}