Browse Source

Creating EditorWindow from C# works

Marko Pintera 11 years ago
parent
commit
6509cf4a7a

+ 1 - 1
BansheeEditor/Include/BsEditorWidget.h

@@ -6,7 +6,7 @@
 
 namespace BansheeEditor
 {
-	class EditorWidgetBase
+	class BS_ED_EXPORT EditorWidgetBase
 	{
 	public:
 		virtual void initialize() { }

+ 1 - 1
BansheeEditor/Include/BsEditorWidgetContainer.h

@@ -5,7 +5,7 @@
 
 namespace BansheeEditor
 {
-	class EditorWidgetContainer
+	class BS_ED_EXPORT EditorWidgetContainer
 	{
 	public:
 		EditorWidgetContainer(BS::GUIWidget* parent, CM::RenderWindow* renderWindow, EditorWindow* parentEditorWindow);

+ 1 - 1
BansheeEditor/Include/BsEditorWidgetManager.h

@@ -11,7 +11,7 @@ namespace BansheeEditor
 	 * 			upon program shutdown/startup, as well as being able to change widget layout on
 	 * 			the fly.
 	 */
-	class EditorWidgetManager : public CM::Module<EditorWidgetManager>
+	class BS_ED_EXPORT EditorWidgetManager : public CM::Module<EditorWidgetManager>
 	{
 	public:
 		EditorWidgetManager();

+ 10 - 10
BansheeEditor/Source/BsEditorApplication.cpp

@@ -66,6 +66,16 @@ namespace BansheeEditor
 
 		ProjectLibrary::startUp(cm_new<ProjectLibrary>(getActiveProjectPath()));
 
+		UndoRedo::startUp(cm_new<UndoRedo>());
+		EditorWindowManager::startUp(cm_new<EditorWindowManager>());
+
+		MainEditorWindow* mainWindow = MainEditorWindow::create(gApplication().getPrimaryWindow());
+		EditorWidgetManager::startUp(cm_new<EditorWidgetManager>());
+
+		EditorWidgetLayoutPtr layout = loadWidgetLayout();
+		if(layout != nullptr)
+			EditorWidgetManager::instance().setLayout(layout);
+
 		gApplication().loadPlugin("SBansheeEditor"); // Managed part of the editor
 
 		/************************************************************************/
@@ -255,16 +265,6 @@ namespace BansheeEditor
 		/* 							END DEBUG CODE                      		*/
 		/************************************************************************/
 
-		UndoRedo::startUp(cm_new<UndoRedo>());
-		EditorWindowManager::startUp(cm_new<EditorWindowManager>());
-		
-		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));
 
 		DbgEditorWidget1::open(); // DEBUG ONLY

+ 6 - 3
BansheeEditor/Source/BsEditorWidgetManager.cpp

@@ -45,7 +45,7 @@ namespace BansheeEditor
 
 		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 + "\"");
+			return nullptr;
 
 		EditorWindow* window = EditorWindow::create();
 		window->widgets().add(*newWidget);
@@ -87,7 +87,9 @@ namespace BansheeEditor
 			return nullptr;
 
 		EditorWidgetBase* newWidget = mCreateCallbacks[name]();
-		mActiveWidgets[name] = newWidget;
+
+		if(newWidget != nullptr)
+			mActiveWidgets[name] = newWidget;
 
 		return newWidget;
 	}
@@ -190,7 +192,8 @@ namespace BansheeEditor
 			for(auto& widgetName : entry.widgetNames)
 			{
 				EditorWidgetBase* widget = create(widgetName); // This will returned previously created widget
-				window->widgets().add(*widget);
+				if(widget != nullptr)
+					window->widgets().add(*widget);
 			}
 
 			window->setPosition(entry.x, entry.y);

+ 9 - 1
BansheeMono/Include/BsMonoClass.h

@@ -28,11 +28,16 @@ namespace BansheeEngine
 	public:
 		~MonoClass();
 
+		const CM::String& getNamespace() const { return mNamespace; }
+		const CM::String& getTypeName() const { return mTypeName; }
+		const CM::String& getFullName() const { return mFullName; }
+
 		MonoMethod& getMethod(const CM::String& name, CM::UINT32 numParams = 0);
 		MonoField& getField(const CM::String& name);
 		MonoProperty& getProperty(const CM::String& name);
 
 		bool hasField(const CM::String& name) const;
+		bool isSubClassOf(const BS::MonoClass* monoClass) const;
 
 		MonoObject* invokeMethod(const CM::String& name, MonoObject* instance = nullptr, void** params = nullptr, CM::UINT32 numParams = 0);
 		void addInternalCall(const CM::String& name, const void* method);
@@ -40,13 +45,16 @@ namespace BansheeEngine
 		::MonoClass* _getInternalClass() const { return mClass; }
 
 		MonoObject* createInstance() const;
+		MonoObject* createInstance(void** params, CM::UINT32 numParams);
 	private:
 		friend class MonoAssembly;
 
-		MonoClass(const CM::String& fullName, ::MonoClass* monoClass, MonoAssembly* parentAssembly);
+		MonoClass(const CM::String& ns, const CM::String& type, ::MonoClass* monoClass, MonoAssembly* parentAssembly);
 
 		MonoAssembly* mParentAssembly;
 		::MonoClass* mClass;
+		CM::String mNamespace;
+		CM::String mTypeName;
 		CM::String mFullName;
 
 		CM::UnorderedMap<MethodId, MonoMethod*, MethodId::Hash, MethodId::Equals>::type mMethods; 

+ 14 - 0
BansheeMono/Include/BsMonoManager.h

@@ -29,6 +29,20 @@ namespace BansheeEngine
 		 *
 		 * @param 	obj	If non-null, the object to get the type name of.
 		 */
+		CM::String getFullTypeName(MonoObject* obj);
+
+		/**
+		 * @brief	Returns the namespace of the provided object.
+		 *
+		 * @param 	obj	If non-null, the object to get the namespace of.
+		 */
+		CM::String getNamespace(MonoObject* obj);
+
+		/**
+		 * @brief	Returns the type name of the provided object, without namespace.
+		 *
+		 * @param 	obj	If non-null, the object to get the type name of.
+		 */
 		CM::String getTypeName(MonoObject* obj);
 
 		MonoDomain* getDomain() const { return mDomain; }

+ 3 - 4
BansheeMono/Source/BsMonoAssembly.cpp

@@ -61,15 +61,14 @@ namespace BansheeEngine
 		// Load all classes
 		int numRows = mono_image_get_table_rows (mMonoImage, MONO_TABLE_TYPEDEF);
 
-		for(int i = 1; i < numRows; i++)
+		for(int i = 1; i < numRows; i++) // Skip Module
 		{
-			::MonoClass* monoClass = mono_class_get (mMonoImage, i | MONO_TOKEN_TYPE_DEF);
+			::MonoClass* monoClass = mono_class_get (mMonoImage, (i + 1) | MONO_TOKEN_TYPE_DEF);
 
 			String ns = mono_class_get_namespace(monoClass);
 			String type = mono_class_get_name(monoClass);
 
-			String fullClassName = ns + "." + type;
-			MonoClass* newClass = new (cm_alloc<MonoClass>()) MonoClass(fullClassName, monoClass, this);
+			MonoClass* newClass = new (cm_alloc<MonoClass>()) MonoClass(ns, type, monoClass, this);
 			mClasses[ClassId(ns, type)] = newClass;
 		}
 

+ 22 - 5
BansheeMono/Source/BsMonoClass.cpp

@@ -30,10 +30,10 @@ namespace BansheeEngine
 
 	}
 
