Browse Source

Widget and dock layout tested and working (just basic functionality)

Marko Pintera 11 years ago
parent
commit
77ff5d094c

+ 6 - 0
BansheeEngine/Source/BsSprite.cpp

@@ -305,6 +305,12 @@ namespace BansheeEngine
 			float du = (uvB->x - uvA->x) / (vecB->x - vecA->x);
 			float du = (uvB->x - uvA->x) / (vecB->x - vecA->x);
 			float dv = (uvA->y - uvC->y) / (vecA->y - vecD->y);
 			float dv = (uvA->y - uvC->y) / (vecA->y - vecD->y);
 
 
+			if(right < left)
+				std::swap(left, right);
+
+			if(bottom < top)
+				std::swap(bottom, top);
+
 			// Clip left
 			// Clip left
 			float newLeft = Math::clamp(vecA->x, left, right);
 			float newLeft = Math::clamp(vecA->x, left, right);
 			float uvLeftOffset = (newLeft - vecA->x) * du;
 			float uvLeftOffset = (newLeft - vecA->x) * du;

+ 1 - 1
CamelotClient/Include/BsDockManager.h

@@ -48,7 +48,7 @@ namespace BansheeEditor
 			EditorWidgetContainer* mWidgets;
 			EditorWidgetContainer* mWidgets;
 			GUIDockSlider* mSlider;
 			GUIDockSlider* mSlider;
 			CM::RectI mArea;
 			CM::RectI mArea;
-			CM::UINT32 mFirstChildSize;
+			float mSplitPosition;
 			bool mIsHorizontal;
 			bool mIsHorizontal;
 
 
 			static const CM::UINT32 SLIDER_SIZE;
 			static const CM::UINT32 SLIDER_SIZE;

+ 8 - 3
CamelotClient/Include/BsDockManagerLayout.h

@@ -2,6 +2,7 @@
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
+#include "CmRectI.h"
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
@@ -14,12 +15,14 @@ namespace BansheeEditor
 			Entry();
 			Entry();
 			~Entry();
 			~Entry();
 
 
-			static Entry* createLeaf(Entry* parent, CM::UINT32 childIdx, const CM::Vector<CM::String>::type& widgetNames);
-			static Entry* createContainer(Entry* parent, CM::UINT32 childIdx, CM::UINT32 firstChildSize, bool horizontalSplit);
+			static Entry* createLeaf(Entry* parent, CM::UINT32 childIdx, 
+				const CM::Vector<CM::String>::type& widgetNames);
+			static Entry* createContainer(Entry* parent, CM::UINT32 childIdx, float splitPosition, 
+				bool horizontalSplit);
 
 
 			CM::Vector<CM::String>::type widgetNames;
 			CM::Vector<CM::String>::type widgetNames;
 			bool isLeaf;
 			bool isLeaf;
-			CM::UINT32 firstChildSize;
+			float splitPosition;
 			bool horizontalSplit;
 			bool horizontalSplit;
 
 
 			Entry* children[2];
 			Entry* children[2];
@@ -27,6 +30,8 @@ namespace BansheeEditor
 		};
 		};
 
 
 	public:
 	public:
+		~DockManagerLayout();
+
 		Entry& getRootEntry() { return mRootEntry; }
 		Entry& getRootEntry() { return mRootEntry; }
 
 
 	private:
 	private:

+ 5 - 5
CamelotClient/Include/BsDockManagerLayoutRTTI.h

@@ -51,7 +51,7 @@ namespace CamelotFramework
 
 
 			memory = rttiWriteElem(data.isLeaf, memory, size);
 			memory = rttiWriteElem(data.isLeaf, memory, size);
 			memory = rttiWriteElem(data.horizontalSplit, memory, size);
 			memory = rttiWriteElem(data.horizontalSplit, memory, size);
-			memory = rttiWriteElem(data.firstChildSize, memory, size);
+			memory = rttiWriteElem(data.splitPosition, memory, size);
 			memory = rttiWriteElem(data.widgetNames, memory, size);
 			memory = rttiWriteElem(data.widgetNames, memory, size);
 
 
 			if(!data.isLeaf)
 			if(!data.isLeaf)
