Просмотр исходного кода

Prefab drag and drop in scene window works
Mesh and prefab drag and drop works for hierarchy

BearishSun 10 лет назад
Родитель
Сommit
1ed2f28f2e

+ 16 - 2
BansheeEditor/Include/BsGUISceneTreeView.h

@@ -100,8 +100,22 @@ namespace BansheeEngine
 		 */
 		void ping(const HSceneObject& object);
 
-		Event<void()> onSelectionChanged; /**< Triggered whenever the selection changes. Call ::getSelection() to retrieve new selection: */
-		Event<void()> onModified; /**< Triggered whenever the scene is modified in any way from within the scene tree view. (e.g. object is deleted, added, etc.) */
+		/** Triggered whenever the selection changes. Call getSelection() to retrieve new selection. */
+		Event<void()> onSelectionChanged; 
+
+		/** 
+		 * Triggered whenever the scene is modified in any way from within the scene tree view (e.g. object is deleted, 
+		 * added, etc.).
+		 */
+		Event<void()> onModified; 
+
+		/**
+		 * Triggered when a resource drag and drop operation finishes over the scene tree view. Provided scene object
+		 * is the tree view element that the operation finished over (or null if none), and the list of paths is the list 
+		 * of relative paths of the resources that were dropped.
+		 */
+		Event<void(const HSceneObject&, const Vector<Path>&)> onResourceDropped;
+		
 		static const MessageId SELECTION_CHANGED_MSG;
 	protected:
 		virtual ~GUISceneTreeView();

+ 1 - 23
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -326,29 +326,7 @@ namespace BansheeEngine
 				newParent = sceneTreeElement->mSceneObject;
 			}
 
-			for (auto& path : draggedResources->resourcePaths)
-			{
-				ProjectLibrary::LibraryEntry* entry = gProjectLibrary().findEntry(path);
-
-				if (entry != nullptr && entry->type == ProjectLibrary::LibraryEntryType::File)
-				{
-					ProjectLibrary::ResourceEntry* resEntry = static_cast<ProjectLibrary::ResourceEntry*>(entry);
-					if (resEntry->meta != nullptr && resEntry->meta->getTypeID() == TID_Prefab)
-					{
-						HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(resEntry->meta->getUUID()));
-
-						if (prefab != nullptr)
-						{
-							HSceneObject instance = CmdInstantiateSO::execute(prefab, L"Instantiated " + prefab->getName());
-
-							if (newParent != nullptr)
-								instance->setParent(newParent);
-
-							onModified();
-						}
-					}
-				}
-			}
+			onResourceDropped(newParent, draggedResources->resourcePaths);
 		}
 	}
 

+ 113 - 57
MBansheeEditor/GUI/GUISceneTreeView.cs

