Bläddra i källkod

WIP: Linux port
- Finishing up drag and drop functionality
- Refactored API for drag and drop so it is cleaner

Marko Pintera 8 år sedan
förälder
incheckning
1adff5e7fa

+ 1 - 1
Source/BansheeCore/BsCorePrerequisites.h

@@ -361,7 +361,7 @@ namespace bs
 	class MeshHeap;
 	class Font;
 	class ResourceMetaData;
-	class OSDropTarget;
+	class DropTarget;
 	class StringTable;
 	class PhysicsMaterial;
 	class PhysicsMesh;

+ 8 - 8
Source/BansheeCore/CMakeSources.cmake

@@ -577,34 +577,34 @@ set(BS_BANSHEECORE_SRC_ANIMATION
 set(BS_BANSHEECORE_INC_PLATFORM
 	"Platform/BsPlatform.h"
 	"Platform/BsFolderMonitor.h"
+	"Platform/BsDropTarget.h"
 )
 
+set(BS_BANSHEECORE_SRC_PLATFORM
+		"Platform/BsDropTarget.cpp"
+		)
+
 set(BS_BANSHEECORE_INC_PLATFORM_WIN32
 	"Win32/BsWin32DropTarget.h"
-	"Win32/BsWin32Defs.h"
-	"Win32/BSWin32PlatformData.h"
 	"Win32/BsWin32Platform.h"
 )
 
-set(BS_BANSHEECORE_SRC_PLATFORM
-	"Platform/BsPlatform.cpp"
-)
-
 set(BS_BANSHEECORE_SRC_PLATFORM_WIN32
 	"Win32/BsWin32FolderMonitor.cpp"
 	"Win32/BsWin32Platform.cpp"
+	"Win32/BsWin32DropTarget.cpp"
 )
 
 set(BS_BANSHEECORE_INC_PLATFORM_UNIX
 	"Linux/BsLinuxPlatform.h"
 	"Linux/BsLinuxWindow.h"
-	"Linux/BsLinuxDragAndDrop.h"
+	"Linux/BsLinuxDropTarget.h"
 )
 
 set(BS_BANSHEECORE_SRC_PLATFORM_UNIX
 	"Linux/BsLinuxPlatform.cpp"
 	"Linux/BsLinuxWindow.cpp"
-	"Linux/BsLinuxDragAndDrop.cpp"
+	"Linux/BsLinuxDropTarget.cpp"
 	"Linux/BsLinuxFolderMonitor.cpp"
 )
 

+ 102 - 54
Source/BansheeCore/Linux/BsLinuxDragAndDrop.cpp → Source/BansheeCore/Linux/BsLinuxDropTarget.cpp

@@ -2,25 +2,28 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "String/BsUnicode.h"
 #include "Platform/BsPlatform.h"
+#include "Platform/BsDropTarget.h"
 #include "RenderAPI/BsRenderWindow.h"
-#include "BsLinuxDragAndDrop.h"
+#include "Math/BsRect2I.h"
+#include "BsLinuxDropTarget.h"
 #include "BsLinuxWindow.h"
 #include "BsLinuxPlatform.h"
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
 
+#undef None
+
 namespace bs
 {
 	::Display* LinuxDragAndDrop::sXDisplay = nullptr;
 	bool LinuxDragAndDrop::sDragActive = false;
-	Vector<OSDropTarget*> LinuxDragAndDrop::sTargets;
+	Vector<LinuxDragAndDrop::DropArea> LinuxDragAndDrop::sDropAreas;
 	Mutex LinuxDragAndDrop::sMutex;
 	INT32 LinuxDragAndDrop::sDNDVersion = 0;
-	::Window LinuxDragAndDrop::sDNDSource = None;
+	::Window LinuxDragAndDrop::sDNDSource = 0;
 	Vector2I LinuxDragAndDrop::sDragPosition;
 	Vector<LinuxDragAndDrop::DragAndDropOp> LinuxDragAndDrop::sQueuedOperations;
-	Vector<OSDropTarget*> LinuxDragAndDrop::sTargetsToRegister;
-	Vector<OSDropTarget*> LinuxDragAndDrop::sTargetsToUnregister;
+	Vector<LinuxDragAndDrop::DropAreaOp> LinuxDragAndDrop::sQueuedAreaOperations;
 
 	Atom LinuxDragAndDrop::sXdndAware;
 	Atom LinuxDragAndDrop::sXdndSelection;
@@ -182,6 +185,26 @@ namespace bs
 		return nullptr;
 	}
 
+	DropTarget::DropTarget(const RenderWindow* ownerWindow, const Rect2I& area)
+		: mArea(area), mActive(false), mOwnerWindow(ownerWindow), mDropType(DropTargetType::None)
+	{
+		LinuxDragAndDrop::registerDropTarget(this);
+	}
+
+	DropTarget::~DropTarget()
+	{
+		LinuxDragAndDrop::unregisterDropTarget(this);
+
+		_clear();
+	}
+
+	void DropTarget::setArea(const Rect2I& area)
+	{
+		mArea = area;
+
+		LinuxDragAndDrop::updateDropTarget(this);
+	}
+
 	void LinuxDragAndDrop::startUp(::Display* xDisplay)
 	{
 #define INIT_ATOM(name)		s##name = XInternAtom(xDisplay, #name, False);
@@ -212,20 +235,22 @@ namespace bs
 		XChangeProperty(sXDisplay, xWindow, sXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1);
 	}
 
-	OSDropTarget& LinuxDragAndDrop::createDropTarget(const RenderWindow* window, INT32 x, INT32 y, UINT32 width,
-		UINT32 height)
+	void LinuxDragAndDrop::registerDropTarget(DropTarget* target)
 	{
 		Lock lock(sMutex);
-		OSDropTarget* newDropTarget = bs_new<OSDropTarget>(window, x, y, width, height);
-		sTargetsToRegister.push_back(newDropTarget);
+		sQueuedAreaOperations.push_back(DropAreaOp(target, DropAreaOpType::Register, target->getArea()));
+	}
 
-		return *newDropTarget;
+	void LinuxDragAndDrop::unregisterDropTarget(DropTarget* target)
+	{
+		Lock lock(sMutex);
+		sQueuedAreaOperations.push_back(DropAreaOp(target, DropAreaOpType::Unregister));
 	}
 
-	void LinuxDragAndDrop::destroyDropTarget(OSDropTarget& target)
+	void LinuxDragAndDrop::updateDropTarget(DropTarget* target)
 	{
 		Lock lock(sMutex);
-		sTargetsToUnregister.push_back(&target);
+		sQueuedAreaOperations.push_back(DropAreaOp(target, DropAreaOpType::Update, target->getArea()));
 	}
 
 	bool LinuxDragAndDrop::handleClientMessage(XClientMessageEvent& event)
@@ -234,26 +259,49 @@ namespace bs
 		{
 			Lock lock(sMutex);
 
-			for(auto& target : sTargetsToRegister)
-				sTargets.push_back(target);
-
-			for(auto& target : sTargetsToUnregister)
+			for(auto& entry : sQueuedAreaOperations)
 			{
-				// Remove any operations queued for this target
-				for(auto iter = sQueuedOperations.begin(); iter !=sQueuedOperations.end();)
+				switch(entry.type)
 				{
-					if(iter->target == target)
-						iter = sQueuedOperations.erase(iter);
-					else
-						++iter;
-				}
+				case DropAreaOpType::Register:
+					sDropAreas.push_back(DropArea(entry.target, entry.area));
+					break;
+				case DropAreaOpType::Unregister:
+					// Remove any operations queued for this target
+					for(auto iter = sQueuedOperations.begin(); iter !=sQueuedOperations.end();)
+					{
+						if(iter->target == entry.target)
+							iter = sQueuedOperations.erase(iter);
+						else
+							++iter;
+					}
+
+					// Remove the area
+					{
+						auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
+						{
+							return area.target == entry.target;
+						});
+
+						sDropAreas.erase(iterFind);
+					}
 
-				auto iterFind = std::find(sTargets.begin(), sTargets.end(), target);
-				if (iterFind != sTargets.end())
-					sTargets.erase(iterFind);
+					break;
+				case DropAreaOpType::Update:
+				{
+					auto iterFind = std::find_if(sDropAreas.begin(), sDropAreas.end(), [&](const DropArea& area)
+					{
+						return area.target == entry.target;
+					});
 
-				bs_delete(target);
+					if (iterFind != sDropAreas.end())
+						iterFind->area = entry.area;
+				}
+					break;
+				}
 			}
