BsWin32DropTarget.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Win32/BsWin32DropTarget.h"
  4. #include "Win32/BsWin32Platform.h"
  5. #include "Platform/BsDropTarget.h"
  6. namespace bs
  7. {
  8. DropTarget::DropTarget(const RenderWindow* ownerWindow, const Rect2I& area)
  9. :mArea(area), mActive(false), mOwnerWindow(ownerWindow), mDropType(DropTargetType::None)
  10. {
  11. Win32Platform::registerDropTarget(this);
  12. }
  13. DropTarget::~DropTarget()
  14. {
  15. Win32Platform::unregisterDropTarget(this);
  16. _clear();
  17. }
  18. void DropTarget::setArea(const Rect2I& area)
  19. {
  20. mArea = area;
  21. }
  22. Win32DropTarget::Win32DropTarget(HWND hWnd)
  23. :mRefCount(1), mHWnd(hWnd), mAcceptDrag(false)
  24. { }
  25. Win32DropTarget::~Win32DropTarget()
  26. {
  27. Lock lock(mSync);
  28. for(auto& fileList : mFileLists)
  29. bs_delete(fileList);
  30. mFileLists.clear();
  31. mQueuedDropOps.clear();
  32. }
  33. void Win32DropTarget::registerWithOS()
  34. {
  35. CoLockObjectExternal(this, TRUE, FALSE);
  36. RegisterDragDrop(mHWnd, this);
  37. }
  38. void Win32DropTarget::unregisterWithOS()
  39. {
  40. RevokeDragDrop(mHWnd);
  41. CoLockObjectExternal(this, FALSE, FALSE);
  42. }
  43. HRESULT __stdcall Win32DropTarget::QueryInterface(REFIID iid, void** ppvObject)
  44. {
  45. if(iid == IID_IDropTarget || iid == IID_IUnknown)
  46. {
  47. AddRef();
  48. *ppvObject = this;
  49. return S_OK;
  50. }
  51. else
  52. {
  53. *ppvObject = nullptr;
  54. return E_NOINTERFACE;
  55. }
  56. }
  57. ULONG __stdcall Win32DropTarget::AddRef()
  58. {
  59. return InterlockedIncrement(&mRefCount);
  60. }
  61. ULONG __stdcall Win32DropTarget::Release()
  62. {
  63. LONG count = InterlockedDecrement(&mRefCount);
  64. if(count == 0)
  65. {
  66. bs_delete(this);
  67. return 0;
  68. }
  69. else
  70. {
  71. return count;
  72. }
  73. }
  74. HRESULT __stdcall Win32DropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  75. {
  76. *pdwEffect = DROPEFFECT_LINK;
  77. mAcceptDrag = isDataValid(pDataObj);
  78. if(!mAcceptDrag)
  79. return S_OK;
  80. {
  81. Lock lock(mSync);
  82. mFileLists.push_back(getFileListFromData(pDataObj));
  83. ScreenToClient(mHWnd, (POINT *)&pt);
  84. mQueuedDropOps.push_back(DropTargetOp(DropOpType::DragOver, Vector2I((int)pt.x, (int)pt.y)));
  85. DropTargetOp& op = mQueuedDropOps.back();
  86. op.dataType = DropOpDataType::FileList;
  87. op.mFileList = mFileLists.back();
  88. }
  89. return S_OK;
  90. }
  91. HRESULT __stdcall Win32DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  92. {
  93. *pdwEffect = DROPEFFECT_LINK;
  94. if(!mAcceptDrag)
  95. return S_OK;
  96. {
  97. Lock lock(mSync);
  98. ScreenToClient(mHWnd, (POINT *)&pt);
  99. mQueuedDropOps.push_back(DropTargetOp(DropOpType::DragOver, Vector2I((int)pt.x, (int)pt.y)));
  100. DropTargetOp& op = mQueuedDropOps.back();
  101. op.dataType = DropOpDataType::FileList;
  102. op.mFileList = mFileLists.back();
  103. }
  104. return S_OK;
  105. }
  106. HRESULT __stdcall Win32DropTarget::DragLeave()
  107. {
  108. {
  109. Lock lock(mSync);
  110. mQueuedDropOps.push_back(DropTargetOp(DropOpType::Leave, Vector2I()));
  111. DropTargetOp& op = mQueuedDropOps.back();
  112. op.dataType = DropOpDataType::FileList;
  113. op.mFileList = mFileLists.back();
  114. }
  115. return S_OK;
  116. }
  117. HRESULT __stdcall Win32DropTarget::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  118. {
  119. *pdwEffect = DROPEFFECT_LINK;
  120. mAcceptDrag = false;
  121. if(!isDataValid(pDataObj))
  122. return S_OK;
  123. {
  124. Lock lock(mSync);
  125. mFileLists.push_back(getFileListFromData(pDataObj));
  126. ScreenToClient(mHWnd, (POINT *)&pt);
  127. mQueuedDropOps.push_back(DropTargetOp(DropOpType::Drop, Vector2I((int)pt.x, (int)pt.y)));
  128. DropTargetOp& op = mQueuedDropOps.back();
  129. op.dataType = DropOpDataType::FileList;
  130. op.mFileList = mFileLists.back();
  131. }
  132. return S_OK;
  133. }
  134. void Win32DropTarget::registerDropTarget(DropTarget* dropTarget)
  135. {
  136. mDropTargets.push_back(dropTarget);
  137. }
  138. void Win32DropTarget::unregisterDropTarget(DropTarget* dropTarget)
  139. {
  140. auto findIter = std::find(begin(mDropTargets), end(mDropTargets), dropTarget);
  141. if(findIter != mDropTargets.end())
  142. mDropTargets.erase(findIter);
  143. }
  144. unsigned int Win32DropTarget::getNumDropTargets() const
  145. {
  146. return (unsigned int)mDropTargets.size();
  147. }
  148. void Win32DropTarget::update()
  149. {
  150. Lock lock(mSync);
  151. for(auto& op: mQueuedDropOps)
  152. {
  153. for(auto& target : mDropTargets)
  154. {
  155. if(op.type != DropOpType::Leave)
  156. {
  157. if(target->_isInside(op.position))
  158. {
  159. if(!target->_isActive())
  160. {
  161. target->_setFileList(*op.mFileList);
  162. target->_setActive(true);
  163. target->onEnter(op.position.x, op.position.y);
  164. }
  165. if(op.type == DropOpType::DragOver)
  166. target->onDragOver(op.position.x, op.position.y);
  167. else if(op.type == DropOpType::Drop)
  168. {
  169. target->_setFileList(*op.mFileList);
  170. target->onDrop(op.position.x, op.position.y);
  171. }
  172. }
  173. else
  174. {
  175. if(target->_isActive())
  176. {
  177. target->onLeave();
  178. target->_clear();
  179. target->_setActive(false);
  180. }
  181. }
  182. }
  183. else
  184. {
  185. if(target->_isActive())
  186. {
  187. target->onLeave();
  188. target->_clear();
  189. target->_setActive(false);
  190. }
  191. }
  192. }
  193. if(op.type == DropOpType::Leave || op.type == DropOpType::Drop)
  194. {
  195. while (!mFileLists.empty())
  196. {
  197. bool done = mFileLists[0] == op.mFileList;
  198. bs_delete(mFileLists[0]);
  199. mFileLists.erase(mFileLists.begin());
  200. if (done)
  201. break;
  202. }
  203. }
  204. }
  205. mQueuedDropOps.clear();
  206. }
  207. bool Win32DropTarget::isDataValid(IDataObject* data)
  208. {
  209. // TODO - Currently only supports file drag and drop, so only CF_HDROP is used
  210. FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  211. return data->QueryGetData(&fmtetc) == S_OK ? true : false;
  212. }
  213. /** Gets a file list from data. Caller must ensure that the data actually contains a file list. */
  214. Vector<Path>* Win32DropTarget::getFileListFromData(IDataObject* data)
  215. {
  216. FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  217. STGMEDIUM stgmed;
  218. Vector<Path>* files = bs_new<Vector<Path>>();
  219. if(data->GetData(&fmtetc, &stgmed) == S_OK)
  220. {
  221. PVOID data = GlobalLock(stgmed.hGlobal);
  222. HDROP hDrop = (HDROP)data;
  223. UINT numFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
  224. files->resize(numFiles);
  225. for(UINT i = 0; i < numFiles; i++)
  226. {
  227. UINT numChars = DragQueryFileW(hDrop, i, nullptr, 0) + 1;
  228. wchar_t* buffer = (wchar_t*)bs_alloc((UINT32)numChars * sizeof(wchar_t));
  229. DragQueryFileW(hDrop, i, buffer, numChars);
  230. (*files)[i] = WString(buffer);
  231. bs_free(buffer);
  232. }
  233. GlobalUnlock(stgmed.hGlobal);
  234. ReleaseStgMedium(&stgmed);
  235. }
  236. return files;
  237. }
  238. }