@@ -1,57 +1,113 @@
-using System;
-using System.Runtime.CompilerServices;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// GUI element that displays all scene objects in the current scene as a tree view.
-    /// </summary>
-    public sealed class GUISceneTreeView : GUIElement
-    {
-        /// <summary>
-        /// Creates a new scene tree view element.
-        /// </summary>
-        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
-        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
-        ///                     default element style is used.</param>
-        /// <param name="options">Options that allow you to control how is the element  positioned and sized. This will 
-        ///                       override any similar options set by style.</param>
-        public GUISceneTreeView(string style = "", params GUIOption[] options)
-        {
-            Internal_CreateInstance(this, style, options);
-        }
-
-        /// <summary>
-        /// Creates a new scene tree view element.
-        /// </summary>
-        /// <param name="options">Options that allow you to control how is the element  positioned and sized. This will 
-        ///                       override any similar options set by style.</param>
-        public GUISceneTreeView(params GUIOption[] options)
-        {
-            Internal_CreateInstance(this, "", options);
-        }
-
-        /// <summary>
-        /// Updates the contents of the tree view with most recent scene data. Should be called once per frame.
-        /// </summary>
-        public void Update()
-        {
-            Internal_Update(mCachedPtr);
-        }
-
-        /// <summary>
-        /// Triggered by the runtime when the scene is modified from the native scene tree view.
-        /// </summary>
-        private void Internal_DoOnModified()
-        {
-            EditorApplication.SetSceneDirty();
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(GUISceneTreeView instance, string style, GUIOption[] options);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Update(IntPtr thisPtr);
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// GUI element that displays all scene objects in the current scene as a tree view.
+    /// </summary>
+    public sealed class GUISceneTreeView : GUIElement
+    {
+        /// <summary>
+        /// Creates a new scene tree view element.
+        /// </summary>
+        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
+        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
+        ///                     default element style is used.</param>
+        /// <param name="options">Options that allow you to control how is the element  positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUISceneTreeView(string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, style, options);
+        }
+
+        /// <summary>
+        /// Creates a new scene tree view element.
+        /// </summary>
+        /// <param name="options">Options that allow you to control how is the element  positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUISceneTreeView(params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, "", options);
+        }
+
+        /// <summary>
+        /// Updates the contents of the tree view with most recent scene data. Should be called once per frame.
+        /// </summary>
+        public void Update()
+        {
+            Internal_Update(mCachedPtr);
+        }
+
+        /// <summary>
+        /// Triggered by the runtime when the scene is modified from the native scene tree view.
+        /// </summary>
+        private void Internal_DoOnModified()
+        {
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Triggered by the runtime when a resource is dropped on the scene tree view.
+        /// </summary>
+        private void Internal_DoOnResourceDropped(SceneObject parent, string[] resourcePaths)
+        {
+            if (resourcePaths == null)
+                return;
+
+            List<SceneObject> addedObjects = new List<SceneObject>(); 
+            for (int i = 0; i < resourcePaths.Length; i++)
+            {
+                LibraryEntry entry = ProjectLibrary.GetEntry(resourcePaths[i]);
+                if (entry != null && entry.Type == LibraryEntryType.File)
+                {
+                    FileEntry fileEntry = (FileEntry)entry;
+                    if (fileEntry.ResType == ResourceType.Mesh)
+                    {
+                        if (!string.IsNullOrEmpty(resourcePaths[i]))
+                        {
+                            string meshName = Path.GetFileNameWithoutExtension(resourcePaths[i]);
+
+                            Mesh mesh = ProjectLibrary.Load<Mesh>(resourcePaths[i]);
+                            if (mesh == null)
+                                continue;
+
+                            SceneObject so = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
+                            so.Parent = parent;
+
+                            Renderable renderable = so.AddComponent<Renderable>();
+                            renderable.Mesh = mesh;
+
+                            addedObjects.Add(so);
+                        }
+                    }
+                    else if (fileEntry.ResType == ResourceType.Prefab)
+                    {
+                        if (!string.IsNullOrEmpty(resourcePaths[i]))
+                        {
+                            Prefab prefab = ProjectLibrary.Load<Prefab>(resourcePaths[i]);
+                            SceneObject so = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);
+                            so.Parent = parent;
+
+                            addedObjects.Add(so);
+                        }
+                    }
+                }
+            }
+
+            if(addedObjects.Count > 0)
+                EditorApplication.SetSceneDirty();
+
+            Selection.SceneObjects = addedObjects.ToArray();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(GUISceneTreeView instance, string style, GUIOption[] options);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Update(IntPtr thisPtr);
+    }
+}

+ 140 - 140
MBansheeEditor/Library/LibraryUtility.cs