+
+			sQueuedAreaOperations.clear();
 		}
 
 		// Source window notifies us a drag has just entered our window area
@@ -339,46 +387,46 @@ namespace bs
 
 			if(sDragActive)
 			{
-				for(auto& dropTarget : sTargets)
+				for(auto& dropArea : sDropAreas)
 				{
 					LinuxWindow* linuxWindow;
-					dropTarget->_getOwnerWindow()->getCustomAttribute("WINDOW", &linuxWindow);
+					dropArea.target->_getOwnerWindow()->getCustomAttribute("WINDOW", &linuxWindow);
 					::Window xWindow = linuxWindow->_getXWindow();
 
 					if(xWindow == event.window)
 					{
 						Vector2I windowPos = linuxWindow->screenToWindowPos(sDragPosition);
-						if(dropTarget->_isInside(windowPos))
+						if(dropArea.area.contains(windowPos))
 						{
 							// Accept drop
 							response.data.l[1] = 1;
 
-							if(dropTarget->_isActive())
+							if(dropArea.target->_isActive())
 							{
 								Lock lock(sMutex);
-								sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::DragOver, dropTarget,
+								sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::DragOver, dropArea.target,
 									windowPos));
 							}
 							else
 							{
 								Lock lock(sMutex);
-								sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Enter, dropTarget,
+								sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Enter, dropArea.target,
 										windowPos));
 							}
 
-							dropTarget->_setActive(true);
+							dropArea.target->_setActive(true);
 						}
 						else
 						{
 							// Cursor left previously active target's area
-							if(dropTarget->_isActive())
+							if(dropArea.target->_isActive())
 							{
 								{
 									Lock lock(sMutex);
-									sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Leave, dropTarget));
+									sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Leave, dropArea.target));
 								}
 
-								dropTarget->_setActive(false);
+								dropArea.target->_setActive(false);
 							}
 						}
 					}
@@ -391,16 +439,16 @@ namespace bs
 		// Cursor left the target window, or the drop was rejected
 		else if(event.message_type == sXdndLeave)
 		{
-			for(auto& dropTarget : sTargets)
+			for(auto& dropArea : sDropAreas)
 			{
-				if(dropTarget->_isActive())
+				if(dropArea.target->_isActive())
 				{
 					{
 						Lock lock(sMutex);
-						sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Leave, dropTarget));
+						sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Leave, dropArea.target));
 					}
 
-					dropTarget->_setActive(false);
+					dropArea.target->_setActive(false);
 				}
 			}
 
@@ -413,9 +461,9 @@ namespace bs
 
 			if(sDragActive)
 			{
-				for (auto& dropTarget : sTargets)
+				for (auto& dropArea : sDropAreas)
 				{
-					if (dropTarget->_isActive())
+					if (dropArea.target->_isActive())
 						dropAccepted = true;
 				}
 			}
@@ -446,8 +494,8 @@ namespace bs
 				response.data.l[0] = LinuxPlatform::getMainXWindow();
 				response.data.l[1] = 0;
 				response.data.l[2] = 0;
-				response.data.l[3] = None;
-				response.data.l[4] = None;
+				response.data.l[3] = 0;
+				response.data.l[4] = 0;
 
 				XSendEvent(sXDisplay, source, False, NoEventMask, (XEvent*)&response);
 				XFlush(sXDisplay);
@@ -474,32 +522,32 @@ namespace bs
 		if(property.format == 8)
 		{
 			// Assuming this is a file list, since we rejected any other drop type
-			Vector<WString> filePaths;
+			Vector<Path> filePaths;
 
 			char* token = strtok((char*)property.data, "\r\n");
 			while(token != nullptr)
 			{
 				char* filePath = convertURIToLocalPath(token);
 				if(filePath != nullptr)
-					filePaths.push_back(UTF8::toWide(filePath));
+					filePaths.push_back(String(filePath));
 
 				token = strtok(nullptr, "\r\n");
 			}
 
-			for(auto& target : sTargets)
+			for(auto& dropArea : sDropAreas)
 			{
-				if(!target->_isActive())
+				if(!dropArea.target->_isActive())
 					continue;
 
 				LinuxWindow* linuxWindow;
-				target->_getOwnerWindow()->getCustomAttribute("WINDOW", &linuxWindow);
+				dropArea.target->_getOwnerWindow()->getCustomAttribute("WINDOW", &linuxWindow);
 
 				Vector2I windowPos = linuxWindow->screenToWindowPos(sDragPosition);
 
 				Lock lock(sMutex);
-				sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Drop, target, windowPos, filePaths));
+				sQueuedOperations.push_back(DragAndDropOp(DragAndDropOpType::Drop, dropArea.target, windowPos, filePaths));
 
-				target->_setActive(false);
+				dropArea.target->_setActive(false);
 			}
 		}
 
@@ -517,8 +565,8 @@ namespace bs
 		response.data.l[0] = LinuxPlatform::getMainXWindow();
 		response.data.l[1] = 1;
 		response.data.l[2] = sXdndActionCopy;
-		response.data.l[3] = None;
-		response.data.l[4] = None;
+		response.data.l[3] = 0;
+		response.data.l[4] = 0;
 
 		XSendEvent(sXDisplay, sDNDSource, False, NoEventMask, (XEvent*)&response);
 		XFlush(sXDisplay);

+ 50 - 13
Source/BansheeCore/Linux/BsLinuxDragAndDrop.h → Source/BansheeCore/Linux/BsLinuxDropTarget.h

@@ -31,23 +31,54 @@ namespace bs
 		/**	Structure describing a drag and drop operation. */
 		struct DragAndDropOp
 		{
-			DragAndDropOp(DragAndDropOpType type, OSDropTarget* target)
+			DragAndDropOp(DragAndDropOpType type, DropTarget* target)
 					:type(type), target(target)
 			{ }
 
-			DragAndDropOp(DragAndDropOpType type, OSDropTarget* target, const Vector2I& pos)
+			DragAndDropOp(DragAndDropOpType type, DropTarget* target, const Vector2I& pos)
 				:type(type), target(target), position(pos)
 			{ }
 
-			DragAndDropOp(DragAndDropOpType type, OSDropTarget* target, const Vector2I& pos,
-				const Vector<WString>& fileList)
+			DragAndDropOp(DragAndDropOpType type, DropTarget* target, const Vector2I& pos,
+				const Vector<Path>& fileList)
 				:type(type), target(target), position(pos), fileList(fileList)
 			{ }
 
 			DragAndDropOpType type;
-			OSDropTarget* target;
+			DropTarget* target;
 			Vector2I position;
-			Vector<WString> fileList;
+			Vector<Path> fileList;
+		};
+
+		/** Represents a single registered drop area. */
+		struct DropArea
+		{
+			DropArea(DropTarget* target, const Rect2I& area)
+				:target(target), area(area)
+			{ }
+
+			DropTarget* target;
+			Rect2I area;
+		};
+
+		/** Type of operations that can happen to a DropArea. */
+		enum class DropAreaOpType
+		{
+			Register, /**< New DropArea is being registered. */
+			Unregister, /**< DropArea is being unregistered. */
+			Update /**< DropArea was updated. */
+		};
+
+		/** Operation that in some way modifies a DropArea. */
+		struct DropAreaOp
+		{
+			DropAreaOp(DropTarget* target, DropAreaOpType type, const Rect2I& area = Rect2I::EMPTY)
+				:target(target), area(area), type(type)
+			{ }
+
+			DropTarget* target;
+			Rect2I area;
+			DropAreaOpType type;
 		};
 
 	public:
