Browse Source

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 12 years ago
parent
commit
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