@@ -71,13 +71,13 @@ namespace CamelotFramework
 
 
 			memory = rttiReadElem(data.isLeaf, memory);
 			memory = rttiReadElem(data.isLeaf, memory);
 			memory = rttiReadElem(data.horizontalSplit, memory);
 			memory = rttiReadElem(data.horizontalSplit, memory);
-			memory = rttiReadElem(data.firstChildSize, memory);
+			memory = rttiReadElem(data.splitPosition, memory);
 			memory = rttiReadElem(data.widgetNames, memory);
 			memory = rttiReadElem(data.widgetNames, memory);
 
 
 			if(!data.isLeaf)
 			if(!data.isLeaf)
 			{
 			{
-				data.children[0] = cm_alloc<BansheeEditor::DockManagerLayout::Entry>();
-				data.children[1] = cm_alloc<BansheeEditor::DockManagerLayout::Entry>();
+				data.children[0] = cm_new<BansheeEditor::DockManagerLayout::Entry>();
+				data.children[1] = cm_new<BansheeEditor::DockManagerLayout::Entry>();
 
 
 				memory = rttiReadElem(*data.children[0], memory);
 				memory = rttiReadElem(*data.children[0], memory);
 				memory = rttiReadElem(*data.children[1], memory);
 				memory = rttiReadElem(*data.children[1], memory);
@@ -92,7 +92,7 @@ namespace CamelotFramework
 		static UINT32 getDynamicSize(const BansheeEditor::DockManagerLayout::Entry& data)	
 		static UINT32 getDynamicSize(const BansheeEditor::DockManagerLayout::Entry& data)	
 		{ 
 		{ 
 			UINT64 dataSize = sizeof(UINT32) + rttiGetElemSize(data.isLeaf) + rttiGetElemSize(data.horizontalSplit) + 
 			UINT64 dataSize = sizeof(UINT32) + rttiGetElemSize(data.isLeaf) + rttiGetElemSize(data.horizontalSplit) + 
-				rttiGetElemSize(data.firstChildSize) + rttiGetElemSize(data.widgetNames);
+				rttiGetElemSize(data.splitPosition) + rttiGetElemSize(data.widgetNames);
 
 
 			if(!data.isLeaf)
 			if(!data.isLeaf)
 			{
 			{

+ 4 - 0
CamelotClient/Include/BsEditorApplication.h

@@ -23,10 +23,14 @@ namespace BansheeEditor
 		bool isProjectLoaded() const;
 		bool isProjectLoaded() const;
 		const CM::WString& getActiveProjectPath() const;
 		const CM::WString& getActiveProjectPath() const;
 	private:
 	private:
+		static const CM::WString WIDGET_LAYOUT_PATH;
 		RenderSystemPlugin mActiveRSPlugin;
 		RenderSystemPlugin mActiveRSPlugin;
 
 
 		static const CM::String& getLibraryNameForRenderSystem(RenderSystemPlugin plugin);
 		static const CM::String& getLibraryNameForRenderSystem(RenderSystemPlugin plugin);
 
 
 		void update();
 		void update();
+
+		EditorWidgetLayoutPtr loadWidgetLayout();
+		void saveWidgetLayout(const EditorWidgetLayoutPtr& layout);
 	};
 	};
 }
 }

+ 50 - 49
CamelotClient/Source/BsDockManager.cpp

@@ -38,7 +38,7 @@ 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), mFirstChildSize(0),
+		:mIsLeaf(true), mWidgets(nullptr), mSplitPosition(0.5f),
 		mIsHorizontal(false), mParent(nullptr), mSlider(nullptr)
 		mIsHorizontal(false), mParent(nullptr), mSlider(nullptr)
 	{
 	{
 		mChildren[0] = nullptr;
 		mChildren[0] = nullptr;
@@ -46,7 +46,7 @@ namespace BansheeEditor
 	}
 	}
 
 
 	DockManager::DockContainer::DockContainer(DockContainer* parent)
 	DockManager::DockContainer::DockContainer(DockContainer* parent)
-		:mIsLeaf(false), mWidgets(nullptr), mFirstChildSize(0),
+		:mIsLeaf(false), mWidgets(nullptr), mSplitPosition(0.5f),
 		mIsHorizontal(false), mParent(parent), mSlider(nullptr)
 		mIsHorizontal(false), mParent(parent), mSlider(nullptr)
 	{
 	{
 		mChildren[0] = nullptr;
 		mChildren[0] = nullptr;
@@ -84,25 +84,6 @@ namespace BansheeEditor
 				mWidgets->setSize(width, height);
 				mWidgets->setSize(width, height);
 			}
 			}
 		}
 		}
