X-Git-Url: http://git.jankratochvil.net/?p=reactos.git;a=blobdiff_plain;f=subsys%2Fsystem%2Fexplorer%2FSeashell%2FSeaShellExt%2FUIDragDropTree.cpp;fp=subsys%2Fsystem%2Fexplorer%2FSeashell%2FSeaShellExt%2FUIDragDropTree.cpp;h=39e434aabf345d6170b7cafff207c4a5ce61b419;hp=0000000000000000000000000000000000000000;hb=ee8b63255465d8c28be3e7bd11628015708fc1ab;hpb=c99688ef1ab339c8746ecc385bde679623084c71 diff --git a/subsys/system/explorer/Seashell/SeaShellExt/UIDragDropTree.cpp b/subsys/system/explorer/Seashell/SeaShellExt/UIDragDropTree.cpp new file mode 100644 index 0000000..39e434a --- /dev/null +++ b/subsys/system/explorer/Seashell/SeaShellExt/UIDragDropTree.cpp @@ -0,0 +1,610 @@ +//******************************************************************************* +// COPYRIGHT NOTES +// --------------- +// You may use this source code, compile or redistribute it as part of your application +// for free. You cannot redistribute it as a part of a software development +// library without the agreement of the author. If the sources are +// distributed along with the application, you should leave the original +// copyright notes in the source code without any changes. +// This code can be used WITHOUT ANY WARRANTIES at your own risk. +// +// For the latest updates to this code, check this site: +// http://www.masmex.com +// after Sept 2000 +// +// Copyright(C) 2000 Philip Oldaker +//******************************************************************************* + +//////////////////////////////////////////////////////////////////////////////////////--*/ +// UIDragDropTree.cpp : implementation file +// + +#include "stdafx.h" +#include "UICtrl.h" +#include "UIDragDropTree.h" +#include "cbformats.h" +#include "UIRes.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +IMPLEMENT_DYNAMIC(CUIDragDropTree,CTreeCtrl) +///////////////////////////////////////////////// +// +// For OLE drag and drop +// +///////////////////////////////////////////////// +void CUI_TreeDropTarget::OnDragLeave(CWnd* pWnd) +{ + CUIDragDropTree *pTree = static_cast(pWnd); + if (pTree == NULL) + return; + pTree->KillDragTimer(); + pTree->SelectDropTarget(NULL); + CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd()); + Info.SetItem(pTree->GetDropHilightItem()); + BOOL bRet = pTree->SendMessage(WM_APP_OLE_DD_LEAVE,(WPARAM)&Info); + if (bRet == FALSE) + bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_LEAVE,(WPARAM)&Info); +} + +DROPEFFECT CUI_TreeDropTarget::OnDragEnter( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point ) +{ +// ASSERT_KINDOF(CUIDragDropTree,pWnd); + CUIDragDropTree *pTree = static_cast(pWnd); + if (pTree == NULL) + return DROPEFFECT_NONE; + ((CUIDragDropTree*)pWnd)->SetDragTimer(); + CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject); + m_dwEnterKeyboardState = dwKeyState; + Info.SetKeyboardState(dwKeyState); + Info.SetItem(pTree->GetDropHilightItem()); + BOOL bRet = pTree->SendMessage(WM_APP_OLE_DD_ENTER,(WPARAM)&Info); + if (bRet == FALSE) + bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_ENTER,(WPARAM)&Info); + return Info.GetDropEffect(); +} + +DROPEFFECT CUI_TreeDropTarget::OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point ) +{ + // disallow if the control key pressed + EraseOldImage(); + CUIDragDropTree *pTree = static_cast(pWnd); + if (pTree == NULL) + return DROPEFFECT_NONE; +// ASSERT_KINDOF(CUIDragDropTree,pWnd); + CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject); + m_dwKeyboardState = dwKeyState; + Info.SetKeyboardState(dwKeyState); + // WM_APP_OLE_DD_OVER message sent in SelectCurrentTarget + DROPEFFECT dropEffect = pTree->SelectCurrentTarget(&Info); + CUI_ImageDropTarget::OnDragOver(pWnd,pDataObject,dwKeyState,point); + return dropEffect; +} + +BOOL CUI_TreeDropTarget::OnDrop( CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point ) +{ + CUIDragDropTree *pTree = static_cast(pWnd); + if (pTree == NULL) + return FALSE; +// ASSERT_KINDOF(CUIDragDropTree,pWnd); + pTree->KillDragTimer(); + HTREEITEM hItem = pTree->GetDropHilightItem(); + BOOL bRet=FALSE; + if (hItem) + { + CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject); + Info.SetDropEffect(dropEffect); + Info.SetItem(hItem); + if (m_dwEnterKeyboardState & MK_RBUTTON) + m_dwKeyboardState |= MK_RBUTTON; + if (m_dwEnterKeyboardState & MK_LBUTTON) + m_dwKeyboardState |= MK_LBUTTON; + Info.SetKeyboardState(m_dwKeyboardState); + bRet = pTree->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info); + if (bRet == FALSE) + bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info); + } + pTree->SelectDropTarget(NULL); + return bRet; +} + +// During slow scroll, process every third message. +#define SLOWSCROLL_FREQUENCY 3 +///////////////////////////////////////////////////////////////////////////// +// CUIDragDropTree + +CUIDragDropTree::CUIDragDropTree(bool bDragDrop): m_nUpperYCoor(0), + m_nLowerYCoor(0), + m_nSlowScrollTimeout(0), + m_nTimerID(0), + m_bDragging(FALSE), + m_pImageList(NULL), + m_hitemDrag(NULL), + m_hitemDrop(NULL), + m_bDragDrop(bDragDrop), + m_bDropFiles(true) + +{ + m_nScrollBarSize = GetSystemMetrics( SM_CYHSCROLL ); + m_CopyMode = eDDCancel; +} + +CUIDragDropTree::~CUIDragDropTree() +{ +} + +void CUIDragDropTree::OnDropFile(HTREEITEM hItem,LPCTSTR pszFile,UINT nFlags) +{ +} + +BEGIN_MESSAGE_MAP(CUIDragDropTree, CTreeCtrl) + //{{AFX_MSG_MAP(CUIDragDropTree) + ON_NOTIFY_REFLECT_EX(TVN_BEGINDRAG, OnBegindrag) + ON_NOTIFY_REFLECT_EX(TVN_BEGINRDRAG, OnBeginRDrag) + ON_WM_TIMER() + ON_WM_RBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_DESTROY() + ON_WM_CREATE() + ON_WM_DROPFILES() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CUIDragDropTree message handlers +void CUIDragDropTree::OnDropFiles(HDROP hDropInfo) +{ + UINT wNumFilesDropped = DragQueryFile(hDropInfo, 0XFFFFFFFF, NULL, 0); + TCHAR szFile[MAX_PATH]; + UINT nLen; + UINT nFlags; + POINT pt; + ::DragQueryPoint(hDropInfo,&pt); + HTREEITEM hitemDrag = HitTest(CPoint(pt), &nFlags); + for(UINT i=0; i < wNumFilesDropped;i++) + { + nLen = DragQueryFile(hDropInfo,i,szFile,sizeof(szFile)/sizeof(TCHAR)); + if (nLen) + OnDropFile(hitemDrag,szFile,nFlags); + } +} + +BOOL CUIDragDropTree::OnBeginRDrag(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + return StartDragDrop(pNMTreeView); +} + +BOOL CUIDragDropTree::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; + return StartDragDrop(pNMTreeView); +} + +BOOL CUIDragDropTree::StartDragDrop(NM_TREEVIEW* pNMTreeView) +{ + if (GetDragDrop() == false || pNMTreeView->itemNew.hItem == GetRootItem()) + return FALSE; + // See if COM drag drop is implemented in this window or parent window + DWORD dwDragEffect = SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pNMTreeView,(LPARAM)&m_OleDataSource); + if (dwDragEffect == 0) + dwDragEffect = GetParent()->SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pNMTreeView,(LPARAM)&m_OleDataSource); + if (dwDragEffect) + { + CRect rcDrag; + m_hitemDrag = pNMTreeView->itemNew.hItem; + // Define starting rect + GetItemRect(pNMTreeView->itemNew.hItem,rcDrag,TRUE); + // Start the DragDrop + DWORD dwEffect = m_OleDataSource.DoDragDrop(dwDragEffect,rcDrag); + // Clear the cache + m_OleDataSource.Empty(); + } + else // otherwise start local drag drop + { + CPoint ptAction; + UINT nFlags; + + GetCursorPos(&ptAction); + ScreenToClient(&ptAction); + + m_bDragging = TRUE; + m_hitemDrag = HitTest(pNMTreeView->ptDrag, &nFlags); + m_hitemDrop = NULL; + + // Create drag image and begin dragging + m_pImageList = CreateDragImage(m_hitemDrag); + m_pImageList->BeginDrag(0, CPoint(0,0)); + m_pImageList->DragEnter(GetDesktopWindow(), ptAction); + SetCapture(); + + SetDragTimer(); + } + return TRUE; +} + +void CUIDragDropTree::SetDragTimer() +{ + // Set the timer to slow down the scrolling when the dragging cursor + // is close to the top/bottom border of the tree control + if (!m_nTimerID) + { + m_nTimerID = SetTimer(1, 75, NULL); + CRect rect; + GetClientRect(&rect); + ClientToScreen(&rect); + m_nUpperYCoor = rect.top; + m_nLowerYCoor = rect.bottom; + } +} + +void CUIDragDropTree::KillDragTimer() +{ + if (m_nTimerID) + { + KillTimer(m_nTimerID); + } + m_nTimerID = 0; + m_nUpperYCoor = 0; + m_nLowerYCoor = 0; + m_nSlowScrollTimeout = 0; +} + +void CUIDragDropTree::OnTimer(UINT nIDEvent) +{ + // TODO: Add your message handler code here and/or call default + if (nIDEvent != m_nTimerID) + { + CTreeCtrl::OnTimer(nIDEvent); + return; + } + + // Get the "current" mouse position + const MSG* pMessage; + CPoint ptMouse; + pMessage = GetCurrentMessage(); + ASSERT(pMessage); + ptMouse = pMessage->pt; + + // Move the ghost image + if (m_pImageList) + m_pImageList->DragMove(ptMouse); + + // Find out if scrolling is needed. + // Scrolling is not needed for example, if the dragging cursor is + // within the tree control itself + if(!NeedToScroll(ptMouse)) + { + CTreeCtrl::OnTimer(nIDEvent); + return; + } + if (!m_bDragging) + m_OleDropTarget.EraseOldImage(); + + // Refine the scrolling mode - + // Scroll Up/Down, Slow/Normal + int nScrollMode = RefineScrollMode(ptMouse); + + switch(nScrollMode) + { + case SCROLL_UP_SLOW: + case SCROLL_DOWN_SLOW: + if( m_nSlowScrollTimeout == 0) + SendMessage( WM_VSCROLL, + nScrollMode == SCROLL_UP_SLOW ? SB_LINEUP : SB_LINEDOWN); + m_nSlowScrollTimeout = ++m_nSlowScrollTimeout%SLOWSCROLL_FREQUENCY; + break; + case SCROLL_UP_NORMAL: + case SCROLL_DOWN_NORMAL: + SendMessage( WM_VSCROLL, + nScrollMode == SCROLL_UP_NORMAL ? SB_LINEUP : SB_LINEDOWN); + break; + default: + ASSERT(FALSE); + return; + break; + } + if (m_bDragging) + { + // Select the drop target + if (m_pImageList) + m_pImageList->DragLeave(this); + HTREEITEM hitem = GetFirstVisibleItem(); + + switch( nScrollMode ) + { + case SCROLL_UP_SLOW: + case SCROLL_UP_NORMAL: + { + SelectDropTarget(hitem); + m_hitemDrop = hitem; + break; + } + case SCROLL_DOWN_SLOW: + case SCROLL_DOWN_NORMAL: + { + // Get the last visible item in the control + int nCount = GetVisibleCount(); + for ( int i=0; iDragEnter(this, ptMouse); CTreeCtrl::OnTimer(nIDEvent); + } +} + +void CUIDragDropTree::OnRButtonUp(UINT nFlags, CPoint point) +{ + if (!m_bDragging) + return; + // Kill the timer and reset all variables + EndDragging(); + CMenu menu; + VERIFY(menu.LoadMenu(IDR_POPUPMENU_DRAGDROP)); + CMenu* pPopup = menu.GetSubMenu(0); + ASSERT(pPopup != NULL); + pPopup->SetDefaultItem(ID_POPUP_DD_MOVE); + CPoint pts(point); + ClientToScreen(&pts); + if (GetRDragMenu(pPopup)) + { + UINT nCmd = pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD, pts.x, pts.y,this); + if (nCmd == ID_POPUP_DD_MOVE) + { + OnButtonUp(true); + } + else if (nCmd == ID_POPUP_DD_COPY) + { + OnButtonUp(false); + } + } + else + { + // otherwise just move + OnButtonUp(true); + } + SelectDropTarget(NULL); + CTreeCtrl::OnRButtonUp(nFlags, point); +} + +void CUIDragDropTree::OnMouseMove(UINT nFlags, CPoint point) +{ + // TODO: Add your message handler code here and/or call default + HTREEITEM hItem; + UINT flags; + + if (!m_bDragging) + return; + CPoint ptScreen(point); + ClientToScreen(&ptScreen); + + m_pImageList->DragMove(ptScreen); + + m_pImageList->DragShowNolock(FALSE); + + if ((hItem = HitTest(point, &flags)) != NULL) + { + CDD_OleDropTargetInfo Info(this->GetSafeHwnd(),point,NULL); + Info.SetItem(hItem); + LRESULT lResult = SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)&Info); + if (lResult == 0) + { + lResult = GetParent()->SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)&Info); + } + if (lResult) + { + SelectDropTarget(hItem); + m_hitemDrop = hItem; + } + } + m_pImageList->DragShowNolock(TRUE); + + CTreeCtrl::OnMouseMove(nFlags, point); +} + +void CUIDragDropTree::OnButtonUp(bool bMove) +{ + if (!m_bDragging) + return; + EndDragging(); + if (m_hitemDrag && m_hitemDrag != m_hitemDrop && !IsChildNodeOf(m_hitemDrop, m_hitemDrag) && + GetParentItem(m_hitemDrag) != m_hitemDrop) + { + CDD_OleDropTargetInfo Info(GetSafeHwnd(),CPoint(),NULL); + Info.SetDropEffect(bMove ? DROPEFFECT_MOVE : DROPEFFECT_COPY); + Info.SetItem(m_hitemDrop); + LRESULT lResult = SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info); + if (lResult == 0) + lResult = GetParent()->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info); + } +} + +void CUIDragDropTree::EndDragging() +{ + if (!m_bDragging) + return; + m_bDragging = FALSE; + if (m_pImageList) + { + m_pImageList->DragLeave(this); + m_pImageList->EndDrag(); + } + delete m_pImageList; + m_pImageList = NULL; + ReleaseCapture(); + KillDragTimer(); +} + +void CUIDragDropTree::NewTransferItem(HTREEITEM hNewItem) +{ +} + +BOOL CUIDragDropTree::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop) +{ + TV_INSERTSTRUCT tvstruct; + TCHAR sztBuffer[256]; + HTREEITEM hNewItem, hFirstChild; + + // avoid an infinite recursion situation + tvstruct.item.hItem = hitemDrag; + tvstruct.item.cchTextMax = sizeof(sztBuffer)-1; + tvstruct.item.pszText = sztBuffer; + tvstruct.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_PARAM; + GetItem(&tvstruct.item); + tvstruct.hParent = hitemDrop; + tvstruct.hInsertAfter = TVI_SORT; + tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_PARAM; + hNewItem = InsertItem(&tvstruct); + NewTransferItem(hNewItem); + + while ((hFirstChild = GetChildItem(hitemDrag)) != NULL) + { + // recursively transfer all the items + TransferItem(hFirstChild, hNewItem); + // delete the first child and all its children + DeleteItem(hFirstChild); + } + return TRUE; +} + + + +BOOL CUIDragDropTree::NeedToScroll( CPoint ptMouse ) +{ + if (m_bDragging) + { + return ptMouse.y < m_nUpperYCoor || ptMouse.y > m_nLowerYCoor; + } + else + { + return ptMouse.y < m_nUpperYCoor+10 || ptMouse.y > m_nLowerYCoor-30; + } +} + + +CUIDragDropTree::SCROLLMODE CUIDragDropTree::RefineScrollMode( CPoint ptMouse ) +{ + int nYCoor = ptMouse.y; + CUIDragDropTree::SCROLLMODE nScrollMode; + + if (m_bDragging) + { + nScrollMode = nYCoor > m_nLowerYCoor + m_nScrollBarSize ? SCROLL_DOWN_NORMAL : + nYCoor > m_nLowerYCoor ? SCROLL_DOWN_SLOW : + nYCoor < m_nUpperYCoor - m_nScrollBarSize ? SCROLL_UP_NORMAL : + SCROLL_UP_SLOW; + } + else + { + nScrollMode = nYCoor > m_nLowerYCoor-30 ? SCROLL_DOWN_NORMAL : + nYCoor < m_nUpperYCoor-10 ? SCROLL_UP_NORMAL : SCROLL_UP_NORMAL; + } + return nScrollMode; +} + +BOOL CUIDragDropTree::IsChildNodeOf(HTREEITEM hitemChild, HTREEITEM hitemSuspectedParent) +{ + do + { + if (hitemChild == hitemSuspectedParent) + break; + } + while ((hitemChild = GetParentItem(hitemChild)) != NULL); + + return (hitemChild != NULL); +} + +void CUIDragDropTree::RegisterDropTarget() +{ + if (GetDragDrop()) + { + VERIFY(m_OleDropTarget.Register(this)); + if (GetDropFiles()) + DragAcceptFiles(); + } +} + +DROPEFFECT CUIDragDropTree::SelectCurrentTarget(CDD_OleDropTargetInfo *pInfo) +{ + HTREEITEM hItem; + UINT flags; + if ((hItem = HitTest(pInfo->GetPoint(), &flags)) != NULL) + { + // select it + SelectDropTarget(hItem); + // save it + m_hitemDrop = hItem; + // returns 1 if allowed + pInfo->SetItem(hItem); + LRESULT lResult = SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo); + if (lResult == 0) + { + lResult = GetParent()->SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo); + } + if (lResult) + { + if (::GetKeyState(VK_LCONTROL) < 0) + { + if (ItemHasChildren(hItem)) + { + Expand(hItem, TVE_EXPAND); + } + } + return pInfo->GetDropEffect(); + } + } + return DROPEFFECT_NONE; +} + +void CUIDragDropTree::OnDestroy() +{ + + CTreeCtrl::OnDestroy(); + + // TODO: Add your message handler code here + +} + +int CUIDragDropTree::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CTreeCtrl::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: Add your specialized creation code here + RegisterDropTarget(); + + return 0; +} + +bool CUIDragDropTree::GetRDragMenu(CMenu *pMenu) +{ + return true; +} + +void CUIDragDropTree::OnDDMove() +{ + m_CopyMode = eDDMove; +} + +void CUIDragDropTree::OnDDCopy() +{ + m_CopyMode = eDDCopy; +} + +void CUIDragDropTree::OnDDCancel() +{ + m_CopyMode = eDDCancel; +}