@@ -80,19 +111,26 @@ namespace bs
 		static void makeDNDAware(::Window xWindow);
 
 		/**
-		 * Creates a new drop target. Any further events processed will take this target into account, trigger its event
+		 * Registers a new drop target Any further events processed will take this target into account, trigger its event
 		 * and populate its data if a drop occurs.
 		 *
 		 * @note 	Thread safe.
 		 */
-		static OSDropTarget& createDropTarget(const RenderWindow* window, INT32 x, INT32 y, UINT32 width, UINT32 height);
+		static void registerDropTarget(DropTarget* target);
+
+		/**
+		 * Updates information about previous registered DropTarget. Call this when drop target area changes.
+		 *
+		 * @note	Thread safe.
+		 */
+		static void updateDropTarget(DropTarget* target);
 
 		/**
-		 * Destroys a drop target.
+		 * Unregisters a drop target. Its events will no longer be triggered.
 		 *
 		 * @note	Thread safe.
 		 */
-		static void destroyDropTarget(OSDropTarget& target);
+		static void unregisterDropTarget(DropTarget* target);
 
 		/**
 		 * Processes X11 ClientMessage event and handles any messages relating to drag and drop. Returns true if a message
@@ -113,15 +151,14 @@ namespace bs
 	private:
 		static ::Display* sXDisplay;
 		static bool sDragActive;
-		static Vector<OSDropTarget*> sTargets;
+		static Vector<DropArea> sDropAreas;
 		static Mutex sMutex;
 		static INT32 sDNDVersion;
 		static Atom sDNDType;
 		static ::Window sDNDSource;
 		static Vector2I sDragPosition;
 		static Vector<DragAndDropOp> sQueuedOperations;
-		static Vector<OSDropTarget*> sTargetsToRegister;
-		static Vector<OSDropTarget*> sTargetsToUnregister;
+		static Vector<DropAreaOp> sQueuedAreaOperations;
 
 		// Awareness
 		static Atom sXdndAware;

+ 1 - 11
Source/BansheeCore/Linux/BsLinuxPlatform.cpp

@@ -6,7 +6,7 @@
 #include "Linux/BsLinuxPlatform.h"
 #include "Linux/BsLinuxWindow.h"
 #include "RenderAPI/BsRenderWindow.h"
-#include "BsLinuxDragAndDrop.h"
+#include "BsLinuxDropTarget.h"
 #include "BsCoreApplication.h"
 #include <X11/X.h>
 #include <X11/Xatom.h>
@@ -382,16 +382,6 @@ namespace bs
 		usleep(duration * 1000);
 	}
 
-	OSDropTarget& Platform::createDropTarget(const RenderWindow* window, INT32 x, INT32 y, UINT32 width, UINT32 height)
-	{
-		return LinuxDragAndDrop::createDropTarget(window, x, y, width, height);
-	}
-
-	void Platform::destroyDropTarget(OSDropTarget& target)
-	{
-		LinuxDragAndDrop::destroyDropTarget(target);
-	}
-
 	void Platform::copyToClipboard(const WString& string)
 	{
 		Lock lock(mData->lock);

+ 1 - 1
Source/BansheeCore/Linux/BsLinuxWindow.cpp

@@ -2,7 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsLinuxWindow.h"
 #include "BsLinuxPlatform.h"
-#include "BsLinuxDragAndDrop.h"
+#include "BsLinuxDropTarget.h"
 
 #include <X11/Xatom.h>
 

+ 31 - 0
Source/BansheeCore/Platform/BsDropTarget.cpp

@@ -0,0 +1,31 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "Platform/BsDropTarget.h"
+
+namespace bs
+{
+	void DropTarget::_clear()
+	{
+		mFileList.clear();
+	}
+
+	bool DropTarget::_isInside(const Vector2I& pos) const
+	{
+		return mArea.contains(pos);
+	}
+
+	void DropTarget::_setFileList(const Vector<Path>& fileList)
+	{
+		_clear();
+
+		mDropType = DropTargetType::FileList;
+		mFileList = fileList;
+	}
+
+	SPtr<DropTarget> DropTarget::create(const RenderWindow* window, const Rect2I& area)
+	{
+		DropTarget* target = new (bs_alloc<DropTarget>()) DropTarget(window, area);
+		return bs_shared_ptr(target);
+	}
+}
+

+ 115 - 0
Source/BansheeCore/Platform/BsDropTarget.h

@@ -0,0 +1,115 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "Utility/BsEvent.h"
+#include "Math/BsRect2I.h"
+
+namespace bs
+{
+	/** @addtogroup Platform-Internal
+	 *  @{
+	 */
+
+	/** Type of drop event type. This is used when dragging items over drop targets. */
+	enum class DropTargetType
+	{
+		FileList,
+		None
+	};
+
+	/**
+	 * Drop targets allow you to register a certain portion of a window as a drop target that accepts certain drop types
+	 * from the OS (platform) specific drag and drop system. Accepted drop types are provided by the OS and include things
+	 * like file and item dragging.
+	 *
+	 * You will receive events with the specified drop area as long as it is active.
+	 */
+	class BS_CORE_EXPORT DropTarget
+	{
+	public:
+		~DropTarget();
+
+		/**	Sets the drop target area, in local window coordinates. */
+		void setArea(const Rect2I& area);
+
+		/** Returns the drop target area, in local window coordinates. */
+		const Rect2I& getArea() const { return mArea;}
+
+		/**	Gets the type of drop that this drop target is looking for. Only valid after a drop has been triggered. */
+		DropTargetType getDropType() const { return mDropType; }
+
+		/**
+		 * Returns a list of files received by the drop target. Only valid after a drop of FileList type has been triggered.
+		 */
+		const Vector<Path>& getFileList() const { return mFileList; }
+
+		/**
+		 * Creates a new drop target. Any drop events that happen on the specified window's drop area will be reported
+		 * through the target's events.
+		 *
+		 * @param[in]	window		Window to which the drop target will be attached to.
+		 * @param[in]	area		Area, relative to the window, in which the drop events are allowed.
+		 * @return					Newly created drop target.
+		 */
+		static SPtr<DropTarget> create(const RenderWindow* window, const Rect2I& area);
+
+		/**
+		 * Triggered when a pointer is being dragged over the drop area. Provides window coordinates of the pointer position.
+		 */
+		Event<void(INT32, INT32)> onDragOver;
+
+		/**
+		 * Triggered when the user completes a drop while pointer is over the drop area. Provides window coordinates of the
+		 * pointer position.
+		 */
+		Event<void(INT32, INT32)> onDrop;
+
+		/**
+		 * Triggered when a pointer enters the drop area. Provides window coordinates of the pointer position.
+		 */
+		Event<void(INT32, INT32)> onEnter;
+
+		/** Triggered when a pointer leaves the drop area. */
+		Event<void()> onLeave;
+
+		/** @name Internal
+		 *  @{
+		 */
+
+		/** Clears all internal values. */
+		void _clear();
+
+		/** Sets the file list and marks the drop event as FileList. */
+		void _setFileList(const Vector<Path>& fileList);
+
+		/** Marks the drop area as inactive or active. */
+		void _setActive(bool active) { mActive = active; }
+
+		/**	Checks is the specified position within the current drop area. Position should be in window local coordinates. */
+		bool _isInside(const Vector2I& pos) const;
+
+		/** Returns true if the drop target is active. */
+		bool _isActive() const { return mActive; }
+
+		/**	Returns a render window this drop target is attached to. */
+		const RenderWindow* _getOwnerWindow() const { return mOwnerWindow; }
+
+		/** @} */
+	private:
+		friend class Platform;
+
+		DropTarget(const RenderWindow* ownerWindow, const Rect2I& area);
+
+		Rect2I mArea;
+		bool mActive;
+		const RenderWindow* mOwnerWindow;
+
+		DropTargetType mDropType;
+		Vector<Path> mFileList;
+	};
+
+	/** @} */
+}
+