-	MonoClass::MonoClass(const String& fullName, ::MonoClass* monoClass, MonoAssembly* parentAssembly)
-		:mFullName(fullName), mClass(monoClass), mParentAssembly(parentAssembly)
+	MonoClass::MonoClass(const String& ns, const String& type, ::MonoClass* monoClass, MonoAssembly* parentAssembly)
+		:mNamespace(ns), mTypeName(type), mClass(monoClass), mParentAssembly(parentAssembly)
 	{
-
+		mFullName = ns + "." + type;
 	}
 
 	MonoClass::~MonoClass()
@@ -87,6 +87,14 @@ namespace BansheeEngine
 		return field != nullptr;
 	}
 
+	bool MonoClass::isSubClassOf(const BS::MonoClass* monoClass) const
+	{
+		if(monoClass == nullptr)
+			return false;
+
+		return mono_class_is_subclass_of(mClass, monoClass->mClass, true) != 0;
+	}
+
 	MonoField& MonoClass::getField(const String& name)
 	{
 		auto iterFind = mFields.find(name);
@@ -96,7 +104,7 @@ namespace BansheeEngine
 		MonoClassField* field = mono_class_get_field_from_name(mClass, name.c_str());
 		if(field == nullptr)
 		{
-			String fullFieldName = mFullName + "::" + name;
+			String fullFieldName = mFullName + "." + name;
 			CM_EXCEPT(InvalidParametersException, "Cannot get Mono field: " + fullFieldName);
 		}
 
@@ -115,7 +123,7 @@ namespace BansheeEngine
 		::MonoProperty* property = mono_class_get_property_from_name(mClass, name.c_str());
 		if(property == nullptr)
 		{
-			String fullPropertyName = mFullName + "::" + name;
+			String fullPropertyName = mFullName + "." + name;
 			CM_EXCEPT(InvalidParametersException, "Cannot get Mono property: " + fullPropertyName);
 		}
 
@@ -139,6 +147,15 @@ namespace BansheeEngine
 	MonoObject* MonoClass::createInstance() const
 	{
 		MonoObject* obj = mono_object_new(MonoManager::instance().getDomain(), mClass);
+		mono_runtime_object_init(obj);
+
+		return obj;
+	}
+
+	MonoObject* MonoClass::createInstance(void** params, UINT32 numParams)
+	{
+		MonoObject* obj = mono_object_new(MonoManager::instance().getDomain(), mClass);
+		getMethod(".ctor", numParams).invoke(obj, params);
 
 		return obj;
 	}

+ 1 - 1
BansheeMono/Source/BsMonoField.cpp

@@ -30,7 +30,7 @@ namespace BansheeEngine
 		::MonoClass* parentClass = mono_field_get_parent(mField);
 		MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, mField);
 
