Browse Source

EditorWidgetLayout & DockManagerLayout added (untested)

Marko Pintera 11 years ago
parent
commit
4ddeec90e0

+ 6 - 0
CamelotClient/CamelotClient.vcxproj

@@ -260,9 +260,13 @@
     <ClInclude Include="Include\BsDbgTestGameObjectRef.h" />
     <ClInclude Include="Include\BsDbgTestGameObjectRefRTTI.h" />
     <ClInclude Include="Include\BsDockManager.h" />
+    <ClInclude Include="Include\BsDockManagerLayout.h" />
+    <ClInclude Include="Include\BsDockManagerLayoutRTTI.h" />
     <ClInclude Include="Include\BsEditorApplication.h" />
     <ClInclude Include="Include\BsEditorCommand.h" />
     <ClInclude Include="Include\BsEditorGUI.h" />
+    <ClInclude Include="Include\BsEditorWidgetLayout.h" />
+    <ClInclude Include="Include\BsEditorWidgetLayoutRTTI.h" />
     <ClInclude Include="Include\BsEditorWidgetManager.h" />
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h" />
     <ClInclude Include="Include\BsEditorPrerequisites.h" />
@@ -300,10 +304,12 @@
     <ClCompile Include="Source\BsCmdReparentSO.cpp" />
     <ClCompile Include="Source\BsDbgTestGameObjectRef.cpp" />
     <ClCompile Include="Source\BsDockManager.cpp" />
+    <ClCompile Include="Source\BsDockManagerLayout.cpp" />
     <ClCompile Include="Source\BsEditorCommand.cpp" />
     <ClCompile Include="Source\BsEditorGUI.cpp" />
     <ClCompile Include="Source\BsEditorWidget.cpp" />
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
+    <ClCompile Include="Source\BsEditorWidgetLayout.cpp" />
     <ClCompile Include="Source\BsEditorWidgetManager.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />

+ 18 - 0
CamelotClient/CamelotClient.vcxproj.filters

@@ -147,6 +147,18 @@
     <ClInclude Include="Include\BsEditorWidgetManager.h">
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsDockManagerLayout.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsDockManagerLayoutRTTI.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsEditorWidgetLayout.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsEditorWidgetLayoutRTTI.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
@@ -251,5 +263,11 @@
     <ClCompile Include="Source\BsEditorWidgetManager.cpp">
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsDockManagerLayout.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsEditorWidgetLayout.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 3 - 0
CamelotClient/Include/BsDockManager.h

@@ -81,6 +81,9 @@ namespace BansheeEditor
 		void render(const CM::Viewport* viewport, CM::RenderQueue& renderQueue);
 		void insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location);
 
+		DockManagerLayoutPtr getLayout() const;
+		void setLayout(const DockManagerLayoutPtr& layout, const CM::Vector<EditorWidgetBase*>::type& widgets);
+
 		void setArea(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
 
 	protected:

+ 44 - 0
CamelotClient/Include/BsDockManagerLayout.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "CmIReflectable.h"
+
+namespace BansheeEditor
+{
+	class DockManagerLayout : public CM::IReflectable
+	{
+	public:
+		struct Entry
+		{
+		public:
+			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);
+
+			CM::Vector<CM::String>::type widgetNames;
+			bool isLeaf;
+			CM::UINT32 firstChildSize;
+			bool horizontalSplit;
+
+			Entry* children[2];
+			Entry* parent;
+		};
+
+	public:
+		Entry& getRootEntry() { return mRootEntry; }
+
+	private:
+		Entry mRootEntry;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+
+	public:
+		friend class DockManagerLayoutRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;	
+	};
+}

+ 113 - 0
CamelotClient/Include/BsDockManagerLayoutRTTI.h

@@ -0,0 +1,113 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsDockManagerLayout.h"
+#include "CmRTTIType.h"
+
+namespace BansheeEditor
+{
+	class DockManagerLayoutRTTI : public CM::RTTIType<DockManagerLayout, CM::IReflectable, DockManagerLayoutRTTI>
+	{
+	private:
+		DockManagerLayout::Entry& getRootEntry(DockManagerLayout* obj) { return obj->mRootEntry; }
+		void setRootEntry(DockManagerLayout* obj, DockManagerLayout::Entry& val) { obj->mRootEntry = val; } 
+
+	public:
+		DockManagerLayoutRTTI()
+		{
+			addPlainField("mRootEntry", 0, &DockManagerLayoutRTTI::getRootEntry, &DockManagerLayoutRTTI::setRootEntry);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "DockManagerLayout";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_DockManagerLayout;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<DockManagerLayout>();
+		}
+	};
+}
+
+namespace CamelotFramework
+{
+	template<> struct CM::RTTIPlainType<BansheeEditor::DockManagerLayout::Entry>
+	{	
+		enum { id = BansheeEditor::TID_DockManagerLayoutEntry }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const BansheeEditor::DockManagerLayout::Entry& data, char* memory)
+		{ 
+			UINT32 size = 0;
+			char* memoryStart = memory;
+			memory += sizeof(UINT32);
+			size += sizeof(UINT32);
+
+			memory = rttiWriteElem(data.isLeaf, memory, size);
+			memory = rttiWriteElem(data.horizontalSplit, memory, size);
+			memory = rttiWriteElem(data.firstChildSize, memory, size);
+			memory = rttiWriteElem(data.widgetNames, memory, size);
+
+			if(!data.isLeaf)
+			{
+				memory = rttiWriteElem(*data.children[0], memory, size);
+				memory = rttiWriteElem(*data.children[1], memory, size);
+			}
+
+			memcpy(memoryStart, &size, sizeof(UINT32));
+		}
+
+		static UINT32 fromMemory(BansheeEditor::DockManagerLayout::Entry& data, char* memory)
+		{ 
+			UINT32 size = 0;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiReadElem(data.isLeaf, memory);
+			memory = rttiReadElem(data.horizontalSplit, memory);
+			memory = rttiReadElem(data.firstChildSize, memory);
+			memory = rttiReadElem(data.widgetNames, memory);
+
+			if(!data.isLeaf)
+			{
+				data.children[0] = cm_alloc<BansheeEditor::DockManagerLayout::Entry>();
+				data.children[1] = cm_alloc<BansheeEditor::DockManagerLayout::Entry>();
+
+				memory = rttiReadElem(*data.children[0], memory);
+				memory = rttiReadElem(*data.children[1], memory);
+				
+				data.children[0]->parent = &data;
+				data.children[1]->parent = &data;
+			}
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const BansheeEditor::DockManagerLayout::Entry& data)	
+		{ 
+			UINT64 dataSize = sizeof(UINT32) + rttiGetElemSize(data.isLeaf) + rttiGetElemSize(data.horizontalSplit) + 
+				rttiGetElemSize(data.firstChildSize) + rttiGetElemSize(data.widgetNames);
+
+			if(!data.isLeaf)
+			{
+				dataSize += rttiGetElemSize(*data.children[0]);
+				dataSize += rttiGetElemSize(*data.children[1]);
+			}
+
+#if CM_DEBUG_MODE
+			if(dataSize > std::numeric_limits<UINT32>::max())
+			{
+				__string_throwDataOverflowException();
+			}
+#endif
+
+			return (UINT32)dataSize;
+		}	
+	}; 
+}