+ 0 - 52
Source/BansheeCore/Platform/BsPlatform.cpp

@@ -1,52 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Platform/BsPlatform.h"
-
-namespace bs
-{
-	OSDropTarget::OSDropTarget(const RenderWindow* ownerWindow, INT32 x, INT32 y, UINT32 width, UINT32 height)
-		:mX(x), mY(y), mWidth(width), mHeight(height), mActive(false), mOwnerWindow(ownerWindow), 
-		mDropType(OSDropType::None), mFileList(nullptr)
-	{
-		
-	}
-
-	OSDropTarget::~OSDropTarget()
-	{
-		_clear();
-	}
-
-	void OSDropTarget::setArea(INT32 x, INT32 y, UINT32 width, UINT32 height)
-	{
-		mX = x;
-		mY = y;
-		mWidth = width;
-		mHeight = height;
-	}
-
-	void OSDropTarget::_clear()
-	{
-		if(mFileList != nullptr)
-		{
-			bs_delete(mFileList);
-			mFileList = nullptr;
-		}
-	}
-
-	bool OSDropTarget::_isInside(const Vector2I& pos) const
-	{
-		INT32 right = mX + mWidth;
-		INT32 bottom = mY + mHeight;
-
-		return (pos.x >= mX && pos.x < right && pos.y >= mY && pos.y < bottom);
-	}
-
-	void OSDropTarget::_setFileList(const Vector<WString>& fileList)
-	{
-		_clear();
-
-		mDropType = OSDropType::FileList;
-		mFileList = bs_new<Vector<WString>>();
-		*mFileList = fileList;
-	}
-}

+ 0 - 100
Source/BansheeCore/Platform/BsPlatform.h

@@ -69,89 +69,6 @@ namespace bs
 		bool shift, ctrl;
 	};
 
-	/** Type of drop event type. This is used when dragging items over drop targets. */
-	enum class OSDropType
-	{
-		FileList,
-		None
-	};
-
-	/**
-	 * Drop targets allow you to register a certain portion of a window as a drop target that accepts certain drop types 
-	 * from the OS (platform) specific drag and drop system. Accepted drop types are provided by the OS and include things
-	 * like file and item dragging.
-	 *
-	 * You will receive events with the specified drop area as long as it is active.
-	 */
-	class BS_CORE_EXPORT OSDropTarget
-	{
-	public:
-		OSDropTarget(const RenderWindow* ownerWindow, INT32 x, INT32 y, UINT32 width, UINT32 height);
-		~OSDropTarget();
-
-		/**
-		 * Triggered when a pointer is being dragged over the drop area. Provides window coordinates of the pointer position.
-		 */
-		Event<void(INT32 x, INT32 y)> onDragOver;
-
-		/**
-		 * Triggered when the user completes a drop while pointer is over the drop area. Provides window coordinates of the 
-		 * pointer position.
-		 */
-		Event<void(INT32 x, INT32 y)> onDrop;
-
-		/**
-		 * Triggered when a pointer enters the drop area. Provides window coordinates of the pointer position.
-		 */
-		Event<void(INT32 x, INT32 y)> onEnter;
-
-		/** Triggered when a pointer leaves the drop area. */
-		Event<void()> onLeave;
-
-		/**	Sets the drop target area, in local window coordinates. */
-		void setArea(INT32 x, INT32 y, UINT32 width, UINT32 height);
-
-		/**	Gets the type of drop that this drop target is looking for. Only valid after a drop has been triggered. */
-		OSDropType getDropType() const { return mDropType; }
-
-		/**	
-		 * Returns a list of files received by the drop target. Only valid after a drop of FileList type has been triggered.
-		 */
-		const Vector<WString>& getFileList() const { return *mFileList; }
-
-		/** Clears all internal values. */
-		void _clear();
-
-		/** Sets the file list and marks the drop event as FileList. */
-		void _setFileList(const Vector<WString>& fileList);
-
-		/** Marks the drop area as inactive or active. */
-		void _setActive(bool active) { mActive = active; }
-
-		/**	Checks is the specified position within the current drop area. Position should be in window local coordinates. */
-		bool _isInside(const Vector2I& pos) const;
-
-		/** Returns true if the drop target is active. */
-		bool _isActive() const { return mActive; }
-
-		/**	Returns a render window this drop target is attached to. */
-		const RenderWindow* _getOwnerWindow() const { return mOwnerWindow; }
-	private:
-		friend class Platform;
-
-		INT32 mX, mY;
-		UINT32 mWidth, mHeight;
-		bool mActive;
-		const RenderWindow* mOwnerWindow;
-
-		OSDropType mDropType;
-
-		union
-		{
-			Vector<WString>* mFileList;
-		};
-	};
-
 	/**	Represents a specific non client area used for window resizing. */
 	struct BS_CORE_EXPORT NonClientResizeArea
 	{
@@ -313,23 +230,6 @@ namespace bs
 		 */
 		static void sleep(UINT32 duration);
 
-		/**
-		 * Creates a drop target that you can use for tracking OS drag and drop operations performed over a certain area 
-		 * on the specified window.
-		 *
-		 * @param[in]	window	The window on which to track drop operations.
-		 * @param[in]	x	  	The x coordinate of the area to track, relative to window.
-		 * @param[in]	y	  	The y coordinate of the area to track, relative to window.
-		 * @param[in]	width 	The width of the area to track.
-		 * @param[in]	height	The height of the area to track.
-		 * @return				OSDropTarget that you will use to receive all drop data. When no longer needed make sure 
-		 *						to destroy it with destroyDropTarget().
-		 */
-		static OSDropTarget& createDropTarget(const RenderWindow* window, INT32 x, INT32 y, UINT32 width, UINT32 height);
-
-		/** Destroys a drop target previously created with createDropTarget. */
-		static void destroyDropTarget(OSDropTarget& target);
-
 		/**
 		 * Opens the provided folder using the default application, as specified by the operating system.
 		 *

+ 0 - 44
Source/BansheeCore/Win32/BSWin32PlatformData.h

@@ -1,44 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Platform/BsPlatform.h"
-#include "Win32/BsWin32Defs.h"
-#include "Win32/BsWin32DropTarget.h"
-
-namespace bs
-{
-	/** @addtogroup Platform-Internal
-	 *  @{
-	 */
-
-	/** Encapsulate native cursor data so we can avoid including windows.h as it pollutes the global namespace. */
-	struct BS_CORE_EXPORT NativeCursorData
-	{
-		HCURSOR cursor;
-	};
-
-	/**	Encapsulate drop target data so we can avoid including windows.h as it pollutes the global namespace. */
-	struct BS_CORE_EXPORT NativeDropTargetData
-	{
-		Map<const RenderWindow*, Win32DropTarget*> dropTargetsPerWindow;
-		Vector<Win32DropTarget*> dropTargetsToInitialize;
-		Vector<Win32DropTarget*> dropTargetsToDestroy;
-	};
-
-	struct Platform::Pimpl
-	{
-		bool mIsCursorHidden = false;
-		NativeCursorData mCursor;
-		bool mUsingCustomCursor = false;
-		Map<const ct::RenderWindow*, WindowNonClientAreaData> mNonClientAreas;
-
-		bool mIsTrackingMouse = false;
-		NativeDropTargetData mDropTargets;
-
-		bool mRequiresStartUp = false;
-		bool mRequiresShutDown = false;
-
-		Mutex mSync;
-	};
-
-	/** @} */
-}

