Przeglądaj źródła

EditorWidgetManager

Marko Pintera 11 lat temu
rodzic
commit
942eb008db

+ 2 - 0
CamelotClient/CamelotClient.vcxproj

@@ -263,6 +263,7 @@
     <ClInclude Include="Include\BsEditorApplication.h" />
     <ClInclude Include="Include\BsEditorApplication.h" />
     <ClInclude Include="Include\BsEditorCommand.h" />
     <ClInclude Include="Include\BsEditorCommand.h" />
     <ClInclude Include="Include\BsEditorGUI.h" />
     <ClInclude Include="Include\BsEditorGUI.h" />
+    <ClInclude Include="Include\BsEditorWidgetManager.h" />
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h" />
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h" />
     <ClInclude Include="Include\BsEditorPrerequisites.h" />
     <ClInclude Include="Include\BsEditorPrerequisites.h" />
     <ClInclude Include="Include\BsEditorWidget.h" />
     <ClInclude Include="Include\BsEditorWidget.h" />
@@ -303,6 +304,7 @@
     <ClCompile Include="Source\BsEditorGUI.cpp" />
     <ClCompile Include="Source\BsEditorGUI.cpp" />
     <ClCompile Include="Source\BsEditorWidget.cpp" />
     <ClCompile Include="Source\BsEditorWidget.cpp" />
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
+    <ClCompile Include="Source\BsEditorWidgetManager.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />
     <ClCompile Include="Source\BsEditorWindowManager.cpp" />
     <ClCompile Include="Source\BsEditorWindowManager.cpp" />

+ 6 - 0
CamelotClient/CamelotClient.vcxproj.filters

@@ -144,6 +144,9 @@
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h">
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h">
       <Filter>Header Files\Editor</Filter>
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsEditorWidgetManager.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
     <ClCompile Include="stdafx.cpp">
@@ -245,5 +248,8 @@
     <ClCompile Include="Source\BsProjectLibraryEntries.cpp">
     <ClCompile Include="Source\BsProjectLibraryEntries.cpp">
       <Filter>Source Files\Editor</Filter>
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsEditorWidgetManager.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 7 - 7
CamelotClient/Include/BsDockManager.h

@@ -22,12 +22,12 @@ namespace BansheeEditor
 			~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, EditorWidgetBase* widget);
 			void makeLeaf(EditorWidgetContainer* existingContainer);
 			void makeLeaf(EditorWidgetContainer* existingContainer);
-			void addLeft(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 addBottom(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget);
+			void addLeft(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidgetBase* widget);
+			void addRight(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidgetBase* widget);
+			void addTop(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidgetBase* widget);
+			void addBottom(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidgetBase* widget);
 
 
 			DockContainer* find(EditorWidgetContainer* widgetContainer);
 			DockContainer* find(EditorWidgetContainer* widgetContainer);
 
 
@@ -55,7 +55,7 @@ namespace BansheeEditor
 			static const CM::UINT32 MIN_CHILD_SIZE;
 			static const CM::UINT32 MIN_CHILD_SIZE;
 
 
 		private:
 		private:
-			void splitContainer(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidget* widget, bool horizontal, bool newChildIsFirst);
+			void splitContainer(BS::GUIWidget* widgetParent, CM::RenderWindow* parentWindow, EditorWidgetBase* widget, bool horizontal, bool newChildIsFirst);
 			void updateChildAreas();
 			void updateChildAreas();
 
 
 			void sliderDragged(const CM::Vector2I& delta);
 			void sliderDragged(const CM::Vector2I& delta);
@@ -79,7 +79,7 @@ namespace BansheeEditor
 		void update();
 		void update();
 
 
 		void render(const CM::Viewport* viewport, CM::RenderQueue& renderQueue);
 		void render(const CM::Viewport* viewport, CM::RenderQueue& renderQueue);
-		void insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location);
+		void insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location);
 
 
 		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);
 
 

+ 2 - 1
CamelotClient/Include/BsEditorPrerequisites.h

@@ -7,8 +7,9 @@ namespace BansheeEditor
 	// GUI
 	// GUI
 	class EditorWindowBase;
 	class EditorWindowBase;
 	class EditorWindow;
 	class EditorWindow;
-	class EditorWidget;
+	class EditorWidgetBase;
 	class EditorWidgetContainer;
 	class EditorWidgetContainer;
+	class EditorWidgetManager;
 	class GUITabbedTitleBar;
 	class GUITabbedTitleBar;
 	class GUITabButton;
 	class GUITabButton;
 	class GUIWindowDropArea;
 	class GUIWindowDropArea;

+ 50 - 4
CamelotClient/Include/BsEditorWidget.h