-		else if(mChildren[0] != nullptr && mChildren[1] != nullptr)
-		{
-			if(mIsHorizontal)
-			{
-				UINT32 currentRemainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
-				float splitPosition = (float)mFirstChildSize / (float)currentRemainingSize;
-
-				UINT32 remainingSize = (UINT32)std::max(0, (INT32)height - (INT32)SLIDER_SIZE);
-				mFirstChildSize = Math::floorToInt(remainingSize * splitPosition);
-			}
-			else
-			{
-				UINT32 currentRemainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
-				float splitPosition = mFirstChildSize / (float)currentRemainingSize;
-
-				UINT32 remainingSize = (UINT32)std::max(0, (INT32)width - (INT32)SLIDER_SIZE);
-				mFirstChildSize = Math::floorToInt(remainingSize * splitPosition);
-			}
-		}
 
 
 		mArea.x = x;
 		mArea.x = x;
 		mArea.y = y;
 		mArea.y = y;
@@ -119,24 +100,26 @@ namespace BansheeEditor
 			if(mIsHorizontal)
 			if(mIsHorizontal)
 			{
 			{
 				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
 				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
-				UINT32 sizeBottom = remainingSize - mFirstChildSize;
+				UINT32 sizeTop = Math::floorToInt(remainingSize * mSplitPosition);
+				UINT32 sizeBottom = remainingSize - sizeTop;
 
 
-				mChildren[0]->setArea(mArea.x, mArea.y, mArea.width, mFirstChildSize);
-				mChildren[1]->setArea(mArea.x, mArea.y + mFirstChildSize + SLIDER_SIZE, mArea.width, sizeBottom);
+				mChildren[0]->setArea(mArea.x, mArea.y, mArea.width, sizeTop);
+				mChildren[1]->setArea(mArea.x, mArea.y + sizeTop + SLIDER_SIZE, mArea.width, sizeBottom);
 
 
-				mSlider->_setOffset(Vector2I(mArea.x, mArea.y + mFirstChildSize));
+				mSlider->_setOffset(Vector2I(mArea.x, mArea.y + sizeTop));
 				mSlider->_setWidth(mArea.width);
 				mSlider->_setWidth(mArea.width);
 				mSlider->_setHeight(SLIDER_SIZE);
 				mSlider->_setHeight(SLIDER_SIZE);
 			}
 			}
 			else
 			else
 			{
 			{
 				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
 				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
-				UINT32 sizeRight = remainingSize - mFirstChildSize;
+				UINT32 sizeLeft = Math::floorToInt(remainingSize * mSplitPosition);
+				UINT32 sizeRight = remainingSize - sizeLeft;
 
 
-				mChildren[0]->setArea(mArea.x, mArea.y, mFirstChildSize, mArea.height);
-				mChildren[1]->setArea(mArea.x + mFirstChildSize + SLIDER_SIZE, mArea.y, sizeRight, mArea.height);
+				mChildren[0]->setArea(mArea.x, mArea.y, sizeLeft, mArea.height);
+				mChildren[1]->setArea(mArea.x + sizeLeft + SLIDER_SIZE, mArea.y, sizeRight, mArea.height);
 
 
-				mSlider->_setOffset(Vector2I(mArea.x + mFirstChildSize, mArea.y));
+				mSlider->_setOffset(Vector2I(mArea.x + sizeLeft, mArea.y));
 				mSlider->_setWidth(SLIDER_SIZE);
 				mSlider->_setWidth(SLIDER_SIZE);
 				mSlider->_setHeight(mArea.height);
 				mSlider->_setHeight(mArea.height);
 			}
 			}