+ 9 - 1
CamelotClient/Include/BsEditorPrerequisites.h

@@ -10,12 +10,14 @@ namespace BansheeEditor
 	class EditorWidgetBase;
 	class EditorWidgetContainer;
 	class EditorWidgetManager;
+	class EditorWidgetLayout;
 	class GUITabbedTitleBar;
 	class GUITabButton;
 	class GUIWindowDropArea;
 	class GUIWindowFrame;
 	class EditorWindowManager;
 	class DockManager;
+	class DockManagerLayout;
 	class MainEditorWindow;
 	class WindowFrameWidget;
 	class GUIMenuBar;
@@ -27,6 +29,8 @@ namespace BansheeEditor
 	class ResourceMeta;
 
 	typedef std::shared_ptr<ResourceMeta> ResourceMetaPtr;
+	typedef std::shared_ptr<DockManagerLayout> DockManagerLayoutPtr;
+	typedef std::shared_ptr<EditorWidgetLayout> EditorWidgetLayoutPtr;
 
 	enum class DragAndDropType
 	{
@@ -40,6 +44,10 @@ namespace BansheeEditor
 		TID_ResourceMeta = 40000,
 		TID_ProjectLibraryEntries = 40001,
 		TID_ProjectLibraryResEntry = 40002,
-		TID_ProjectLibraryDirEntry = 40003
+		TID_ProjectLibraryDirEntry = 40003,
+		TID_DockManagerLayout = 40004,
+		TID_DockManagerLayoutEntry = 40005,
+		TID_EditorWidgetLayout = 40006,
+		TID_EditorWidgetLayoutEntry = 40007
 	};
 }

+ 12 - 8
CamelotClient/Include/BsEditorWidget.h

@@ -9,30 +9,34 @@ namespace BansheeEditor
 	class EditorWidgetBase
 	{
 	public:
-		virtual ~EditorWidgetBase();
-
 		virtual void initialize() { }
 
-		const CM::HString& getName() const { return mName; }
+		const CM::String& getName() const { return mName; }
+		const CM::HString& getDisplayName() const { return mDisplayName; }
 
 		void _setSize(CM::UINT32 width, CM::UINT32 height);
 		void _setPosition(CM::INT32 x, CM::INT32 y);
 		void _changeParent(EditorWidgetContainer* parent);
+		EditorWidgetContainer* _getParent() const { return mParent; }
 
 		void _disable();
 		void _enable();
 
-		static void destroy(EditorWidgetBase* widget);
+		void close();
 	protected:
 		friend class EditorWidgetManager;
 
-		EditorWidgetBase(const CM::HString& name);
+		EditorWidgetBase(const CM::HString& displayName, const CM::String& name);
+		virtual ~EditorWidgetBase();
 
-		CM::HString mName;
+		CM::String mName;
+		CM::HString mDisplayName;
 		EditorWidgetContainer* mParent;
 		BS::GUIArea* mContent;
 
 		BS::GUIWidget& getParentWidget() const;
+
+		static void destroy(EditorWidgetBase* widget);
 	};
 
 	template<typename Type>
@@ -62,8 +66,8 @@ namespace BansheeEditor
 
 		struct ConstructPrivately {};
 
-		EditorWidget(const CM::HString& name)
-			:EditorWidgetBase(name)
+		EditorWidget(const CM::HString& displayName)
+			:EditorWidgetBase(displayName, Type::getTypeName())
 		{
 			RegisterOnStart.makeSureIAmInstantiated();
 		}

+ 5 - 1
CamelotClient/Include/BsEditorWidgetContainer.h