@@ -1,14 +1,17 @@
 #pragma once
 #pragma once
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
+#include "BsEditorWidgetManager.h"
 #include "boost/signal.hpp"
 #include "boost/signal.hpp"
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	class EditorWidget
+	class EditorWidgetBase
 	{
 	{
 	public:
 	public:
-		virtual ~EditorWidget();
+		virtual ~EditorWidgetBase();
+
+		virtual void initialize() { }
 
 
 		const CM::HString& getName() const { return mName; }
 		const CM::HString& getName() const { return mName; }
 
 
@@ -19,9 +22,11 @@ namespace BansheeEditor
 		void _disable();
 		void _disable();
 		void _enable();
 		void _enable();
 
 
-		static void destroy(EditorWidget* widget);
+		static void destroy(EditorWidgetBase* widget);
 	protected:
 	protected:
-		EditorWidget(const CM::HString& name);
+		friend class EditorWidgetManager;
+
+		EditorWidgetBase(const CM::HString& name);
 
 
 		CM::HString mName;
 		CM::HString mName;
 		EditorWidgetContainer* mParent;
 		EditorWidgetContainer* mParent;
@@ -29,4 +34,45 @@ namespace BansheeEditor
 
 
 		BS::GUIWidget& getParentWidget() const;
 		BS::GUIWidget& getParentWidget() const;
 	};
 	};
+
+	template<typename Type>
+	struct RegisterWidgetOnStart
+	{
+	public:
+		RegisterWidgetOnStart()
+		{
+			EditorWidgetManager::preRegisterWidget(Type::getTypeName(), &create);
+		}
+
+		static EditorWidgetBase* create()
+		{
+			return cm_new<Type>(EditorWidget<Type>::ConstructPrivately());
+		}
+
+		void makeSureIAmInstantiated() { }
+	};
+
+	template <class Type>
+	class EditorWidget : public EditorWidgetBase
+	{
+		static RegisterWidgetOnStart<Type> RegisterOnStart;
+
+	protected:
+		friend struct RegisterWidgetOnStart<Type>;
+
+		struct ConstructPrivately {};
+
+		EditorWidget(const CM::HString& name)
+			:EditorWidgetBase(name)
+		{
+			RegisterOnStart.makeSureIAmInstantiated();
+		}
+
+	public:
+
+		virtual ~EditorWidget() { }
+	};
+
+	template <typename Type>
+	RegisterWidgetOnStart<Type> EditorWidget<Type>::RegisterOnStart;
 }
 }

+ 5 - 5
CamelotClient/Include/BsEditorWidgetContainer.h

@@ -11,9 +11,9 @@ namespace BansheeEditor
 		EditorWidgetContainer(BS::GUIWidget* parent, CM::RenderWindow* renderWindow);
 		EditorWidgetContainer(BS::GUIWidget* parent, CM::RenderWindow* renderWindow);
 		virtual ~EditorWidgetContainer();
 		virtual ~EditorWidgetContainer();
 
 
-		void add(EditorWidget& widget);
-		void remove(EditorWidget& widget);
-		void insert(CM::UINT32 idx, EditorWidget& widget);
+		void add(EditorWidgetBase& widget);
+		void remove(EditorWidgetBase& widget);
+		void insert(CM::UINT32 idx, EditorWidgetBase& widget);
 
 
 		void setSize(CM::UINT32 width, CM::UINT32 height);
 		void setSize(CM::UINT32 width, CM::UINT32 height);
 		void setPosition(CM::INT32 x, CM::INT32 y);
 		void setPosition(CM::INT32 x, CM::INT32 y);
@@ -23,7 +23,7 @@ namespace BansheeEditor
 
 
 		CM::RectI getContentBounds() const;
 		CM::RectI getContentBounds() const;
 
 
-		void _notifyWidgetDestroyed(EditorWidget* widget);
+		void _notifyWidgetDestroyed(EditorWidgetBase* widget);
 
 
 		boost::signal<void()> onWidgetClosed;
 		boost::signal<void()> onWidgetClosed;
 	private:
 	private:
@@ -32,7 +32,7 @@ namespace BansheeEditor
 		BS::GUIWidget* mParent;
 		BS::GUIWidget* mParent;
 		CM::INT32 mX, mY;
 		CM::INT32 mX, mY;
 		CM::UINT32 mWidth, mHeight;
 		CM::UINT32 mWidth, mHeight;
-		CM::UnorderedMap<CM::UINT32, EditorWidget*>::type mWidgets;
+		CM::UnorderedMap<CM::UINT32, EditorWidgetBase*>::type mWidgets;
 		CM::INT32 mActiveWidget;
 		CM::INT32 mActiveWidget;
 
 
 		static const CM::UINT32 TitleBarHeight;
 		static const CM::UINT32 TitleBarHeight;

+ 58 - 0
CamelotClient/Include/BsEditorWidgetManager.h