-		bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->_getInternalClass());
+		bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->_getInternalClass()) != 0;
 
 		mono_custom_attrs_free(attrInfo);
 

+ 41 - 1
BansheeMono/Source/BsMonoManager.cpp

@@ -126,6 +126,41 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	String MonoManager::getFullTypeName(MonoObject* obj)
+	{
+		if(obj == nullptr)
+			CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
+
+		::MonoClass* monoClass = mono_object_get_class(obj);
+
+		const char* nameSpaceChars = mono_class_get_namespace(monoClass);
+		String namespaceStr;
+		if(nameSpaceChars != nullptr)
+			namespaceStr = nameSpaceChars;
+
+		const char* typeNameChars = mono_class_get_name(monoClass);
+		String typeNameStr;
+		if(typeNameChars != nullptr)
+			typeNameStr = typeNameChars;
+
+		return namespaceStr + "." + typeNameStr;
+	}
+
+	String MonoManager::getNamespace(MonoObject* obj)
+	{
+		if(obj == nullptr)
+			CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
+
+		::MonoClass* monoClass = mono_object_get_class(obj);
+
+		const char* nameSpaceChars = mono_class_get_namespace(monoClass);
+		String namespaceStr;
+		if(nameSpaceChars != nullptr)
+			namespaceStr = nameSpaceChars;
+
+		return namespaceStr;
+	}
+
 	String MonoManager::getTypeName(MonoObject* obj)
 	{
 		if(obj == nullptr)
@@ -133,6 +168,11 @@ namespace BansheeEngine
 
 		::MonoClass* monoClass = mono_object_get_class(obj);
 
-		return String(mono_class_get_namespace(monoClass)) + "." + String(mono_class_get_name(monoClass));
+		const char* typeNameChars = mono_class_get_name(monoClass);
+		String typeNameStr;
+		if(typeNameChars != nullptr)
+			typeNameStr = typeNameChars;
+
+		return typeNameStr;
 	}
 }

