| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "Win32/BsWin32DropTarget.h"
- #include "Win32/BsWin32Platform.h"
- #include "Platform/BsDropTarget.h"
- namespace bs
- {
- DropTarget::DropTarget(const RenderWindow* ownerWindow, const Rect2I& area)
- :mArea(area), mActive(false), mOwnerWindow(ownerWindow), mDropType(DropTargetType::None)
- {
- Win32Platform::registerDropTarget(this);
- }
- DropTarget::~DropTarget()
- {
- Win32Platform::unregisterDropTarget(this);
- _clear();
- }
- void DropTarget::setArea(const Rect2I& area)
- {
- mArea = area;
- }
- Win32DropTarget::Win32DropTarget(HWND hWnd)
- :mRefCount(1), mHWnd(hWnd), mAcceptDrag(false)
- { }
- Win32DropTarget::~Win32DropTarget()
- {
- Lock lock(mSync);
- for(auto& fileList : mFileLists)
- bs_delete(fileList);
- mFileLists.clear();
- mQueuedDropOps.clear();
- }
- void Win32DropTarget::registerWithOS()
- {
- CoLockObjectExternal(this, TRUE, FALSE);
- RegisterDragDrop(mHWnd, this);
- }
- void Win32DropTarget::unregisterWithOS()
- {
- RevokeDragDrop(mHWnd);
- CoLockObjectExternal(this, FALSE, FALSE);
- }
- HRESULT __stdcall Win32DropTarget::QueryInterface(REFIID iid, void** ppvObject)
- {
- if(iid == IID_IDropTarget || iid == IID_IUnknown)
- {
- AddRef();
- *ppvObject = this;
- return S_OK;
- }
- else
- {
- *ppvObject = nullptr;
- return E_NOINTERFACE;
- }
- }
- ULONG __stdcall Win32DropTarget::AddRef()
- {
- return InterlockedIncrement(&mRefCount);
- }
- ULONG __stdcall Win32DropTarget::Release()
- {
- LONG count = InterlockedDecrement(&mRefCount);
- if(count == 0)
- {
- bs_delete(this);
- return 0;
- }
- else
- {
- return count;
- }
- }
- HRESULT __stdcall Win32DropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
- {
- *pdwEffect = DROPEFFECT_LINK;
- mAcceptDrag = isDataValid(pDataObj);
- if(!mAcceptDrag)
- return S_OK;
- {
- Lock lock(mSync);
- mFileLists.push_back(getFileListFromData(pDataObj));
- ScreenToClient(mHWnd, (POINT *)&pt);
- mQueuedDropOps.push_back(DropTargetOp(DropOpType::DragOver, Vector2I((int)pt.x, (int)pt.y)));
- DropTargetOp& op = mQueuedDropOps.back();
- op.dataType = DropOpDataType::FileList;
- op.mFileList = mFileLists.back();
- }
- return S_OK;
- }
- HRESULT __stdcall Win32DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
- {
- *pdwEffect = DROPEFFECT_LINK;
- if(!mAcceptDrag)
- return S_OK;
- {
- Lock lock(mSync);
- ScreenToClient(mHWnd, (POINT *)&pt);
- mQueuedDropOps.push_back(DropTargetOp(DropOpType::DragOver, Vector2I((int)pt.x, (int)pt.y)));
- DropTargetOp& op = mQueuedDropOps.back();
- op.dataType = DropOpDataType::FileList;
- op.mFileList = mFileLists.back();
- }
- return S_OK;
- }
- HRESULT __stdcall Win32DropTarget::DragLeave()
- {
- {
- Lock lock(mSync);
- mQueuedDropOps.push_back(DropTargetOp(DropOpType::Leave, Vector2I()));
- DropTargetOp& op = mQueuedDropOps.back();
- op.dataType = DropOpDataType::FileList;
- op.mFileList = mFileLists.back();
- }
- return S_OK;
- }
- HRESULT __stdcall Win32DropTarget::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
- {
- *pdwEffect = DROPEFFECT_LINK;
- mAcceptDrag = false;
- if(!isDataValid(pDataObj))
- return S_OK;
- {
- Lock lock(mSync);
- mFileLists.push_back(getFileListFromData(pDataObj));
- ScreenToClient(mHWnd, (POINT *)&pt);
- mQueuedDropOps.push_back(DropTargetOp(DropOpType::Drop, Vector2I((int)pt.x, (int)pt.y)));
- DropTargetOp& op = mQueuedDropOps.back();
- op.dataType = DropOpDataType::FileList;
- op.mFileList = mFileLists.back();
- }
- return S_OK;
- }
- void Win32DropTarget::registerDropTarget(DropTarget* dropTarget)
- {
- mDropTargets.push_back(dropTarget);
- }
- void Win32DropTarget::unregisterDropTarget(DropTarget* dropTarget)
- {
- auto findIter = std::find(begin(mDropTargets), end(mDropTargets), dropTarget);
- if(findIter != mDropTargets.end())
- mDropTargets.erase(findIter);
- }
- unsigned int Win32DropTarget::getNumDropTargets() const
- {
- return (unsigned int)mDropTargets.size();
- }
- void Win32DropTarget::update()
- {
- Lock lock(mSync);
- for(auto& op: mQueuedDropOps)
- {
- for(auto& target : mDropTargets)
- {
- if(op.type != DropOpType::Leave)
- {
- if(target->_isInside(op.position))
- {
- if(!target->_isActive())
- {
- target->_setFileList(*op.mFileList);
- target->_setActive(true);
- target->onEnter(op.position.x, op.position.y);
- }
- if(op.type == DropOpType::DragOver)
- target->onDragOver(op.position.x, op.position.y);
- else if(op.type == DropOpType::Drop)
- {
- target->_setFileList(*op.mFileList);
- target->onDrop(op.position.x, op.position.y);
- }
- }
- else
- {
- if(target->_isActive())
- {
- target->onLeave();
- target->_clear();
- target->_setActive(false);
- }
- }
- }
- else
- {
- if(target->_isActive())
- {
- target->onLeave();
- target->_clear();
- target->_setActive(false);
- }
- }
- }
- if(op.type == DropOpType::Leave || op.type == DropOpType::Drop)
- {
- while (!mFileLists.empty())
- {
- bool done = mFileLists[0] == op.mFileList;
- bs_delete(mFileLists[0]);
- mFileLists.erase(mFileLists.begin());
- if (done)
- break;
- }
- }
- }
- mQueuedDropOps.clear();
- }
- bool Win32DropTarget::isDataValid(IDataObject* data)
- {
- // TODO - Currently only supports file drag and drop, so only CF_HDROP is used
- FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
- return data->QueryGetData(&fmtetc) == S_OK ? true : false;
- }
- /** Gets a file list from data. Caller must ensure that the data actually contains a file list. */
- Vector<Path>* Win32DropTarget::getFileListFromData(IDataObject* data)
- {
- FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
- STGMEDIUM stgmed;
- Vector<Path>* files = bs_new<Vector<Path>>();
- if(data->GetData(&fmtetc, &stgmed) == S_OK)
- {
- PVOID data = GlobalLock(stgmed.hGlobal);
- HDROP hDrop = (HDROP)data;
- UINT numFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
- files->resize(numFiles);
- for(UINT i = 0; i < numFiles; i++)
- {
- UINT numChars = DragQueryFileW(hDrop, i, nullptr, 0) + 1;
- wchar_t* buffer = (wchar_t*)bs_alloc((UINT32)numChars * sizeof(wchar_t));
- DragQueryFileW(hDrop, i, buffer, numChars);
- (*files)[i] = WString(buffer);
- bs_free(buffer);
- }
- GlobalUnlock(stgmed.hGlobal);
- ReleaseStgMedium(&stgmed);
- }
- return files;
- }
- }
|