@@ -1,140 +1,140 @@
-using System;
-using System.IO;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Contains various helper methods for dealing with the project library.
-    /// </summary>
-    public static class LibraryUtility
-    {
-        /// <summary>
-        /// Creates a new folder with in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the new foldeer in.</param>
-        public static void CreateFolder(string folder)
-        {
-            string path = Path.Combine(folder, "New Folder");
-            path = GetUniquePath(path);
-
-            ProjectLibrary.CreateFolder(path);
-        }
-
-        /// <summary>
-        /// Creates a new material with the default shader in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the material in.</param>
-        public static void CreateEmptyMaterial(string folder)
-        {
-            string path = Path.Combine(folder, "New Material.asset");
-            path = GetUniquePath(path);
-
-            Material material = new Material(Builtin.DiffuseShader);
-            ProjectLibrary.Create(material, path);
-        }
-
-        /// <summary>
-        /// Creates a new empty sprite texture in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the sprite texture in.</param>
-        public static void CreateEmptySpriteTexture(string folder)
-        {
-            string path = Path.Combine(folder, "New Sprite Texture.asset");
-            path = GetUniquePath(path);
-
-            SpriteTexture spriteTexture = new SpriteTexture(null);
-            ProjectLibrary.Create(spriteTexture, path);
-        }
-
-        /// <summary>
-        /// Creates a new empty string table in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the string table in.</param>
-        public static void CreateEmptyStringTable(string folder)
-        {
-            string path = Path.Combine(folder, "New String Table.asset");
-            path = GetUniquePath(path);
-
-            StringTable stringTable = new StringTable();
-            ProjectLibrary.Create(stringTable, path);
-        }
-
-        /// <summary>
-        /// Creates a new empty GUI skin in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the GUI skin in.</param>
-        public static void CreateEmptyGUISkin(string folder)
-        {
-            string path = Path.Combine(folder, "New GUI Skin.asset");
-            path = GetUniquePath(path);
-
-            GUISkin guiSkin = new GUISkin();
-            ProjectLibrary.Create(guiSkin, path);
-        }
-
-        /// <summary>
-        /// Creates a new shader containing a rough code outline in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the shader in.</param>
-        public static void CreateEmptyShader(string folder)
-        {
-            string path = Path.Combine(folder, "New Shader.bsl");
-            path = Path.Combine(ProjectLibrary.ResourceFolder, path);
-            path = GetUniquePath(path);
-
-            File.WriteAllText(path, EditorBuiltin.EmptyShaderCode);
-            ProjectLibrary.Refresh(path);
-        }
-
-        /// <summary>
-        /// Creates a new C# script containing a rough code outline in the specified folder.
-        /// </summary>
-        /// <param name="folder">Folder relative to project library to create the C# script in.</param>
-        public static void CreateEmptyCSScript(string folder)
-        {
-            string path = Path.Combine(folder, "New Script.cs");
-            path = Path.Combine(ProjectLibrary.ResourceFolder, path);
-            path = GetUniquePath(path);
-
-            File.WriteAllText(path, EditorBuiltin.EmptyCSScriptCode);
-            ProjectLibrary.Refresh(path);
-        }
-
-        /// <summary>
-        /// Checks if a file or folder at the specified path exists in the library, and if it does generates a new unique 
-        /// name for the file or folder.
-        /// </summary>
-        /// <param name="path">Path to the file or folder to generate a unique name.</param>
-        /// <returns>New path with the unique name. This will be unchanged from input path if the input path doesn't
-        ///          already exist.</returns>
-        public static string GetUniquePath(string path)
-        {
-            string extension = Path.GetExtension(path);
-            string pathClean = path;
-            if (!String.IsNullOrEmpty(extension))
-                pathClean = path.Remove(path.Length - extension.Length);
-
-            int idx = 0;
-            int separatorIdx = pathClean.LastIndexOf('_');
-            if (separatorIdx != -1)
-            {
-                string numberString = pathClean.Substring(separatorIdx + 1, pathClean.Length - (separatorIdx + 1));
-                if (int.TryParse(numberString, out idx))
-                {
-                    pathClean = pathClean.Substring(0, separatorIdx);
-                    idx++;
-                }
-            }
-           
-            string destination = path;
-            while (ProjectLibrary.Exists(destination))
-            {
-                destination = pathClean + "_" + idx + extension;
-                idx++;
-            }
-
-            return destination;
-        }
-    }
-}
+using System;
+using System.IO;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains various helper methods for dealing with the project library.
+    /// </summary>
+    public static class LibraryUtility
+    {
+        /// <summary>
+        /// Creates a new folder with in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the new folder in.</param>
+        public static void CreateFolder(string folder)
+        {
+            string path = Path.Combine(folder, "New Folder");
+            path = GetUniquePath(path);
+
+            ProjectLibrary.CreateFolder(path);
+        }
+
+        /// <summary>
+        /// Creates a new material with the default shader in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the material in.</param>
+        public static void CreateEmptyMaterial(string folder)
+        {
+            string path = Path.Combine(folder, "New Material.asset");
+            path = GetUniquePath(path);
+
+            Material material = new Material(Builtin.DiffuseShader);
+            ProjectLibrary.Create(material, path);
+        }
+
+        /// <summary>
+        /// Creates a new empty sprite texture in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the sprite texture in.</param>
+        public static void CreateEmptySpriteTexture(string folder)
+        {
+            string path = Path.Combine(folder, "New Sprite Texture.asset");
+            path = GetUniquePath(path);
+
+            SpriteTexture spriteTexture = new SpriteTexture(null);
+            ProjectLibrary.Create(spriteTexture, path);
+        }
+
+        /// <summary>
+        /// Creates a new empty string table in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the string table in.</param>
+        public static void CreateEmptyStringTable(string folder)
+        {
+            string path = Path.Combine(folder, "New String Table.asset");
+            path = GetUniquePath(path);
+
+            StringTable stringTable = new StringTable();
+            ProjectLibrary.Create(stringTable, path);
+        }
+
+        /// <summary>
+        /// Creates a new empty GUI skin in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the GUI skin in.</param>
+        public static void CreateEmptyGUISkin(string folder)
+        {
+            string path = Path.Combine(folder, "New GUI Skin.asset");
+            path = GetUniquePath(path);
+
+            GUISkin guiSkin = new GUISkin();
+            ProjectLibrary.Create(guiSkin, path);
+        }
+
+        /// <summary>
+        /// Creates a new shader containing a rough code outline in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the shader in.</param>
+        public static void CreateEmptyShader(string folder)
+        {
+            string path = Path.Combine(folder, "New Shader.bsl");
+            path = Path.Combine(ProjectLibrary.ResourceFolder, path);
+            path = GetUniquePath(path);
+
+            File.WriteAllText(path, EditorBuiltin.EmptyShaderCode);
+            ProjectLibrary.Refresh(path);
+        }
+
+        /// <summary>
+        /// Creates a new C# script containing a rough code outline in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the C# script in.</param>
+        public static void CreateEmptyCSScript(string folder)
+        {
+            string path = Path.Combine(folder, "New Script.cs");
+            path = Path.Combine(ProjectLibrary.ResourceFolder, path);
+            path = GetUniquePath(path);
+
+            File.WriteAllText(path, EditorBuiltin.EmptyCSScriptCode);
+            ProjectLibrary.Refresh(path);
+        }
+
+        /// <summary>
+        /// Checks if a file or folder at the specified path exists in the library, and if it does generates a new unique 
+        /// name for the file or folder.
+        /// </summary>
+        /// <param name="path">Path to the file or folder to generate a unique name.</param>
+        /// <returns>New path with the unique name. This will be unchanged from input path if the input path doesn't
+        ///          already exist.</returns>
+        public static string GetUniquePath(string path)
+        {
+            string extension = Path.GetExtension(path);
+            string pathClean = path;
+            if (!String.IsNullOrEmpty(extension))
+                pathClean = path.Remove(path.Length - extension.Length);
+
+            int idx = 0;
+            int separatorIdx = pathClean.LastIndexOf('_');
+            if (separatorIdx != -1)
+            {
+                string numberString = pathClean.Substring(separatorIdx + 1, pathClean.Length - (separatorIdx + 1));
+                if (int.TryParse(numberString, out idx))
+                {
+                    pathClean = pathClean.Substring(0, separatorIdx);
+                    idx++;
+                }
+            }
+           
+            string destination = path;
+            while (ProjectLibrary.Exists(destination))
+            {
+                destination = pathClean + "_" + idx + extension;
+                idx++;
+            }
+
+            return destination;
+        }
+    }
+}