@@ -0,0 +1,58 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "CmModule.h"
+
+namespace BansheeEditor
+{
+	/**
+	 * @brief	Handles opening and closing of EditorWidgets. Its primary purpose
+	 * 			is to keep track of all types of widgets so they can be saved and restored
+	 * 			upon program shutdown/startup, as well as being able to change widget layout on
+	 * 			the fly.
+	 */
+	class EditorWidgetManager : public CM::Module<EditorWidgetManager>
+	{
+	public:
+		EditorWidgetManager();
+
+		/**
+		 * @brief	Registers a widget that can then be opened by calling "open". When loading
+		 * 			a widget layout this name and callback will be used to attempt creating the widget.
+		 *
+		 * @param	name				  	Unique name for the widget.
+		 * @param 	createCallback			Callback that returns a new instance of the widget.
+		 */
+		void registerWidget(const CM::String& name, std::function<EditorWidgetBase*()> createCallback);
+
+		/**
+		 * @brief	Creates a widget with the given name. If widget is already created it returns the existing instance.
+		 * 			Widget is opened in a new window.
+		 *
+		 * @param	name	The name of the widget.
+		 *
+		 * @return	Always returns the created widget, and throws an exception if it fails.
+		 */
+		EditorWidgetBase* open(const CM::String& name);
+
+		/**
+		 * @brief	Closes the given widget.
+		 */
+		void close(EditorWidgetBase* widget);
+
+		/**
+		 * @brief	Allows you to queue up widgets that will be registered as soon as an instance of EditorWidgetManager is
+		 * 			created.
+		 *
+		 * @note	Useful primarily when widgets are being registered from static methods, because then there is no
+		 * 			EditorWidgetManager instance yet.
+		 */
+		static void preRegisterWidget(const CM::String& name, std::function<EditorWidgetBase*()> createCallback);
+
+	private:
+		CM::Map<CM::String, EditorWidgetBase*>::type mActiveWidgets;
+		CM::Map<CM::String, std::function<EditorWidgetBase*()>>::type mCreateCallbacks;
+
+		static CM::Stack<std::pair<CM::String, std::function<EditorWidgetBase*()>>>::type QueuedCreateCallbacks;
+	};
+}

+ 1 - 1
CamelotClient/Include/BsGUITabbedTitleBar.h

@@ -54,7 +54,7 @@ namespace BansheeEditor
 		BS::GUIToggleGroupPtr mTabToggleGroup;
 		BS::GUIToggleGroupPtr mTabToggleGroup;
 		CM::RenderWindow* mParentWindow;
 		CM::RenderWindow* mParentWindow;
 
 
-		EditorWidget* mTempDraggedWidget;
+		EditorWidgetBase* mTempDraggedWidget;
 		CM::UINT32 mTempDraggedTabIdx;
 		CM::UINT32 mTempDraggedTabIdx;
 
 
 		bool mDragInProgress;
 		bool mDragInProgress;

+ 4 - 3
CamelotClient/Include/DbgEditorWidget1.h

@@ -5,19 +5,20 @@
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	class DbgEditorWidget1 : public EditorWidget
+	class DbgEditorWidget1 : public EditorWidget<DbgEditorWidget1>
 	{
 	{
 	public:
 	public:
+		DbgEditorWidget1(const ConstructPrivately& dummy);
 		virtual ~DbgEditorWidget1();
 		virtual ~DbgEditorWidget1();
 
 
 		static DbgEditorWidget1* instance();
 		static DbgEditorWidget1* instance();
 		static DbgEditorWidget1* open();
 		static DbgEditorWidget1* open();
 		static void close();
 		static void close();
+		static const CM::String& getTypeName();
 
 
 	protected:
 	protected:
-		DbgEditorWidget1();
-
 		void initialize();
 		void initialize();
+
 	private:
 	private:
 		static DbgEditorWidget1* Instance;
 		static DbgEditorWidget1* Instance;
 	};
 	};

+ 4 - 3
CamelotClient/Include/DbgEditorWidget2.h

@@ -5,19 +5,20 @@
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	class DbgEditorWidget2 : public EditorWidget
+	class DbgEditorWidget2 : public EditorWidget<DbgEditorWidget2>
 	{
 	{
 	public:
 	public:
+		DbgEditorWidget2(const ConstructPrivately& dummy);
 		virtual ~DbgEditorWidget2();
 		virtual ~DbgEditorWidget2();
 
 
 		static DbgEditorWidget2* instance();
 		static DbgEditorWidget2* instance();
 		static DbgEditorWidget2* open();
 		static DbgEditorWidget2* open();
 		static void close();
 		static void close();
+		static const CM::String& getTypeName();
 
 
 	protected:
 	protected:
-		DbgEditorWidget2();
-
 		void initialize();
 		void initialize();
+
 	private:
 	private:
 		static DbgEditorWidget2* Instance;
 		static DbgEditorWidget2* Instance;
 	};
 	};