@@ -8,18 +8,21 @@ namespace BansheeEditor
 	class EditorWidgetContainer
 	{
 	public:
-		EditorWidgetContainer(BS::GUIWidget* parent, CM::RenderWindow* renderWindow);
+		EditorWidgetContainer(BS::GUIWidget* parent, CM::RenderWindow* renderWindow, EditorWindow* parentEditorWindow);
 		virtual ~EditorWidgetContainer();
 
 		void add(EditorWidgetBase& widget);
 		void remove(EditorWidgetBase& widget);
 		void insert(CM::UINT32 idx, EditorWidgetBase& widget);
+		bool contains(EditorWidgetBase& widget);
 
 		void setSize(CM::UINT32 width, CM::UINT32 height);
 		void setPosition(CM::INT32 x, CM::INT32 y);
 
 		CM::UINT32 getNumWidgets() const { return (CM::UINT32)mWidgets.size(); }
+		EditorWidgetBase* getWidget(CM::UINT32 idx) const;
 		BS::GUIWidget& getParentWidget() const { return *mParent; }
+		EditorWindow* getParentWindow() const { return mParentWindow; }
 
 		CM::RectI getContentBounds() const;
 
@@ -27,6 +30,7 @@ namespace BansheeEditor
 
 		boost::signal<void()> onWidgetClosed;
 	private:
+		EditorWindow* mParentWindow;
 		GUITabbedTitleBar* mTitleBar;
 		BS::GUIArea* mTitleBarArea;
 		BS::GUIWidget* mParent;

+ 45 - 0
CamelotClient/Include/BsEditorWidgetLayout.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "CmIReflectable.h"
+
+namespace BansheeEditor
+{
+	class EditorWidgetLayout : public CM::IReflectable
+	{
+	public:
+		struct Entry
+		{
+		public:
+			Entry();
+			~Entry();
+
+			CM::Vector<CM::String>::type widgetNames;
+			bool isDocked;
+			CM::INT32 x, y;
+			CM::UINT32 width, height;
+		};
+
+	private:
+		struct PrivatelyConstruct {};
+
+	public:
+		EditorWidgetLayout(const DockManagerLayoutPtr& dockLayout);
+		EditorWidgetLayout(const PrivatelyConstruct& dummy) { }
+
+		CM::Vector<Entry>::type& getEntries() { return mEntries; }
+		const DockManagerLayoutPtr& getDockLayout() const { return mDockLayout; }
+
+	private:
+		CM::Vector<Entry>::type mEntries;
+		DockManagerLayoutPtr mDockLayout;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class EditorWidgetLayoutRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;	
+	};
+}

+ 102 - 0
CamelotClient/Include/BsEditorWidgetLayoutRTTI.h

@@ -0,0 +1,102 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsEditorWidgetLayout.h"
+#include "BsDockManagerLayout.h"
+#include "CmRTTIType.h"
+
+namespace BansheeEditor
+{
+	class EditorWidgetLayoutRTTI : public CM::RTTIType<EditorWidgetLayout, CM::IReflectable, EditorWidgetLayoutRTTI>
+	{
+	private:
+		EditorWidgetLayout::Entry& getEntry(EditorWidgetLayout* obj, CM::UINT32 idx) { return obj->mEntries[idx]; }
+		void setEntry(EditorWidgetLayout* obj, CM::UINT32 idx, EditorWidgetLayout::Entry& val) { obj->mEntries[idx] = val; } 
+		CM::UINT32 getEntriesArraySize(EditorWidgetLayout* obj) { return (CM::UINT32)obj->mEntries.size(); }
+		void setEntriesArraySize(EditorWidgetLayout* obj, CM::UINT32 size) { obj->mEntries.resize(size); }
+
+		DockManagerLayoutPtr getDockLayout(EditorWidgetLayout* obj) { return obj->mDockLayout; }
+		void setDockLayout(EditorWidgetLayout* obj, DockManagerLayoutPtr val) { obj->mDockLayout = val; }
+
+	public:
+		EditorWidgetLayoutRTTI()
+		{
+			addPlainArrayField("mRootEntry", 0, &EditorWidgetLayoutRTTI::getEntry, &EditorWidgetLayoutRTTI::getEntriesArraySize, 
+				&EditorWidgetLayoutRTTI::setEntry, &EditorWidgetLayoutRTTI::setEntriesArraySize);
+
+			addReflectablePtrField("mDockLayout", 1, &EditorWidgetLayoutRTTI::getDockLayout, &EditorWidgetLayoutRTTI::setDockLayout);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "EditorWidgetLayout";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_EditorWidgetLayout;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<EditorWidgetLayout>(EditorWidgetLayout::PrivatelyConstruct());
+		}
+	};
+}
+
+namespace CamelotFramework
+{
+	template<> struct CM::RTTIPlainType<BansheeEditor::EditorWidgetLayout::Entry>
+	{	
+		enum { id = BansheeEditor::TID_EditorWidgetLayoutEntry }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const BansheeEditor::EditorWidgetLayout::Entry& data, char* memory)
+		{ 
+			UINT32 size = 0;
+			char* memoryStart = memory;
+			memory += sizeof(UINT32);
+			size += sizeof(UINT32);
+
+			memory = rttiWriteElem(data.widgetNames, memory, size);
+			memory = rttiWriteElem(data.isDocked, memory, size);
+			memory = rttiWriteElem(data.x, memory, size);
+			memory = rttiWriteElem(data.y, memory, size);
+			memory = rttiWriteElem(data.width, memory, size);
+			memory = rttiWriteElem(data.height, memory, size);
+
+			memcpy(memoryStart, &size, sizeof(UINT32));
+		}
+
+		static UINT32 fromMemory(BansheeEditor::EditorWidgetLayout::Entry& data, char* memory)
+		{ 
+			UINT32 size = 0;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiReadElem(data.widgetNames, memory);
+			memory = rttiReadElem(data.isDocked, memory);
+			memory = rttiReadElem(data.x, memory);
+			memory = rttiReadElem(data.y, memory);
+			memory = rttiReadElem(data.width, memory);
+			memory = rttiReadElem(data.height, memory);
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const BansheeEditor::EditorWidgetLayout::Entry& data)	
+		{ 
+			UINT64 dataSize = sizeof(UINT32) + rttiGetElemSize(data.widgetNames) + rttiGetElemSize(data.isDocked) + 
+				rttiGetElemSize(data.x) + rttiGetElemSize(data.y) + rttiGetElemSize(data.width) + rttiGetElemSize(data.height);
+
+#if CM_DEBUG_MODE
+			if(dataSize > std::numeric_limits<UINT32>::max())
+			{
+				__string_throwDataOverflowException();
+			}
+#endif
+
+			return (UINT32)dataSize;
+		}	
+	}; 
+}