+ 18 - 6
MBansheeEditor/Library/LibraryWindow.cs

@@ -1289,6 +1289,7 @@ namespace BansheeEditor
 
             if (paths != null)
             {
+                List<string> addedResources = new List<string>();
                 foreach (var path in paths)
                 {
                     if (path == null)
@@ -1312,23 +1313,28 @@ namespace BansheeEditor
 
                     bool doCopy = !ProjectLibrary.Exists(absolutePath);
 
+                    string uniqueDestination = LibraryUtility.GetUniquePath(destination);
                     if (Directory.Exists(path))
                     {
                         if (doCopy)
-                            DirectoryEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
+                            DirectoryEx.Copy(absolutePath, uniqueDestination);
                         else
-                            DirectoryEx.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
+                            DirectoryEx.Move(absolutePath, uniqueDestination);
                     }
                     else if (File.Exists(path))
                     {
                         if (doCopy)
-                            FileEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
+                            FileEx.Copy(absolutePath, uniqueDestination);
                         else
-                            ProjectLibrary.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
+                            ProjectLibrary.Move(absolutePath, uniqueDestination);
                     }
 
+                    string relativeDestination = uniqueDestination.Substring(resourceDir.Length, uniqueDestination.Length - resourceDir.Length);
+                    addedResources.Add(relativeDestination);
                     ProjectLibrary.Refresh();
                 }
+
+                SetSelection(addedResources);
             }
         }
 
