Browse Source

Various dock manager improvements

Marko Pintera 12 years ago
parent
commit
0ec5fa301f

+ 1 - 1
BansheeEngine/Include/BsGUIManager.h

@@ -103,7 +103,7 @@ namespace BansheeEngine
 		 */
 		 */
 		void setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element);
 		void setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element);
 
 
-		boost::signal<void(GUIWidget*, GUIElement*, const GUIMouseEvent&)> mouseEventFilter;
+		boost::signal<bool(GUIWidget*, GUIElement*, const GUIMouseEvent&)> mouseEventFilter;
 		boost::signal<void(GUIWidget*, GUIElement*, const GUITextInputEvent&)> textInputEventFilter;
 		boost::signal<void(GUIWidget*, GUIElement*, const GUITextInputEvent&)> textInputEventFilter;
 	private:
 	private:
 		struct SelectiveInputData
 		struct SelectiveInputData

+ 10 - 2
BansheeEngine/Source/BsGUIManager.cpp

@@ -576,7 +576,12 @@ namespace BansheeEngine
 		{
 		{
 			if(mElementUnderCursor != nullptr)
 			if(mElementUnderCursor != nullptr)
 			{
 			{
-				mMouseEvent.setDragAndDropDroppedData(mElementUnderCursor, Vector2I(), DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
+				Vector2I localPos;
+
+				if(mWidgetUnderCursor != nullptr)
+					localPos = getWidgetRelativePos(*mWidgetUnderCursor, event.screenPos);
+
+				mMouseEvent.setDragAndDropDroppedData(mElementUnderCursor, localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
 				bool processed = sendMouseEvent(mWidgetUnderCursor, mElementUnderCursor, mMouseEvent);
 				bool processed = sendMouseEvent(mWidgetUnderCursor, mElementUnderCursor, mMouseEvent);
 
 
 				return processed;
 				return processed;
@@ -1243,7 +1248,10 @@ namespace BansheeEngine
 	bool GUIManager::sendMouseEvent(GUIWidget* widget, GUIElement* element, const GUIMouseEvent& event)
 	bool GUIManager::sendMouseEvent(GUIWidget* widget, GUIElement* element, const GUIMouseEvent& event)
 	{
 	{
 		if(!mouseEventFilter.empty())
 		if(!mouseEventFilter.empty())
-			mouseEventFilter(widget, element, event);
+		{
+			if(mouseEventFilter(widget, element, event)) // TODO - If multiple filters and processed at once I should only call the first one
+				return true;
+		}
 
 
 		return widget->_mouseEvent(element, event);
 		return widget->_mouseEvent(element, event);
 	}
 	}

+ 8 - 3
CamelotClient/Include/BsDockManager.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
+#include "CmRectI.h"
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
@@ -15,10 +16,12 @@ namespace BansheeEditor
 		{
 		{
 		public:
 		public:
 			DockContainer();
 			DockContainer();
+			DockContainer(DockContainer* parent);
 			~DockContainer();
 			~DockContainer();
 
 
 			void setArea(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
 			void setArea(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
 			void makeLeaf(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void makeLeaf(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
+			void makeLeaf(EditorWidgetContainer* existingContainer);
 			void addLeft(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void addLeft(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void addRight(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void addRight(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void addTop(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
 			void addTop(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
@@ -37,9 +40,9 @@ namespace BansheeEditor
 
 
 			bool mIsLeaf;
 			bool mIsLeaf;
 			DockContainer* mChildren[2];
 			DockContainer* mChildren[2];
+			DockContainer* mParent;
 			EditorWidgetContainer* mWidgets;
 			EditorWidgetContainer* mWidgets;
-			CM::INT32 mX, mY;
-			CM::UINT32 mWidth, mHeight;
+			CM::RectI mArea;
 			float mSplitPosition;
 			float mSplitPosition;
 			bool mIsHorizontal;
 			bool mIsHorizontal;
 
 
@@ -47,6 +50,7 @@ namespace BansheeEditor
 
 
 		private:
 		private:
 			void splitContainer(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget, bool horizontal, bool newChildIsFirst);
 			void splitContainer(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget, bool horizontal, bool newChildIsFirst);
+			void widgetRemoved();
 		};
 		};
 
 
 		enum class DockLocation
 		enum class DockLocation
@@ -84,6 +88,7 @@ namespace BansheeEditor
 
 
 		DockContainer* mMouseOverContainer;
 		DockContainer* mMouseOverContainer;
 		DockLocation mHighlightedDropLoc;
 		DockLocation mHighlightedDropLoc;
+		bool mShowOverlay;
 		CM::Vector2* mTopDropPolygon;
 		CM::Vector2* mTopDropPolygon;
 		CM::Vector2* mBotDropPolygon;
 		CM::Vector2* mBotDropPolygon;
 		CM::Vector2* mLeftDropPolygon;
 		CM::Vector2* mLeftDropPolygon;
@@ -91,7 +96,7 @@ namespace BansheeEditor
 
 
 		void updateDropOverlay(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
 		void updateDropOverlay(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
 
 
-		void onGUIMouseEvent(BS::GUIWidget* widget, BS::GUIElement* element, const BS::GUIMouseEvent& event);
+		bool onGUIMouseEvent(BS::GUIWidget* widget, BS::GUIElement* element, const BS::GUIMouseEvent& event);
 		bool insidePolygon(CM::Vector2* polyPoints, CM::UINT32 numPoints, CM::Vector2 point) const;
 		bool insidePolygon(CM::Vector2* polyPoints, CM::UINT32 numPoints, CM::Vector2 point) const;
 	};
 	};
 }
 }

+ 147 - 43
CamelotClient/Source/BsDockManager.cpp

@@ -27,8 +27,16 @@ namespace BansheeEditor
 	const CM::Color DockManager::HIGHLIGHT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.42f);
 	const CM::Color DockManager::HIGHLIGHT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.42f);
 
 
 	DockManager::DockContainer::DockContainer()
 	DockManager::DockContainer::DockContainer()
-		:mIsLeaf(false), mWidgets(nullptr), mX(0), mY(0), mWidth(0), mHeight(0), mSplitPosition(0.5f),
-		mIsHorizontal(false)
+		:mIsLeaf(false), mWidgets(nullptr), mSplitPosition(0.5f),
+		mIsHorizontal(false), mParent(nullptr)
+	{
+		mChildren[0] = nullptr;
+		mChildren[1] = nullptr;
+	}
+
+	DockManager::DockContainer::DockContainer(DockContainer* parent)
+		:mIsLeaf(false), mWidgets(nullptr), mSplitPosition(0.5f),
+		mIsHorizontal(false), mParent(parent)
 	{
 	{
 		mChildren[0] = nullptr;
 		mChildren[0] = nullptr;
 		mChildren[1] = nullptr;
 		mChildren[1] = nullptr;
@@ -53,10 +61,10 @@ namespace BansheeEditor
 
 
 	void DockManager::DockContainer::setArea(CM::INT32 x, CM::INT32 y, UINT32 width, UINT32 height)
 	void DockManager::DockContainer::setArea(CM::INT32 x, CM::INT32 y, UINT32 width, UINT32 height)
 	{
 	{
-		mX = x;
-		mY = y;
-		mWidth = width;
-		mHeight = height;
+		mArea.x = x;
+		mArea.y = y;
+		mArea.width = width;
+		mArea.height = height;
 
 
 		if(mIsLeaf)
 		if(mIsLeaf)
 		{
 		{
@@ -70,23 +78,23 @@ namespace BansheeEditor
 		{
 		{
 			if(mIsHorizontal)
 			if(mIsHorizontal)
 			{
 			{
-				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mHeight - (INT32)SliderSize);
+				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SliderSize);
 				UINT32 sizeTop = Math::floorToInt(remainingSize * mSplitPosition);
 				UINT32 sizeTop = Math::floorToInt(remainingSize * mSplitPosition);
 				UINT32 sizeBottom = remainingSize - sizeTop;
 				UINT32 sizeBottom = remainingSize - sizeTop;
 
 
-				mChildren[0]->setArea(mX, mY, mWidth, sizeTop);
-				mChildren[1]->setArea(mX, mY + sizeTop + SliderSize, mWidth, sizeBottom);
+				mChildren[0]->setArea(mArea.x, mArea.y, mArea.width, sizeTop);
+				mChildren[1]->setArea(mArea.x, mArea.y + sizeTop + SliderSize, mArea.width, sizeBottom);
 
 
 				// TODO - Set slider position
 				// TODO - Set slider position
 			}
 			}
 			else
 			else
 			{
 			{
-				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mWidth - (INT32)SliderSize);
+				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SliderSize);
 				UINT32 sizeLeft = Math::floorToInt(remainingSize * mSplitPosition);
 				UINT32 sizeLeft = Math::floorToInt(remainingSize * mSplitPosition);
 				UINT32 sizeRight = remainingSize - sizeLeft;
 				UINT32 sizeRight = remainingSize - sizeLeft;
 
 
-				mChildren[0]->setArea(mX, mY, sizeLeft, mHeight);
-				mChildren[1]->setArea(mX + sizeLeft + SliderSize, mY, sizeRight, mHeight);
+				mChildren[0]->setArea(mArea.x, mArea.y, sizeLeft, mArea.height);
+				mChildren[1]->setArea(mArea.x + sizeLeft + SliderSize, mArea.y, sizeRight, mArea.height);
 
 
 				// TODO - Set slider position
 				// TODO - Set slider position
 			}
 			}
@@ -98,9 +106,22 @@ namespace BansheeEditor
 		mIsLeaf = true;
 		mIsLeaf = true;
 		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow);
 		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow);
 
 
+		mWidgets->onWidgetClosed.connect(boost::bind(&DockManager::DockContainer::widgetRemoved, this));
+
 		mWidgets->add(*widget);
 		mWidgets->add(*widget);
-		mWidgets->setPosition(mX, mY);
-		mWidgets->setSize(mWidth, mHeight);
+		mWidgets->setPosition(mArea.x, mArea.y);
+		mWidgets->setSize(mArea.width, mArea.height);
+	}
+
+	void DockManager::DockContainer::makeLeaf(EditorWidgetContainer* existingContainer)
+	{
+		mIsLeaf = true;
+		mWidgets = existingContainer;
+
+		mWidgets->onWidgetClosed.connect(boost::bind(&DockManager::DockContainer::widgetRemoved, this));
+
+		mWidgets->setPosition(mArea.x, mArea.y);
+		mWidgets->setSize(mArea.width, mArea.height);
 	}
 	}
 
 
 	void DockManager::DockContainer::addLeft(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
 	void DockManager::DockContainer::addLeft(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
@@ -128,19 +149,59 @@ namespace BansheeEditor
 		UINT32 idxA = newChildIsFirst ? 0 : 1;
 		UINT32 idxA = newChildIsFirst ? 0 : 1;
 		UINT32 idxB = (idxA + 1) % 2;
 		UINT32 idxB = (idxA + 1) % 2;
 
 
-		mChildren[idxA] = cm_new<DockContainer>();
-		mChildren[idxB] = cm_new<DockContainer>(*this);
+		mChildren[idxA] = cm_new<DockContainer>(this);
+		mChildren[idxB] = cm_new<DockContainer>(this);
 
 
 		mChildren[idxA]->makeLeaf(widgetParent, parentWindow, widget);
 		mChildren[idxA]->makeLeaf(widgetParent, parentWindow, widget);
 
 
 		mIsLeaf = false;
 		mIsLeaf = false;
 		mIsHorizontal = horizontal;
 		mIsHorizontal = horizontal;
-		mWidgets = nullptr;
 		mSplitPosition = 0.5f;
 		mSplitPosition = 0.5f;
 
 
+		if(mWidgets != nullptr)
+			cm_delete(mWidgets);
+
+		mWidgets = nullptr;
+
 		// TODO - Add slider
 		// TODO - Add slider
 
 
-		setArea(mX, mY, mWidth, mHeight);
+		setArea(mArea.x, mArea.y, mArea.width, mArea.height);
+	}
+
+	void DockManager::DockContainer::widgetRemoved()
+	{
+		assert(mIsLeaf);
+
+		if(mWidgets->getNumWidgets() == 0)
+		{
+			if(mParent == nullptr) // We're root so we just reset ourselves, can't delete root
+			{
+				cm_delete(mWidgets);
+				mWidgets = nullptr;
+
+				mIsLeaf = false;
+				mSplitPosition = 0.5f;
+				mIsHorizontal = false;
+			}
+			else
+			{
+				// Replace our parent with our sibling
+				DockContainer* sibling = nullptr;
+				if(mParent->mChildren[0] == this)
+					sibling = mParent->mChildren[1];
+				else
+					sibling = mParent->mChildren[0];
+
+				sibling->mWidgets->onWidgetClosed.disconnect_all_slots();
+				sibling->mWidgets->onWidgetHidden.disconnect_all_slots();
+				sibling->mWidgets = nullptr;
+
+				mParent->makeLeaf(sibling->mWidgets);
+
+				cm_delete(sibling);
+				cm_delete(this);
+			}
+		}
 	}
 	}
 
 
 	DockManager::DockContainer* DockManager::DockContainer::find(EditorWidgetContainer* widgetContainer)
 	DockManager::DockContainer* DockManager::DockContainer::find(EditorWidgetContainer* widgetContainer)
@@ -168,8 +229,7 @@ namespace BansheeEditor
 	{
 	{
 		if(mIsLeaf)
 		if(mIsLeaf)
 		{
 		{
-			if(pos.x >= (float)mX && pos.x < (float)(mX + mWidth) &&
-				pos.y >= (float)mY && pos.y < (float)(mY + mHeight))
+			if(mArea.contains(pos))
 			{
 			{
 				return this;
 				return this;
 			}
 			}
@@ -187,7 +247,8 @@ namespace BansheeEditor
 	}
 	}
 
 
 	DockManager::DockManager(BS::GUIWidget* parent, CM::RenderWindow* parentWindow)
 	DockManager::DockManager(BS::GUIWidget* parent, CM::RenderWindow* parentWindow)
-		:mParent(parent), mParentWindow(parentWindow), mMouseOverContainer(nullptr), mHighlightedDropLoc(DockLocation::None)
+		:mParent(parent), mParentWindow(parentWindow), mMouseOverContainer(nullptr), mHighlightedDropLoc(DockLocation::None),
+		mShowOverlay(false)
 	{
 	{
 		mTopDropPolygon = cm_newN<Vector2>(4);
 		mTopDropPolygon = cm_newN<Vector2>(4);
 		mBotDropPolygon = cm_newN<Vector2>(4);
 		mBotDropPolygon = cm_newN<Vector2>(4);
@@ -212,11 +273,17 @@ namespace BansheeEditor
 	void DockManager::update()
 	void DockManager::update()
 	{
 	{
 		if(!DragAndDropManager::instance().isDragInProgress())
 		if(!DragAndDropManager::instance().isDragInProgress())
+		{
 			mHighlightedDropLoc = DockLocation::None;
 			mHighlightedDropLoc = DockLocation::None;
+			mShowOverlay = false;
+		}
 	}
 	}
 
 
 	void DockManager::render(const Viewport* viewport, CM::RenderQueue& renderQueue)
 	void DockManager::render(const Viewport* viewport, CM::RenderQueue& renderQueue)
 	{
 	{
+		if(!mShowOverlay)
+			return;
+
 		float invViewportWidth = 1.0f / (viewport->getWidth() * 0.5f);
 		float invViewportWidth = 1.0f / (viewport->getWidth() * 0.5f);
 		float invViewportHeight = 1.0f / (viewport->getHeight() * 0.5f);
 		float invViewportHeight = 1.0f / (viewport->getHeight() * 0.5f);
 
 
@@ -450,13 +517,16 @@ namespace BansheeEditor
 		mDropOverlayMesh = Mesh::create(meshData);
 		mDropOverlayMesh = Mesh::create(meshData);
 	}
 	}
 
 
-	void DockManager::onGUIMouseEvent(GUIWidget* widget, GUIElement* element, const GUIMouseEvent& event)
+	bool DockManager::onGUIMouseEvent(GUIWidget* widget, GUIElement* element, const GUIMouseEvent& event)
 	{
 	{
 		if(widget->getTarget() != mParent->getTarget())
 		if(widget->getTarget() != mParent->getTarget())
-			return;
+			return false;
 
 
 		if(event.getType() == GUIMouseEventType::MouseDragAndDropDragged)
 		if(event.getType() == GUIMouseEventType::MouseDragAndDropDragged)
 		{
 		{
+			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
+				return false;
+
 			const Vector2I& widgetRelPos = event.getPosition();
 			const Vector2I& widgetRelPos = event.getPosition();
 
 
 			const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
 			const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
@@ -466,17 +536,23 @@ namespace BansheeEditor
 			Vector2I windowPos(Math::roundToInt(windowPosVec.x), Math::roundToInt(windowPosVec.y));
 			Vector2I windowPos(Math::roundToInt(windowPosVec.x), Math::roundToInt(windowPosVec.y));
 
 
 			DockContainer* mouseOverContainer = mRootContainer.findAtPos(windowPos);
 			DockContainer* mouseOverContainer = mRootContainer.findAtPos(windowPos);
+			if(mouseOverContainer == nullptr)
+				mouseOverContainer = &mRootContainer;
 
 
+			// Update mesh if needed
+			if(mouseOverContainer != mMouseOverContainer)
+			{
+				mMouseOverContainer = mouseOverContainer;
 
 
-
-			// DEBUG ONLY
-			mouseOverContainer = &mRootContainer;
-			// END DEBUG ONLY
-
-
-
-
-
+				if(mMouseOverContainer == nullptr)
+				{
+					mDropOverlayMesh = HMesh();
+				}
+				else
+				{
+					updateDropOverlay(mMouseOverContainer->mArea.x, mMouseOverContainer->mArea.y, mMouseOverContainer->mArea.width, mMouseOverContainer->mArea.height);
+				}
+			}
 
 
 			// Check if we need to highlight any drop locations
 			// Check if we need to highlight any drop locations
 			if(mouseOverContainer)
 			if(mouseOverContainer)
@@ -491,27 +567,55 @@ namespace BansheeEditor
 					mHighlightedDropLoc = DockLocation::Right;
 					mHighlightedDropLoc = DockLocation::Right;
 				else
 				else
 					mHighlightedDropLoc = DockLocation::None;
 					mHighlightedDropLoc = DockLocation::None;
+
+				if(mouseOverContainer->mArea.contains(windowPos))
+					mShowOverlay = true;
+				else
+					mShowOverlay = false;
 			}
 			}
+			else
+				mShowOverlay = false;
 
 
-			// Update mesh if needed
-			if(mouseOverContainer == mMouseOverContainer)
-				return;
+			return true;
+		}
+		else if(event.getType() == GUIMouseEventType::MouseDragAndDropDropped)
+		{
+			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
+				return false;
 
 
-			mMouseOverContainer = mouseOverContainer;
+			EditorWidget* draggedWidget = reinterpret_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
 
 
-			if(mMouseOverContainer == nullptr)
+			const Vector2I& widgetRelPos = event.getPosition();
+			const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
+
+			Vector4 tfrmdPos = worldTfrm.multiply3x4(Vector4((float)widgetRelPos.x, (float)widgetRelPos.y, 0.0f, 1.0f));
+			Vector2 windowPosVec(tfrmdPos.x, tfrmdPos.y);
+			Vector2I windowPos(Math::roundToInt(windowPosVec.x), Math::roundToInt(windowPosVec.y));
+
+			DockContainer* mouseOverContainer = mRootContainer.findAtPos(windowPos);
+			if(mouseOverContainer == nullptr)
 			{
 			{
-				mDropOverlayMesh = HMesh();
+				if(mRootContainer.mArea.contains(windowPos))
+				{
+					insert(nullptr, draggedWidget, DockLocation::None);
+				}
 			}
 			}
 			else
 			else
 			{
 			{
-				updateDropOverlay(mMouseOverContainer->mX, mMouseOverContainer->mY, mMouseOverContainer->mWidth, mMouseOverContainer->mHeight);
+				if(insidePolygon(mTopDropPolygon, 4, windowPosVec))
+					insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Top);
+				else if(insidePolygon(mBotDropPolygon, 4, windowPosVec))
+					insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Bottom);
+				else if(insidePolygon(mLeftDropPolygon, 4, windowPosVec))
+					insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Left);
+				else if(insidePolygon(mRightDropPolygon, 4, windowPosVec))
+					insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Right);
 			}
 			}
+
+			return true;
 		}
 		}
-		else if(event.getType() == GUIMouseEventType::MouseDragAndDropDropped)
-		{
-			int a = 5; // TODO
-		}
+
+		return false;
 	}
 	}
 
 
 	// TODO - Move to a separate Polygon class?
 	// TODO - Move to a separate Polygon class?