+ 0 - 12
Source/BansheeCore/Win32/BsWin32Defs.h

@@ -1,12 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#define WIN32_LEAN_AND_MEAN
-#if !defined(NOMINMAX) && defined(_MSC_VER)
-#	define NOMINMAX // Required to stop windows.h messing up std::min
-#endif
-#include <windows.h>
-#include <windowsx.h>
-#include <oleidl.h>
-
-#define WM_BS_SETCAPTURE WM_USER + 101
-#define WM_BS_RELEASECAPTURE WM_USER + 102

+ 298 - 0
Source/BansheeCore/Win32/BsWin32DropTarget.cpp

@@ -0,0 +1,298 @@
+//********************************** 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;
+	}
+}
+

+ 24 - 269
Source/BansheeCore/Win32/BsWin32DropTarget.h

@@ -2,9 +2,10 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #pragma once
 
-#include "Shellapi.h"
-
-// This is just a helper include for BsPlatformImpl.cpp, it's not meant to be used on its own
+#include "BsCorePrerequisites.h"
+#include "Math/BsVector2I.h"
+#include <windows.h>
+#include <oleidl.h>
 
 namespace bs
 {
@@ -47,337 +48,91 @@ namespace bs
 			Vector2I position;
 
 			DropOpDataType dataType;
-			union 
-			{
-				Vector<WString>* mFileList;
-			};
+			Vector<Path>* mFileList;
 		};
 
 	public:
-		Win32DropTarget(HWND hWnd)
-			:mRefCount(1), mHWnd(hWnd), mAcceptDrag(false)
-		{ }
-
-		~Win32DropTarget()
-		{
-			Lock lock(mSync);
-
-			for(auto& fileList : mFileLists)
-			{
-				bs_delete(fileList);
-			}
-
-			mFileLists.clear();
-			mQueuedDropOps.clear();
-		}
-
-		/** Registers the drop target with the operating system. Monitoring for drag and drop operations starts. */
-		void registerWithOS()
-		{
-			CoLockObjectExternal(this, TRUE, FALSE);
-			RegisterDragDrop(mHWnd, this);
-		}
+		Win32DropTarget(HWND hWnd);
+		~Win32DropTarget();
 
-		/** Unregisters the drop target with the operating system. Monitoring for drag and drop operations stops. */
-		void unregisterWithOS()
-		{
-			RevokeDragDrop(mHWnd);
-			CoLockObjectExternal(this, FALSE, FALSE);
-		}
+		void registerWithOS();
+		void unregisterWithOS();
 
-		/** COM requirement. Returns instance of an interface of the provided type. */
-		HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject) override
-		{
-			if(iid == IID_IDropTarget || iid == IID_IUnknown)
-			{
-				AddRef();
-				*ppvObject = this;
-				return S_OK;
-			}
-			else
-			{
-				*ppvObject = nullptr;
-				return E_NOINTERFACE;
-			}
-		}
+		HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject) override;
 
 		/**	COM requirement. Increments objects reference count. */
-		ULONG __stdcall AddRef() override
-		{
-			return InterlockedIncrement(&mRefCount);
-		} 
+		ULONG __stdcall AddRef() override;
 
 		/** COM requirement. Decreases the objects reference count and deletes the object if its zero. */
-		ULONG __stdcall Release() override
-		{
-			LONG count = InterlockedDecrement(&mRefCount);
-
-			if(count == 0)
-			{
-				bs_delete(this);
-				return 0;
-			}
-			else
-			{
-				return count;
-			}
-		} 
+		ULONG __stdcall Release() override;
 
 		/**
 		 * Called by the OS when user enters the drop target area while dragging an object.
 		 * 			
 		 * @note	Called on core thread.
 		 */
-		HRESULT __stdcall DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override
-		{
-			*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 DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override;
 
 		/**
 		 * Called by the OS while user continues to drag an object over the drop target.
 		 * 			
 		 * @note	Called on core thread.
 		 */
-		HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override
-		{
-			*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 DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override;
 
 		/**
 		 * Called by the OS when user leaves the drop target.
 		 * 			
 		 * @note	Called on core thread.
 		 */
-		HRESULT __stdcall DragLeave() override
-		{
-			{
-				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 DragLeave() override;
 
 		/**
 		 * Called by the OS when the user ends the drag operation while over the drop target.
 		 * 			
 		 * @note	Called on core thread.
 		 */
-		HRESULT __stdcall Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override
-		{
-			*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;
-		}
+		HRESULT __stdcall Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) override;
 
 		/**
 		 * Registers a new drop target to monitor.
 		 *
 		 * @note	Sim thread only.
 		 */
-		void registerDropTarget(OSDropTarget* dropTarget)
-		{
-			mDropTargets.push_back(dropTarget);
-		}
+		void registerDropTarget(DropTarget* dropTarget);
 
 		/**
 		 * Unregisters an existing drop target and stops monitoring it.
 		 *
 		 * @note	Sim thread only.
 		 */
-		void unregisterDropTarget(OSDropTarget* dropTarget)
-		{
-			auto findIter = std::find(begin(mDropTargets), end(mDropTargets), dropTarget);
-			if(findIter != mDropTargets.end())
-				mDropTargets.erase(findIter);
-		}
+		void unregisterDropTarget(DropTarget* dropTarget);
 
 		/**
 		 * Gets the total number of monitored drop targets.
 		 * 			
 		 * @note	Sim thread only.
 		 */
-		unsigned int getNumDropTargets() const 
-		{ 
-			return (unsigned int)mDropTargets.size(); 
-		}
+		unsigned int getNumDropTargets() const;
 
 		/** Called every frame by the sim thread. Internal method. */
-		void 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();
-		}
+		void update();
 	private:
 		/**	Check if we support the data in the provided drag and drop data object. */
-		bool 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;
-		}
+		bool isDataValid(IDataObject* data);
 
 		/**	Gets a file list from data. Caller must ensure that the data actually contains a file list. */
-		Vector<WString>* getFileListFromData(IDataObject* data)
-		{
-			FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
-			STGMEDIUM stgmed;
-
-			Vector<WString>* files = bs_new<Vector<WString>>();
-			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;
-		}
+		Vector<Path>* getFileListFromData(IDataObject* data);
 
 	private:
-		Vector<OSDropTarget*> mDropTargets;
+		Vector<DropTarget*> mDropTargets;
 
 		LONG mRefCount;
 		HWND mHWnd;
 		bool mAcceptDrag;
 
 		Vector<DropTargetOp> mQueuedDropOps;
-		Vector<Vector<WString>*> mFileLists; 
+		Vector<Vector<Path>*> mFileLists;
 
 		Mutex mSync;
 	};

+ 49 - 49
Source/BansheeCore/Win32/BsWin32FolderMonitor.cpp