+ 15 - 0
CamelotClient/Include/BsEditorWidgetManager.h

@@ -40,6 +40,18 @@ namespace BansheeEditor
 		 */
 		void close(EditorWidgetBase* widget);
 
+		/**
+		 * @brief	Retrieves the layout of all currently active widgets. You may later
+		 * 			use this layout to restore exact position of the widgets.
+		 */
+		EditorWidgetLayoutPtr getLayout() const;
+
+		/**
+		 * @brief	Positions all widgets according to the provided layout. It will open
+		 * 			new widgets or close current ones if needed.
+		 */
+		void setLayout(const EditorWidgetLayoutPtr& layout);
+
 		/**
 		 * @brief	Allows you to queue up widgets that will be registered as soon as an instance of EditorWidgetManager is
 		 * 			created.
@@ -54,5 +66,8 @@ namespace BansheeEditor
 		CM::Map<CM::String, std::function<EditorWidgetBase*()>>::type mCreateCallbacks;
 
 		static CM::Stack<std::pair<CM::String, std::function<EditorWidgetBase*()>>>::type QueuedCreateCallbacks;
+
+		bool isOpen(const CM::String& name) const;
+		EditorWidgetBase* create(const CM::String& name);
 	};
 }

+ 2 - 0
CamelotClient/Include/BsEditorWindowManager.h

@@ -16,6 +16,8 @@ namespace BansheeEditor
 		EditorWindow* create();
 		void destroy(EditorWindowBase* window);
 
+		MainEditorWindow* getMainWindow() const { return mMainWindow; }
+
 		void update();
 	protected:
 		MainEditorWindow* mMainWindow;

+ 2 - 0
CamelotClient/Include/BsMainEditorWindow.h

@@ -12,6 +12,8 @@ namespace BansheeEditor
 
 		void update();
 
+		DockManager& getDockManager() const { return *mDockManager; }
+
 		static MainEditorWindow* create(const CM::RenderWindowPtr& renderWindow);
 	protected:
 		friend class EditorWindowManager;

+ 220 - 2
CamelotClient/Source/BsDockManager.cpp

@@ -1,5 +1,6 @@
 #include "BsDockManager.h"
 #include "BsEditorWidgetContainer.h"
+#include "BsEditorWidget.h"
 #include "CmMath.h"
 #include "CmException.h"
 #include "CmMesh.h"
@@ -19,6 +20,7 @@
 #include "CmVertexDataDesc.h"
 #include "BsGUISkin.h"
 #include "BsEngineGUI.h"
+#include "BsDockManagerLayout.h"
 
 #include "BsGUISkin.h"
 #include "BsEngineGUI.h"
@@ -144,7 +146,7 @@ namespace BansheeEditor
 	void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget)
 	{
 		mIsLeaf = true;
-		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow);
+		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow, nullptr);
 
 		mWidgets->onWidgetClosed.connect(boost::bind(&DockManager::DockContainer::widgetRemoved, this));
 
@@ -459,9 +461,225 @@ namespace BansheeEditor
 		updateDropOverlay(x, y, width, height);
 	}
 
+	DockManagerLayoutPtr DockManager::getLayout() const
+	{
+		struct StackElem
+		{
+			StackElem(DockManagerLayout::Entry* layoutEntry, const DockContainer* container)
+				:layoutEntry(layoutEntry), container(container)
+			{ }
+
+			DockManagerLayout::Entry* layoutEntry;
+			const DockContainer* container;
+		};
+
+		auto GetWidgetNamesInContainer = [&] (const DockContainer* container)
+		{
+			Vector<String>::type widgetNames;
+			if(container->mWidgets != nullptr)
+			{
+				UINT32 numWidgets = container->mWidgets->getNumWidgets();
+
+				for(UINT32 i = 0; i < numWidgets; i++)
+				{
+					EditorWidgetBase* widget = container->mWidgets->getWidget(i);
+					widgetNames.push_back(widget->getName());
+				}				
+			}
+
+			return widgetNames;
+		};
+
+		DockManagerLayoutPtr layout = cm_shared_ptr<DockManagerLayout>();
+		DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
+		
+		if(mRootContainer.mIsLeaf)
+		{
+			rootEntry->isLeaf = true;
+			rootEntry->widgetNames = GetWidgetNamesInContainer(&mRootContainer);
+		}
+		else
+		{
+			rootEntry->isLeaf = true;
+			rootEntry->horizontalSplit = mRootContainer.mIsHorizontal;
+			rootEntry->firstChildSize = mRootContainer.mFirstChildSize;
+			rootEntry->parent = nullptr;
+		}
+
+		Stack<StackElem>::type todo;
+		todo.push(StackElem(rootEntry, &mRootContainer));
+
+		while(!todo.empty())
+		{
+			StackElem currentElem = todo.top();
+			todo.pop();
+
+			if(!currentElem.container->mIsLeaf)
+			{
+				for(UINT32 i = 0; i < 2; i++)
+				{
+					if(currentElem.container->mChildren[i] == nullptr)
+						continue;
+
+					if(currentElem.container->mChildren[i]->mIsLeaf)
+					{
+						Vector<String>::type widgetNames = GetWidgetNamesInContainer(currentElem.container);
+						currentElem.layoutEntry->children[i] = 
+							DockManagerLayout::Entry::createLeaf(currentElem.layoutEntry, i, widgetNames);
+					}
+					else
+					{
+						currentElem.layoutEntry->children[i] = 
+							DockManagerLayout::Entry::createContainer(currentElem.layoutEntry, i, currentElem.container->mFirstChildSize, 
+							currentElem.container->mIsHorizontal);
+					}
+				}
+			}
+		}
+
+		return layout;
+	}
+
+	void DockManager::setLayout(const DockManagerLayoutPtr& layout, const Vector<EditorWidgetBase*>::type& widgets)
+	{
+		// Undock all currently docked widgets
+		Vector<EditorWidgetBase*>::type undockedWidgets;
+
+		Stack<DockContainer*>::type todo;
+		todo.push(&mRootContainer);
+
+		while(!todo.empty())
+		{
+			DockContainer* current = todo.top();
+			todo.pop();
+
+			if(current->mIsLeaf)
+			{
+				if(current->mWidgets != nullptr)
+				{
+					while(current->mWidgets->getNumWidgets() > 0)
+					{
+						EditorWidgetBase* curWidget = current->mWidgets->getWidget(0);
+						current->mWidgets->remove(*curWidget);
+
+						undockedWidgets.push_back(curWidget);
+					}
+				}
+			}
+			else
+			{
+				todo.push(current->mChildren[0]);
+				todo.push(current->mChildren[1]);
+			}
+		}
+
+		mRootContainer = DockContainer();
+
+		// Load layout
+		struct StackEntry
+		{
+			StackEntry(const DockManagerLayout::Entry* layoutEntry, DockContainer* container)
+				:layoutEntry(layoutEntry), container(container)
+			{ }
+
+			const DockManagerLayout::Entry* layoutEntry;
+			DockContainer* container;
+		};
+
+		auto GetLeafEntry = [] (const DockManagerLayout::Entry* parentEntry, UINT32 childIdx) -> const DockManagerLayout::Entry*
+		{
+			while(true)
+			{
+				if(parentEntry->isLeaf)
+					return parentEntry;
+
+				parentEntry = parentEntry->children[childIdx];
+			}
+
+			return nullptr;
+		};
+
+		auto GetWidgets = [&] (const Vector<String>::type& widgetNames)
+		{
+			Vector<EditorWidgetBase*>::type resultWidgets;
+			for(auto& widgetName : widgetNames)
+			{
+				for(auto& widget : widgets)
+				{
+					if(widgetName == widget->getName())
+					{
+						resultWidgets.push_back(widget);
+						break;
+					}
+				}
+			}
+
+			return resultWidgets;
+		};
+
+		// Dock elements
+		const DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
+		const DockManagerLayout::Entry* leafEntry = GetLeafEntry(rootEntry, 0);
+		Vector<EditorWidgetBase*>::type currentWidgets = GetWidgets(leafEntry->widgetNames);
+
+		if(currentWidgets.size() > 0) // If zero, entire layout is empty
+		{
+			mRootContainer.makeLeaf(mParent, mParentWindow, currentWidgets[0]);
+			for(UINT32 i = 1; i < (UINT32)currentWidgets.size(); i++)
+				mRootContainer.mWidgets->add(*currentWidgets[i]);
+
+			if(!rootEntry->isLeaf)
+			{
+				Stack<StackEntry>::type layoutTodo;
+				layoutTodo.push(StackEntry(rootEntry, &mRootContainer));
+
+				while(!layoutTodo.empty())
+				{
+					StackEntry curEntry = layoutTodo.top();
+					layoutTodo.pop();
+
+					leafEntry = GetLeafEntry(curEntry.layoutEntry->children[1], 0);
+					currentWidgets = GetWidgets(leafEntry->widgetNames);
+
+					bool isEmpty = currentWidgets.size() == 0;
+
+					if(!isEmpty)
+					{
+						if(curEntry.layoutEntry->horizontalSplit)
+							curEntry.container->addBottom(mParent, mParentWindow, currentWidgets[0]);
+						else
+							curEntry.container->addRight(mParent, mParentWindow, currentWidgets[0]);
+
+						DockContainer* otherChild = curEntry.container->mChildren[1];
+						for(UINT32 i = 0; i < (UINT32)currentWidgets.size(); i++)
+							otherChild->mWidgets->add(*currentWidgets[i]);
+
+						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]));
+						}
+					}
+					else
+					{
+						if(!curEntry.layoutEntry->isLeaf)
+							layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container));
+					}
+				}
+			}
+		}
+
+		// Destroy any widgets that are no longer docked anywhere
+		for(auto& widget : undockedWidgets)
+		{
+			if(widget->_getParent() == nullptr)
+				widget->close();
+		}
+	}
+
 	void DockManager::updateClippedBounds()
 	{
-		// TODO - Clipping not actually accounted for
+		// TODO - Clipping not actually accounted for but shouldn't matter as right now DockManager is only used in one specific situation
 		mClippedBounds = mRootContainer.mArea;
 	}
 

+ 71 - 0
CamelotClient/Source/BsDockManagerLayout.cpp

@@ -0,0 +1,71 @@
+#include "BsDockManagerLayout.h"
+#include "BsDockManagerLayoutRTTI.h"
+
+using namespace CamelotFramework;
+using namespace BansheeEngine;
+
+namespace BansheeEditor
+{
+	DockManagerLayout::Entry::Entry()
+		:isLeaf(true), firstChildSize(0), horizontalSplit(false),
+		parent(nullptr)
+	{
+		children[0] = nullptr;
+		children[1] = nullptr;
+	}
+
+	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)
+	{
+		Entry* newEntry = cm_new<Entry>();
+		newEntry->isLeaf = true;
+		newEntry->parent = parent;
+
+		if(parent != nullptr)
+			parent->children[childIdx] = newEntry;
+
+		newEntry->widgetNames = widgetNames;
+
+		return newEntry;
+	}
+
+	DockManagerLayout::Entry* DockManagerLayout::Entry::createContainer(Entry* parent, CM::UINT32 childIdx, CM::UINT32 firstChildSize, bool horizontalSplit)
+	{
+		Entry* newEntry = cm_new<Entry>();
+		newEntry->isLeaf = false;
+		newEntry->parent = parent;
+
+		if(parent != nullptr)
+			parent->children[childIdx] = newEntry;
+
+		newEntry->horizontalSplit = horizontalSplit;
+		newEntry->firstChildSize = firstChildSize;
+
+		return newEntry;
+	}
+
+	/************************************************************************/
+	/* 								RTTI		                     		*/
+	/************************************************************************/
+
+	RTTITypeBase* DockManagerLayout::getRTTIStatic()
+	{
+		return DockManagerLayoutRTTI::instance();
+	}
+
+	RTTITypeBase* DockManagerLayout::getRTTI() const
+	{
+		return DockManagerLayout::getRTTIStatic();
+	}
+}