@@ -1358,6 +1364,7 @@ namespace BansheeEditor
 
             if (objects != null)
             {
+                List<string> addedResources = new List<string>();
                 foreach (var so in objects)
                 {
                     if (so == null)
@@ -1366,10 +1373,13 @@ namespace BansheeEditor
                     Prefab newPrefab = new Prefab(so);
 
                     string destination = LibraryUtility.GetUniquePath(Path.Combine(destinationFolder, so.Name + ".prefab"));
-                    ProjectLibrary.Create(newPrefab, destination);
+                    addedResources.Add(destination);
 
+                    ProjectLibrary.Create(newPrefab, destination);
                     ProjectLibrary.Refresh();
                 }
+
+                SetSelection(addedResources);
             }
         }
 
@@ -1390,8 +1400,10 @@ namespace BansheeEditor
         /// <param name="resourcePaths">A set of paths for newly selected resources.</param>
         private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
         {
-            if(sceneObjects.Length > 0)
+            if (sceneObjects.Length > 0)
                 DeselectAll(true);
+            else
+                SetSelection(new List<string>(resourcePaths), true);
         }
 
         /// <summary>

+ 27 - 14
MBansheeEditor/Scene/SceneWindow.cs

@@ -338,6 +338,10 @@ namespace BansheeEditor
                 if (DragDrop.DropInProgress)
                 {
                     dragActive = false;
+
+                    if (draggedSO != null)
+                        Selection.SceneObject = draggedSO;
+
                     draggedSO = null;
                 }
                 else
@@ -348,7 +352,6 @@ namespace BansheeEditor
 
                         ResourceDragDropData dragData = (ResourceDragDropData)DragDrop.Data;
 
-                        string draggedMeshPath = "";
                         string[] draggedPaths = dragData.Paths;
 
                         for (int i = 0; i < draggedPaths.Length; i++)
@@ -359,23 +362,33 @@ namespace BansheeEditor
                                 FileEntry fileEntry = (FileEntry) entry;
                                 if (fileEntry.ResType == ResourceType.Mesh)
                                 {
-                                    draggedMeshPath = draggedPaths[i];
-                                    break;
-                                }
-                            }
-                        }
+                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
+                                    {
+                                        string meshName = Path.GetFileNameWithoutExtension(draggedPaths[i]);
+                                        draggedSO = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
+                                        Mesh mesh = ProjectLibrary.Load<Mesh>(draggedPaths[i]);
 
-                        if (!string.IsNullOrEmpty(draggedMeshPath))
-                        {
-                            string meshName = Path.GetFileNameWithoutExtension(draggedMeshPath);
+                                        Renderable renderable = draggedSO.AddComponent<Renderable>();
+                                        renderable.Mesh = mesh;
 
-                            draggedSO = new SceneObject(meshName);
-                            Mesh mesh = ProjectLibrary.Load<Mesh>(draggedMeshPath);
+                                        EditorApplication.SetSceneDirty();
+                                    }
 
-                            Renderable renderable = draggedSO.AddComponent<Renderable>();
-                            renderable.Mesh = mesh;
+                                    break;
+                                }
+                                else if (fileEntry.ResType == ResourceType.Prefab)
+                                {
+                                    if (!string.IsNullOrEmpty(draggedPaths[i]))
+                                    {
+                                        Prefab prefab = ProjectLibrary.Load<Prefab>(draggedPaths[i]);
+                                        draggedSO = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);
 
-                            EditorApplication.SetSceneDirty();
+                                        EditorApplication.SetSceneDirty();
+                                    }
+
+                                    break;
+                                }
+                            }
                         }
                     }
 

+ 38 - 36
SBansheeEditor/Include/BsScriptGUISceneTreeView.h