@@ -307,9 +307,9 @@ namespace bs
 
 	FolderMonitor::FolderMonitor()
 	{
-		mPimpl = bs_new<Pimpl>();
-		mPimpl->mWorkerThread = nullptr;
-		mPimpl->mCompPortHandle = nullptr;
+		m = bs_new<Pimpl>();
+		m->mWorkerThread = nullptr;
+		m->mCompPortHandle = nullptr;
 	}
 
 	FolderMonitor::~FolderMonitor()
@@ -317,15 +317,15 @@ namespace bs
 		stopMonitorAll();
 
 		// No need for mutex since we know worker thread is shut down by now
-		while(!mPimpl->mFileActions.empty())
+		while(!m->mFileActions.empty())
 		{
-			FileAction* action = mPimpl->mFileActions.front();
-			mPimpl->mFileActions.pop();
+			FileAction* action = m->mFileActions.front();
+			m->mFileActions.pop();
 
 			FileAction::destroy(action);
 		}
 
-		bs_delete(mPimpl);
+		bs_delete(m);
 	}
 
 	void FolderMonitor::startMonitor(const Path& folderPath, bool subdirectories, FolderChangeBits changeFilter)
@@ -354,40 +354,40 @@ namespace bs
 		if(changeFilter.isSet(FolderChangeBit::DirName))
 			filterFlags |= FILE_NOTIFY_CHANGE_DIR_NAME;
 
-		if(changeFilter.isSet(FolderChangeBit::LastWrite))
+		if(changeFilter.isSet(FolderChangeBit::FileWrite))
 			filterFlags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
 
-		mPimpl->mFoldersToWatch.push_back(bs_new<FolderWatchInfo>(folderPath, dirHandle, subdirectories, filterFlags));
-		FolderWatchInfo* watchInfo = mPimpl->mFoldersToWatch.back();
+		m->mFoldersToWatch.push_back(bs_new<FolderWatchInfo>(folderPath, dirHandle, subdirectories, filterFlags));
+		FolderWatchInfo* watchInfo = m->mFoldersToWatch.back();
 
-		mPimpl->mCompPortHandle = CreateIoCompletionPort(dirHandle, mPimpl->mCompPortHandle, (ULONG_PTR)watchInfo, 0);
+		m->mCompPortHandle = CreateIoCompletionPort(dirHandle, m->mCompPortHandle, (ULONG_PTR)watchInfo, 0);
 
-		if(mPimpl->mCompPortHandle == nullptr)
+		if(m->mCompPortHandle == nullptr)
 		{
-			mPimpl->mFoldersToWatch.erase(mPimpl->mFoldersToWatch.end() - 1);
+			m->mFoldersToWatch.erase(m->mFoldersToWatch.end() - 1);
 			bs_delete(watchInfo);
 			BS_EXCEPT(InternalErrorException, "Failed to open completion port for folder monitoring. Error code: " + toString((UINT64)GetLastError()));
 		}
 
-		if(mPimpl->mWorkerThread == nullptr)
+		if(m->mWorkerThread == nullptr)
 		{
-			mPimpl->mWorkerThread = bs_new<Thread>(std::bind(&FolderMonitor::workerThreadMain, this));
+			m->mWorkerThread = bs_new<Thread>(std::bind(&FolderMonitor::workerThreadMain, this));
 
-			if(mPimpl->mWorkerThread == nullptr)
+			if(m->mWorkerThread == nullptr)
 			{
-				mPimpl->mFoldersToWatch.erase(mPimpl->mFoldersToWatch.end() - 1);
+				m->mFoldersToWatch.erase(m->mFoldersToWatch.end() - 1);
 				bs_delete(watchInfo);
 				BS_EXCEPT(InternalErrorException, "Failed to create a new worker thread for folder monitoring");
 			}
 		}
 
-		if(mPimpl->mWorkerThread != nullptr)
+		if(m->mWorkerThread != nullptr)
 		{
-			watchInfo->startMonitor(mPimpl->mCompPortHandle);
+			watchInfo->startMonitor(m->mCompPortHandle);
 		}
 		else
 		{
-			mPimpl->mFoldersToWatch.erase(mPimpl->mFoldersToWatch.end() - 1);
+			m->mFoldersToWatch.erase(m->mFoldersToWatch.end() - 1);
 			bs_delete(watchInfo);
 			BS_EXCEPT(InternalErrorException, "Failed to create a new worker thread for folder monitoring");
 		}
@@ -395,54 +395,54 @@ namespace bs
 
 	void FolderMonitor::stopMonitor(const Path& folderPath)
 	{
-		auto findIter = std::find_if(mPimpl->mFoldersToWatch.begin(), mPimpl->mFoldersToWatch.end(), 
+		auto findIter = std::find_if(m->mFoldersToWatch.begin(), m->mFoldersToWatch.end(), 
 			[&](const FolderWatchInfo* x) { return x->mFolderToMonitor == folderPath; });
 
-		if(findIter != mPimpl->mFoldersToWatch.end())
+		if(findIter != m->mFoldersToWatch.end())
 		{
 			FolderWatchInfo* watchInfo = *findIter;
 
-			watchInfo->stopMonitor(mPimpl->mCompPortHandle);
+			watchInfo->stopMonitor(m->mCompPortHandle);
 			bs_delete(watchInfo);
 
-			mPimpl->mFoldersToWatch.erase(findIter);
+			m->mFoldersToWatch.erase(findIter);
 		}
 
-		if(mPimpl->mFoldersToWatch.size() == 0)
+		if(m->mFoldersToWatch.size() == 0)
 			stopMonitorAll();
 	}
 
 	void FolderMonitor::stopMonitorAll()
 	{
-		for(auto& watchInfo : mPimpl->mFoldersToWatch)
+		for(auto& watchInfo : m->mFoldersToWatch)
 		{
-			watchInfo->stopMonitor(mPimpl->mCompPortHandle);
+			watchInfo->stopMonitor(m->mCompPortHandle);
 
 			{
 				// Note: Need this mutex to ensure worker thread is done with watchInfo.
 				// Even though we wait for a condition variable from the worker thread in stopMonitor,
 				// that doesn't mean the worker thread is done with the condition variable
 				// (which is stored inside watchInfo)
-				Lock lock(mPimpl->mMainMutex);
+				Lock lock(m->mMainMutex);
 				bs_delete(watchInfo);
 			}
 		}
 
-		mPimpl->mFoldersToWatch.clear();
+		m->mFoldersToWatch.clear();
 
-		if(mPimpl->mWorkerThread != nullptr)
+		if(m->mWorkerThread != nullptr)
 		{
-			PostQueuedCompletionStatus(mPimpl->mCompPortHandle, 0, 0, nullptr);
+			PostQueuedCompletionStatus(m->mCompPortHandle, 0, 0, nullptr);
 
-			mPimpl->mWorkerThread->join();
-			bs_delete(mPimpl->mWorkerThread);
-			mPimpl->mWorkerThread = nullptr;
+			m->mWorkerThread->join();
+			bs_delete(m->mWorkerThread);
+			m->mWorkerThread = nullptr;
 		}
 
-		if(mPimpl->mCompPortHandle != nullptr)
+		if(m->mCompPortHandle != nullptr)
 		{
-			CloseHandle(mPimpl->mCompPortHandle);
-			mPimpl->mCompPortHandle = nullptr;
+			CloseHandle(m->mCompPortHandle);
+			m->mCompPortHandle = nullptr;
 		}
 	}
 
@@ -455,7 +455,7 @@ namespace bs
 			DWORD numBytes;
 			LPOVERLAPPED overlapped;
 
-			if(!GetQueuedCompletionStatus(mPimpl->mCompPortHandle, &numBytes, (PULONG_PTR) &watchInfo, &overlapped, INFINITE))
+			if(!GetQueuedCompletionStatus(m->mCompPortHandle, &numBytes, (PULONG_PTR) &watchInfo, &overlapped, INFINITE))
 			{
 				assert(false);
 				// TODO: Folder handle was lost most likely. Not sure how to deal with that. Shutdown watch on this folder and cleanup?
@@ -528,7 +528,7 @@ namespace bs
 						}
 
 						{
-							Lock lock(mPimpl->mMainMutex); // Ensures that we don't delete "watchInfo" before this thread is done with mStartStopEvent
+							Lock lock(m->mMainMutex); // Ensures that we don't delete "watchInfo" before this thread is done with mStartStopEvent
 							watchInfo->mStartStopEvent.notify_one();
 						}
 					}