+ 10 - 3
CamelotClient/Source/BsEditorWidget.cpp

@@ -7,14 +7,15 @@
 #include "BsEngineGUI.h"
 #include "BsGUIArea.h"
 #include "BsEditorWidgetContainer.h"
+#include "BsEditorWidgetManager.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 
 namespace BansheeEditor
 {
-	EditorWidgetBase::EditorWidgetBase(const HString& name)
-		:mName(name), mParent(nullptr), mContent(nullptr)
+	EditorWidgetBase::EditorWidgetBase(const HString& displayName, const CM::String& name)
+		:mDisplayName(displayName), mName(name), mParent(nullptr), mContent(nullptr)
 	{
 		
 	}
@@ -24,9 +25,15 @@ namespace BansheeEditor
 
 	}
 
+	void EditorWidgetBase::close()
+	{
+		EditorWidgetManager::instance().close(this);
+	}
+
 	void EditorWidgetBase::destroy(EditorWidgetBase* widget)
 	{
-		cm_delete(widget);
+		widget->~EditorWidgetBase();
+		cm_free(widget);
 	}
 
 	void EditorWidgetBase::_setPosition(INT32 x, INT32 y)

+ 36 - 14
CamelotClient/Source/BsEditorWidgetContainer.cpp

@@ -16,9 +16,9 @@ namespace BansheeEditor
 {
 	const CM::UINT32 EditorWidgetContainer::TitleBarHeight = 13;
 
-	EditorWidgetContainer::EditorWidgetContainer(BS::GUIWidget* parent, RenderWindow* renderWindow)
+	EditorWidgetContainer::EditorWidgetContainer(BS::GUIWidget* parent, RenderWindow* renderWindow, EditorWindow* parentEditorWindow)
 		:mParent(parent), mX(0), mY(0), mWidth(0), mHeight(0), mTitleBar(nullptr), mActiveWidget(-1),
-		mTitleBarArea(nullptr)
+		mTitleBarArea(nullptr), mParentWindow(parentEditorWindow)
 	{
 		mTitleBarArea = GUIArea::create(*parent, 0, 0, 0, 0, 9900);
 
@@ -33,13 +33,13 @@ namespace BansheeEditor
 
 	EditorWidgetContainer::~EditorWidgetContainer()
 	{
-		GUIArea::destroy(mTitleBarArea);
-		GUIElement::destroy(mTitleBar);
-
 		for(auto& widget : mWidgets)
 		{
-			EditorWidgetBase::destroy(widget.second);
+			widget.second->close();
 		}
+
+		GUIArea::destroy(mTitleBarArea);
+		GUIElement::destroy(mTitleBar);
 	}
 
 	void EditorWidgetContainer::add(EditorWidgetBase& widget)
@@ -78,15 +78,12 @@ namespace BansheeEditor
 
 	void EditorWidgetContainer::insert(CM::UINT32 idx, EditorWidgetBase& widget)
 	{
-		for(auto& curWidget : mWidgets)
-		{
-			if(curWidget.second == &widget)
-				return;
-		}
+		if(contains(widget))
+			return;
 
 		idx = Math::clamp(idx, 0U, (UINT32)mWidgets.size());
 
-		UINT32 tabIdx = mTitleBar->insertTab(idx, widget.getName());
+		UINT32 tabIdx = mTitleBar->insertTab(idx, widget.getDisplayName());
 		mWidgets[tabIdx] = &widget;
 		widget._changeParent(this);
 
@@ -96,6 +93,32 @@ namespace BansheeEditor
 			widget._disable();
 	}
 
+	bool EditorWidgetContainer::contains(EditorWidgetBase& widget)
+	{
+		for(auto& curWidget : mWidgets)
+		{
+			if(curWidget.second == &widget)
+				return true;
+		}
+
+		return false;
+	}
+
+	EditorWidgetBase* EditorWidgetContainer::getWidget(CM::UINT32 idx) const
+	{
+		if(idx >= (UINT32)mWidgets.size())
+			return nullptr;
+
+		UINT32 tabIdx = mTitleBar->getTabIdx(idx);
+
+		auto iterFind = mWidgets.find(tabIdx);
+
+		if(iterFind != mWidgets.end())
+			return iterFind->second;
+
+		return nullptr;
+	}
+
 	void EditorWidgetContainer::setSize(UINT32 width, UINT32 height)
 	{
 		// TODO - Title bar is always TitleBarHeight size, so what happens when the container area is smaller than that?
@@ -157,8 +180,7 @@ namespace BansheeEditor
 	void EditorWidgetContainer::tabClosed(UINT32 uniqueIdx)
 	{
 		EditorWidgetBase* widget = mWidgets[uniqueIdx];
-		remove(*widget);
-		EditorWidgetBase::destroy(widget);
+		widget->close();
 
 		if(!onWidgetClosed.empty())
 			onWidgetClosed();

+ 33 - 0
CamelotClient/Source/BsEditorWidgetLayout.cpp

@@ -0,0 +1,33 @@
+#include "BsEditorWidgetLayout.h"
+#include "BsEditorWidgetLayoutRTTI.h"
+
+using namespace CamelotFramework;
+using namespace BansheeEngine;
+
+namespace BansheeEditor
+{
+	EditorWidgetLayout::Entry::Entry()
+		:isDocked(true), x(0), y(0), width(0), height(0)
+	{ }
+
+	EditorWidgetLayout::Entry::~Entry()
+	{ }
+
+	EditorWidgetLayout::EditorWidgetLayout(const DockManagerLayoutPtr& dockLayout)
+		:mDockLayout(dockLayout)
+	{ }
+
+	/************************************************************************/
+	/* 								RTTI		                     		*/
+	/************************************************************************/
+
+	RTTITypeBase* EditorWidgetLayout::getRTTIStatic()
+	{
+		return EditorWidgetLayoutRTTI::instance();
+	}
+
+	RTTITypeBase* EditorWidgetLayout::getRTTI() const
+	{
+		return EditorWidgetLayout::getRTTIStatic();
+	}
+}

+ 153 - 11
CamelotClient/Source/BsEditorWidgetManager.cpp

@@ -2,6 +2,10 @@
 #include "BsEditorWidget.h"
 #include "BsEditorWindow.h"
 #include "BsEditorWidgetContainer.h"
+#include "BsEditorWindowManager.h"
+#include "BsMainEditorWindow.h"
+#include "BsEditorWidgetLayout.h"
+#include "BsDockManager.h"
 #include "CmException.h"
 
 using namespace CamelotFramework;
@@ -34,22 +38,14 @@ namespace BansheeEditor
 
 	EditorWidgetBase* EditorWidgetManager::open(const String& name)
 	{
-		auto iterFind = mActiveWidgets.find(name);
-
-		if(iterFind != mActiveWidgets.end())
-			return iterFind->second;
-
-		auto iterFindCreate = mCreateCallbacks.find(name);
-		if(iterFindCreate == mCreateCallbacks.end())
+		EditorWidgetBase* newWidget = create(name);
+		if(newWidget == nullptr)
 			CM_EXCEPT(InvalidParametersException, "Trying to open a widget that is not registered with the widget manager. Name: \"" + name + "\"");
 
-		EditorWidgetBase* newWidget = mCreateCallbacks[name]();
 		EditorWindow* window = EditorWindow::create();
 		window->widgets().add(*newWidget);
 		newWidget->initialize();
 
-		mActiveWidgets[name] = newWidget;
-
 		return newWidget;
 	}
 
@@ -61,11 +57,157 @@ namespace BansheeEditor
 		if(findIter != mActiveWidgets.end())
 			mActiveWidgets.erase(findIter);
 
-		widget->mParent->_notifyWidgetDestroyed(widget);
+		if(widget->mParent != nullptr)
+			widget->mParent->_notifyWidgetDestroyed(widget);
 
 		EditorWidgetBase::destroy(widget);
 	}
 
+	bool EditorWidgetManager::isOpen(const CM::String& name) const
+	{
+		auto iterFind = mActiveWidgets.find(name);
+
+		return iterFind != mActiveWidgets.end();
+	}
+
+	EditorWidgetBase* EditorWidgetManager::create(const CM::String& name)
+	{
+		auto iterFind = mActiveWidgets.find(name);
+
+		if(iterFind != mActiveWidgets.end())
+			return iterFind->second;
+
+		auto iterFindCreate = mCreateCallbacks.find(name);
+		if(iterFindCreate == mCreateCallbacks.end())
+			return nullptr;
+
+		EditorWidgetBase* newWidget = mCreateCallbacks[name]();
+		mActiveWidgets[name] = newWidget;
+
+		return newWidget;
+	}
+
+	EditorWidgetLayoutPtr EditorWidgetManager::getLayout() const
+	{
+		auto GetWidgetNamesInContainer = [&] (const EditorWidgetContainer* container)
+		{
+			Vector<String>::type widgetNames;
+			if(container != nullptr)
+			{
+				UINT32 numWidgets = container->getNumWidgets();
+
+				for(UINT32 i = 0; i < numWidgets; i++)
+				{
+					EditorWidgetBase* widget = container->getWidget(i);
+					widgetNames.push_back(widget->getName());
+				}				
+			}
+
+			return widgetNames;
+		};
+
+		MainEditorWindow* mainWindow = EditorWindowManager::instance().getMainWindow();
+		DockManager& dockManager = mainWindow->getDockManager();
+		EditorWidgetLayoutPtr layout = cm_shared_ptr<EditorWidgetLayout>(dockManager.getLayout());
+
+		Vector<EditorWidgetLayout::Entry>::type& layoutEntries = layout->getEntries();
+		UnorderedSet<EditorWidgetContainer*>::type widgetContainers;
+
+		for(auto& widget : mActiveWidgets)
+		{
+			widgetContainers.insert(widget.second->_getParent());
+		}
+
+		for(auto& widgetContainer : widgetContainers)
+		{
+			if(widgetContainer == nullptr)
+				continue;
+
+			layoutEntries.push_back(EditorWidgetLayout::Entry());
+			EditorWidgetLayout::Entry& entry = layoutEntries.back();
+
+			entry.widgetNames = GetWidgetNamesInContainer(widgetContainer);
+
+			EditorWindow* parentWindow = widgetContainer->getParentWindow();
+			entry.isDocked = parentWindow == nullptr;
+			
+			if(!entry.isDocked)
+			{
+				entry.x = parentWindow->getLeft();
+				entry.y = parentWindow->getTop();
+				entry.width = parentWindow->getWidth();
+				entry.height = parentWindow->getHeight();
+			}
+		}
+
+		return layout;
+	}
+
+	void EditorWidgetManager::setLayout(const EditorWidgetLayoutPtr& layout)
+	{
+		Vector<EditorWidgetBase*>::type openWidgets;
+		Vector<EditorWidgetBase*>::type widgetsNeedInitialization;
+
+		// Create any necessary widgets
+		for(auto& entry : layout->getEntries())
+		{
+			for(auto& widgetName : entry.widgetNames)
+			{
+				bool needsInitialization = !isOpen(widgetName);
+				EditorWidgetBase* newWidget = create(widgetName);
+				if(newWidget != nullptr)
+				{
+					openWidgets.push_back(newWidget);
+
+					if(needsInitialization)
+						widgetsNeedInitialization.push_back(newWidget);
+				}
+			}
+		}
+
+		// Unparent all widgets
+		Vector<EditorWidgetBase*>::type unparentedWidgets;
+		for(auto& widget : mActiveWidgets)
+		{
+			if(widget.second->_getParent() != nullptr)
+				widget.second->_getParent()->remove(*(widget.second));
+		}
+
+		// Restore floating widgets
+		for(auto& entry : layout->getEntries())
+		{
+			if(entry.isDocked)
+				continue;
+
+			EditorWindow* window = EditorWindow::create();
+			for(auto& widgetName : entry.widgetNames)
+			{
+				EditorWidgetBase* widget = create(widgetName); // This will returned previously created widget
+				window->widgets().add(*widget);
+			}
+
+			window->setPosition(entry.x, entry.y);
+			window->setSize(entry.width, entry.height);
+		}
+
+		// Restore docked widgets
+		MainEditorWindow* mainWindow = EditorWindowManager::instance().getMainWindow();
+		DockManager& dockManager = mainWindow->getDockManager();
+
+		dockManager.setLayout(layout->getDockLayout(), openWidgets);
+
+		// Initialize any newly opened widgets
+		for(auto& widget : widgetsNeedInitialization)
+			widget->initialize();
+
+		// Destroy any widgets that are no longer have parents
+		for(auto& widget : unparentedWidgets)
+		{
+			if(widget->_getParent() == nullptr)
+				widget->close();
+		}
+	}
+
 	void EditorWidgetManager::preRegisterWidget(const String& name, std::function<EditorWidgetBase*()> createCallback)
 	{
 		QueuedCreateCallbacks.push(std::pair<String, std::function<EditorWidgetBase*()>>(name, createCallback));

+ 1 - 1
CamelotClient/Source/BsEditorWindow.cpp

@@ -9,7 +9,7 @@ using namespace BansheeEngine;
 namespace BansheeEditor
 {
 	EditorWindow::EditorWindow()
-		:EditorWindowBase(), mWidgets(cm_new<EditorWidgetContainer>(mGUI.get(), mRenderWindow.get()))
+		:EditorWindowBase(), mWidgets(cm_new<EditorWidgetContainer>(mGUI.get(), mRenderWindow.get(), this))
 	{
 		updateSize();
 		

+ 4 - 4
CamelotClient/Source/BsGUITabbedTitleBar.cpp

@@ -149,14 +149,14 @@ namespace BansheeEditor
 					{
 						if(i == 0 && widgetRelPos.x <= centerX)
 						{
-							insertTab(0, draggedWidget->getName());
+							insertTab(0, draggedWidget->getDisplayName());
 							mTempDraggedTabIdx = mTabButtons[0]->getIndex();
 
 							break;
 						}
 						else if(widgetRelPos.x > centerX)
 						{
-							addTab(draggedWidget->getName());
+							addTab(draggedWidget->getDisplayName());
 							mTempDraggedTabIdx = mTabButtons[i + 1]->getIndex();
 
 							break;
@@ -166,7 +166,7 @@ namespace BansheeEditor
 					{
 						if(i == 0 && widgetRelPos.x <= centerX)
 						{
-							insertTab(0, draggedWidget->getName());
+							insertTab(0, draggedWidget->getDisplayName());
 							mTempDraggedTabIdx = mTabButtons[0]->getIndex();
 
 							break;
@@ -178,7 +178,7 @@ namespace BansheeEditor
 
 							if(widgetRelPos.x > centerX && widgetRelPos.x < nextCenterX)
 							{
-								insertTab(i + 1, draggedWidget->getName());
+								insertTab(i + 1, draggedWidget->getDisplayName());
 								mTempDraggedTabIdx = mTabButtons[i + 1]->getIndex();
 
 								break;

+ 1 - 1
CamelotCore/Include/CmCoreThreadAccessor.h

@@ -212,7 +212,7 @@ namespace CamelotFramework
 		}
 
 		/**
-		 * @copydoc RenderSystem::writeSubresource()
+		 * @copydoc RenderSystem::readSubresource()
 		 *
 		 * @note "data" parameter is populated with subresource data when the async operation completes. 
 		 * 		 Until the async operation completes "data" is owned by the core thread and you won't

+ 1 - 1
CamelotCore/Include/CmResourceManifest.h

@@ -9,7 +9,7 @@ namespace CamelotFramework
 	 * @brief	Serializable class that contains UUID <-> file path mapping for resources.
 	 * 			
 	 * @note	This class allows you to reference resources between sessions. At the end of a session
-	 * 			save the resource manifest, and then restore it at the start of your session. This way
+	 * 			save the resource manifest, and then restore it at the start of a new session. This way
 	 * 			ensures that resource UUIDs stay consistent and anything referencing them can find the
 	 * 			resources.
 	 */

+ 12 - 4
EditorWindowDock.txt

@@ -6,17 +6,25 @@ Polish TOOD:
  - Change cursor icon when window is dragged
  - Prevent docking if available size is less than 20 pixels, otherwise there might be some weirdness
 
+------------------------
+Layout saving/loading:
+TODO:
+ DockManager::setLayout
+ DockManagerLayoutRTTI
+ EditorWidgetLayout & EditorWidgetLayoutRTTI
+ EditorWidgetManager::setLayout, EditorWidgetManager::getLayout
+ Some kind of automatic loading & saving of currently selected EditorWidgetLayout
+ C# EditorWindows
+
 ------------------------
 
 Other things to remember:
  - Possibly add a way to have hidden widgets in the EditorWidgetContainer (like side-bars that pop on mouse over in Visual Studio)
- - A way to persist window states
- - Also a way to reset all widgets to original locations
-
 
  ------------------------
 
- EditorWindow enumeraton in C#:
+ EditorWindow enumeraton in C#: - HOWEVER I think it's almost certainly better do just use C# reflection. I don't see any advantages
+ to doing it in C++.
 
  To get all classes in a mono image:
 MonoClass*