Bläddra i källkod

Drag and drop system now properly sets cursors

Marko Pintera 11 år sedan
förälder
incheckning
cae09d9c91

+ 1 - 0
BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -76,6 +76,7 @@ namespace BansheeEditor
 		virtual void dragAndDropStart();
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
+		virtual bool _acceptDragAndDrop(const CM::Vector2I position, CM::UINT32 typeId) const;
 
 		void updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry);
 		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const CM::WString& fullPath);

+ 1 - 0
BansheeEditor/Include/BsGUISceneTreeView.h

@@ -64,6 +64,7 @@ namespace BansheeEditor
 		virtual void dragAndDropStart();
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
+		virtual bool _acceptDragAndDrop(const CM::Vector2I position, CM::UINT32 typeId) const;
 
 		void deleteTreeElementInternal(TreeElement* element);
 	};

+ 2 - 3
BansheeEditor/Source/BsEditorWidgetContainer.cpp

@@ -199,9 +199,8 @@ namespace BansheeEditor
 		EditorWidgetBase* widget = mWidgets[uniqueIdx];
 		removeInternal(*widget);
 
-		// TODO - Hook up drag and drop texture
-		DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::EditorWidget, (void*)widget, 
-			boost::bind(&EditorWidgetContainer::tabDroppedCallback, _1));
+		DragAndDropManager::instance().startDrag((UINT32)DragAndDropType::EditorWidget, (void*)widget, 
+			boost::bind(&EditorWidgetContainer::tabDroppedCallback, _1), false);
 
 		if(!onWidgetClosed.empty())
 			onWidgetClosed();

+ 7 - 2
BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -412,8 +412,8 @@ namespace BansheeEditor
 
 		mDraggedResources = internalDraggedResources;
 
-		DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::Resources, (void*)draggedResources, 
-			boost::bind(&GUIResourceTreeView::dragAndDropFinalize, this));
+		DragAndDropManager::instance().startDrag((UINT32)DragAndDropType::Resources, (void*)draggedResources, 
+			boost::bind(&GUIResourceTreeView::dragAndDropFinalize, this), true);
 	}
 
 	void GUIResourceTreeView::dragAndDropEnded(TreeElement* overTreeElement)
@@ -468,6 +468,11 @@ namespace BansheeEditor
 			clearDropTarget();
 	}
 
+	bool GUIResourceTreeView::_acceptDragAndDrop(const CM::Vector2I position, CM::UINT32 typeId) const
+	{
+		return typeId == (UINT32)DragAndDropType::Resources;
+	}
+
 	const String& GUIResourceTreeView::getGUITypeName()
 	{
 		static String typeName = "ResourceTreeView";

+ 7 - 2
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -225,8 +225,8 @@ namespace BansheeEditor
 			cnt++;
 		}
 
-		DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::SceneObject, (void*)draggedSceneObjects, 
-			boost::bind(&GUISceneTreeView::dragAndDropFinalize, this));
+		DragAndDropManager::instance().startDrag((UINT32)DragAndDropType::SceneObject, (void*)draggedSceneObjects, 
+			boost::bind(&GUISceneTreeView::dragAndDropFinalize, this), true);
 	}
 
 	void GUISceneTreeView::dragAndDropEnded(TreeElement* overTreeElement)
@@ -258,6 +258,11 @@ namespace BansheeEditor
 		cm_delete(draggedSceneObjects);
 	}
 