+ 8 - 8
CamelotClient/Source/BsDockManager.cpp

@@ -141,7 +141,7 @@ namespace BansheeEditor
 		}
 		}
 	}
 	}
 
 
-	void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
+	void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget)
 	{
 	{
 		mIsLeaf = true;
 		mIsLeaf = true;
 		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow);
 		mWidgets = cm_new<EditorWidgetContainer>(widgetParent, parentWindow);
@@ -176,27 +176,27 @@ namespace BansheeEditor
 		mWidgets->setSize(mArea.width, mArea.height);
 		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, EditorWidgetBase* widget)
 	{
 	{
 		splitContainer(widgetParent, parentWindow, widget, false, true);
 		splitContainer(widgetParent, parentWindow, widget, false, true);
 	}
 	}
 
 
-	void DockManager::DockContainer::addRight(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
+	void DockManager::DockContainer::addRight(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget)
 	{
 	{
 		splitContainer(widgetParent, parentWindow, widget, false, false);
 		splitContainer(widgetParent, parentWindow, widget, false, false);
 	}
 	}
 
 
-	void DockManager::DockContainer::addTop(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
+	void DockManager::DockContainer::addTop(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget)
 	{
 	{
 		splitContainer(widgetParent, parentWindow, widget, true, true);
 		splitContainer(widgetParent, parentWindow, widget, true, true);
 	}
 	}
 
 
-	void DockManager::DockContainer::addBottom(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget)
+	void DockManager::DockContainer::addBottom(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget)
 	{
 	{
 		splitContainer(widgetParent, parentWindow, widget, true, false);
 		splitContainer(widgetParent, parentWindow, widget, true, false);
 	}
 	}
 
 
-	void DockManager::DockContainer::splitContainer(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidget* widget, bool horizontal, bool newChildIsFirst)
+	void DockManager::DockContainer::splitContainer(BS::GUIWidget* widgetParent, RenderWindow* parentWindow, EditorWidgetBase* widget, bool horizontal, bool newChildIsFirst)
 	{
 	{
 		UINT32 idxA = newChildIsFirst ? 0 : 1;
 		UINT32 idxA = newChildIsFirst ? 0 : 1;
 		UINT32 idxB = (idxA + 1) % 2;
 		UINT32 idxB = (idxA + 1) % 2;
@@ -419,7 +419,7 @@ namespace BansheeEditor
 		renderQueue.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
 		renderQueue.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
 	}
 	}
 
 
-	void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location)
+	void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location)
 	{
 	{
 		if(relativeTo != nullptr)
 		if(relativeTo != nullptr)
 		{
 		{
@@ -682,7 +682,7 @@ namespace BansheeEditor
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 				return false;
 				return false;
 
 
-			EditorWidget* draggedWidget = reinterpret_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
+			EditorWidgetBase* draggedWidget = reinterpret_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
 
 
 			const Vector2I& widgetRelPos = event.getPosition();
 			const Vector2I& widgetRelPos = event.getPosition();
 			const Matrix4& worldTfrm = mParent->SO()->getWorldTfrm();
 			const Matrix4& worldTfrm = mParent->SO()->getWorldTfrm();

+ 3 - 0
CamelotClient/Source/BsEditorApplication.cpp

@@ -1,5 +1,6 @@
 #include "BsEditorApplication.h"
 #include "BsEditorApplication.h"
 #include "BsEditorWindowManager.h"
 #include "BsEditorWindowManager.h"
+#include "BsEditorWidgetManager.h"
 #include "BsMainEditorWindow.h"
 #include "BsMainEditorWindow.h"
 #include "BsApplication.h"
 #include "BsApplication.h"
 #include "CmApplication.h"
 #include "CmApplication.h"
@@ -250,6 +251,7 @@ 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());
 
 
 		gApplication().mainLoopCallback.connect(boost::bind(&EditorApplication::update, this));
 		gApplication().mainLoopCallback.connect(boost::bind(&EditorApplication::update, this));
@@ -259,6 +261,7 @@ namespace BansheeEditor
 
 
 		gBansheeApp().runMainLoop();
 		gBansheeApp().runMainLoop();
 
 
+		EditorWidgetManager::shutDown();
 		EditorWindowManager::shutDown();
 		EditorWindowManager::shutDown();
 		UndoRedo::shutDown();
 		UndoRedo::shutDown();
 
 

+ 9 - 9
CamelotClient/Source/BsEditorWidget.cpp

@@ -13,23 +13,23 @@ using namespace BansheeEngine;
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	EditorWidget::EditorWidget(const HString& name)
+	EditorWidgetBase::EditorWidgetBase(const HString& name)
 		:mName(name), mParent(nullptr), mContent(nullptr)
 		:mName(name), mParent(nullptr), mContent(nullptr)
 	{
 	{
 		
 		
 	}
 	}
 
 
-	EditorWidget::~EditorWidget()
+	EditorWidgetBase::~EditorWidgetBase()
 	{
 	{
 
 
 	}
 	}
 
 
-	void EditorWidget::destroy(EditorWidget* widget)
+	void EditorWidgetBase::destroy(EditorWidgetBase* widget)
 	{
 	{
 		cm_delete(widget);
 		cm_delete(widget);
 	}
 	}
 
 
-	void EditorWidget::_setPosition(INT32 x, INT32 y)
+	void EditorWidgetBase::_setPosition(INT32 x, INT32 y)
 	{
 	{
 		if(mContent == nullptr)
 		if(mContent == nullptr)
 			return;
 			return;
@@ -37,7 +37,7 @@ namespace BansheeEditor
 		mContent->setPosition(x, y);
 		mContent->setPosition(x, y);
 	}
 	}
 
 
-	void EditorWidget::_setSize(UINT32 width, UINT32 height)
+	void EditorWidgetBase::_setSize(UINT32 width, UINT32 height)
 	{
 	{
 		if(mContent == nullptr)
 		if(mContent == nullptr)
 			return;
 			return;
@@ -45,7 +45,7 @@ namespace BansheeEditor
 		mContent->setSize(width, height);
 		mContent->setSize(width, height);
 	}
 	}
 
 
-	void EditorWidget::_changeParent(EditorWidgetContainer* parent)
+	void EditorWidgetBase::_changeParent(EditorWidgetContainer* parent)
 	{
 	{
 		if(mParent != parent) 
 		if(mParent != parent) 
 		{
 		{
@@ -66,17 +66,17 @@ namespace BansheeEditor
 		}
 		}
 	}
 	}
 
 
-	void EditorWidget::_disable()
+	void EditorWidgetBase::_disable()
 	{
 	{
 		mContent->disable();
 		mContent->disable();
 	}
 	}
 
 
-	void EditorWidget::_enable()
+	void EditorWidgetBase::_enable()
 	{
 	{
 		mContent->enable();
 		mContent->enable();
 	}
 	}
 
 
-	GUIWidget& EditorWidget::getParentWidget() const
+	GUIWidget& EditorWidgetBase::getParentWidget() const
 	{
 	{
 		return mParent->getParentWidget();
 		return mParent->getParentWidget();
 	}
 	}

+ 12 - 12
CamelotClient/Source/BsEditorWidgetContainer.cpp

@@ -38,16 +38,16 @@ namespace BansheeEditor
 
 
 		for(auto& widget : mWidgets)
 		for(auto& widget : mWidgets)
 		{
 		{
-			EditorWidget::destroy(widget.second);
+			EditorWidgetBase::destroy(widget.second);
 		}
 		}
 	}
 	}
 
 
-	void EditorWidgetContainer::add(EditorWidget& widget)
+	void EditorWidgetContainer::add(EditorWidgetBase& widget)
 	{
 	{
 		insert((UINT32)mWidgets.size(), widget);
 		insert((UINT32)mWidgets.size(), widget);
 	}
 	}
 
 
-	void EditorWidgetContainer::remove(EditorWidget& widget)
+	void EditorWidgetContainer::remove(EditorWidgetBase& widget)
 	{
 	{
 		INT32 tabIdx = 0;
 		INT32 tabIdx = 0;
 		for(auto& curWidget : mWidgets)
 		for(auto& curWidget : mWidgets)
@@ -76,7 +76,7 @@ namespace BansheeEditor
 		}
 		}
 	}
 	}
 
 