@@ -214,22 +197,17 @@ namespace BansheeEditor
 		mIsLeaf = false;
 		mIsLeaf = false;
 		mIsHorizontal = horizontal;
 		mIsHorizontal = horizontal;
 		mWidgets = nullptr;
 		mWidgets = nullptr;
+		mSplitPosition = 0.5f;
 
 
 		if(horizontal)
 		if(horizontal)
 		{
 		{
 			mSlider = GUIDockSlider::create(*widgetParent, true, widgetParent->getSkin().getStyle("DockSliderBtn"));
 			mSlider = GUIDockSlider::create(*widgetParent, true, widgetParent->getSkin().getStyle("DockSliderBtn"));
 			mSlider->_setWidgetDepth(widgetParent->getDepth());
 			mSlider->_setWidgetDepth(widgetParent->getDepth());
-
-			UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
-			mFirstChildSize = Math::floorToInt(remainingSize * 0.5f);
 		}
 		}
 		else
 		else
 		{
 		{
 			mSlider = GUIDockSlider::create(*widgetParent, false, widgetParent->getSkin().getStyle("DockSliderBtn"));
 			mSlider = GUIDockSlider::create(*widgetParent, false, widgetParent->getSkin().getStyle("DockSliderBtn"));
 			mSlider->_setWidgetDepth(widgetParent->getDepth());
 			mSlider->_setWidgetDepth(widgetParent->getDepth());
-
-			UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
-			mFirstChildSize = Math::floorToInt(remainingSize * 0.5f);
 		}
 		}
 
 
 		mSlider->onDragged.connect(boost::bind(&DockManager::DockContainer::sliderDragged, this, _1));
 		mSlider->onDragged.connect(boost::bind(&DockManager::DockContainer::sliderDragged, this, _1));
@@ -242,14 +220,16 @@ namespace BansheeEditor
 		if(mIsHorizontal && delta.y != 0)
 		if(mIsHorizontal && delta.y != 0)
 		{
 		{
 			UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.height - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
 			UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.height - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
-			mFirstChildSize = Math::clamp(mFirstChildSize + delta.y, MIN_CHILD_SIZE, maxSize);
+			UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
+			mSplitPosition = Math::clamp((UINT32)Math::floorToInt(remainingSize * mSplitPosition) + delta.y, MIN_CHILD_SIZE, maxSize) / (float)remainingSize;
 
 
 			updateChildAreas();
 			updateChildAreas();
 		}
 		}
 		else if(!mIsHorizontal && delta.x != 0)
 		else if(!mIsHorizontal && delta.x != 0)
 		{
 		{
 			UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.width - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
 			UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.width - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
-			mFirstChildSize = Math::clamp(mFirstChildSize + delta.x, MIN_CHILD_SIZE, maxSize);
+			UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
+			mSplitPosition = Math::clamp((UINT32)Math::floorToInt(remainingSize * mSplitPosition) + delta.x, MIN_CHILD_SIZE, maxSize) / (float)remainingSize;
 
 
 			updateChildAreas();
 			updateChildAreas();
 		}
 		}
@@ -267,7 +247,7 @@ namespace BansheeEditor
 				mWidgets = nullptr;
 				mWidgets = nullptr;
 
 
 				mIsLeaf = false;
 				mIsLeaf = false;
-				mFirstChildSize = 0;
+				mSplitPosition = 0.5f;
 				mIsHorizontal = false;
 				mIsHorizontal = false;
 			}
 			}
 			else
 			else