@@ -549,7 +549,7 @@ namespace bs
 						}
 
 						{
-							Lock lock(mPimpl->mMainMutex); // Ensures that we don't delete "watchInfo" before this thread is done with mStartStopEvent
+							Lock lock(m->mMainMutex); // Ensures that we don't delete "watchInfo" before this thread is done with mStartStopEvent
 							watchInfo->mStartStopEvent.notify_one();
 						}
 					}
@@ -597,28 +597,28 @@ namespace bs
 		} while(notifyInfo.getNext());
 
 		{
-			Lock lock(mPimpl->mMainMutex);
+			Lock lock(m->mMainMutex);
 
 			for(auto& action : mActions)
-				mPimpl->mFileActions.push(action);
+				m->mFileActions.push(action);
 		}
 	}
 
 	void FolderMonitor::_update()
 	{
 		{
-			Lock lock(mPimpl->mMainMutex);
+			Lock lock(m->mMainMutex);
 
-			while (!mPimpl->mFileActions.empty())
+			while (!m->mFileActions.empty())
 			{
-				FileAction* action = mPimpl->mFileActions.front();
-				mPimpl->mFileActions.pop();
+				FileAction* action = m->mFileActions.front();
+				m->mFileActions.pop();
 
-				mPimpl->mActiveFileActions.push_back(action);
+				m->mActiveFileActions.push_back(action);
 			}
 		}
 
-		for (auto iter = mPimpl->mActiveFileActions.begin(); iter != mPimpl->mActiveFileActions.end();)
+		for (auto iter = m->mActiveFileActions.begin(); iter != m->mActiveFileActions.end();)
 		{
 			FileAction* action = *iter;
 			
@@ -668,7 +668,7 @@ namespace bs
 				break;
 			}
 
-			mPimpl->mActiveFileActions.erase(iter++);
+			m->mActiveFileActions.erase(iter++);
 			FileAction::destroy(action);
 		}
 	}

+ 39 - 12
Source/BansheeCore/Win32/BsWin32Platform.cpp

@@ -6,14 +6,44 @@
 #include "BsCoreApplication.h"
 #include "Debug/BsDebug.h"
 #include "Managers/BsRenderWindowManager.h"
-#include "Win32/BsWin32Defs.h"
+#include "Platform/BsDropTarget.h"
 #include "Win32/BsWin32DropTarget.h"
-#include "Win32/BsWin32PlatformData.h"
 #include "Win32/BsWin32PlatformUtility.h"
 #include "TimeAPI.h"
+#include <shellapi.h>
 
 namespace bs
 {
+	/** Encapsulate native cursor data so we can avoid including windows.h as it pollutes the global namespace. */
+	struct BS_CORE_EXPORT NativeCursorData
+	{
+		HCURSOR cursor;
+	};
+
+	/**	Encapsulate drop target data so we can avoid including windows.h as it pollutes the global namespace. */
+	struct BS_CORE_EXPORT NativeDropTargetData
+	{
+		Map<const RenderWindow*, Win32DropTarget*> dropTargetsPerWindow;
+		Vector<Win32DropTarget*> dropTargetsToInitialize;
+		Vector<Win32DropTarget*> dropTargetsToDestroy;
+	};
+
+	struct Platform::Pimpl
+	{
+		bool mIsCursorHidden = false;
+		NativeCursorData mCursor;
+		bool mUsingCustomCursor = false;
+		Map<const ct::RenderWindow*, WindowNonClientAreaData> mNonClientAreas;
+
+		bool mIsTrackingMouse = false;
+		NativeDropTargetData mDropTargets;
+
+		bool mRequiresStartUp = false;
+		bool mRequiresShutDown = false;
+
+		Mutex mSync;
+	};
+
 	Event<void(const Vector2I&, const OSPointerButtonStates&)> Platform::onCursorMoved;
 	Event<void(const Vector2I&, OSMouseButton button, const OSPointerButtonStates&)> Platform::onCursorButtonPressed;
 	Event<void(const Vector2I&, OSMouseButton button, const OSPointerButtonStates&)> Platform::onCursorButtonReleased;
@@ -250,8 +280,10 @@ namespace bs
 		Sleep((DWORD)duration);
 	}
 
-	OSDropTarget& Platform::createDropTarget(const RenderWindow* window, INT32 x, INT32 y, UINT32 width, UINT32 height)
+	void Win32Platform::registerDropTarget(DropTarget* target)
 	{
+		const RenderWindow* window = target->_getOwnerWindow();
+
 		Win32DropTarget* win32DropTarget = nullptr;
 		auto iterFind = mData->mDropTargets.dropTargetsPerWindow.find(window);
 		if (iterFind == mData->mDropTargets.dropTargetsPerWindow.end())
@@ -270,15 +302,12 @@ namespace bs
 		else
 			win32DropTarget = iterFind->second;
 
-		OSDropTarget* newDropTarget = new (bs_alloc<OSDropTarget>()) OSDropTarget(window, x, y, width, height);
-		win32DropTarget->registerDropTarget(newDropTarget);
-
-		return *newDropTarget;
+		win32DropTarget->registerDropTarget(target);
 	}
 
-	void Platform::destroyDropTarget(OSDropTarget& target)
+	void Win32Platform::unregisterDropTarget(DropTarget* target)
 	{
-		auto iterFind = mData->mDropTargets.dropTargetsPerWindow.find(target._getOwnerWindow());
+		auto iterFind = mData->mDropTargets.dropTargetsPerWindow.find(target->_getOwnerWindow());
 		if (iterFind == mData->mDropTargets.dropTargetsPerWindow.end())
 		{
 			LOGWRN("Attempting to destroy a drop target but cannot find its parent window.");
@@ -286,7 +315,7 @@ namespace bs
 		else
 		{
 			Win32DropTarget* win32DropTarget = iterFind->second;
-			win32DropTarget->unregisterDropTarget(&target);
+			win32DropTarget->unregisterDropTarget(target);
 
 			if(win32DropTarget->getNumDropTargets() == 0)
 			{
@@ -298,8 +327,6 @@ namespace bs
 				}
 			}
 		}
-		
-		BS_PVT_DELETE(OSDropTarget, &target);
 	}
 
 	void Platform::copyToClipboard(const WString& string)

+ 17 - 8
Source/BansheeCore/Win32/BsWin32Platform.h

@@ -3,7 +3,16 @@
 #pragma once
 
 #include "Platform/BsPlatform.h"