+ 5 - 2
EditorWindowDock.txt

@@ -2,6 +2,11 @@ TODO:
  - Closing all docked widgets causes an exception
  - Test out minimum dock container size and maybe increase it a bit
 
+I should consider adding multiple C# EditorWindow types (via an enum)
+ - Normal dockable EditorWindow, a tool window (unockable, no tabs), a modal window or maybe others
+   - Dockable EditorWindow would internally be EditorWidgetBase as it is now and I would create different types for other windows
+   - (Other windows should not need layout)
+
 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
@@ -9,8 +14,6 @@ Polish TOOD:
 ------------------------
 Layout saving/loading:
 TODO:
- EditorWindow creation from Scripts is currently disabled as I need to export EditorWidget classes
-   - I will probably want to move BansheeEditor stuff into its own BansheeEditor .dll (need it for singleton instantiation as well)
  Register a bunch of duplicate widgets and open and dock them
  C# EditorWindows
 

+ 12 - 0
MBansheeEditor/DbgEditorWindow.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BansheeEditor
+{
+    class DbgEditorWindow : EditorWindow
+    {
+    }
+}

+ 7 - 3
MBansheeEditor/EditorWindow.cs

@@ -13,16 +13,20 @@ namespace BansheeEditor
             return Internal_CreateOrGetInstance(typeof(T).Namespace, typeof(T).Name);
         }
 
-        public EditorWindow()
+        protected EditorWindow()
         {
             Internal_CreateInstance(this);
+        }
+
+        private void Initialize()
+        {
             GUI = new EditorGUI(this);
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern EditorWindow Internal_CreateOrGetInstance(string ns, string typeName);
+        private static extern void Internal_CreateInstance(EditorWindow instance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(EditorWindow instance);
+        private static extern EditorWindow Internal_CreateOrGetInstance(string ns, string typeName);
     }
 }

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -39,6 +39,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="DbgEditorWindow.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorGUI.cs" />
     <Compile Include="EditorWindow.cs" />

+ 32 - 5
SBansheeEditor/Include/BsScriptEditorWindow.h

@@ -2,21 +2,31 @@
 
 #include "BsScriptEditorPrerequisites.h"
 #include "BsScriptObject.h"
+#include "BsEditorWidget.h"
 
 namespace BansheeEditor
 {
+	class ScriptEditorWidget;
+
 	class BS_SCR_BED_EXPORT ScriptEditorWindow : public BansheeEngine::ScriptObject<ScriptEditorWindow>
 	{
+		struct EditorWindowHandle
+		{
+			uint32_t gcHandle;
+			ScriptEditorWindow* nativeObj;
+		};
 	public:
 		~ScriptEditorWindow();
 
-		static void initMetaData();
+		EditorWidgetBase* getEditorWidget() const { return mEditorWidget; }
 
-		EditorWidgetBase* getEditorWidget() const { return mWidget; }
+		static void initMetaData();
 
 		static void registerManagedEditorWindows();
 	private:
-		ScriptEditorWindow(const CM::String& windowName);
+		friend class ScriptEditorWidget;
+
+		ScriptEditorWindow(const CM::String& windowName, const CM::String& displayName);
 
 		static MonoObject* internal_createOrGetInstance(MonoString* ns, MonoString* typeName);
 		static void internal_createInstance(MonoObject* instance);
@@ -24,8 +34,25 @@ namespace BansheeEditor
 
 		static void initRuntimeData();
 
-		static CM::UnorderedMap<CM::String, ScriptEditorWindow*>::type OpenScriptEditorWindows;
+		CM::String mName;
+		EditorWidgetBase* mEditorWidget;
+
+		// Global editor window management methods
+		static void registerScriptEditorWindow(ScriptEditorWindow* editorWindow);
+		static void unregisterScriptEditorWindow(ScriptEditorWindow* editorWindow);
+
+		static CM::UnorderedMap<CM::String, EditorWindowHandle>::type OpenScriptEditorWindows;
 
-		EditorWidgetBase* mWidget;
+		static EditorWidgetBase* openEditorWidgetCallback(CM::String ns, CM::String type);
+	};
+
+	class BS_SCR_BED_EXPORT ScriptEditorWidget : public EditorWidgetBase
+	{
+	public:
+		ScriptEditorWidget(const CM::HString& displayName, ScriptEditorWindow* window);
+		~ScriptEditorWidget();
+
+	private:
+		ScriptEditorWindow* mWindow;
 	};
 }