@@ -1,37 +1,39 @@
-#pragma once
-
-#include "BsScriptEditorPrerequisites.h"
-#include "BsScriptGUIElement.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Interop class between C++ & CLR for GUISceneTreeView.
-	 */
-	class BS_SCR_BED_EXPORT ScriptGUISceneTreeView : public TScriptGUIElement<ScriptGUISceneTreeView>
-	{
-	public:
-		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "GUISceneTreeView")
-
-	private:
-		ScriptGUISceneTreeView(MonoObject* instance, GUISceneTreeView* treeView);
-		~ScriptGUISceneTreeView();
-
-		/**
-		 * @brief	Triggered when the native scene tree view modifies the scene.
-		 */
-		void sceneModified();
-
-		HEvent mOnModifiedConn;
-
-		/************************************************************************/
-		/* 								CLR HOOKS						   		*/
-		/************************************************************************/
-		static void internal_createInstance(MonoObject* instance, MonoString* style, MonoArray* guiOptions);
-		static void internal_update(ScriptGUISceneTreeView* thisPtr);
-
-		typedef void(__stdcall *OnModifiedThunkDef) (MonoObject*, MonoException**);
-
-		static OnModifiedThunkDef onModifiedThunk;
-	};
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptGUIElement.h"
+
+namespace BansheeEngine
+{
+	/**	Interop class between C++ & CLR for GUISceneTreeView. */
+	class BS_SCR_BED_EXPORT ScriptGUISceneTreeView : public TScriptGUIElement<ScriptGUISceneTreeView>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "GUISceneTreeView")
+
+	private:
+		ScriptGUISceneTreeView(MonoObject* instance, GUISceneTreeView* treeView);
+		~ScriptGUISceneTreeView();
+
+		/** Triggered when the native scene tree view modifies the scene. */
+		void sceneModified();
+
+		/** Triggered when a resource is dragged and dropped over the native scene tree view. */
+		void resourceDropped(const HSceneObject& parent, const Vector<Path>& resourcePaths);
+
+		HEvent mOnModifiedConn;
+		HEvent mOnResourceDroppedConn;
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_createInstance(MonoObject* instance, MonoString* style, MonoArray* guiOptions);
+		static void internal_update(ScriptGUISceneTreeView* thisPtr);
+
+		typedef void(__stdcall *OnModifiedThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnResourceDroppedThunkDef) (MonoObject*, MonoObject*, MonoArray*, MonoException**);
+
+		static OnModifiedThunkDef onModifiedThunk;
+		static OnResourceDroppedThunkDef onResourceDroppedThunk;
+	};
 }

+ 86 - 61
SBansheeEditor/Source/BsScriptGUISceneTreeView.cpp

