|
|
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include "debug.h"
#include "common.h"
#include "autoscrl.h"
#include "nsc.h"
// BUGBUG: do nothing for now
#define DAD_DragLeave()
#define DAD_DragEnterEx(hwndLock, pt)
#define DAD_ShowDragImage(f)
#define DAD_DragMove(pt)
typedef struct { // tdt
IDropTarget dtgt; UINT cRef;
NSC *pns;
RECT _rcLockWindow; HTREEITEM _htiCur; // current tree item (dragging over)
IDropTarget *_pdtgtCur; // current drop target
IDataObject *_pdtobjCur; // current data object
DWORD _dwEffectCur; // current drag effect
DWORD _dwEffectIn; // *pdwEffect passed-in on last Move/Enter
DWORD _grfKeyState; // cached key state
POINT _ptLast; // last dragged over position
DWORD _dwLastTime; AUTO_SCROLL_DATA asd; } CTreeDropTarget;
STDMETHODIMP CTreeDropTarget_QueryInterface(IDropTarget *pdtgt, REFIID riid, void **ppvObj) { CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
if (IsEqualIID(riid, &IID_IDropTarget) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = pdtgt; this->cRef++; return S_OK; }
*ppvObj = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CTreeDropTarget_AddRef(IDropTarget *pdtgt) { CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
this->cRef++; return this->cRef; }
void CTreeDropTarget_ReleaseDataObject(CTreeDropTarget *this) { if (this->_pdtobjCur) Release(this->_pdtobjCur);
this->_pdtobjCur = NULL; }
void CTreeDropTarget_ReleaseCurrentDropTarget(CTreeDropTarget *this) { if (this->_pdtgtCur) { this->_pdtgtCur->lpVtbl->DragLeave(this->_pdtgtCur); Release(this->_pdtgtCur); this->_pdtgtCur = NULL; this->_htiCur = NULL; } else { Assert(this->_htiCur == NULL); } }
STDMETHODIMP_(ULONG) CTreeDropTarget_Release(IDropTarget * pdtgt) { CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
this->cRef--; if (this->cRef > 0) return this->cRef;
AssertMsg(this->_pdtgtCur == NULL, "drag leave was not called properly");
// if above is true we can remove this...
CTreeDropTarget_ReleaseCurrentDropTarget(this);
LocalFree(this);
return 0; }
STDMETHODIMP CTreeDropTarget_DragEnter(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt); POINT pt; HWND hwndLock;
DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragEnter called"); CTreeDropTarget_ReleaseDataObject(this); this->_pdtobjCur = pdtobj; this->_grfKeyState = grfKeyState; AddRef(pdtobj); Assert(this->_pdtgtCur == NULL); Assert(this->_htiCur == NULL);
hwndLock = this->pns->hwndTree; // clip to this
GetWindowRect(hwndLock, &this->_rcLockWindow); pt.x = ptl.x-this->_rcLockWindow.left; pt.y = ptl.y-this->_rcLockWindow.top; DAD_DragEnterEx(hwndLock, pt);
this->_ptLast.x = this->_ptLast.y = 0x7ffffff; // set bogus position
return S_OK; }
STDMETHODIMP CTreeDropTarget_DragOver(IDropTarget *pdtgt, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { HRESULT hres = S_OK; CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt); TV_HITTESTINFO tvht; HTREEITEM htiNew; POINT pt = { ptl.x, ptl.y }; BOOL fSameImage = FALSE; DWORD dwEffectScroll = 0;
ScreenToClient(this->pns->hwndTree, &pt);
if (DAD_AutoScroll(this->pns->hwndTree, &this->asd, &pt)) dwEffectScroll = DROPEFFECT_SCROLL;
tvht.pt = pt;
htiNew = TreeView_HitTest(this->pns->hwndTree, &tvht);
// don't allow droping on the item being dragged
if (htiNew == this->pns->htiDragging) htiNew = NULL;
if (this->_htiCur != htiNew) { // change in target
this->_dwLastTime = GetTickCount(); // keep track for auto-expanding the tree
CTreeDropTarget_ReleaseCurrentDropTarget(this);
this->_dwEffectCur = 0; // assume error
DAD_ShowDragImage(FALSE);
TreeView_SelectDropTarget(this->pns->hwndTree, htiNew);
DAD_ShowDragImage(TRUE);
if (htiNew) { // get the drop target for the item we hit
LPITEMIDLIST pidl = _CacheParentShellFolder(this->pns, htiNew, NULL); if (pidl) { IShellFolder *psf = this->pns->psfCache;
AddRef(psf);
if (pidl->mkid.cb == 0) { hres = psf->lpVtbl->CreateViewObject(psf, this->pns->hwnd, &IID_IDropTarget, &this->_pdtgtCur); } else { UINT dwAttr = SFGAO_DROPTARGET;
hres = psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &dwAttr);
if (SUCCEEDED(hres) && (dwAttr & SFGAO_DROPTARGET)) { hres = psf->lpVtbl->GetUIObjectOf(psf, this->pns->hwnd, 1, &pidl, &IID_IDropTarget, NULL, &this->_pdtgtCur); } else { hres = E_INVALIDARG; } }
Release(psf); }
if (SUCCEEDED(hres)) { this->_htiCur = htiNew;
this->_dwEffectCur = *pdwEffect; // pdwEffect is In/Out
hres = this->_pdtgtCur->lpVtbl->DragEnter(this->_pdtgtCur, this->_pdtobjCur, grfKeyState, ptl, &this->_dwEffectCur); } } } else { // No target change
// auto expand the tree
if (this->_htiCur) { DWORD dwNow = GetTickCount();
if ((dwNow - this->_dwLastTime) >= 1000) { this->_dwLastTime = dwNow; DAD_ShowDragImage(FALSE); this->pns->fAutoExpanding = TRUE; TreeView_Expand(this->pns->hwndTree, this->_htiCur, TVE_EXPAND); this->pns->fAutoExpanding = FALSE; DAD_ShowDragImage(TRUE); } }
// maybe the key state changed
if ((this->_grfKeyState != grfKeyState) && this->_pdtgtCur) { this->_dwEffectCur = *pdwEffect; hres = this->_pdtgtCur->lpVtbl->DragOver(this->_pdtgtCur, grfKeyState, ptl, &this->_dwEffectCur); } else { fSameImage = TRUE; hres = S_OK; } }
DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget_DragOver (In=%x, Out=%x)", *pdwEffect, this->_dwEffectCur);
this->_grfKeyState = grfKeyState; *pdwEffect = this->_dwEffectCur | dwEffectScroll;
// We need pass pt relative to the locked window (not the client).
pt.x = ptl.x-this->_rcLockWindow.left; pt.y = ptl.y-this->_rcLockWindow.top;
if (!(fSameImage && this->_ptLast.x == pt.x && this->_ptLast.y == pt.y)) { DAD_DragMove(pt); this->_ptLast.x = pt.x; this->_ptLast.y = pt.y; }
return hres; }
STDMETHODIMP CTreeDropTarget_DragLeave(IDropTarget *pdtgt) { CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragLeave called"); CTreeDropTarget_ReleaseCurrentDropTarget(this); CTreeDropTarget_ReleaseDataObject(this);
DAD_DragLeave();
TreeView_SelectDropTarget(this->pns->hwndTree, NULL);
return S_OK; }
STDMETHODIMP CTreeDropTarget_Drop(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hres; CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
if (this->_pdtgtCur) { hres = this->_pdtgtCur->lpVtbl->Drop(this->_pdtgtCur, pdtobj, grfKeyState, pt, pdwEffect); } else { DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget::Drop - this->_pdtgtCur==NULL"); *pdwEffect = 0; hres = S_OK; }
CTreeDropTarget_DragLeave(pdtgt);
return hres; }
const IDropTargetVtbl c_CTreeDropTargetVtbl = { CTreeDropTarget_QueryInterface, CTreeDropTarget_AddRef, CTreeDropTarget_Release, CTreeDropTarget_DragEnter, CTreeDropTarget_DragOver, CTreeDropTarget_DragLeave, CTreeDropTarget_Drop };
HRESULT CTreeDropTarget_Create(NSC *pns, IDropTarget **ppdtgt) { CTreeDropTarget * this = LocalAlloc(LPTR, sizeof(CTreeDropTarget)); if (this) { this->dtgt.lpVtbl = (IDropTargetVtbl *)&c_CTreeDropTargetVtbl; this->cRef = 1; this->pns = pns;
*ppdtgt = &this->dtgt; return S_OK; }
*ppdtgt = NULL; return E_OUTOFMEMORY; }
void CTreeDropTarget_Register(NSC *pns) { IDropTarget *pdtgt;
if (SUCCEEDED(CTreeDropTarget_Create(pns, &pdtgt))) { RegisterDragDrop(pns->hwndTree, pdtgt); Release(pdtgt); } }
void CTreeDropTarget_Revoke(NSC *pns) { RevokeDragDrop(pns->hwndTree); }
|