@@ -334,7 +314,7 @@ namespace BansheeEditor
 
 
 	RectI DockManager::DockContainer::getContentBounds() const
 	RectI DockManager::DockContainer::getContentBounds() const
 	{
 	{
-		if(!mIsLeaf)
+		if(!mIsLeaf || mWidgets == nullptr)
 			return mArea;
 			return mArea;
 
 
 		return mWidgets->getContentBounds();
 		return mWidgets->getContentBounds();
@@ -492,7 +472,7 @@ namespace BansheeEditor
 
 
 		DockManagerLayoutPtr layout = cm_shared_ptr<DockManagerLayout>();
 		DockManagerLayoutPtr layout = cm_shared_ptr<DockManagerLayout>();
 		DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
 		DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
-		
+
 		if(mRootContainer.mIsLeaf)
 		if(mRootContainer.mIsLeaf)
 		{
 		{
 			rootEntry->isLeaf = true;
 			rootEntry->isLeaf = true;
@@ -500,9 +480,9 @@ namespace BansheeEditor
 		}
 		}
 		else
 		else
 		{
 		{
-			rootEntry->isLeaf = true;
+			rootEntry->isLeaf = false;
 			rootEntry->horizontalSplit = mRootContainer.mIsHorizontal;
 			rootEntry->horizontalSplit = mRootContainer.mIsHorizontal;
-			rootEntry->firstChildSize = mRootContainer.mFirstChildSize;
+			rootEntry->splitPosition = mRootContainer.mSplitPosition;
 			rootEntry->parent = nullptr;
 			rootEntry->parent = nullptr;
 		}
 		}
 
 
@@ -523,14 +503,14 @@ namespace BansheeEditor
 
 
 					if(currentElem.container->mChildren[i]->mIsLeaf)
 					if(currentElem.container->mChildren[i]->mIsLeaf)
 					{
 					{
-						Vector<String>::type widgetNames = GetWidgetNamesInContainer(currentElem.container);
+						Vector<String>::type widgetNames = GetWidgetNamesInContainer(currentElem.container->mChildren[i]);
 						currentElem.layoutEntry->children[i] = 
 						currentElem.layoutEntry->children[i] = 
 							DockManagerLayout::Entry::createLeaf(currentElem.layoutEntry, i, widgetNames);
 							DockManagerLayout::Entry::createLeaf(currentElem.layoutEntry, i, widgetNames);
 					}
 					}
 					else
 					else
 					{
 					{
 						currentElem.layoutEntry->children[i] = 
 						currentElem.layoutEntry->children[i] = 
-							DockManagerLayout::Entry::createContainer(currentElem.layoutEntry, i, currentElem.container->mFirstChildSize, 
+							DockManagerLayout::Entry::createContainer(currentElem.layoutEntry, i, currentElem.container->mSplitPosition, 
 							currentElem.container->mIsHorizontal);
 							currentElem.container->mIsHorizontal);
 					}
 					}
 				}
 				}
@@ -625,6 +605,7 @@ namespace BansheeEditor
 		if(currentWidgets.size() > 0) // If zero, entire layout is empty
 		if(currentWidgets.size() > 0) // If zero, entire layout is empty
 		{
 		{
 			mRootContainer.makeLeaf(mParent, mParentWindow, currentWidgets[0]);
 			mRootContainer.makeLeaf(mParent, mParentWindow, currentWidgets[0]);
+
 			for(UINT32 i = 1; i < (UINT32)currentWidgets.size(); i++)
 			for(UINT32 i = 1; i < (UINT32)currentWidgets.size(); i++)
 				mRootContainer.mWidgets->add(*currentWidgets[i]);
 				mRootContainer.mWidgets->add(*currentWidgets[i]);
 
 
@@ -650,25 +631,45 @@ namespace BansheeEditor
 						else
 						else
 							curEntry.container->addRight(mParent, mParentWindow, currentWidgets[0]);
 							curEntry.container->addRight(mParent, mParentWindow, currentWidgets[0]);
 
 
+						curEntry.container->mSplitPosition = curEntry.layoutEntry->splitPosition;
+
 						DockContainer* otherChild = curEntry.container->mChildren[1];
 						DockContainer* otherChild = curEntry.container->mChildren[1];
-						for(UINT32 i = 0; i < (UINT32)currentWidgets.size(); i++)
+						for(UINT32 i = 1; i < (UINT32)currentWidgets.size(); i++)
 							otherChild->mWidgets->add(*currentWidgets[i]);
 							otherChild->mWidgets->add(*currentWidgets[i]);
 
 
-						if(!curEntry.layoutEntry->isLeaf)
-						{
+						if(!curEntry.layoutEntry->children[0]->isLeaf)
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container->mChildren[0]));
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container->mChildren[0]));
+
+						if(!curEntry.layoutEntry->children[1]->isLeaf)
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[1], curEntry.container->mChildren[1]));
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[1], curEntry.container->mChildren[1]));
-						}
 					}
 					}
 					else
 					else
 					{
 					{
-						if(!curEntry.layoutEntry->isLeaf)
+						if(!curEntry.layoutEntry->children[0]->isLeaf)
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container));
 							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container));
 					}
 					}
 				}
 				}
 			}
 			}
 		}
 		}
 
 