@@ -1,62 +1,87 @@
-#include "BsScriptGUISceneTreeView.h"
-#include "BsScriptMeta.h"
-#include "BsMonoClass.h"
-#include "BsMonoMethod.h"
-#include "BsMonoManager.h"
-#include "BsMonoUtil.h"
-#include "BsGUISceneTreeView.h"
-#include "BsGUIOptions.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	ScriptGUISceneTreeView::OnModifiedThunkDef ScriptGUISceneTreeView::onModifiedThunk;
-
-	ScriptGUISceneTreeView::ScriptGUISceneTreeView(MonoObject* instance, GUISceneTreeView* treeView)
-		:TScriptGUIElement(instance, treeView)
-	{
-		mOnModifiedConn = treeView->onModified.connect(std::bind(&ScriptGUISceneTreeView::sceneModified, this));
-	}
-
-	ScriptGUISceneTreeView::~ScriptGUISceneTreeView()
-	{
-		mOnModifiedConn.disconnect();
-	}
-
-	void ScriptGUISceneTreeView::initRuntimeData()
-	{
-		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUISceneTreeView::internal_createInstance);
-		metaData.scriptClass->addInternalCall("Internal_Update", &ScriptGUISceneTreeView::internal_update);
-
-		onModifiedThunk = (OnModifiedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnModified", 0)->getThunk();
-	}
-
-	void ScriptGUISceneTreeView::sceneModified()
-	{
-		MonoUtil::invokeThunk(onModifiedThunk, getManagedInstance());
-	}
-
-	void ScriptGUISceneTreeView::internal_createInstance(MonoObject* instance, MonoString* style, MonoArray* guiOptions)
-	{
-		GUIOptions options;
-
-		UINT32 arrayLen = (UINT32)mono_array_length(guiOptions);
-		for (UINT32 i = 0; i < arrayLen; i++)
-			options.addOption(mono_array_get(guiOptions, GUIOption, i));
-
-		String styleName = toString(MonoUtil::monoToWString(style));
-
-		GUISceneTreeView* treeView = GUISceneTreeView::create(options);
-		ScriptGUISceneTreeView* nativeInstance = new (bs_alloc<ScriptGUISceneTreeView>()) ScriptGUISceneTreeView(instance, treeView);
-	}
-
-	void ScriptGUISceneTreeView::internal_update(ScriptGUISceneTreeView* thisPtr)
-	{
-		if (thisPtr->mIsDestroyed)
-			return;
-
-		GUISceneTreeView* treeView = static_cast<GUISceneTreeView*>(thisPtr->getGUIElement());
-		treeView->_update();
-	}
+#include "BsScriptGUISceneTreeView.h"
+#include "BsScriptMeta.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsGUISceneTreeView.h"
+#include "BsGUIOptions.h"
+#include "BsScriptGameObjectManager.h"
+#include "BsScriptSceneObject.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGUISceneTreeView::OnModifiedThunkDef ScriptGUISceneTreeView::onModifiedThunk;
+	ScriptGUISceneTreeView::OnResourceDroppedThunkDef ScriptGUISceneTreeView::onResourceDroppedThunk;
+
+	ScriptGUISceneTreeView::ScriptGUISceneTreeView(MonoObject* instance, GUISceneTreeView* treeView)
+		:TScriptGUIElement(instance, treeView)
+	{
+		mOnModifiedConn = treeView->onModified.connect(std::bind(&ScriptGUISceneTreeView::sceneModified, this));
+		mOnResourceDroppedConn = treeView->onResourceDropped.connect(
+			std::bind(&ScriptGUISceneTreeView::resourceDropped, this, _1, _2));
+	}
+
+	ScriptGUISceneTreeView::~ScriptGUISceneTreeView()
+	{
+		mOnModifiedConn.disconnect();
+		mOnResourceDroppedConn.disconnect();
+	}
+
+	void ScriptGUISceneTreeView::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUISceneTreeView::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_Update", &ScriptGUISceneTreeView::internal_update);
+
+		onModifiedThunk = (OnModifiedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnModified", 0)->getThunk();
+		onResourceDroppedThunk = (OnResourceDroppedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnResourceDropped", 2)->getThunk();
+	}
+
+	void ScriptGUISceneTreeView::sceneModified()
+	{
+		MonoUtil::invokeThunk(onModifiedThunk, getManagedInstance());
+	}
+
+	void ScriptGUISceneTreeView::resourceDropped(const HSceneObject& parent, const Vector<Path>& resourcePaths)
+	{
+		MonoObject* sceneMonoObject = nullptr;
+
+		if (parent != nullptr)
+		{
+			ScriptSceneObject* scriptSceneObject = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(parent);
+			sceneMonoObject = scriptSceneObject->getManagedInstance();
+		}
+
+		UINT32 numPaths = (UINT32)resourcePaths.size();
+		ScriptArray array = ScriptArray::create<WString>(numPaths);
+		for (UINT32 i = 0; i < numPaths; i++)
+			array.set(i, resourcePaths[i].toWString());
+
+		MonoUtil::invokeThunk(onResourceDroppedThunk, getManagedInstance(), sceneMonoObject, array.getInternal());
+	}
+
+	void ScriptGUISceneTreeView::internal_createInstance(MonoObject* instance, MonoString* style, MonoArray* guiOptions)
+	{
+		GUIOptions options;
+
+		UINT32 arrayLen = (UINT32)mono_array_length(guiOptions);
+		for (UINT32 i = 0; i < arrayLen; i++)
+			options.addOption(mono_array_get(guiOptions, GUIOption, i));
+
+		String styleName = toString(MonoUtil::monoToWString(style));
+
+		GUISceneTreeView* treeView = GUISceneTreeView::create(options);
+		ScriptGUISceneTreeView* nativeInstance = new (bs_alloc<ScriptGUISceneTreeView>()) ScriptGUISceneTreeView(instance, treeView);
+	}
+
+	void ScriptGUISceneTreeView::internal_update(ScriptGUISceneTreeView* thisPtr)
+	{
+		if (thisPtr->mIsDestroyed)
+			return;
+
+		GUISceneTreeView* treeView = static_cast<GUISceneTreeView*>(thisPtr->getGUIElement());
+		treeView->_update();
+	}
 }