treedragdrophelper.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 957 行 · 第 1/2 页
CPP
957 行
hItem = NULL;
m_dropPos.htiDrop = hItem;
m_dropPos.nWhere = nWhere;
// Highlight the item, or unhighlight all items if the cursor isn't
// over an item.
if (hItem)
{
if (nWhere == DD_ON)
{
m_tree.SetInsertMark(NULL);
m_tree.SelectDropTarget(hItem);
}
else
{
m_tree.SelectDropTarget(NULL);
m_tree.SetInsertMark(hItem, (nWhere == DD_BELOW));
}
}
else
{
m_tree.SetInsertMark(NULL);
m_tree.SelectDropTarget(NULL);
}
// Return the handle of the highlighted item.
return hItem;
}
void CTreeDragDropHelper::OnTimer(UINT nIDEvent)
{
TRACE ("CTreeDragDropHelper::OnTimer\n");
if (nIDEvent == m_nScrollTimer)
{
// Reset the timer
SetTimer(TIMER_SCROLL, SCROLL_INTERVAL);
// Get the current cursor position and window height.
CPoint point(::GetMessagePos());
ScreenToClient(m_tree, &point);
CRect rect;
m_tree.GetClientRect(rect);
int cy = rect.Height();
HTREEITEM hFirstVisible = m_tree.GetFirstVisibleItem();
// Scroll the window if the cursor is near the top or bottom.
m_ddMgr.DragShowNolock(FALSE);
if (point.y >= 0 && point.y <= SCROLL_MARGIN)
{
m_tree.SelectDropTarget(NULL);
m_tree.SetInsertMark(NULL);
m_tree.SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), NULL);
}
else if (point.y >= cy - SCROLL_MARGIN && point.y <= cy)
{
m_tree.SelectDropTarget(NULL);
m_tree.SetInsertMark(NULL);
m_tree.SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), NULL);
}
m_ddMgr.DragShowNolock(TRUE);
// Kill the timer if the window did not scroll
// redraw the drop target highlight regardless
if (m_tree.GetFirstVisibleItem() == hFirstVisible)
SetTimer(TIMER_SCROLL, 0);
HighlightDropTarget();
}
else if (nIDEvent == m_nExpandTimer)
{
// If the cursor is hovering over a collapsed item, expand the tree.
CPoint point(::GetMessagePos());
m_tree.ScreenToClient(&point);
DDWHERE nWhere;
HTREEITEM hItem = HitTest(point, nWhere);
if (hItem != NULL && nWhere == DD_ON && m_tree.ItemHasChildren(hItem) &&
!(m_tree.GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED))
{
m_ddMgr.DragShowNolock(FALSE);
m_tree.SelectDropTarget(NULL);
m_tree.SetInsertMark(NULL);
m_tree.Expand(hItem, TVE_EXPAND);
m_ddMgr.DragShowNolock(TRUE);
HighlightDropTarget();
SetTimer(TIMER_EXPAND, 0); // kill the timer
return;
}
}
}
VOID CALLBACK CTreeDragDropHelper::TimerProc(HWND /*hwnd*/, UINT /*uMsg*/, UINT idEvent, DWORD /*dwTime*/)
{
if (s_pTDDH)
s_pTDDH->OnTimer(idEvent); // pseudo message handler
}
HTREEITEM CTreeDragDropHelper::MoveTree(HTREEITEM hDest, HTREEITEM hSrc, DDWHERE nWhere)
{
CHoldRedraw hr(m_tree);
HTREEITEM htiNew = CopyTree(hDest, hSrc, nWhere);
m_tree.DeleteItem(hSrc);
return htiNew;
}
void CTreeDragDropHelper::BuildCopy(const HTREEITEM hti, TDDHCOPY* pCopy) const
{
pCopy->hti = hti;
pCopy->dwItemData = m_tree.GetItemData(hti);
HTREEITEM htiChild = m_tree.GetChildItem(hti);
while (htiChild)
{
TDDHCOPY htcChild;
BuildCopy(htiChild, &htcChild);
pCopy->childItems.Add(htcChild);
htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
}
}
HTREEITEM CTreeDragDropHelper::CopyTree(HTREEITEM hDest, const TDDHCOPY* pSrc, DDWHERE nWhere)
{
HTREEITEM hSrc = pSrc->hti;
// Get the attributes of item to be copied.
int nImage = I_IMAGECALLBACK, nSelectedImage = I_IMAGECALLBACK;
if (!m_bTreeUsesImageCallback)
m_tree.GetItemImage(hSrc, nImage, nSelectedImage);
CString sText = m_tree.GetItemText(hSrc);
LPSTR szText = m_bTreeUsesTextCallback ? LPSTR_TEXTCALLBACK : (LPSTR)(LPCTSTR)sText;
DWORD dwItemData = m_tree.GetItemData(hSrc);
UINT uState = m_tree.GetItemState(hSrc, TVIS_BOLD | TVIS_STATEIMAGEMASK);
UINT uMask = TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_TEXT;
HTREEITEM hParent = (nWhere != DD_ON) ? m_tree.GetParentItem(hDest) : hDest;
HTREEITEM hAfter = NULL;
if (nWhere == DD_ON)
hAfter = TVI_LAST;
else if (nWhere == DD_BELOW)
hAfter = hDest;
else // above
{
hAfter = m_tree.GetNextItem(hDest, TVGN_PREVIOUS);
if (!hAfter)
hAfter = TVI_FIRST;
}
// Create an exact copy of the item at the destination.
HTREEITEM hNewItem = m_tree.InsertItem(uMask, szText, nImage, nSelectedImage, uState,
TVIS_BOLD | TVIS_STATEIMAGEMASK, dwItemData, hParent, hAfter);
// copy children too
if (pSrc->childItems.GetSize())
{
for (int nChild = 0; nChild < pSrc->childItems.GetSize(); nChild++)
{
const TDDHCOPY& htcChild = pSrc->childItems[nChild];
CopyTree(hNewItem, &htcChild, DD_ON);
}
}
// restore the expanded state
if (m_tree.GetItemState(hSrc, TVIS_EXPANDED) & TVIS_EXPANDED)
m_tree.Expand(hNewItem, TVE_EXPAND);
else
m_tree.Expand(hNewItem, TVE_COLLAPSE);
return hNewItem;
}
HTREEITEM CTreeDragDropHelper::CopyTree(HTREEITEM hDest, HTREEITEM hSrc, DDWHERE nWhere)
{
TDDHCOPY htcSrc;
BuildCopy(hSrc, &htcSrc);
return CopyTree(hDest, &htcSrc, nWhere);
}
BOOL CTreeDragDropHelper::CanMoveItem(HTREEITEM hti, TDDH_MOVE nDirection) const
{
if (!hti)
return FALSE;
switch (nDirection)
{
case MOVE_DOWN:
return (m_tree.GetNextItem(hti, TVGN_NEXT) != NULL);
case MOVE_UP:
return (m_tree.GetNextItem(hti, TVGN_PREVIOUS) != NULL);
case MOVE_LEFT:
{
// must have a parent which will become its sibling
// and not the root
HTREEITEM htiParent = m_tree.GetParentItem(hti);
return (htiParent && htiParent != TVI_ROOT);
}
break;
case MOVE_RIGHT:
// must have a prior sibling (which will become the parent)
return CanMoveItem(hti, MOVE_UP);
}
return FALSE;
}
BOOL CTreeDragDropHelper::MoveSelection(TDDH_MOVE nDirection)
{
switch (nDirection)
{
case MOVE_DOWN:
return MoveSelectionDown();
case MOVE_UP:
return MoveSelectionUp();
case MOVE_LEFT:
return MoveSelectionLeft();
case MOVE_RIGHT:
return MoveSelectionRight();
}
return FALSE;
}
BOOL CTreeDragDropHelper::CanMoveSelection(TDDH_MOVE nDirection) const
{
if (!m_selection.GetCount() || !m_selection.ItemsAreAllSiblings())
return FALSE;
// must be able to move all items
POSITION pos = m_selection.GetFirstItemPos();
while (pos)
{
HTREEITEM hti = m_selection.GetNextItem(pos);
if (!CanMoveItem(hti, nDirection))
return FALSE;
}
return TRUE;
}
BOOL CTreeDragDropHelper::MoveSelectionDown()
{
if (CanMoveSelection(MOVE_DOWN))
{
// 0. save off the selection state so we can restore it after
HTREEITEM htiTreeSel, htiAnchor;
GetAnchorSel(htiAnchor, htiTreeSel);
// 1. sort items
m_selection.SortIfAllSiblings(FALSE);
// 2. move items as siblings after the item following the last item
CHTIList selection;
m_selection.CopySelection(selection);
m_selection.RemoveAll(TRUE, FALSE);
HTREEITEM htiNext = m_tree.GetNextItem(selection.GetTail(), TVGN_NEXT);
POSITION pos = selection.GetHeadPosition();
while (pos)
{
HTREEITEM htiSel = selection.GetNext(pos);
htiNext = CopyTree(htiNext, htiSel, DD_BELOW);
UpdateAnchorSel(htiSel, htiNext, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiSel);
m_selection.AddItem(htiNext, FALSE);
}
// 5. restore tree state
RestoreAnchorSel(htiAnchor, htiTreeSel);
return TRUE;
}
return FALSE;
}
BOOL CTreeDragDropHelper::MoveSelectionUp()
{
if (CanMoveSelection(MOVE_UP))
{
// 0. save off the selection state so we can restore it after
HTREEITEM htiTreeSel, htiAnchor;
GetAnchorSel(htiAnchor, htiTreeSel);
// 1. sort items
m_selection.SortIfAllSiblings(FALSE);
// 2. move first item before its preceding item
CHTIList selection;
m_selection.CopySelection(selection);
m_selection.RemoveAll(TRUE, FALSE);
POSITION pos = selection.GetHeadPosition();
HTREEITEM htiFirst = m_selection.GetNextItem(pos);
HTREEITEM htiPrev = m_tree.GetNextItem(htiFirst, TVGN_PREVIOUS);
HTREEITEM htiNew = CopyTree(htiPrev, htiFirst, DD_ABOVE);
if (htiNew)
{
UpdateAnchorSel(htiFirst, htiNew, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiFirst);
m_selection.AddItem(htiNew, FALSE);
// 3. copy rest of siblings after htiNew
while (pos)
{
HTREEITEM htiSel = selection.GetNext(pos);
htiNew = CopyTree(htiNew, htiSel, DD_BELOW);
UpdateAnchorSel(htiSel, htiNew, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiSel);
m_selection.AddItem(htiNew, FALSE);
}
// 5. restore tree state
RestoreAnchorSel(htiAnchor, htiTreeSel);
return TRUE;
}
}
return FALSE;
}
BOOL CTreeDragDropHelper::MoveSelectionLeft()
{
if (CanMoveSelection(MOVE_LEFT))
{
// 0. save off the selection state so we can restore it after
HTREEITEM htiTreeSel, htiAnchor;
GetAnchorSel(htiAnchor, htiTreeSel);
// 1. sort items
m_selection.SortIfAllSiblings(FALSE);
CHTIList selection;
m_selection.CopySelection(selection);
m_selection.RemoveAll(TRUE, FALSE);
// 2. copy the items as siblings of the parent of the first item
HTREEITEM htiPrev = m_tree.GetParentItem(selection.GetHead());
POSITION pos = selection.GetHeadPosition();
while (pos)
{
HTREEITEM htiSel = selection.GetNext(pos);
htiPrev = CopyTree(htiPrev, htiSel, DD_BELOW);
UpdateAnchorSel(htiSel, htiPrev, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiSel);
m_selection.AddItem(htiPrev, FALSE);
}
// 5. restore tree state
RestoreAnchorSel(htiAnchor, htiTreeSel);
return TRUE;
}
return FALSE;
}
BOOL CTreeDragDropHelper::MoveSelectionRight()
{
if (CanMoveSelection(MOVE_RIGHT))
{
// 0. save off the selection state so we can restore it after
HTREEITEM htiTreeSel, htiAnchor;
GetAnchorSel(htiAnchor, htiTreeSel);
// 1. sort items
m_selection.SortIfAllSiblings(FALSE);
CHTIList selection;
m_selection.CopySelection(selection);
m_selection.RemoveAll(TRUE, FALSE);
// 2. copy the first item as a child of its immediate sibling
POSITION pos = selection.GetHeadPosition();
HTREEITEM htiFirst = m_selection.GetNextItem(pos);
HTREEITEM htiParent = m_tree.GetNextItem(htiFirst, TVGN_PREVIOUS);
HTREEITEM htiNew = CopyTree(htiParent, htiFirst, DD_ON);
if (htiNew)
{
UpdateAnchorSel(htiFirst, htiNew, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiFirst);
m_selection.AddItem(htiNew, FALSE);
// 3. then copy the rest of the selection as siblings of the first
while (pos)
{
HTREEITEM htiSel = selection.GetNext(pos);
htiNew = CopyTree(htiNew, htiSel, DD_BELOW);
UpdateAnchorSel(htiSel, htiNew, htiAnchor, htiTreeSel);
m_tree.DeleteItem(htiSel);
m_selection.AddItem(htiNew, FALSE);
}
// 4. expand parent
m_tree.Expand(htiParent, TVE_EXPAND);
// 5. restore tree state
RestoreAnchorSel(htiAnchor, htiTreeSel);
return TRUE;
}
}
return FALSE;
}
void CTreeDragDropHelper::GetAnchorSel(HTREEITEM& htiAnchor, HTREEITEM& htiTreeSel) const
{
htiTreeSel = m_tree.GetSelectedItem();
htiAnchor = m_selection.GetAnchor();
}
void CTreeDragDropHelper::UpdateAnchorSel(HTREEITEM htiPrev, HTREEITEM htiNew,
HTREEITEM& htiAnchor, HTREEITEM& htiTreeSel) const
{
if (htiTreeSel == htiPrev)
htiTreeSel = htiNew;
if (htiAnchor == htiPrev)
htiAnchor = htiNew;
}
void CTreeDragDropHelper::RestoreAnchorSel(HTREEITEM htiAnchor, HTREEITEM htiTreeSel)
{
#ifdef _DEBUG
// DWORD dwIDAnchor = m_tree.GetItemData(htiAnchor);
// DWORD dwIDSel = m_tree.GetItemData(htiTreeSel);
#endif
m_tree.SelectItem(htiTreeSel);
m_selection.SetAnchor(htiAnchor);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?