+ 6 - 6
SBansheeEditor/SBansheeEditor.vcxproj

@@ -127,7 +127,7 @@
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x86/$(Configuration);../Dependencies/lib/x86/Debug</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x86\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -142,7 +142,7 @@
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x64/$(Configuration);../Dependencies/lib/x64/Debug</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x64\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -162,7 +162,7 @@
       <GenerateDebugInformation>false</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x86/$(Configuration);../Dependencies/lib/x86/Release</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x86\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -181,7 +181,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x86/$(Configuration);../Dependencies/lib/x86/DebugRelease</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x86\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -201,7 +201,7 @@
       <GenerateDebugInformation>false</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x64/$(Configuration);../Dependencies/lib/x64/Release</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x64\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
@@ -220,7 +220,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotCore.lib;CamelotUtility.lib;BansheeEngine.lib;BansheeEditor.lib;BansheeMono.lib;SBansheeEngine.lib;mono-2.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>../lib/x64/$(Configuration);../Dependencies/lib/x64/DebugRelease</AdditionalLibraryDirectories>
       <ImportLibrary>..\lib\x64\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>

+ 3 - 1
SBansheeEditor/Source/BsScriptEditorPlugin.cpp

@@ -1,4 +1,5 @@
 #include "BsScriptEditorPrerequisites.h"
+#include "BsScriptEditorWindow.h"
 #include "BsMonoManager.h"
 #include "BsMonoAssembly.h"
 
@@ -19,7 +20,8 @@ namespace BansheeEditor
 		const CM::String ENGINE_ASSEMBLY_NAME = "MBansheeEditor";
 		const CM::String ASSEMBLY_ENTRY_POINT = "ProgramEd::Main";
 
-		MonoManager::instance().loadAssembly(ENGINE_ASSEMBLY_PATH, ENGINE_ASSEMBLY_NAME, ASSEMBLY_ENTRY_POINT);
+		BS::MonoAssembly& assembly = MonoManager::instance().loadAssembly(ENGINE_ASSEMBLY_PATH, ENGINE_ASSEMBLY_NAME, ASSEMBLY_ENTRY_POINT);
+		ScriptEditorWindow::registerManagedEditorWindows();
 
 		return nullptr;
 	}

+ 112 - 14
SBansheeEditor/Source/BsScriptEditorWindow.cpp

@@ -6,24 +6,26 @@
 #include "BsMonoUtil.h"
 #include "BsEditorWidget.h"
 #include "BsEditorWidgetManager.h"