-	void EditorWidgetContainer::insert(CM::UINT32 idx, EditorWidget& widget)
+	void EditorWidgetContainer::insert(CM::UINT32 idx, EditorWidgetBase& widget)
 	{
 	{
 		for(auto& curWidget : mWidgets)
 		for(auto& curWidget : mWidgets)
 		{
 		{
@@ -103,7 +103,7 @@ namespace BansheeEditor
 
 
 		if(mActiveWidget >= 0)
 		if(mActiveWidget >= 0)
 		{
 		{
-			EditorWidget* activeWidgetPtr = mWidgets[mActiveWidget];
+			EditorWidgetBase* activeWidgetPtr = mWidgets[mActiveWidget];
 			UINT32 contentHeight = (UINT32)std::max(0, (INT32)height - (INT32)TitleBarHeight);
 			UINT32 contentHeight = (UINT32)std::max(0, (INT32)height - (INT32)TitleBarHeight);
 
 
 			activeWidgetPtr->_setSize(width, contentHeight);
 			activeWidgetPtr->_setSize(width, contentHeight);
@@ -119,7 +119,7 @@ namespace BansheeEditor
 
 
 		if(mActiveWidget >= 0)
 		if(mActiveWidget >= 0)
 		{
 		{
-			EditorWidget* activeWidgetPtr = mWidgets[mActiveWidget];
+			EditorWidgetBase* activeWidgetPtr = mWidgets[mActiveWidget];
 
 
 			activeWidgetPtr->_setPosition(x, y + TitleBarHeight);
 			activeWidgetPtr->_setPosition(x, y + TitleBarHeight);
 		}
 		}
@@ -156,9 +156,9 @@ namespace BansheeEditor
 
 
 	void EditorWidgetContainer::tabClosed(UINT32 uniqueIdx)
 	void EditorWidgetContainer::tabClosed(UINT32 uniqueIdx)
 	{
 	{
-		EditorWidget* widget = mWidgets[uniqueIdx];
+		EditorWidgetBase* widget = mWidgets[uniqueIdx];
 		remove(*widget);
 		remove(*widget);
-		EditorWidget::destroy(widget);
+		EditorWidgetBase::destroy(widget);
 
 
 		if(!onWidgetClosed.empty())
 		if(!onWidgetClosed.empty())
 			onWidgetClosed();
 			onWidgetClosed();
@@ -166,7 +166,7 @@ namespace BansheeEditor
 
 
 	void EditorWidgetContainer::tabDraggedOff(CM::UINT32 uniqueIdx)
 	void EditorWidgetContainer::tabDraggedOff(CM::UINT32 uniqueIdx)
 	{
 	{
-		EditorWidget* widget = mWidgets[uniqueIdx];
+		EditorWidgetBase* widget = mWidgets[uniqueIdx];
 		remove(*widget);
 		remove(*widget);
 
 
 		// TODO - Hook up drag and drop texture
 		// TODO - Hook up drag and drop texture
@@ -187,7 +187,7 @@ namespace BansheeEditor
 			CM_EXCEPT(InternalErrorException, "Tab drag and drop reported but drag type is invalid.");
 			CM_EXCEPT(InternalErrorException, "Tab drag and drop reported but drag type is invalid.");
 #endif
 #endif
 
 
-		EditorWidget* draggedWidget = static_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
+		EditorWidgetBase* draggedWidget = static_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
 
 
 		insert(seqIdx, *draggedWidget);
 		insert(seqIdx, *draggedWidget);
 		setActiveWidget(mTitleBar->getTabIdx(seqIdx));
 		setActiveWidget(mTitleBar->getTabIdx(seqIdx));
@@ -200,7 +200,7 @@ namespace BansheeEditor
 
 
 		if(!wasDragProcessed)
 		if(!wasDragProcessed)
 		{
 		{
-			EditorWidget* draggedWidget = static_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
+			EditorWidgetBase* draggedWidget = static_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
 			EditorWindow* newWindow = EditorWindow::create();
 			EditorWindow* newWindow = EditorWindow::create();
 
 
 			newWindow->widgets().add(*draggedWidget);
 			newWindow->widgets().add(*draggedWidget);
@@ -215,7 +215,7 @@ namespace BansheeEditor
 		return RectI(mX, mY + TitleBarHeight, mWidth, (UINT32)std::max(0, (INT32)mHeight - (INT32)TitleBarHeight));
 		return RectI(mX, mY + TitleBarHeight, mWidth, (UINT32)std::max(0, (INT32)mHeight - (INT32)TitleBarHeight));
 	}
 	}
 
 
-	void EditorWidgetContainer::_notifyWidgetDestroyed(EditorWidget* widget)
+	void EditorWidgetContainer::_notifyWidgetDestroyed(EditorWidgetBase* widget)
 	{
 	{
 		for(auto& curWidget : mWidgets)
 		for(auto& curWidget : mWidgets)
 		{
 		{

+ 73 - 0
CamelotClient/Source/BsEditorWidgetManager.cpp

@@ -0,0 +1,73 @@
+#include "BsEditorWidgetManager.h"
+#include "BsEditorWidget.h"
+#include "BsEditorWindow.h"
+#include "BsEditorWidgetContainer.h"
+#include "CmException.h"
+
+using namespace CamelotFramework;
+using namespace BansheeEngine;
+
+namespace BansheeEditor
+{
+	Stack<std::pair<String, std::function<EditorWidgetBase*()>>>::type EditorWidgetManager::QueuedCreateCallbacks;
+
+	EditorWidgetManager::EditorWidgetManager()
+	{
+		while(!QueuedCreateCallbacks.empty())
+		{
+			std::pair<String, std::function<EditorWidgetBase*()>> curElement = QueuedCreateCallbacks.top();
+			QueuedCreateCallbacks.pop();
+
+			registerWidget(curElement.first, curElement.second);
+		}
+	}
+
+	void EditorWidgetManager::registerWidget(const String& name, std::function<EditorWidgetBase*()> createCallback)
+	{
+		auto iterFind = mCreateCallbacks.find(name);
+
+		if(iterFind != mCreateCallbacks.end())
+			CM_EXCEPT(InvalidParametersException, "Widget with the same name is already registered. Name: \"" + name + "\"");
+
+		mCreateCallbacks[name] = createCallback;
+	}
+
+	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())
+			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;
+	}
+
+	void EditorWidgetManager::close(EditorWidgetBase* widget)
+	{
+		auto findIter = std::find_if(mActiveWidgets.begin(), mActiveWidgets.end(),
+			[&] (const std::pair<String, EditorWidgetBase*>& entry) { return entry.second == widget; });
+
+		if(findIter != mActiveWidgets.end())
+			mActiveWidgets.erase(findIter);
+
+		widget->mParent->_notifyWidgetDestroyed(widget);
+
+		EditorWidgetBase::destroy(widget);
+	}
+
+	void EditorWidgetManager::preRegisterWidget(const String& name, std::function<EditorWidgetBase*()> createCallback)
+	{
+		QueuedCreateCallbacks.push(std::pair<String, std::function<EditorWidgetBase*()>>(name, createCallback));
+	}
+}

+ 2 - 2
CamelotClient/Source/BsGUITabbedTitleBar.cpp

@@ -134,7 +134,7 @@ namespace BansheeEditor
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 				return false;
 				return false;
 
 
-			EditorWidget* draggedWidget = reinterpret_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
+			EditorWidgetBase* draggedWidget = reinterpret_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
 			const Vector2I& widgetRelPos = event.getPosition();
 			const Vector2I& widgetRelPos = event.getPosition();
 
 
 			if(mTempDraggedWidget == nullptr)
 			if(mTempDraggedWidget == nullptr)
@@ -202,7 +202,7 @@ namespace BansheeEditor
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 			if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
 				return false;
 				return false;
 
 
-			EditorWidget* draggedWidget = reinterpret_cast<EditorWidget*>(DragAndDropManager::instance().getDragData());
+			EditorWidgetBase* draggedWidget = reinterpret_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
 			const Vector2I& widgetRelPos = event.getPosition();
 			const Vector2I& widgetRelPos = event.getPosition();
 
 
 			if(mTempDraggedWidget != nullptr)
 			if(mTempDraggedWidget != nullptr)

+ 11 - 20
CamelotClient/Source/DbgEditorWidget1.cpp

@@ -6,8 +6,7 @@
 #include "BsGUIScrollArea.h"
 #include "BsGUIScrollArea.h"
 #include "BsGUIArea.h"
 #include "BsGUIArea.h"
 #include "BsGUILayout.h"
 #include "BsGUILayout.h"
-#include "BsEditorWindow.h"
-#include "BsEditorWidgetContainer.h"
+#include "BsEditorWidgetManager.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 using namespace BansheeEngine;
@@ -16,8 +15,8 @@ namespace BansheeEditor
 {
 {
 	DbgEditorWidget1* DbgEditorWidget1::Instance = nullptr;
 	DbgEditorWidget1* DbgEditorWidget1::Instance = nullptr;
 
 
-	DbgEditorWidget1::DbgEditorWidget1()
-		:EditorWidget(HString(L"DbgEditorWidget1"))
+	DbgEditorWidget1::DbgEditorWidget1(const ConstructPrivately& dummy)
+		:EditorWidget<DbgEditorWidget1>(HString(L"DbgEditorWidget1"))
 	{
 	{
 		
 		
 	}
 	}
@@ -91,28 +90,20 @@ namespace BansheeEditor
 
 
 	DbgEditorWidget1* DbgEditorWidget1::open()
 	DbgEditorWidget1* DbgEditorWidget1::open()
 	{
 	{
-		if(Instance != nullptr)
-			return Instance;
-
-		EditorWindow* newWindow = EditorWindow::create();
-
-		DbgEditorWidget1* newWidget = new (cm_alloc<DbgEditorWidget1>()) DbgEditorWidget1();
-		newWindow->widgets().add(*newWidget);
-		newWidget->initialize();
-		Instance = newWidget;
-
-		return newWidget;
+		return static_cast<DbgEditorWidget1*>(EditorWidgetManager::instance().open(getTypeName()));
 	}
 	}
 
 
 	void DbgEditorWidget1::close()
 	void DbgEditorWidget1::close()
 	{
 	{
 		if(Instance != nullptr)
 		if(Instance != nullptr)
-		{
-			Instance->mParent->_notifyWidgetDestroyed(Instance);
-
-			EditorWidget::destroy(Instance);
-		}
+			EditorWidgetManager::instance().close(Instance);
 		
 		
 		Instance = nullptr; 
 		Instance = nullptr; 
 	}
 	}
+
+	const String& DbgEditorWidget1::getTypeName()
+	{
+		static String name = "DbgEditorWidget1";
+		return name;
+	}
 }
 }

+ 11 - 21
CamelotClient/Source/DbgEditorWidget2.cpp

@@ -1,11 +1,9 @@
 #include "DbgEditorWidget2.h"
 #include "DbgEditorWidget2.h"
-#include "BsEditorWindow.h"
+#include "BsEditorWidgetManager.h"
 #include "BsGUIToggle.h"
 #include "BsGUIToggle.h"
 #include "BsGUIScrollArea.h"
 #include "BsGUIScrollArea.h"
 #include "BsGUIArea.h"
 #include "BsGUIArea.h"
 #include "BsGUILayout.h"
 #include "BsGUILayout.h"
-#include "BsEditorWindow.h"
-#include "BsEditorWidgetContainer.h"
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 
 
@@ -16,8 +14,8 @@ namespace BansheeEditor
 {
 {
 	DbgEditorWidget2* DbgEditorWidget2::Instance = nullptr;
 	DbgEditorWidget2* DbgEditorWidget2::Instance = nullptr;
 
 
-	DbgEditorWidget2::DbgEditorWidget2()
-		:EditorWidget(HString(L"DbgEditorWidget2"))
+	DbgEditorWidget2::DbgEditorWidget2(const ConstructPrivately& dummy)
+		:EditorWidget<DbgEditorWidget2>(HString(L"DbgEditorWidget2"))
 	{
 	{
 
 
 	}
 	}
@@ -52,28 +50,20 @@ namespace BansheeEditor
 
 
 	DbgEditorWidget2* DbgEditorWidget2::open()
 	DbgEditorWidget2* DbgEditorWidget2::open()
 	{
 	{
-		if(Instance != nullptr)
-			return Instance;
-
-		EditorWindow* newWindow = EditorWindow::create();
-
-		DbgEditorWidget2* newWidget = new (cm_alloc<DbgEditorWidget2>()) DbgEditorWidget2();
-		newWindow->widgets().add(*newWidget);
-		newWidget->initialize();
-		Instance = newWidget;
-
-		return newWidget;
+		return static_cast<DbgEditorWidget2*>(EditorWidgetManager::instance().open(getTypeName()));
 	}
 	}
 
 
 	void DbgEditorWidget2::close()
 	void DbgEditorWidget2::close()
 	{
 	{
 		if(Instance != nullptr)
 		if(Instance != nullptr)
-		{
-			Instance->mParent->_notifyWidgetDestroyed(Instance);
-
-			EditorWidget::destroy(Instance);
-		}
+			EditorWidgetManager::instance().close(Instance);
 
 
 		Instance = nullptr; 
 		Instance = nullptr; 
 	}
 	}
+
+	const String& DbgEditorWidget2::getTypeName()
+	{
+		static String name = "DbgEditorWidget2";
+		return name;
+	}
 }
 }

+ 45 - 1
EditorWindowDock.txt

@@ -11,4 +11,48 @@ Polish TOOD:
 Other things to remember:
 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)
  - 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
  - A way to persist window states
- - Also a way to reset all widgets to original locations
+ - Also a way to reset all widgets to original locations
+
+
+ ------------------------
+
+ EditorWindow enumeraton in C#:
+
+ To get all classes in a mono image:
+MonoClass*
+mono_assembly_get_classes (MonoAssembly *assembly, gpointer *iter)
+{
+	MonoImage *image;
+	int num_types;
+	gssize *index;
+
+	if (!iter)
+		return NULL;
+
+	index = (gssize *) iter;
+
+	/* skip the <Module> */
+	if (!*index)
+		*index = 1;
+
+	image = mono_assembly_get_image (assembly);
+	num_types = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF);
+
+	if (*index < num_types) {
+		(*index)++;
+		return mono_class_get (image, *index | MONO_TOKEN_TYPE_DEF);
+	} else {
+		*index = 0;
+		return NULL;
+	}
+}
+
+More info on how to potentially access other properties, here: http://docs.go-mono.com/?link=xhtml%3adeploy%2fmono-api-metadata.html
+
+
+To get class hierarchy:
+ mono_class_get_parent to get parent class (does this mean base class?)
+ mono_class_is_assignable_from potentially
+ mono_class_is_subclass_of
+
+Attributes: Very much undocumented but a lot of stuff here relates to attributes: http://docs.go-mono.com/?link=xhtml%3adeploy%2fmono-api-reflection.html

+ 0 - 5
ProjectLibrary.txt

@@ -1,11 +1,6 @@
 
 
  - Resource import queue (ability to display progress bar for resources that are importing)
  - Resource import queue (ability to display progress bar for resources that are importing)
   - Plus modal windows?
   - Plus modal windows?
- - Implement Delete command for ResourceTreeView
-
- TODO OTHER:
-  - Shutting down causes a crash in FolderMonitor
-  - During app startup I get ~10 first chance exceptions
 
 
 -------------------
 -------------------