-#include "Win32/BsWin32Defs.h"
+
+#define WIN32_LEAN_AND_MEAN
+#if !defined(NOMINMAX) && defined(_MSC_VER)
+#	define NOMINMAX // Required to stop windows.h messing up std::min
+#endif
+#include <windows.h>
+#include <windowsx.h>
+
+#define WM_BS_SETCAPTURE WM_USER + 101
+#define WM_BS_RELEASECAPTURE WM_USER + 102
 
 namespace bs
 {
@@ -11,16 +20,16 @@ namespace bs
 	 *  @{
 	 */
 
-	/**
-	 * Contains the main message loop.
-	 *
-	 * @note	
-	 * This is separated from the main Platform because we don't want to include various Windows defines in a lot of our 
-	 * code that includes "Platform.h".
-	 */
+	/** Various Win32 specific functionality. Contains the main message loop. */
 	class BS_CORE_EXPORT Win32Platform : public Platform
 	{
 	public:
+		/** Called when a new DropTarget gets created. */
+		static void registerDropTarget(DropTarget* target);
+
+		/** Called just before a DropTarget gets destroyed. */
+		static void unregisterDropTarget(DropTarget* target);
+
 		/** Main message loop callback that processes messages received from windows. */
 		static LRESULT CALLBACK _win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 	};

+ 6 - 8
Source/BansheeEditor/GUI/BsGUIResourceTreeView.cpp

@@ -7,7 +7,7 @@
 #include "GUI/BsGUIWidget.h"
 #include "RenderAPI/BsViewport.h"
 #include "RenderAPI/BsRenderWindow.h"
-#include "Platform/BsPlatform.h"
+#include "Platform/BsDropTarget.h"
 
 using namespace std::placeholders;
 
@@ -78,9 +78,7 @@ namespace bs
 		GUITreeView::_updateLayoutInternal(data);
 
 		if(mDropTarget != nullptr)
-		{
-			mDropTarget->setArea(data.area.x, data.area.y, data.area.width, data.area.height);
-		}
+			mDropTarget->setArea(data.area);
 	}
 
 	void GUIResourceTreeView::updateTreeElementHierarchy()
@@ -273,7 +271,7 @@ namespace bs
 	{
 		if(mDropTarget != nullptr)
 		{
-			Platform::destroyDropTarget(*mDropTarget);
+			mDropTarget = nullptr;
 
 			mDropTargetEnterConn.disconnect();
 			mDropTargetLeaveConn.disconnect();
@@ -284,7 +282,7 @@ namespace bs
 		if(parentWindow != nullptr)
 		{
 			mCurrentWindow = parentWindow;
-			mDropTarget = &Platform::createDropTarget(mCurrentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
+			mDropTarget = DropTarget::create(mCurrentWindow, mLayoutData.area);
 
 			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
 			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
@@ -341,9 +339,9 @@ namespace bs
 				treeElement = element->parent;
 		}
 
-		if(mDropTarget->getDropType() == OSDropType::FileList)
+		if(mDropTarget->getDropType() == DropTargetType::FileList)
 		{
-			Vector<WString> fileList = mDropTarget->getFileList();
+			Vector<Path> fileList = mDropTarget->getFileList();
 
 			mDraggedResources = bs_new<InternalDraggedResources>((UINT32)fileList.size());
 			for(UINT32 i = 0; i < (UINT32)fileList.size(); i++)

+ 3 - 1
Source/BansheeEditor/GUI/BsGUIResourceTreeView.h

@@ -10,6 +10,8 @@
 
 namespace bs
 {
+	class DropTarget;
+
 	/** @addtogroup GUI-Editor-Internal
 	 *  @{
 	 */
@@ -105,7 +107,7 @@ namespace bs
 		InternalDraggedResources* mDraggedResources;
 		ResourceTreeElement mRootElement;
 		RenderWindow* mCurrentWindow;
-		OSDropTarget* mDropTarget;
+		SPtr<DropTarget> mDropTarget;
 		bool mDropTargetDragActive;
 
 		HEvent mDropTargetEnterConn;

+ 0 - 7
Source/BansheeUtility/Linux/BsUnixPlatformUtility.cpp

@@ -130,11 +130,4 @@ namespace bs
 
 		return String(uuidChars);
 	}
-
-	void PlatformUtility::open(const Path& path)
-	{
-		// TODOPORT - This call will likely need to be renamed to openURL, and additionals calls
-		// added depending on exact usage, since there is no direct equivalent to ShellExecute on
-		// Linux.
-	}
 }

+ 1 - 0
Source/SBansheeEditor/Wrappers/BsScriptEditorApplication.cpp

@@ -19,6 +19,7 @@
 #include "GUI/BsGUIMenuBar.h"
 #include "BsPlayInEditorManager.h"
 #include "Wrappers/BsScriptRenderTarget.h"
+#include "Platform/BsPlatform.h"
 #include "BsScriptResourceManager.h"
 #include "FileSystem/BsFileSystem.h"
 #include "Wrappers/BsScriptPrefab.h"

+ 7 - 7
Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.cpp

@@ -9,7 +9,7 @@
 #include "BsMonoUtil.h"
 #include "BsMonoArray.h"
 #include "Reflection/BsRTTIType.h"
-#include "Platform/BsPlatform.h"
+#include "Platform/BsDropTarget.h"
 #include "EditorWindow/BsEditorWidget.h"
 #include "EditorWindow/BsEditorWindowBase.h"
 #include "EditorWindow/BsEditorWidgetContainer.h"
@@ -86,12 +86,12 @@ namespace bs
 
 	MonoArray* ScriptOSDropTarget::internal_GetFilePaths(ScriptOSDropTarget* nativeInstance)
 	{
-		OSDropTarget* dropTarget = nativeInstance->mDropTarget;
+		SPtr<DropTarget> dropTarget = nativeInstance->mDropTarget;
 
-		if (nativeInstance->mIsDestroyed || dropTarget == nullptr || dropTarget->getDropType() != OSDropType::FileList)
+		if (nativeInstance->mIsDestroyed || dropTarget == nullptr || dropTarget->getDropType() != DropTargetType::FileList)
 			return ScriptArray::create<String>(0).getInternal();
 
-		Vector<WString> fileList = dropTarget->getFileList();
+		Vector<Path> fileList = dropTarget->getFileList();
 		ScriptArray output = ScriptArray::create<WString>((UINT32)fileList.size());
 
 		UINT32 idx = 0;
@@ -139,7 +139,7 @@ namespace bs
 	{
 		if (mDropTarget != nullptr)
 		{
-			Platform::destroyDropTarget(*mDropTarget);
+			mDropTarget = nullptr;
 
 			mDropTargetEnterConn.disconnect();
 			mDropTargetLeaveConn.disconnect();
@@ -149,7 +149,7 @@ namespace bs
 
 		if (parentWindow != nullptr)
 		{
-			mDropTarget = &Platform::createDropTarget(parentWindow.get(), x, y, width, height);
+			mDropTarget = DropTarget::create(parentWindow.get(), Rect2I(x, y, width, height));
 
 			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&ScriptOSDropTarget::dropTargetDragEnter, this, _1, _2));
 			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&ScriptOSDropTarget::dropTargetDragMove, this, _1, _2));
@@ -166,7 +166,7 @@ namespace bs
 		Rect2I dropTargetArea = getDropTargetArea();
 
 		if (mDropTarget != nullptr)
-			mDropTarget->setArea(dropTargetArea.x, dropTargetArea.y, dropTargetArea.width, dropTargetArea.height);
+			mDropTarget->setArea(dropTargetArea);
 	}
 
 	void ScriptOSDropTarget::dropTargetDragEnter(ScriptOSDropTarget* thisPtr, INT32 x, INT32 y)

+ 3 - 1
Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.h

@@ -8,6 +8,8 @@
 
 namespace bs
 {
+	class DropTarget;
+
 	/** @addtogroup ScriptInteropEditor
 	 *  @{
 	 */
@@ -102,7 +104,7 @@ namespace bs
 		static void dropTargetDragDropped(ScriptOSDropTarget* thisPtr, INT32 x, INT32 y);
 
 		ScriptEditorWindow* mParent;
-		OSDropTarget* mDropTarget;
+		SPtr<DropTarget> mDropTarget;
 		Rect2I mParentArea;
 		Rect2I mArea;
 		bool mIsDestroyed;