+#include "BsMonoAssembly.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 
 namespace BansheeEditor
 {
-	UnorderedMap<String, ScriptEditorWindow*>::type ScriptEditorWindow::OpenScriptEditorWindows;
+	UnorderedMap<String, ScriptEditorWindow::EditorWindowHandle>::type ScriptEditorWindow::OpenScriptEditorWindows;
 
-	ScriptEditorWindow::ScriptEditorWindow(const CM::String& windowName)
-		:mWidget(nullptr)
+	ScriptEditorWindow::ScriptEditorWindow(const CM::String& windowName, const CM::String& displayName)
+		:mName(windowName)
 	{
-		//mWidget = EditorWidgetManager::instance().open(windowName);
+		// This will be cleaned up by EditorWidgetManager since technically this should be done in the "create"
+		// callback but we're doing it here for convenience.
+		mEditorWidget = cm_new<ScriptEditorWidget>(HString(toWString(displayName)), this); 
 	}
 
 	ScriptEditorWindow::~ScriptEditorWindow()
 	{
-		//if(mWidget != nullptr)
-		//	mWidget->close();
+
 	}
 
 	void ScriptEditorWindow::initMetaData()
@@ -48,20 +50,23 @@ namespace BansheeEditor
 
 		auto findIter = OpenScriptEditorWindows.find(fullName);
 		if(findIter != OpenScriptEditorWindows.end())
-			return findIter->second->mManagedInstance;
+			return findIter->second.nativeObj->mManagedInstance;
+
+		EditorWidgetManager::instance().open(fullName); // This will trigger openEditorWidgetCallback and update OpenScriptEditorWindows
 
-		BS::MonoClass* monoClass = MonoManager::instance().findClass(strNamespace, strTypeName);
-		if(monoClass == nullptr)
-			CM_EXCEPT(InvalidParametersException, "Provided name is not a valid type name \"" + fullName + "\"");
+		auto findIter2 = OpenScriptEditorWindows.find(fullName);
+		if(findIter2 != OpenScriptEditorWindows.end())
+			return findIter2->second.nativeObj->mManagedInstance;
 
-		return monoClass->createInstance();
+		return nullptr;
 	}
 
 	void ScriptEditorWindow::internal_createInstance(MonoObject* instance)
 	{
-		String windowTypeName = MonoManager::instance().getTypeName(instance);
+		String windowFullTypeName = MonoManager::instance().getFullTypeName(instance);
+		String displayName = MonoManager::instance().getTypeName(instance);
 
-		ScriptEditorWindow* nativeInstance = new (cm_alloc<ScriptEditorWindow>()) ScriptEditorWindow(windowTypeName);
+		ScriptEditorWindow* nativeInstance = new (cm_alloc<ScriptEditorWindow>()) ScriptEditorWindow(windowFullTypeName, displayName);
 		nativeInstance->createInstance(instance);
 
 		metaData.thisPtrField->setValue(instance, nativeInstance);
@@ -69,12 +74,105 @@ namespace BansheeEditor
 
 	void ScriptEditorWindow::internal_destroyInstance(ScriptEditorWindow* nativeInstance)
 	{
+#if CM_DEBUG_MODE
+		auto iterFind = OpenScriptEditorWindows.find(nativeInstance->mName);
+
+		// It is assumed that this method will only be called after "unregisterScriptEditorWindow" is called,
+		// since that is the only place keeping a reference to the managed editor window. So if window was
+		// not removed from OpenScriptEditorWindows array, then something went wrong earlier.
+		assert(iterFind == OpenScriptEditorWindows.end());
+#endif
+
 		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 
 	void ScriptEditorWindow::registerManagedEditorWindows()
 	{
-		// TODO
+		BS::MonoAssembly* assembly = MonoManager::instance().getAssembly("MBansheeEditor");
+
+		if(assembly != nullptr)
+		{
+			BS::MonoClass* editorWindowClass = assembly->getClass("BansheeEditor", "EditorWindow");
+
+			CM::Vector<BS::MonoClass*>::type allClasses = assembly->getAllClasses();
+			for(auto& curClass : allClasses)
+			{
+				if(curClass->isSubClassOf(editorWindowClass) && curClass != editorWindowClass)
+				{
+					const String& className = curClass->getFullName();
+					EditorWidgetManager::instance().registerWidget(className, 
+						std::bind(&ScriptEditorWindow::openEditorWidgetCallback, curClass->getNamespace(), curClass->getTypeName()));
+
+					// DEBUG ONLY
+					EditorWidgetManager::instance().open(className);
+				}
+			}
+		}
+	}
+
+	EditorWidgetBase* ScriptEditorWindow::openEditorWidgetCallback(CM::String ns, CM::String type)
+	{
+		BS::MonoAssembly* assembly = MonoManager::instance().getAssembly("MBansheeEditor");
+
+		if(assembly == nullptr)
+			return nullptr;
+
+		BS::MonoClass* editorWindowClass = assembly->getClass(ns, type);
+
+		if(editorWindowClass == nullptr)
+			return nullptr;
+
+		MonoObject* editorWindowInstance = editorWindowClass->createInstance();
+		if(editorWindowInstance == nullptr)
+			return nullptr;
+
+		ScriptEditorWindow* scriptEditorWindow = ScriptEditorWindow::toNative(editorWindowInstance);
+		return scriptEditorWindow->getEditorWidget();
+	}
+
+	void ScriptEditorWindow::registerScriptEditorWindow(ScriptEditorWindow* editorWindow)
+	{
+		if(editorWindow == nullptr)
+			return;
+
+		auto findIter = OpenScriptEditorWindows.find(editorWindow->mName);
+		if(findIter == OpenScriptEditorWindows.end())
+		{
+			EditorWindowHandle newHandle;
+			newHandle.nativeObj = editorWindow;
+			newHandle.gcHandle = mono_gchandle_new(editorWindow->mManagedInstance, false);
+
+			OpenScriptEditorWindows[editorWindow->mName] = newHandle;
+		}
+	}
+
+	void ScriptEditorWindow::unregisterScriptEditorWindow(ScriptEditorWindow* editorWindow)
+	{
+		if(editorWindow == nullptr)
+			return;
+
+		auto findIter = OpenScriptEditorWindows.find(editorWindow->mName);
+		if(findIter != OpenScriptEditorWindows.end())
+		{
+			EditorWindowHandle& foundHandle = findIter->second;
+			mono_gchandle_free(foundHandle.gcHandle);
+
+			OpenScriptEditorWindows.erase(findIter);
+		}
+	}
+
+	ScriptEditorWidget::ScriptEditorWidget(const CM::HString& displayName, ScriptEditorWindow* window)
+		:EditorWidgetBase(displayName, window->mName), mWindow(window)
+	{
+		ScriptEditorWindow::registerScriptEditorWindow(mWindow);
+
+		// TODO - This is clumsy. Try to create a window in one step
+		window->metaData.scriptClass->invokeMethod("Initialize", window->mManagedInstance);
+	}
+
+	ScriptEditorWidget::~ScriptEditorWidget()
+	{
+		ScriptEditorWindow::unregisterScriptEditorWindow(mWindow);
 	}
 }

+ 1 - 8
SBansheeEngine/Include/BsScriptGUIElementStateStyle.h

@@ -22,14 +22,7 @@ namespace BansheeEngine
 		static void internal_createInstanceExternal(MonoObject* instance, GUIElementStyle::GUIElementStateStyle* externalStateStyle);
 		static void internal_destroyInstance(ScriptGUIElementStateStyle* nativeInstance);
 
-		static void initRuntimeData()
-		{
-			metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIElementStateStyle::internal_createInstance);
-			metaData.scriptClass->addInternalCall("Internal_DestroyInstance", &ScriptGUIElementStateStyle::internal_destroyInstance);
-
-			CM_SCRIPT_SETGET_META(ScriptGUIElementStateStyle, Texture);
-			CM_SCRIPT_SETGET_META(ScriptGUIElementStateStyle, TextColor);
-		}
+		static void initRuntimeData();
 
 		CM_SCRIPT_GETSET_OBJECT_SHRDPTR(ScriptGUIElementStateStyle, ScriptSpriteTexture, Texture, mElementStateStyle->texture, mSpriteTexture);
 		CM_SCRIPT_GETSET_VALUE_REF(ScriptGUIElementStateStyle, CM::Color, TextColor, mElementStateStyle->textColor);

+ 9 - 0
SBansheeEngine/Source/BsScriptGUIElementStateStyle.cpp

@@ -36,6 +36,15 @@ namespace BansheeEngine
 		MonoManager::registerScriptType(&metaData);
 	}
 
+	void ScriptGUIElementStateStyle::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIElementStateStyle::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_DestroyInstance", &ScriptGUIElementStateStyle::internal_destroyInstance);
+
+		CM_SCRIPT_SETGET_META(ScriptGUIElementStateStyle, Texture);
+		CM_SCRIPT_SETGET_META(ScriptGUIElementStateStyle, TextColor);
+	}
+
 	void ScriptGUIElementStateStyle::internal_createInstance(MonoObject* instance)
 	{
 		ScriptGUIElementStateStyle* nativeInstance = new (cm_alloc<ScriptGUIElementStateStyle>()) ScriptGUIElementStateStyle();