+	bool GUISceneTreeView::_acceptDragAndDrop(const CM::Vector2I position, CM::UINT32 typeId) const
+	{
+		return typeId == (UINT32)DragAndDropType::SceneObject;
+	}
+
 	const String& GUISceneTreeView::getGUITypeName()
 	{
 		static String typeName = "SceneTreeView";

+ 18 - 2
BansheeEngine/Include/BsDragAndDropManager.h

@@ -13,10 +13,26 @@ namespace BansheeEngine
 	public:
 		DragAndDropManager();
 
-		void startDrag(CM::HTexture icon, CM::UINT32 typeId, void* data, std::function<void(bool)> dropCallback);
+		/**
+		 * @brief	Starts a drag operation of the specified type. This means GUI elements will start receiving
+		 * 			drag and drop related events and they may choose to handle them.
+		 *
+		 * @param	typeId					Type of the drag and drop operation that other objects may query and decide if they want
+		 * 									to handle it.
+		 * @param 	data					Some operation specific data that is just passed through to however needs it.
+		 * @param	dropCallback			The drop callback that gets triggered whenever mouse button is released and drag operation ends.
+		 * 									You should perform any cleanup here.
+		 * @param	needsValidDropTarget	(optional) Determines whether the drop operation may happen anywhere or does the GUI element need to specifically
+		 * 									accept the drag of this type. If false all GUI elements we mouse over will receive drag/drop events, otherwise only
+		 * 									those that specifically subscribe to the specified drag operation of this typeId will.
+		 * 									
+		 *									Additionally this will determine the cursor displayed (whether or not it can have a "denied" state).
+		 */
+		void startDrag(CM::UINT32 typeId, void* data, std::function<void(bool)> dropCallback, bool needsValidDropTarget = false);
 		bool isDragInProgress() const { return mIsDragInProgress; }
 		CM::UINT32 getDragTypeId() const { return mDragTypeId; }
 		void* getDragData() const { return mData; }
+		bool needsValidDropTarget() const { return mNeedsValidDropTarget; }
 		void addDropCallback(std::function<void(bool)> dropCallback);
 
 		/**
@@ -26,11 +42,11 @@ namespace BansheeEngine
 
 		boost::signal<bool(const CM::PositionalInputEvent&)> onDragEnded;
 	private:
-		CM::HTexture mIcon;
 		CM::UINT32 mDragTypeId;
 		void* mData;
 		CM::Vector<std::function<void(bool)>>::type mDropCallbacks;
 		bool mIsDragInProgress;
+		bool mNeedsValidDropTarget;
 
 		std::atomic<bool> mCaptureChanged;
 		std::atomic<int> mCaptureActive;

+ 1 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -132,6 +132,7 @@ namespace BansheeEngine
 		GUIWidget& _getParentWidget() const { return *mParent; }
 		virtual bool _isInBounds(const CM::Vector2I position) const;
 		virtual bool _hasCustomCursor(const CM::Vector2I position, CursorType& type) const { return false; }
+		virtual bool _acceptDragAndDrop(const CM::Vector2I position, CM::UINT32 typeId) const { return false; }
 
 		virtual GUIContextMenu* getContextMenu() const { return nullptr; }
 

+ 3 - 3
BansheeEngine/Source/BsDragAndDropManager.cpp

@@ -7,7 +7,7 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	DragAndDropManager::DragAndDropManager()
-		:mIsDragInProgress(false), mDragTypeId(0), mData(nullptr), mCaptureChanged(false), mCaptureActive(0)
+		:mIsDragInProgress(false), mDragTypeId(0), mData(nullptr), mCaptureChanged(false), mCaptureActive(0), mNeedsValidDropTarget(false)
 	{
 		Platform::onMouseCaptureChanged.connect(boost::bind(&DragAndDropManager::mouseCaptureChanged, this));
 		Input::instance().onCursorReleased.connect(boost::bind(&DragAndDropManager::cursorReleased, this, _1));
@@ -18,11 +18,11 @@ namespace BansheeEngine
 		mDropCallbacks.push_back(dropCallback);
 	}
 
-	void DragAndDropManager::startDrag(CM::HTexture icon, CM::UINT32 typeId, void* data, std::function<void(bool)> dropCallback)
+	void DragAndDropManager::startDrag(CM::UINT32 typeId, void* data, std::function<void(bool)> dropCallback, bool needsValidDropTarget)
 	{
-		mIcon = icon;
 		mDragTypeId = typeId;
 		mData = data;
+		mNeedsValidDropTarget = needsValidDropTarget;
 		addDropCallback(dropCallback);
 		mIsDragInProgress = true;
 

+ 44 - 8
BansheeEngine/Source/BsGUIManager.cpp

@@ -627,11 +627,20 @@ namespace BansheeEngine
 				if(elementInfo.widget != nullptr)
 					localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
 
-				mMouseEvent.setDragAndDropDroppedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
-				bool processed = sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent);
+				bool acceptDrop = true;
+				if(DragAndDropManager::instance().needsValidDropTarget())
+				{
+					acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
+				}
 
-				if(processed)
-					return true;
+				if(acceptDrop)
+				{
+					mMouseEvent.setDragAndDropDroppedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
+					bool processed = sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent);
+
+					if(processed)
+						return true;
+				}
 			}
 		}
 
@@ -690,17 +699,44 @@ namespace BansheeEngine
 			// Also if drag is in progress send DragAndDrop events
 			if(DragAndDropManager::instance().isDragInProgress())
 			{
+				bool acceptDrop = true;
 				for(auto& elementInfo : mElementsUnderCursor)
 				{
 					Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
 
-					mMouseEvent.setDragAndDropDraggedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
-					if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
+					acceptDrop = true;
+					if(DragAndDropManager::instance().needsValidDropTarget())
 					{
-						event.markAsUsed();
-						break;
+						acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
+					}
+
+					if(acceptDrop)
+					{
+						mMouseEvent.setDragAndDropDraggedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
+						if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
+						{
+							event.markAsUsed();
+							break;
+						}
 					}
 				}
+
+				if(acceptDrop)
+				{
+					if(mActiveCursor != CursorType::ArrowDrag)
+					{
+						Cursor::instance().setCursor(CursorType::ArrowDrag);
+						mActiveCursor = CursorType::ArrowDrag;
+					}
+				}
+				else
+				{
+					if(mActiveCursor != CursorType::Deny)
+					{
+						Cursor::instance().setCursor(CursorType::Deny);
+						mActiveCursor = CursorType::Deny;
+					}
+				}				
 			}
 		}
 		else // Otherwise, send MouseMove events if we are hovering over any element