+		// Set container sizes
+		{
+			Stack<StackEntry>::type layoutTodo;
+			layoutTodo.push(StackEntry(rootEntry, &mRootContainer));
+
+			while(!layoutTodo.empty())
+			{
+				StackEntry curEntry = layoutTodo.top();
+				layoutTodo.pop();
+
+				if(!curEntry.layoutEntry->isLeaf)
+				{
+					layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container->mChildren[0]));
+					layoutTodo.push(StackEntry(curEntry.layoutEntry->children[1], curEntry.container->mChildren[1]));
+				}
+			}
+		}
+
 		// Destroy any widgets that are no longer docked anywhere
 		// Destroy any widgets that are no longer docked anywhere
 		for(auto& widget : undockedWidgets)
 		for(auto& widget : undockedWidgets)
 		{
 		{

+ 31 - 14
CamelotClient/Source/BsDockManagerLayout.cpp

@@ -7,7 +7,7 @@ using namespace BansheeEngine;
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
 	DockManagerLayout::Entry::Entry()
 	DockManagerLayout::Entry::Entry()
-		:isLeaf(true), firstChildSize(0), horizontalSplit(false),
+		:isLeaf(true), splitPosition(0), horizontalSplit(false),
 		parent(nullptr)
 		parent(nullptr)
 	{
 	{
 		children[0] = nullptr;
 		children[0] = nullptr;
@@ -15,18 +15,10 @@ namespace BansheeEditor
 	}
 	}
 
 
 	DockManagerLayout::Entry::~Entry()
 	DockManagerLayout::Entry::~Entry()
-	{
-		if(!isLeaf)
-		{
-			if(children[0] != nullptr)
-				cm_delete(children[0]);
-
-			if(children[1] != nullptr)
-				cm_delete(children[1]);
-		}
-	}
+	{ }
 
 
-	DockManagerLayout::Entry* DockManagerLayout::Entry::createLeaf(Entry* parent, CM::UINT32 childIdx, const CM::Vector<CM::String>::type& widgetNames)
+	DockManagerLayout::Entry* DockManagerLayout::Entry::createLeaf(Entry* parent, UINT32 childIdx, 
+		const Vector<String>::type& widgetNames)
 	{
 	{
 		Entry* newEntry = cm_new<Entry>();
 		Entry* newEntry = cm_new<Entry>();
 		newEntry->isLeaf = true;
 		newEntry->isLeaf = true;
@@ -40,7 +32,8 @@ namespace BansheeEditor
 		return newEntry;
 		return newEntry;
 	}
 	}
 
 
-	DockManagerLayout::Entry* DockManagerLayout::Entry::createContainer(Entry* parent, CM::UINT32 childIdx, CM::UINT32 firstChildSize, bool horizontalSplit)
+	DockManagerLayout::Entry* DockManagerLayout::Entry::createContainer(Entry* parent, UINT32 childIdx, 
+		float splitPosition, bool horizontalSplit)
 	{
 	{
 		Entry* newEntry = cm_new<Entry>();
 		Entry* newEntry = cm_new<Entry>();
 		newEntry->isLeaf = false;
 		newEntry->isLeaf = false;
@@ -50,11 +43,35 @@ namespace BansheeEditor
 			parent->children[childIdx] = newEntry;
 			parent->children[childIdx] = newEntry;
 
 
 		newEntry->horizontalSplit = horizontalSplit;
 		newEntry->horizontalSplit = horizontalSplit;
-		newEntry->firstChildSize = firstChildSize;
+		newEntry->splitPosition = splitPosition;
 
 
 		return newEntry;
 		return newEntry;
 	}
 	}
 
 
+	DockManagerLayout::~DockManagerLayout()
+	{
+		Stack<Entry*>::type todo;
+		if(!mRootEntry.isLeaf)
+		{
+			todo.push(mRootEntry.children[0]);
+			todo.push(mRootEntry.children[1]);
+		}
+
+		while(!todo.empty())
+		{
+			Entry* current = todo.top();
+			todo.pop();
+
+			if(!current->isLeaf)
+			{
+				todo.push(current->children[0]);
+				todo.push(current->children[1]);
+			}
+
+			cm_delete(current);
+		}
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								RTTI		                     		*/
 	/* 								RTTI		                     		*/
 	/************************************************************************/
 	/************************************************************************/

+ 35 - 1
CamelotClient/Source/BsEditorApplication.cpp

@@ -7,6 +7,10 @@
 #include "CmRenderWindow.h"
 #include "CmRenderWindow.h"
 #include "BsEditorGUI.h"
 #include "BsEditorGUI.h"
 #include "BsUndoRedo.h"
 #include "BsUndoRedo.h"
+#include "CmFileSerializer.h"
+#include "CmFileSystem.h"
+#include "CmPath.h"
+#include "BsEditorWidgetLayout.h"
 
 
 // DEBUG ONLY
 // DEBUG ONLY
 #include "DbgEditorWidget1.h"
 #include "DbgEditorWidget1.h"
@@ -32,6 +36,8 @@ using namespace BansheeEngine;
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
+	const WString EditorApplication::WIDGET_LAYOUT_PATH = L"Internal\\Layout.asset";
+
 	EditorApplication::EditorApplication(RenderSystemPlugin renderSystemPlugin)
 	EditorApplication::EditorApplication(RenderSystemPlugin renderSystemPlugin)
 		:mActiveRSPlugin(renderSystemPlugin)
 		:mActiveRSPlugin(renderSystemPlugin)
 	{
 	{
@@ -251,8 +257,13 @@ namespace BansheeEditor
 
 
 		UndoRedo::startUp(cm_new<UndoRedo>());
 		UndoRedo::startUp(cm_new<UndoRedo>());
 		EditorWindowManager::startUp(cm_new<EditorWindowManager>());
 		EditorWindowManager::startUp(cm_new<EditorWindowManager>());
-		EditorWidgetManager::startUp(cm_new<EditorWidgetManager>());
+		
 		MainEditorWindow* mainWindow = MainEditorWindow::create(gApplication().getPrimaryWindow());
 		MainEditorWindow* mainWindow = MainEditorWindow::create(gApplication().getPrimaryWindow());
+		EditorWidgetManager::startUp(cm_new<EditorWidgetManager>());
+
+		EditorWidgetLayoutPtr layout = loadWidgetLayout();
+		if(layout != nullptr)
+			EditorWidgetManager::instance().setLayout(layout);
 
 
 		gApplication().mainLoopCallback.connect(boost::bind(&EditorApplication::update, this));
 		gApplication().mainLoopCallback.connect(boost::bind(&EditorApplication::update, this));
 
 
@@ -261,6 +272,8 @@ namespace BansheeEditor
 
 
 		gBansheeApp().runMainLoop();
 		gBansheeApp().runMainLoop();
 
 
+		saveWidgetLayout(EditorWidgetManager::instance().getLayout());
+
 		EditorWidgetManager::shutDown();
 		EditorWidgetManager::shutDown();
 		EditorWindowManager::shutDown();
 		EditorWindowManager::shutDown();
 		UndoRedo::shutDown();
 		UndoRedo::shutDown();
@@ -353,4 +366,25 @@ namespace BansheeEditor
 
 
 		return StringUtil::BLANK;
 		return StringUtil::BLANK;
 	}
 	}
+
+	EditorWidgetLayoutPtr EditorApplication::loadWidgetLayout()
+	{
+		WString layoutPath = Path::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+
+		if(FileSystem::exists(layoutPath))
+		{
+			FileSerializer fs;
+			return std::static_pointer_cast<EditorWidgetLayout>(fs.decode(layoutPath));
+		}
+
+		return nullptr;
+	}
+
+	void EditorApplication::saveWidgetLayout(const EditorWidgetLayoutPtr& layout)
+	{
+		WString layoutPath = Path::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+
+		FileSerializer fs;
+		fs.encode(layout.get(), layoutPath);
+	}
 }
 }

+ 11 - 1
CamelotClient/Source/BsEditorWidgetManager.cpp

@@ -38,6 +38,11 @@ namespace BansheeEditor
 
 
 	EditorWidgetBase* EditorWidgetManager::open(const String& name)
 	EditorWidgetBase* EditorWidgetManager::open(const String& name)
 	{
 	{
+		auto iterFind = mActiveWidgets.find(name);
+
+		if(iterFind != mActiveWidgets.end())
+			return iterFind->second;
+
 		EditorWidgetBase* newWidget = create(name);
 		EditorWidgetBase* newWidget = create(name);
 		if(newWidget == nullptr)
 		if(newWidget == nullptr)
 			CM_EXCEPT(InvalidParametersException, "Trying to open a widget that is not registered with the widget manager. Name: \"" + name + "\"");
 			CM_EXCEPT(InvalidParametersException, "Trying to open a widget that is not registered with the widget manager. Name: \"" + name + "\"");
@@ -171,6 +176,8 @@ namespace BansheeEditor
 		{
 		{
 			if(widget.second->_getParent() != nullptr)
 			if(widget.second->_getParent() != nullptr)
 				widget.second->_getParent()->remove(*(widget.second));
 				widget.second->_getParent()->remove(*(widget.second));
+
+			unparentedWidgets.push_back(widget.second);
 		}
 		}
 
 
 		// Restore floating widgets
 		// Restore floating widgets
@@ -198,7 +205,10 @@ namespace BansheeEditor
 
 
 		// Initialize any newly opened widgets
 		// Initialize any newly opened widgets
 		for(auto& widget : widgetsNeedInitialization)
 		for(auto& widget : widgetsNeedInitialization)
-			widget->initialize();
+		{
+			if(widget->_getParent() != nullptr)
+				widget->initialize();
+		}
 
 
 		// Destroy any widgets that are no longer have parents
 		// Destroy any widgets that are no longer have parents
 		for(auto& widget : unparentedWidgets)
 		for(auto& widget : unparentedWidgets)

+ 1 - 1
CamelotClient/Source/BsEditorWindowManager.cpp

@@ -44,7 +44,7 @@ namespace BansheeEditor
 		auto iterFind = std::find(begin(mEditorWindows), end(mEditorWindows), window);
 		auto iterFind = std::find(begin(mEditorWindows), end(mEditorWindows), window);
 
 
 		if(iterFind == end(mEditorWindows))
 		if(iterFind == end(mEditorWindows))
-			CM_EXCEPT(InternalErrorException, "Trying to destroy an editor window that's not registered in the window manager.");
+			return;
 
 
 		auto iterFind2 = std::find(begin(mScheduledForDestruction), end(mScheduledForDestruction), window);
 		auto iterFind2 = std::find(begin(mScheduledForDestruction), end(mScheduledForDestruction), window);