Explorar o código

Fixed an issue where dragging widgets off the dock manager would cause an exception because the widget container was destroyed before the Drop callback was called

Marko Pintera %!s(int64=12) %!d(string=hai) anos
pai
achega
6085bed845

+ 2 - 1
BansheeEngine/Include/BsDragAndDropManager.h

@@ -17,6 +17,7 @@ namespace BansheeEngine
 		bool isDragInProgress() const { return mIsDragInProgress; }
 		CM::UINT32 getDragTypeId() const { return mDragTypeId; }
 		void* getDragData() const { return mData; }
+		void addDropCallback(std::function<void(bool)> dropCallback);
 
 		/**
 		 * @brief	Called once per frame. Internal method.
@@ -28,7 +29,7 @@ namespace BansheeEngine
 		CM::HTexture mIcon;
 		CM::UINT32 mDragTypeId;
 		void* mData;
-		std::function<void(bool)> mDropCallback;
+		CM::Vector<std::function<void(bool)>>::type mDropCallbacks;
 		bool mIsDragInProgress;
 
 		std::atomic<bool> mCaptureChanged;

+ 9 - 4
BansheeEngine/Source/BsDragAndDropManager.cpp

@@ -13,12 +13,17 @@ namespace BansheeEngine
 		Input::instance().onCursorReleased.connect(boost::bind(&DragAndDropManager::cursorReleased, this, _1));
 	}
 
+	void DragAndDropManager::addDropCallback(std::function<void(bool)> dropCallback)
+	{
+		mDropCallbacks.push_back(dropCallback);
+	}
+
 	void DragAndDropManager::startDrag(CM::HTexture icon, CM::UINT32 typeId, void* data, std::function<void(bool)> dropCallback)
 	{
 		mIcon = icon;
 		mDragTypeId = typeId;
 		mData = data;
-		mDropCallback = dropCallback;
+		addDropCallback(dropCallback);
 		mIsDragInProgress = true;
 
 		mCaptureActive.store(false);
@@ -42,12 +47,12 @@ namespace BansheeEngine
 
 	void DragAndDropManager::endDrag(bool processed)
 	{
-		if(mDropCallback != nullptr)
-			mDropCallback(processed);
+		for(auto& callback : mDropCallbacks)
+			callback(processed);
 
 		mDragTypeId = 0;
 		mData = nullptr;
-		mDropCallback = nullptr;
+		mDropCallbacks.clear();
 		mIsDragInProgress = false;
 	}
 

+ 1 - 6
CamelotClient/Include/BsEditorWidgetContainer.h

@@ -24,8 +24,6 @@ namespace BansheeEditor
 		CM::RectI getContentBounds() const;
 
 		void _notifyWidgetDestroyed(EditorWidget* widget);
-		bool _isHandlingWidgetDragAndDrop() const { return mIsHandlingWidgetDragAndDrop; }
-		void _addCallbackOnDraggedWidgetDropped(std::function<void()> callback);
 
 		boost::signal<void()> onWidgetClosed;
 	private:
@@ -36,9 +34,6 @@ namespace BansheeEditor
 		CM::Vector<EditorWidget*>::type mWidgets;
 		CM::INT32 mActiveWidget;
 
-		std::function<void()> mWidgetDroppedCallback;
-		bool mIsHandlingWidgetDragAndDrop;
-
 		static const CM::UINT32 TitleBarHeight;
 
 		void setActiveWidget(CM::UINT32 idx);
@@ -47,6 +42,6 @@ namespace BansheeEditor
 		void tabDraggedOff(CM::UINT32 idx);
 		void tabDraggedOn(CM::UINT32 idx);
 
-		void tabDroppedCallback(bool wasDragProcessed);
+		static void tabDroppedCallback(bool wasDragProcessed);
 	};
 }

+ 3 - 19
CamelotClient/Source/BsEditorWidgetContainer.cpp

@@ -15,8 +15,7 @@ namespace BansheeEditor
 	const CM::UINT32 EditorWidgetContainer::TitleBarHeight = 13;
 
 	EditorWidgetContainer::EditorWidgetContainer(BS::GUIWidget* parent, RenderWindow* renderWindow)
-		:mParent(parent), mX(0), mY(0), mWidth(0), mHeight(0), mTitleBar(nullptr), mActiveWidget(-1),
-		mIsHandlingWidgetDragAndDrop(false)
+		:mParent(parent), mX(0), mY(0), mWidth(0), mHeight(0), mTitleBar(nullptr), mActiveWidget(-1)
 	{
 		mTitleBar = GUITabbedTitleBar::create(*parent, renderWindow);
 		mTitleBar->onTabActivated.connect(boost::bind(&EditorWidgetContainer::tabActivated, this, _1));
@@ -191,10 +190,9 @@ namespace BansheeEditor
 		EditorWidget* widget = mWidgets[idx];
 		remove(*widget);
 
-		mIsHandlingWidgetDragAndDrop = true;
-
 		// TODO - Hook up drag and drop texture
-		DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::EditorWidget, (void*)widget, boost::bind(&EditorWidgetContainer::tabDroppedCallback, this, _1));
+		DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::EditorWidget, (void*)widget, 
+			boost::bind(&EditorWidgetContainer::tabDroppedCallback, _1));
 
 		if(!onWidgetClosed.empty())
 			onWidgetClosed();
@@ -230,14 +228,6 @@ namespace BansheeEditor
 			Vector2I mousePos = Input::instance().getCursorPosition();
 			newWindow->setPosition(mousePos.x, mousePos.y);
 		}
-
-		mIsHandlingWidgetDragAndDrop = false;
-
-		if(mWidgetDroppedCallback != nullptr)
-		{
-			mWidgetDroppedCallback();
-			mWidgetDroppedCallback = nullptr;
-		}
 	}
 
 	RectI EditorWidgetContainer::getContentBounds() const
@@ -260,10 +250,4 @@ namespace BansheeEditor
 			}
 		}		
 	}
-
-	void EditorWidgetContainer::_addCallbackOnDraggedWidgetDropped(std::function<void()> callback)
-	{
-		if(mIsHandlingWidgetDragAndDrop)
-			mWidgetDroppedCallback = callback;
-	}
 }

+ 3 - 2
CamelotClient/Source/BsEditorWindow.cpp

@@ -1,6 +1,7 @@
 #include "BsEditorWindow.h"
 #include "BsEditorWidgetContainer.h"
 #include "BsEditorWindowManager.h"
+#include "BsDragAndDropManager.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
@@ -45,12 +46,12 @@ namespace BansheeEditor
 			// destroy its parent window just yet because Windows doesn't approve of
 			// windows being destroyed while mouse is being held down (some events won't get
 			// fired). I should probably handle this at a lower level, in RenderWindowManager.
-			if(mWidgets->_isHandlingWidgetDragAndDrop())
+			if(DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::EditorWidget)
 			{
 				hide();
 
 				// Get notified when drag and drop is done
-				mWidgets->_addCallbackOnDraggedWidgetDropped(std::bind(&EditorWindow::closeWindowDelayed, this));
+				DragAndDropManager::instance().addDropCallback(std::bind(&EditorWindow::closeWindowDelayed, this));
 			}
 			else
 				close();

+ 2 - 0
EditorWindowDock.txt

@@ -1,4 +1,6 @@
 TODO:
+ - Add GUIElementContainer, a class that does no rendering but contains other GUIElements. Use it for GUIScrolArea, GUITabbedTitleBar and GUIDockManager
+ - DO NOT make EditorWidgetContainer a GUIElement. Instead refactor _updateLayoutInternal in GUITabbedTitleBar into "updateLayout" and make it do all the work EditorWidgetContainer does now
  - Docking/Undocking elements will cause an exception. Happened after TabbedTitleBar refactor
  - When I dock two windows (maybe even just one?) and drag the title bar, layout seems to get messed up
  - Ensure that dragging items onto the title bar works