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

Added drag and drop functionality for prefabs (save & load)

Marko Pintera 10 лет назад
Родитель
Сommit
ade33f8b54

+ 2 - 1
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -12,7 +12,7 @@ namespace BansheeEngine
 	 */
 	 */
 	enum class ProjectIcon
 	enum class ProjectIcon
 	{
 	{
-		Folder, Mesh, Font, Texture, PlainText, ScriptCode, SpriteTexture, Shader, ShaderInclude, Material
+		Folder, Mesh, Font, Texture, PlainText, ScriptCode, SpriteTexture, Shader, ShaderInclude, Material, Prefab
 	};
 	};
 
 
 	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
 	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
@@ -173,6 +173,7 @@ namespace BansheeEngine
 		static const WString ShaderIncludeIconTex;
 		static const WString ShaderIncludeIconTex;
 		static const WString MaterialIconTex;
 		static const WString MaterialIconTex;
 		static const WString SpriteTextureIconTex;
 		static const WString SpriteTextureIconTex;
+		static const WString PrefabIconTex;
 
 
 		static const WString WindowBackgroundTexture;
 		static const WString WindowBackgroundTexture;
 
 

+ 11 - 11
BansheeEditor/Include/BsGUISceneTreeView.h

@@ -60,17 +60,17 @@ namespace BansheeEngine
 
 
 		void updateTreeElement(SceneTreeElement* element);
 		void updateTreeElement(SceneTreeElement* element);
 
 
-		virtual TreeElement& getRootElement() { return mRootElement; }
-		virtual const TreeElement& getRootElementConst() const { return mRootElement; }
-		virtual void updateTreeElementHierarchy();
-		virtual void renameTreeElement(TreeElement* element, const WString& name);
-		virtual void deleteTreeElement(TreeElement* element);
-		virtual bool acceptDragAndDrop() const;
-		virtual void dragAndDropStart();
-		virtual void dragAndDropEnded(TreeElement* overTreeElement);
-		virtual void dragAndDropFinalize();
-		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const;
-		virtual void selectionChanged();
+		virtual TreeElement& getRootElement() override { return mRootElement; }
+		virtual const TreeElement& getRootElementConst() const override { return mRootElement; }
+		virtual void updateTreeElementHierarchy() override;
+		virtual void renameTreeElement(TreeElement* element, const WString& name) override;
+		virtual void deleteTreeElement(TreeElement* element) override;
+		virtual bool acceptDragAndDrop() const override;
+		virtual void dragAndDropStart() override;
+		virtual void dragAndDropEnded(TreeElement* overTreeElement) override;
+		virtual void dragAndDropFinalize() override;
+		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const override;
+		virtual void selectionChanged() override;
 
 
 		void deleteTreeElementInternal(TreeElement* element);
 		void deleteTreeElementInternal(TreeElement* element);
 	};
 	};

+ 3 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -83,6 +83,7 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::ShaderIncludeIconTex = L"ShaderIncludeIcon.psd";
 	const WString BuiltinEditorResources::ShaderIncludeIconTex = L"ShaderIncludeIcon.psd";
 	const WString BuiltinEditorResources::MaterialIconTex = L"MaterialIcon.psd";
 	const WString BuiltinEditorResources::MaterialIconTex = L"MaterialIcon.psd";
 	const WString BuiltinEditorResources::SpriteTextureIconTex = L"SpriteIcon.psd";
 	const WString BuiltinEditorResources::SpriteTextureIconTex = L"SpriteIcon.psd";
+	const WString BuiltinEditorResources::PrefabIconTex = L"PrefabIcon.psd";
 
 
 	const WString BuiltinEditorResources::WindowBackgroundTexture = L"WindowBgTile.psd";
 	const WString BuiltinEditorResources::WindowBackgroundTexture = L"WindowBgTile.psd";
 
 
@@ -1383,6 +1384,8 @@ namespace BansheeEngine
 			return getGUIIcon(MaterialIconTex);
 			return getGUIIcon(MaterialIconTex);
 		case ProjectIcon::SpriteTexture:
 		case ProjectIcon::SpriteTexture:
 			return getGUIIcon(SpriteTextureIconTex);
 			return getGUIIcon(SpriteTextureIconTex);
+		case ProjectIcon::Prefab:
+			return getGUIIcon(PrefabIconTex);
 		}
 		}
 
 
 		return HSpriteTexture();
 		return HSpriteTexture();

+ 61 - 13
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -6,6 +6,11 @@
 #include "BsDragAndDropManager.h"
 #include "BsDragAndDropManager.h"
 #include "BsCmdReparentSO.h"
 #include "BsCmdReparentSO.h"
 #include "BsSelection.h"
 #include "BsSelection.h"
+#include "BsGUIResourceTreeView.h"
+#include "BsProjectLibrary.h"
+#include "BsProjectResourceMeta.h"
+#include "BsPrefab.h"
+#include "BsResources.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -230,7 +235,9 @@ namespace BansheeEngine
 
 
 	bool GUISceneTreeView::acceptDragAndDrop() const
 	bool GUISceneTreeView::acceptDragAndDrop() const
 	{
 	{
-		return DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject;
+		return DragAndDropManager::instance().isDragInProgress() && 
+			(DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject ||
+			DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::Resources);
 	}
 	}
 
 
 	void GUISceneTreeView::dragAndDropStart()
 	void GUISceneTreeView::dragAndDropStart()
@@ -251,21 +258,59 @@ namespace BansheeEngine
 
 
 	void GUISceneTreeView::dragAndDropEnded(TreeElement* overTreeElement)
 	void GUISceneTreeView::dragAndDropEnded(TreeElement* overTreeElement)
 	{
 	{
-		if(overTreeElement != nullptr)
+		UINT32 dragTypeId = DragAndDropManager::instance().getDragTypeId();
+
+		if (dragTypeId == (UINT32)DragAndDropType::SceneObject)
 		{
 		{
-			DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
+			if (overTreeElement != nullptr)
+			{
+				DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
 
 
-			Vector<HSceneObject> sceneObjects;
-			SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(overTreeElement);
-			HSceneObject newParent = sceneTreeElement->mSceneObject;
+				Vector<HSceneObject> sceneObjects;
+				SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(overTreeElement);
+				HSceneObject newParent = sceneTreeElement->mSceneObject;
+
+				for (UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
+				{
+					if (draggedSceneObjects->objects[i] != newParent)
+						sceneObjects.push_back(draggedSceneObjects->objects[i]);
+				}
 
 
-			for(UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
+				CmdReparentSO::execute(sceneObjects, newParent);
+			}
+		}
+		else if (dragTypeId == (UINT32)DragAndDropType::Resources)
+		{
+			DraggedResources* draggedResources = reinterpret_cast<DraggedResources*>(DragAndDropManager::instance().getDragData());
+
+			HSceneObject newParent;
+			if (overTreeElement != nullptr)
 			{
 			{
-				if(draggedSceneObjects->objects[i] != newParent)
-					sceneObjects.push_back(draggedSceneObjects->objects[i]);
+				SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(overTreeElement);
+				newParent = sceneTreeElement->mSceneObject;
 			}
 			}
 
 
-			CmdReparentSO::execute(sceneObjects, newParent);
+			for (auto& path : draggedResources->resourcePaths)
+			{
+				ProjectLibrary::LibraryEntry* entry = ProjectLibrary::instance().findEntry(path);
+
+				if (entry != nullptr && entry->type == ProjectLibrary::LibraryEntryType::File)
+				{
+					ProjectLibrary::ResourceEntry* resEntry = static_cast<ProjectLibrary::ResourceEntry*>(entry);
+					if (resEntry->meta->getTypeID() == TID_Prefab)
+					{
+						HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(resEntry->meta->getUUID()));
+
+						if (prefab != nullptr)
+						{
+							HSceneObject instance = prefab->instantiate();
+
+							if (newParent != nullptr)
+								instance->setParent(newParent);
+						}
+					}
+				}
+			}
 		}
 		}
 	}
 	}
 
 
@@ -274,13 +319,16 @@ namespace BansheeEngine
 		mDragInProgress = false;
 		mDragInProgress = false;
 		_markContentAsDirty();
 		_markContentAsDirty();
 
 
-		DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
-		bs_delete(draggedSceneObjects);
+		if (DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject)
+		{
+			DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
+			bs_delete(draggedSceneObjects);
+		}
 	}
 	}
 
 
 	bool GUISceneTreeView::_acceptDragAndDrop(const Vector2I position, UINT32 typeId) const
 	bool GUISceneTreeView::_acceptDragAndDrop(const Vector2I position, UINT32 typeId) const
 	{
 	{
-		return typeId == (UINT32)DragAndDropType::SceneObject;
+		return typeId == (UINT32)DragAndDropType::SceneObject || typeId == (UINT32)DragAndDropType::Resources;
 	}
 	}
 
 
 	void GUISceneTreeView::selectionChanged()
 	void GUISceneTreeView::selectionChanged()

+ 4 - 0
MBansheeEditor/EditorBuiltin.cs

@@ -15,6 +15,7 @@ namespace BansheeEditor
         public static SpriteTexture ShaderIncludeIcon { get { return Internal_GetShaderIncludeIcon(); } }
         public static SpriteTexture ShaderIncludeIcon { get { return Internal_GetShaderIncludeIcon(); } }
         public static SpriteTexture MaterialIcon { get { return Internal_GetMaterialIcon(); } }
         public static SpriteTexture MaterialIcon { get { return Internal_GetMaterialIcon(); } }
         public static SpriteTexture SpriteTextureIcon { get { return Internal_GetSpriteTextureIcon(); } }
         public static SpriteTexture SpriteTextureIcon { get { return Internal_GetSpriteTextureIcon(); } }
+        public static SpriteTexture PrefabIcon { get { return Internal_GetPrefabIcon(); } }
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SpriteTexture Internal_GetFolderIcon();
         private static extern SpriteTexture Internal_GetFolderIcon();
@@ -45,5 +46,8 @@ namespace BansheeEditor
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SpriteTexture Internal_GetSpriteTextureIcon();
         private static extern SpriteTexture Internal_GetSpriteTextureIcon();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SpriteTexture Internal_GetPrefabIcon();
     }
     }
 }
 }

+ 19 - 7
MBansheeEditor/ProjectDropTarget.cs

@@ -9,7 +9,8 @@ namespace BansheeEditor
     {
     {
         private const int DragStartDistancePx = 3;
         private const int DragStartDistancePx = 3;
 
 
-        public Action<Vector2I, string[]> OnDrop;
+        public Action<Vector2I, string[]> OnDropResource;
+        public Action<Vector2I, SceneObject[]> OnDropSceneObject;
         public Action<Vector2I> OnStart;
         public Action<Vector2I> OnStart;
         public Action<Vector2I> OnEnter;
         public Action<Vector2I> OnEnter;
         public Action OnLeave;
         public Action OnLeave;
@@ -140,12 +141,23 @@ namespace BansheeEditor
                 }
                 }
             }
             }
 
 
-            if (DragDrop.DropInProgress && DragDrop.Type == DragDropType.Resource)
+            if (DragDrop.DropInProgress)
             {
             {
-                if (OnDrop != null)
+                if (DragDrop.Type == DragDropType.Resource)
                 {
                 {
-                    ResourceDragDropData resourceDragDrop = (ResourceDragDropData)DragDrop.Data;
-                    OnDrop(currentWindowPos, resourceDragDrop.Paths);
+                    if (OnDropResource != null)
+                    {
+                        ResourceDragDropData resourceDragDrop = (ResourceDragDropData) DragDrop.Data;
+                        OnDropResource(currentWindowPos, resourceDragDrop.Paths);
+                    }
+                }
+                else if (DragDrop.Type == DragDropType.SceneObject)
+                {
+                    if (OnDropSceneObject != null)
+                    {
+                        SceneObjectDragDropData sceneDragDrop = (SceneObjectDragDropData) DragDrop.Data;
+                        OnDropSceneObject(currentWindowPos, sceneDragDrop.Objects);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -182,8 +194,8 @@ namespace BansheeEditor
         {
         {
             isOSDragActive = false;
             isOSDragActive = false;
 
 
-            if (OnDrop != null)
-                OnDrop(new Vector2I(x, y), dropTargetOS.FilePaths);
+            if (OnDropResource != null)
+                OnDropResource(new Vector2I(x, y), dropTargetOS.FilePaths);
         }
         }
     }
     }
 }
 }

+ 1 - 1
MBansheeEditor/ProjectLibrary.cs

@@ -237,7 +237,7 @@ namespace BansheeEditor
     // Note: Must be the same as C++ enum ScriptResourceType
     // Note: Must be the same as C++ enum ScriptResourceType
     public enum ResourceType
     public enum ResourceType
     {
     {
-        Texture, SpriteTexture, Mesh, Font, Shader, Material, PlainText, ScriptCode, Undefined
+        Texture, SpriteTexture, Mesh, Font, Shader, Material, Prefab, PlainText, ScriptCode, Undefined
     }
     }
 
 
     public class LibraryEntry : ScriptObject
     public class LibraryEntry : ScriptObject

+ 722 - 674
MBansheeEditor/ProjectWindow.cs

@@ -12,312 +12,6 @@ namespace BansheeEditor
 
 
     internal sealed class ProjectWindow : EditorWindow
     internal sealed class ProjectWindow : EditorWindow
     {
     {
-        private class ContentInfo
-        {
-            public ContentInfo(ProjectWindow window, ProjectViewType viewType, int numEntries)
-            {
-                GUIPanel parentPanel = window.scrollAreaPanel;
-
-                GUIPanel contentPanel = parentPanel.AddPanel(1);
-                overlay = parentPanel.AddPanel(0);
-                underlay = parentPanel.AddPanel(2);
-                inputOverlay = parentPanel.AddPanel(-1);
-
-                main = contentPanel.AddLayoutY();
-
-                if (viewType == ProjectViewType.List16)
-                {
-                    tileSize = 16;
-                    gridLayout = false;
-                    elementsPerRow = 1;
-                }
-                else
-                {
-                    switch (viewType)
-                    {
-                        case ProjectViewType.Grid64:
-                            tileSize = 64;
-                            break;
-                        case ProjectViewType.Grid48:
-                            tileSize = 48;
-                            break;
-                        case ProjectViewType.Grid32:
-                            tileSize = 32;
-                            break;
-                    }
-
-                    gridLayout = true;
-
-                    Rect2I scrollBounds = window.contentScrollArea.Bounds;
-                    int availableWidth = scrollBounds.width;
-
-                    int elemSize = tileSize + GRID_ENTRY_SPACING;
-                    elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
-                    int numRows = MathEx.CeilToInt(numEntries / (float)elementsPerRow);
-                    int neededHeight = numRows * (elemSize);
-
-                    bool requiresScrollbar = neededHeight > scrollBounds.height;
-                    if (requiresScrollbar)
-                    {
-                        availableWidth -= window.contentScrollArea.ScrollBarWidth;
-                        elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
-                    }
-
-                    labelWidth = (availableWidth - (elementsPerRow + 1)*MIN_HORZ_SPACING) / elementsPerRow;
-                }
-
-                this.window = window;
-            }
-
-            public GUILayout main;
-            public GUIPanel overlay;
-            public GUIPanel underlay;
-            public GUIPanel inputOverlay;
-
-            public ProjectWindow window;
-            public int tileSize;
-            public bool gridLayout;
-
-            public int elementsPerRow;
-            public int labelWidth;
-        }
-
-        private class ElementEntry
-        {
-            // Note: Order of these is relevant
-            enum UnderlayState
-            {
-                None, Hovered, Selected, Pinged
-            }
-
-            public int index;
-            public string path;
-            public GUITexture icon;
-            public GUILabel label;
-            public Rect2I bounds;
-
-            private GUITexture underlay;
-            private ContentInfo info;
-            private UnderlayState underlayState;
-            private GUITextBox renameTextBox;
-
-            public ElementEntry(ContentInfo info, GUILayout parent, LibraryEntry entry, int index)
-            {
-                GUILayout entryLayout;
-
-                if (info.gridLayout)
-                    entryLayout = parent.AddLayoutY();
-                else
-                    entryLayout = parent.AddLayoutX();
-
-                SpriteTexture iconTexture = GetIcon(entry);
-
-                icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit,
-                    true, GUIOption.FixedHeight(info.tileSize), GUIOption.FixedWidth(info.tileSize));
-
-                label = null;
-
-                if (info.gridLayout)
-                {
-                    label = new GUILabel(entry.Name, EditorStyles.MultiLineLabelCentered,
-                        GUIOption.FixedWidth(info.labelWidth), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
-                }
-                else
-                {
-                    label = new GUILabel(entry.Name);
-                }
-
-                entryLayout.AddElement(icon);
-                entryLayout.AddElement(label);
-
-                this.info = info;
-                this.index = index;
-                this.path = entry.Path;
-                this.bounds = new Rect2I();
-                this.underlay = null;
-            }
-
-            public void Initialize()
-            {
-                bounds = icon.Bounds;
-                Rect2I labelBounds = label.Bounds;
-
-                bounds.x = MathEx.Min(bounds.x, labelBounds.x - SELECTION_EXTRA_WIDTH);
-                bounds.y = MathEx.Min(bounds.y, labelBounds.y) - 5; // 5 - Just padding for better look
-                bounds.width = MathEx.Max(bounds.x + bounds.width,
-                    labelBounds.x + labelBounds.width) - bounds.x + SELECTION_EXTRA_WIDTH;
-                bounds.height = MathEx.Max(bounds.y + bounds.height,
-                    labelBounds.y + labelBounds.height) - bounds.y;
-
-                ProjectWindow hoistedWindow = info.window;
-                string hoistedPath = path;
-
-                GUIButton overlayBtn = new GUIButton("", EditorStyles.Blank);
-                overlayBtn.Bounds = bounds;
-                overlayBtn.OnClick += () => hoistedWindow.OnEntryClicked(hoistedPath);
-                overlayBtn.OnDoubleClick += () => hoistedWindow.OnEntryDoubleClicked(hoistedPath);
-                overlayBtn.SetContextMenu(info.window.entryContextMenu);
-
-                info.overlay.AddElement(overlayBtn);
-            }
-
-            public Rect2I Bounds
-            {
-                get { return bounds; }
-            }
-
-            public void MarkAsCut(bool enable)
-            {
-                if (enable)
-                    icon.SetTint(CUT_COLOR);
-                else
-                    icon.SetTint(Color.White);
-            }
-
-            public void MarkAsSelected(bool enable)
-            {
-                if ((int)underlayState > (int) UnderlayState.Selected)
-                    return;
-
-                if (enable)
-                {
-                    CreateUnderlay();
-                    underlay.SetTint(SELECTION_COLOR);
-                }
-                else
-                    ClearUnderlay();
-
-                underlayState = UnderlayState.Selected;
-            }
-
-            public void MarkAsPinged(bool enable)
-            {
-                if ((int)underlayState > (int)UnderlayState.Pinged)
-                    return;
-
-                if (enable)
-                {
-                    CreateUnderlay();
-                    underlay.SetTint(PING_COLOR);
-                }
-                else
-                    ClearUnderlay();
-
-                underlayState = UnderlayState.Pinged;
-            }
-
-            public void MarkAsHovered(bool enable)
-            {
-                if ((int)underlayState > (int)UnderlayState.Hovered)
-                    return;
-
-                if (enable)
-                {
-                    CreateUnderlay();
-                    underlay.SetTint(HOVER_COLOR);
-                }
-                else
-                    ClearUnderlay();
-
-                underlayState = UnderlayState.Hovered;
-            }
-
-            public void StartRename()
-            {
-                if (renameTextBox != null)
-                    return;
-
-                renameTextBox = new GUITextBox(false);
-                renameTextBox.Bounds = label.Bounds;
-                info.inputOverlay.AddElement(renameTextBox);
-
-                string name = Path.GetFileNameWithoutExtension(PathEx.GetTail(path));
-                renameTextBox.Text = name;
-                renameTextBox.Focus = true;
-
-                label.Visible = false;
-            }
-
-            public void StopRename()
-            {
-                if (renameTextBox != null)
-                {
-                    renameTextBox.Destroy();
-                    renameTextBox = null;
-                }
-
-                label.Visible = true;
-            }
-
-            public string GetRenamedName()
-            {
-                if (renameTextBox != null)
-                    return renameTextBox.Text;
-
-                return "";
-            }
-
-            private void ClearUnderlay()
-            {
-                if (underlay != null)
-                {
-                    underlay.Destroy();
-                    underlay = null;
-                }
-
-                underlayState = UnderlayState.None;
-            }
-
-            private void CreateUnderlay()
-            {
-                if (underlay == null)
-                {
-                    underlay = new GUITexture(Builtin.WhiteTexture);
-                    underlay.Bounds = Bounds;
-
-                    info.underlay.AddElement(underlay);
-                }
-            }
-
-            private static SpriteTexture GetIcon(LibraryEntry entry)
-            {
-                if (entry.Type == LibraryEntryType.Directory)
-                {
-                    return EditorBuiltin.FolderIcon;
-                }
-                else
-                {
-                    FileEntry fileEntry = (FileEntry)entry;
-                    switch (fileEntry.ResType)
-                    {
-                        case ResourceType.Font:
-                            return EditorBuiltin.FontIcon;
-                        case ResourceType.Mesh:
-                            return EditorBuiltin.MeshIcon;
-                        case ResourceType.Texture:
-                            return EditorBuiltin.TextureIcon;
-                        case ResourceType.PlainText:
-                            return EditorBuiltin.PlainTextIcon;
-                        case ResourceType.ScriptCode:
-                            return EditorBuiltin.ScriptCodeIcon;
-                        case ResourceType.SpriteTexture:
-                            return EditorBuiltin.SpriteTextureIcon;
-                        case ResourceType.Shader:
-                            return EditorBuiltin.ShaderIcon;
-                        case ResourceType.Material:
-                            return EditorBuiltin.MaterialIcon;
-                    }
-                }
-
-                return null;
-            }
-        }
-
-        enum MoveDirection
-        {
-            Up, Down, Left, Right
-        }
-
         private const int GRID_ENTRY_SPACING = 15;
         private const int GRID_ENTRY_SPACING = 15;
         private const int LIST_ENTRY_SPACING = 7;
         private const int LIST_ENTRY_SPACING = 7;
         private const int MAX_LABEL_HEIGHT = 50;
         private const int MAX_LABEL_HEIGHT = 50;
@@ -438,7 +132,8 @@ namespace BansheeEditor
             dropTarget.OnStart += DoOnDragStart;
             dropTarget.OnStart += DoOnDragStart;
             dropTarget.OnDrag += DoOnDragMove;
             dropTarget.OnDrag += DoOnDragMove;
             dropTarget.OnLeave += DoOnDragLeave;
             dropTarget.OnLeave += DoOnDragLeave;
-            dropTarget.OnDrop += DoOnDragDropped;
+            dropTarget.OnDropResource += DoOnResourceDragDropped;
+            dropTarget.OnDropSceneObject += DoOnSceneObjectDragDropped;
             dropTarget.OnEnd += DoOnDragEnd;
             dropTarget.OnEnd += DoOnDragEnd;
         }
         }
 
 
@@ -523,7 +218,7 @@ namespace BansheeEditor
             autoScrollAmount = 0;
             autoScrollAmount = 0;
         }
         }
 
 
-        private void DoOnDragDropped(Vector2I windowPos, string[] paths)
+        private void DoOnResourceDragDropped(Vector2I windowPos, string[] paths)
         {
         {
             ClearHoverHighlight();
             ClearHoverHighlight();
             autoScrollAmount = 0;
             autoScrollAmount = 0;
@@ -559,25 +254,61 @@ namespace BansheeEditor
                     if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
                     if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
                         continue;
                         continue;
 
 
-                    string pathTail = PathEx.GetTail(absolutePath);
-                    string destination = Path.Combine(destinationFolder, pathTail);
+                    string pathTail = PathEx.GetTail(absolutePath);
+                    string destination = Path.Combine(destinationFolder, pathTail);
+
+                    bool doCopy = !ProjectLibrary.Exists(path);
+
+                    if (Directory.Exists(path))
+                    {
+                        if (doCopy)
+                            DirectoryEx.Copy(path, GetUniquePath(destination));
+                        else
+                            DirectoryEx.Move(path, GetUniquePath(destination));
+                    }
+                    else if (File.Exists(path))
+                    {
+                        if (doCopy)
+                            FileEx.Copy(path, GetUniquePath(destination));
+                        else
+                            FileEx.Move(path, GetUniquePath(destination));
+                    }
+
+                    ProjectLibrary.Refresh();
+                }
+            }
+        }
+
+        private void DoOnSceneObjectDragDropped(Vector2I windowPos, SceneObject[] objects)
+        {
+            ClearHoverHighlight();
+            autoScrollAmount = 0;
+
+            if (EndDragSelection())
+                return;
+
+            string resourceDir = ProjectLibrary.ResourceFolder;
+            string destinationFolder = Path.Combine(resourceDir, currentDirectory);
+
+            ElementEntry underCursorElement = FindElementAt(windowPos);
+            if (underCursorElement != null)
+            {
+                LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
+                if (entry != null && entry.Type == LibraryEntryType.Directory)
+                    destinationFolder = Path.Combine(resourceDir, entry.Path);
+            }
+
+            if (objects != null)
+            {
+                foreach (var so in objects)
+                {
+                    if (so == null)
+                        continue;
 
 
-                    bool doCopy = !ProjectLibrary.Exists(path);
+                    Prefab newPrefab = new Prefab(so);
 
 
-                    if (Directory.Exists(path))
-                    {
-                        if (doCopy)
-                            DirectoryEx.Copy(path, GetUniquePath(destination));
-                        else
-                            DirectoryEx.Move(path, GetUniquePath(destination));
-                    }
-                    else if (File.Exists(path))
-                    {
-                        if (doCopy)
-                            FileEx.Copy(path, GetUniquePath(destination));
-                        else
-                            FileEx.Move(path, GetUniquePath(destination));
-                    }
+                    string destination = GetUniquePath(Path.Combine(destinationFolder, so.Name + ".prefab"));
+                    ProjectLibrary.Create(newPrefab, destination);
 
 
                     ProjectLibrary.Refresh();
                     ProjectLibrary.Refresh();
                 }
                 }
@@ -1125,473 +856,790 @@ namespace BansheeEditor
 
 
                 contentInfo.main.AddFlexibleSpace();
                 contentInfo.main.AddFlexibleSpace();
             }
             }
-            else
+            else
+            {
+                int tileSize = 64;
+                switch (viewType)
+                {
+                    case ProjectViewType.Grid64: tileSize = 64; break;
+                    case ProjectViewType.Grid48: tileSize = 48; break;
+                    case ProjectViewType.Grid32: tileSize = 32; break;
+                }
+
+                contentInfo.main.AddSpace(GRID_ENTRY_SPACING / 2);
+                GUILayoutX rowLayout = contentInfo.main.AddLayoutX();
+                contentInfo.main.AddSpace(GRID_ENTRY_SPACING);
+                rowLayout.AddFlexibleSpace();
+
+                int elemsInRow = 0;
+
+                for (int i = 0; i < entriesToDisplay.Length; i++)
+                {
+                    if (elemsInRow == contentInfo.elementsPerRow && elemsInRow > 0)
+                    {
+                        rowLayout = contentInfo.main.AddLayoutX();
+                        contentInfo.main.AddSpace(GRID_ENTRY_SPACING);
+
+                        rowLayout.AddFlexibleSpace();
+                        elemsInRow = 0;
+                    }
+
+                    ElementEntry guiEntry = new ElementEntry(contentInfo, rowLayout, entriesToDisplay[i], i);
+                    entries.Add(guiEntry);
+                    entryLookup[guiEntry.path] = guiEntry;
+
+                    rowLayout.AddFlexibleSpace();
+
+                    elemsInRow++;
+                }
+
+                int extraElements = contentInfo.elementsPerRow - elemsInRow;
+                for (int i = 0; i < extraElements; i++)
+                {
+                    rowLayout.AddSpace(contentInfo.labelWidth);
+                    rowLayout.AddFlexibleSpace();
+                }
+
+                contentInfo.main.AddFlexibleSpace();
+            }
+
+            for (int i = 0; i < entries.Count; i++)
+            {
+                ElementEntry guiEntry = entries[i];
+                guiEntry.Initialize();
+
+                if (cutPaths.Contains(guiEntry.path))
+                    guiEntry.MarkAsCut(true);
+
+                if (selectionPaths.Contains(guiEntry.path))
+                    guiEntry.MarkAsSelected(true);
+                else if (pingPath == guiEntry.path)
+                    guiEntry.MarkAsPinged(true);
+            }
+
+            Rect2I contentBounds = contentInfo.main.Bounds;
+            Rect2I minimalBounds = GetScrollAreaBounds();
+            contentBounds.height = Math.Max(contentBounds.height, minimalBounds.height);
+
+            GUIButton catchAll = new GUIButton("", EditorStyles.Blank);
+            catchAll.Bounds = contentBounds;
+            catchAll.OnClick += OnCatchAllClicked;
+            catchAll.SetContextMenu(entryContextMenu);
+
+            contentInfo.underlay.AddElement(catchAll);
+
+            Rect2I focusBounds = contentBounds; // Contents + Folder bar
+            Rect2I scrollBounds = contentScrollArea.Bounds;
+            focusBounds.x += scrollBounds.x;
+            focusBounds.y += scrollBounds.y;
+
+            Rect2I folderBarBounds = folderListLayout.Bounds;
+            focusBounds.y -= folderBarBounds.height;
+            focusBounds.height += folderBarBounds.height;
+
+            GUIButton focusCatcher = new GUIButton("", EditorStyles.Blank);
+            focusCatcher.OnFocusChanged += OnContentsFocusChanged;
+            focusCatcher.Bounds = focusBounds;
+
+            GUIPanel focusPanel = GUI.AddPanel(3);
+            focusPanel.AddElement(focusCatcher);
+
+            UpdateDragSelection(dragSelectionEnd);
+        }
+
+        private Vector2I WindowToScrollAreaCoords(Vector2I windowPos)
+        {
+            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
+            Vector2I scrollPos = windowPos;
+            scrollPos.x -= scrollBounds.x;
+            scrollPos.y -= scrollBounds.y;
+
+            return scrollPos;
+        }
+
+        private void StartDragSelection(Vector2I windowPos)
+        {
+            isDraggingSelection = true;
+            dragSelectionStart = WindowToScrollAreaCoords(windowPos);
+            dragSelectionEnd = dragSelectionStart;
+        }
+
+        private bool UpdateDragSelection(Vector2I windowPos)
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection == null)
+            {
+                dragSelection = new GUITexture(null, true, EditorStyles.SelectionArea);
+                contentInfo.overlay.AddElement(dragSelection);
+            }
+
+            dragSelectionEnd = WindowToScrollAreaCoords(windowPos);
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+            dragSelection.Bounds = selectionArea;
+
+            return true;
+        }
+
+        private bool EndDragSelection()
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection != null)
+            {
+                dragSelection.Destroy();
+                dragSelection = null;
+            }
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+
+            isDraggingSelection = false;
+            return false;
+        }
+
+        private Rect2I CalculateSelectionArea()
+        {
+            Rect2I selectionArea = new Rect2I();
+            if (dragSelectionStart.x < dragSelectionEnd.x)
+            {
+                selectionArea.x = dragSelectionStart.x;
+                selectionArea.width = dragSelectionEnd.x - dragSelectionStart.x;
+            }
+            else
+            {
+                selectionArea.x = dragSelectionEnd.x;
+                selectionArea.width = dragSelectionStart.x - dragSelectionEnd.x;
+            }
+
+            if (dragSelectionStart.y < dragSelectionEnd.y)
+            {
+                selectionArea.y = dragSelectionStart.y;
+                selectionArea.height = dragSelectionEnd.y - dragSelectionStart.y;
+            }
+            else
+            {
+                selectionArea.y = dragSelectionEnd.y;
+                selectionArea.height = dragSelectionStart.y - dragSelectionEnd.y;
+            }
+
+            Rect2I maxBounds = contentScrollArea.Layout.Bounds;
+            maxBounds.x = 0;
+            maxBounds.y = 0;
+
+            selectionArea.Clip(maxBounds);
+
+            return selectionArea;
+        }
+
+        private void SelectInArea(Rect2I scrollBounds)
+        {
+            ElementEntry[] foundElements = FindElementsOverlapping(scrollBounds);
+
+            if (foundElements.Length > 0)
+            {
+                selectionAnchorStart = foundElements[0].index;
+                selectionAnchorEnd = foundElements[foundElements.Length - 1].index;
+            }
+            else
+            {
+                selectionAnchorStart = -1;
+                selectionAnchorEnd = -1;
+            }
+
+            List<string> elementPaths = new List<string>();
+            foreach (var elem in foundElements)
+                elementPaths.Add(elem.path);
+
+            SetSelection(elementPaths);
+        }
+
+        private void RefreshDirectoryBar()
+        {
+            if (folderListLayout != null)
+            {
+                folderListLayout.Destroy();
+                folderListLayout = null;
+            }
+
+            folderListLayout = folderBarLayout.AddLayoutX();
+
+            string[] folders = null;
+            string[] fullPaths = null;
+
+            if (IsSearchActive)
+            {
+                folders = new[] {searchQuery};
+                fullPaths = new[] { searchQuery };
+            }
+            else
+            {
+                string currentDir = Path.Combine("Resources", currentDirectory);
+
+                folders = currentDir.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar },
+                    StringSplitOptions.RemoveEmptyEntries);
+
+                fullPaths = new string[folders.Length];
+                for (int i = 0; i < folders.Length; i++)
+                {
+                    if (i == 0)
+                        fullPaths[i] = "";
+                    else
+                        fullPaths[i] = Path.Combine(fullPaths[i - 1], folders[i]);
+                }
+            }
+
+            int availableWidth = folderBarLayout.Bounds.width - FOLDER_BUTTON_WIDTH * 2;
+            int numFolders = 0;
+            for (int i = folders.Length - 1; i >= 0; i--)
             {
             {
-                int tileSize = 64;
-                switch (viewType)
+                GUIButton folderButton = new GUIButton(folders[i]);
+
+                if (!IsSearchActive)
                 {
                 {
-                    case ProjectViewType.Grid64: tileSize = 64; break;
-                    case ProjectViewType.Grid48: tileSize = 48; break;
-                    case ProjectViewType.Grid32: tileSize = 32; break;
+                    string fullPath = fullPaths[i];
+                    folderButton.OnClick += () => OnFolderButtonClicked(fullPath);
                 }
                 }
 
 
-                contentInfo.main.AddSpace(GRID_ENTRY_SPACING / 2);
-                GUILayoutX rowLayout = contentInfo.main.AddLayoutX();
-                contentInfo.main.AddSpace(GRID_ENTRY_SPACING);
-                rowLayout.AddFlexibleSpace();
+                GUILabel separator = new GUILabel("/", GUIOption.FixedWidth(FOLDER_SEPARATOR_WIDTH));
 
 
-                int elemsInRow = 0;
+                folderListLayout.InsertElement(0, separator);
+                folderListLayout.InsertElement(0, folderButton);
+                numFolders++;
 
 
-                for (int i = 0; i < entriesToDisplay.Length; i++)
+                Rect2I folderListBounds = folderListLayout.Bounds;
+                if (folderListBounds.width > availableWidth)
                 {
                 {
-                    if (elemsInRow == contentInfo.elementsPerRow && elemsInRow > 0)
+                    if (numFolders > 2)
                     {
                     {
-                        rowLayout = contentInfo.main.AddLayoutX();
-                        contentInfo.main.AddSpace(GRID_ENTRY_SPACING);
-
-                        rowLayout.AddFlexibleSpace();
-                        elemsInRow = 0;
+                        separator.Destroy();
+                        folderButton.Destroy();
+                        break;
                     }
                     }
+                }
+            }
+        }
 
 
-                    ElementEntry guiEntry = new ElementEntry(contentInfo, rowLayout, entriesToDisplay[i], i);
-                    entries.Add(guiEntry);
-                    entryLookup[guiEntry.path] = guiEntry;
+        private void SortEntries(LibraryEntry[] input)
+        {
+            Array.Sort(input, (x, y) =>
+            {
+                if (x.Type == y.Type)
+                    return x.Name.CompareTo(y.Name);
+                else
+                    return x.Type == LibraryEntryType.File ? 1 : -1;
+            });
+        }
 
 
-                    rowLayout.AddFlexibleSpace();
+        private void OnFolderButtonClicked(string path)
+        {
+            EnterDirectory(path);
+        }
 
 
-                    elemsInRow++;
-                }
+        private void OnContentsFocusChanged(bool focus)
+        {
+            hasContentFocus = focus;
+        }
 
 
-                int extraElements = contentInfo.elementsPerRow - elemsInRow;
-                for (int i = 0; i < extraElements; i++)
+        private void OnEntryClicked(string path)
+        {
+            Select(path);
+        }
+
+        private void OnEntryDoubleClicked(string path)
+        {
+            LibraryEntry entry = ProjectLibrary.GetEntry(path);
+            if (entry != null)
+            {
+                if (entry.Type == LibraryEntryType.Directory)
+                    EnterDirectory(path);
+                else
                 {
                 {
-                    rowLayout.AddSpace(contentInfo.labelWidth);
-                    rowLayout.AddFlexibleSpace();
+                    FileEntry resEntry = (FileEntry) entry;
+                    if (resEntry.ResType == ResourceType.Prefab)
+                    {
+                        Scene.Load(resEntry.Path);
+                    }
                 }
                 }
-
-                contentInfo.main.AddFlexibleSpace();
             }
             }
+        }
 
 
-            for (int i = 0; i < entries.Count; i++)
+        private void OnCatchAllClicked()
+        {
+            DeselectAll();
+        }
+
+        private void OnHomeClicked()
+        {
+            currentDirectory = ProjectLibrary.Root.Path;
+            Refresh();
+        }
+
+        private void OnUpClicked()
+        {
+            currentDirectory = currentDirectory.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+
+            if (!string.IsNullOrEmpty(currentDirectory))
             {
             {
-                ElementEntry guiEntry = entries[i];
-                guiEntry.Initialize();
+                string parent = Path.GetDirectoryName(currentDirectory);
 
 
-                if (cutPaths.Contains(guiEntry.path))
-                    guiEntry.MarkAsCut(true);
+                currentDirectory = parent;
+                Refresh();
+            }
+        }
 
 
-                if (selectionPaths.Contains(guiEntry.path))
-                    guiEntry.MarkAsSelected(true);
-                else if (pingPath == guiEntry.path)
-                    guiEntry.MarkAsPinged(true);
+        private void CutSelection()
+        {
+            if (selectionPaths.Count > 0)
+                Cut(selectionPaths);
+        }
+
+        private void CopySelection()
+        {
+            if (selectionPaths.Count > 0)
+                Copy(selectionPaths);
+        }
+
+        private void DuplicateSelection()
+        {
+            if (selectionPaths.Count > 0)
+                Duplicate(selectionPaths);
+        }
+
+        private void PasteToSelection()
+        {
+            DirectoryEntry selectedDirectory = null;
+            if (selectionPaths.Count == 1)
+            {
+                LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
+                if (entry != null && entry.Type == LibraryEntryType.Directory)
+                    selectedDirectory = (DirectoryEntry) entry;
             }
             }
 
 
-            Rect2I contentBounds = contentInfo.main.Bounds;
-            Rect2I minimalBounds = GetScrollAreaBounds();
-            contentBounds.height = Math.Max(contentBounds.height, minimalBounds.height);
+            if(selectedDirectory != null)
+                Paste(selectedDirectory.Path);
+            else
+                Paste(currentDirectory);
+        }
 
 
-            GUIButton catchAll = new GUIButton("", EditorStyles.Blank);
-            catchAll.Bounds = contentBounds;
-            catchAll.OnClick += OnCatchAllClicked;
-            catchAll.SetContextMenu(entryContextMenu);
+        private void RenameSelection()
+        {
+            if (selectionPaths.Count == 0)
+                return;
 
 
-            contentInfo.underlay.AddElement(catchAll);
+            if (selectionPaths.Count > 1)
+            {
+                DeselectAll();
+                Select(selectionPaths[0]);
+            }
 
 
-            Rect2I focusBounds = contentBounds; // Contents + Folder bar
-            Rect2I scrollBounds = contentScrollArea.Bounds;
-            focusBounds.x += scrollBounds.x;
-            focusBounds.y += scrollBounds.y;
+            ElementEntry entry;
+            if (entryLookup.TryGetValue(selectionPaths[0], out entry))
+            {
+                entry.StartRename();
+                inProgressRenameElement = entry;
+            }
+        }
 
 
-            Rect2I folderBarBounds = folderListLayout.Bounds;
-            focusBounds.y -= folderBarBounds.height;
-            focusBounds.height += folderBarBounds.height;
+        private void StopRename()
+        {
+            if (inProgressRenameElement != null)
+            {
+                inProgressRenameElement.StopRename();
+                inProgressRenameElement = null;
+            }
+        }
 
 
-            GUIButton focusCatcher = new GUIButton("", EditorStyles.Blank);
-            focusCatcher.OnFocusChanged += OnContentsFocusChanged;
-            focusCatcher.Bounds = focusBounds;
+        private void DeleteSelection()
+        {
+            if (selectionPaths.Count == 0)
+                return;
 
 
-            GUIPanel focusPanel = GUI.AddPanel(3);
-            focusPanel.AddElement(focusCatcher);
+            DialogBox.Open("Confirm deletion", "Are you sure you want to delete the selected object(s)?",
+                DialogBox.Type.YesNo,
+                type =>
+                {
+                    if (type == DialogBox.ResultType.Yes)
+                    {
+                        foreach (var path in selectionPaths)
+                        {
+                            ProjectLibrary.Delete(path);
+                        }
 
 
-            UpdateDragSelection(dragSelectionEnd);
+                        DeselectAll();
+                        Refresh();
+                    }
+                });
         }
         }
 
 
-        private Vector2I WindowToScrollAreaCoords(Vector2I windowPos)
+        private void OnSearchChanged(string newValue)
         {
         {
-            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
-            Vector2I scrollPos = windowPos;
-            scrollPos.x -= scrollBounds.x;
-            scrollPos.y -= scrollBounds.y;
+            searchQuery = newValue;
+            Refresh();
+        }
 
 
-            return scrollPos;
+        private void ClearSearch()
+        {
+            searchField.Value = "";
+            searchQuery = "";
+            Refresh();
         }
         }
 
 
-        private void StartDragSelection(Vector2I windowPos)
+        private void OpenOptionsWindow()
         {
         {
-            isDraggingSelection = true;
-            dragSelectionStart = WindowToScrollAreaCoords(windowPos);
-            dragSelectionEnd = dragSelectionStart;
+            Vector2I openPosition;
+            Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
+
+            openPosition.x = buttonBounds.x + buttonBounds.width / 2;
+            openPosition.y = buttonBounds.y + buttonBounds.height / 2;
+
+            ProjectDropDown dropDown = DropDownWindow.Open<ProjectDropDown>(this, openPosition);
+            dropDown.SetParent(this);
         }
         }
 
 
-        private bool UpdateDragSelection(Vector2I windowPos)
+        private void Reset()
         {
         {
-            if (!isDraggingSelection)
-                return false;
+            currentDirectory = ProjectLibrary.Root.Path;
+            selectionAnchorStart = -1;
+            selectionAnchorEnd = -1;
+            selectionPaths.Clear();
+            pingPath = "";
+            hoverHighlightPath = "";
 
 
-            if (dragSelection == null)
-            {
-                dragSelection = new GUITexture(null, true, EditorStyles.SelectionArea);
-                contentInfo.overlay.AddElement(dragSelection);
-            }
+            Refresh();
+        }
 
 
-            dragSelectionEnd = WindowToScrollAreaCoords(windowPos);
+        private Rect2I GetScrollAreaBounds()
+        {
+            Rect2I bounds = GUI.Bounds;
+            Rect2I folderListBounds = folderListLayout.Bounds;
+            Rect2I searchBarBounds = searchBarLayout.Bounds;
 
 
-            Rect2I selectionArea = CalculateSelectionArea();
-            SelectInArea(selectionArea);
-            dragSelection.Bounds = selectionArea;
+            bounds.y += folderListBounds.height + searchBarBounds.height;
+            bounds.height -= folderListBounds.height + searchBarBounds.height;
 
 
-            return true;
+            return bounds;
         }
         }
 
 
-        private bool EndDragSelection()
+        protected override void WindowResized(int width, int height)
         {
         {
-            if (!isDraggingSelection)
-                return false;
-
-            if (dragSelection != null)
-            {
-                dragSelection.Destroy();
-                dragSelection = null;
-            }
+            base.WindowResized(width, height);
 
 
-            Rect2I selectionArea = CalculateSelectionArea();
-            SelectInArea(selectionArea);
+            Refresh();
 
 
-            isDraggingSelection = false;
-            return false;
+            dropTarget.Bounds = contentScrollArea.Bounds;
         }
         }
 
 
-        private Rect2I CalculateSelectionArea()
+        private class ContentInfo
         {
         {
-            Rect2I selectionArea = new Rect2I();
-            if (dragSelectionStart.x < dragSelectionEnd.x)
-            {
-                selectionArea.x = dragSelectionStart.x;
-                selectionArea.width = dragSelectionEnd.x - dragSelectionStart.x;
-            }
-            else
+            public ContentInfo(ProjectWindow window, ProjectViewType viewType, int numEntries)
             {
             {
-                selectionArea.x = dragSelectionEnd.x;
-                selectionArea.width = dragSelectionStart.x - dragSelectionEnd.x;
-            }
+                GUIPanel parentPanel = window.scrollAreaPanel;
 
 
-            if (dragSelectionStart.y < dragSelectionEnd.y)
-            {
-                selectionArea.y = dragSelectionStart.y;
-                selectionArea.height = dragSelectionEnd.y - dragSelectionStart.y;
-            }
-            else
-            {
-                selectionArea.y = dragSelectionEnd.y;
-                selectionArea.height = dragSelectionStart.y - dragSelectionEnd.y;
-            }
+                GUIPanel contentPanel = parentPanel.AddPanel(1);
+                overlay = parentPanel.AddPanel(0);
+                underlay = parentPanel.AddPanel(2);
+                inputOverlay = parentPanel.AddPanel(-1);
 
 
-            Rect2I maxBounds = contentScrollArea.Layout.Bounds;
-            maxBounds.x = 0;
-            maxBounds.y = 0;
+                main = contentPanel.AddLayoutY();
 
 
-            selectionArea.Clip(maxBounds);
+                if (viewType == ProjectViewType.List16)
+                {
+                    tileSize = 16;
+                    gridLayout = false;
+                    elementsPerRow = 1;
+                }
+                else
+                {
+                    switch (viewType)
+                    {
+                        case ProjectViewType.Grid64:
+                            tileSize = 64;
+                            break;
+                        case ProjectViewType.Grid48:
+                            tileSize = 48;
+                            break;
+                        case ProjectViewType.Grid32:
+                            tileSize = 32;
+                            break;
+                    }
 
 
-            return selectionArea;
-        }
+                    gridLayout = true;
 
 
-        private void SelectInArea(Rect2I scrollBounds)
-        {
-            ElementEntry[] foundElements = FindElementsOverlapping(scrollBounds);
+                    Rect2I scrollBounds = window.contentScrollArea.Bounds;
+                    int availableWidth = scrollBounds.width;
 
 
-            if (foundElements.Length > 0)
-            {
-                selectionAnchorStart = foundElements[0].index;
-                selectionAnchorEnd = foundElements[foundElements.Length - 1].index;
-            }
-            else
-            {
-                selectionAnchorStart = -1;
-                selectionAnchorEnd = -1;
-            }
+                    int elemSize = tileSize + GRID_ENTRY_SPACING;
+                    elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
+                    int numRows = MathEx.CeilToInt(numEntries / (float)elementsPerRow);
+                    int neededHeight = numRows * (elemSize);
 
 
-            List<string> elementPaths = new List<string>();
-            foreach (var elem in foundElements)
-                elementPaths.Add(elem.path);
+                    bool requiresScrollbar = neededHeight > scrollBounds.height;
+                    if (requiresScrollbar)
+                    {
+                        availableWidth -= window.contentScrollArea.ScrollBarWidth;
+                        elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
+                    }
 
 
-            SetSelection(elementPaths);
-        }
+                    labelWidth = (availableWidth - (elementsPerRow + 1) * MIN_HORZ_SPACING) / elementsPerRow;
+                }
 
 
-        private void RefreshDirectoryBar()
-        {
-            if (folderListLayout != null)
-            {
-                folderListLayout.Destroy();
-                folderListLayout = null;
+                this.window = window;
             }
             }
 
 
-            folderListLayout = folderBarLayout.AddLayoutX();
+            public GUILayout main;
+            public GUIPanel overlay;
+            public GUIPanel underlay;
+            public GUIPanel inputOverlay;
 
 
-            string[] folders = null;
-            string[] fullPaths = null;
+            public ProjectWindow window;
+            public int tileSize;
+            public bool gridLayout;
 
 
-            if (IsSearchActive)
+            public int elementsPerRow;
+            public int labelWidth;
+        }
+
+        private class ElementEntry
+        {
+            // Note: Order of these is relevant
+            enum UnderlayState
             {
             {
-                folders = new[] {searchQuery};
-                fullPaths = new[] { searchQuery };
+                None, Hovered, Selected, Pinged
             }
             }
-            else
-            {
-                string currentDir = Path.Combine("Resources", currentDirectory);
 
 
-                folders = currentDir.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar },
-                    StringSplitOptions.RemoveEmptyEntries);
+            public int index;
+            public string path;
+            public GUITexture icon;
+            public GUILabel label;
+            public Rect2I bounds;
 
 
-                fullPaths = new string[folders.Length];
-                for (int i = 0; i < folders.Length; i++)
-                {
-                    if (i == 0)
-                        fullPaths[i] = "";
-                    else
-                        fullPaths[i] = Path.Combine(fullPaths[i - 1], folders[i]);
-                }
-            }
+            private GUITexture underlay;
+            private ContentInfo info;
+            private UnderlayState underlayState;
+            private GUITextBox renameTextBox;
 
 
-            int availableWidth = folderBarLayout.Bounds.width - FOLDER_BUTTON_WIDTH * 2;
-            int numFolders = 0;
-            for (int i = folders.Length - 1; i >= 0; i--)
+            public ElementEntry(ContentInfo info, GUILayout parent, LibraryEntry entry, int index)
             {
             {
-                GUIButton folderButton = new GUIButton(folders[i]);
+                GUILayout entryLayout;
 
 
-                if (!IsSearchActive)
-                {
-                    string fullPath = fullPaths[i];
-                    folderButton.OnClick += () => OnFolderButtonClicked(fullPath);
-                }
+                if (info.gridLayout)
+                    entryLayout = parent.AddLayoutY();
+                else
+                    entryLayout = parent.AddLayoutX();
 
 
-                GUILabel separator = new GUILabel("/", GUIOption.FixedWidth(FOLDER_SEPARATOR_WIDTH));
+                SpriteTexture iconTexture = GetIcon(entry);
 
 
-                folderListLayout.InsertElement(0, separator);
-                folderListLayout.InsertElement(0, folderButton);
-                numFolders++;
+                icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit,
+                    true, GUIOption.FixedHeight(info.tileSize), GUIOption.FixedWidth(info.tileSize));
 
 
-                Rect2I folderListBounds = folderListLayout.Bounds;
-                if (folderListBounds.width > availableWidth)
+                label = null;
+
+                if (info.gridLayout)
                 {
                 {
-                    if (numFolders > 2)
-                    {
-                        separator.Destroy();
-                        folderButton.Destroy();
-                        break;
-                    }
+                    label = new GUILabel(entry.Name, EditorStyles.MultiLineLabelCentered,
+                        GUIOption.FixedWidth(info.labelWidth), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
                 }
                 }
-            }
-        }
-
-        private void SortEntries(LibraryEntry[] input)
-        {
-            Array.Sort(input, (x, y) =>
-            {
-                if (x.Type == y.Type)
-                    return x.Name.CompareTo(y.Name);
                 else
                 else
-                    return x.Type == LibraryEntryType.File ? 1 : -1;
-            });
-        }
-
-        private void OnFolderButtonClicked(string path)
-        {
-            EnterDirectory(path);
-        }
+                {
+                    label = new GUILabel(entry.Name);
+                }
 
 
-        private void OnContentsFocusChanged(bool focus)
-        {
-            hasContentFocus = focus;
-        }
+                entryLayout.AddElement(icon);
+                entryLayout.AddElement(label);
 
 
-        private void OnEntryClicked(string path)
-        {
-            Select(path);
-        }
+                this.info = info;
+                this.index = index;
+                this.path = entry.Path;
+                this.bounds = new Rect2I();
+                this.underlay = null;
+            }
 
 
-        private void OnEntryDoubleClicked(string path)
-        {
-            LibraryEntry entry = ProjectLibrary.GetEntry(path);
-            if (entry != null && entry.Type == LibraryEntryType.Directory)
+            public void Initialize()
             {
             {
-                EnterDirectory(path);
-            }
-        }
+                bounds = icon.Bounds;
+                Rect2I labelBounds = label.Bounds;
 
 
-        private void OnCatchAllClicked()
-        {
-            DeselectAll();
-        }
+                bounds.x = MathEx.Min(bounds.x, labelBounds.x - SELECTION_EXTRA_WIDTH);
+                bounds.y = MathEx.Min(bounds.y, labelBounds.y) - 5; // 5 - Just padding for better look
+                bounds.width = MathEx.Max(bounds.x + bounds.width,
+                    labelBounds.x + labelBounds.width) - bounds.x + SELECTION_EXTRA_WIDTH;
+                bounds.height = MathEx.Max(bounds.y + bounds.height,
+                    labelBounds.y + labelBounds.height) - bounds.y;
+
+                ProjectWindow hoistedWindow = info.window;
+                string hoistedPath = path;
 
 
-        private void OnHomeClicked()
-        {
-            currentDirectory = ProjectLibrary.Root.Path;
-            Refresh();
-        }
+                GUIButton overlayBtn = new GUIButton("", EditorStyles.Blank);
+                overlayBtn.Bounds = bounds;
+                overlayBtn.OnClick += () => hoistedWindow.OnEntryClicked(hoistedPath);
+                overlayBtn.OnDoubleClick += () => hoistedWindow.OnEntryDoubleClicked(hoistedPath);
+                overlayBtn.SetContextMenu(info.window.entryContextMenu);
 
 
-        private void OnUpClicked()
-        {
-            currentDirectory = currentDirectory.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+                info.overlay.AddElement(overlayBtn);
+            }
 
 
-            if (!string.IsNullOrEmpty(currentDirectory))
+            public Rect2I Bounds
             {
             {
-                string parent = Path.GetDirectoryName(currentDirectory);
-
-                currentDirectory = parent;
-                Refresh();
+                get { return bounds; }
             }
             }
-        }
 
 
-        private void CutSelection()
-        {
-            if (selectionPaths.Count > 0)
-                Cut(selectionPaths);
-        }
+            public void MarkAsCut(bool enable)
+            {
+                if (enable)
+                    icon.SetTint(CUT_COLOR);
+                else
+                    icon.SetTint(Color.White);
+            }
 
 
-        private void CopySelection()
-        {
-            if (selectionPaths.Count > 0)
-                Copy(selectionPaths);
-        }
+            public void MarkAsSelected(bool enable)
+            {
+                if ((int)underlayState > (int)UnderlayState.Selected)
+                    return;
 
 
-        private void DuplicateSelection()
-        {
-            if (selectionPaths.Count > 0)
-                Duplicate(selectionPaths);
-        }
+                if (enable)
+                {
+                    CreateUnderlay();
+                    underlay.SetTint(SELECTION_COLOR);
+                }
+                else
+                    ClearUnderlay();
 
 
-        private void PasteToSelection()
-        {
-            DirectoryEntry selectedDirectory = null;
-            if (selectionPaths.Count == 1)
-            {
-                LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
-                if (entry != null && entry.Type == LibraryEntryType.Directory)
-                    selectedDirectory = (DirectoryEntry) entry;
+                underlayState = UnderlayState.Selected;
             }
             }
 
 
-            if(selectedDirectory != null)
-                Paste(selectedDirectory.Path);
-            else
-                Paste(currentDirectory);
-        }
+            public void MarkAsPinged(bool enable)
+            {
+                if ((int)underlayState > (int)UnderlayState.Pinged)
+                    return;
 
 
-        private void RenameSelection()
-        {
-            if (selectionPaths.Count == 0)
-                return;
+                if (enable)
+                {
+                    CreateUnderlay();
+                    underlay.SetTint(PING_COLOR);
+                }
+                else
+                    ClearUnderlay();
 
 
-            if (selectionPaths.Count > 1)
-            {
-                DeselectAll();
-                Select(selectionPaths[0]);
+                underlayState = UnderlayState.Pinged;
             }
             }
 
 
-            ElementEntry entry;
-            if (entryLookup.TryGetValue(selectionPaths[0], out entry))
+            public void MarkAsHovered(bool enable)
             {
             {
-                entry.StartRename();
-                inProgressRenameElement = entry;
+                if ((int)underlayState > (int)UnderlayState.Hovered)
+                    return;
+
+                if (enable)
+                {
+                    CreateUnderlay();
+                    underlay.SetTint(HOVER_COLOR);
+                }
+                else
+                    ClearUnderlay();
+
+                underlayState = UnderlayState.Hovered;
             }
             }
-        }
 
 
-        private void StopRename()
-        {
-            if (inProgressRenameElement != null)
+            public void StartRename()
             {
             {
-                inProgressRenameElement.StopRename();
-                inProgressRenameElement = null;
-            }
-        }
+                if (renameTextBox != null)
+                    return;
 
 
-        private void DeleteSelection()
-        {
-            if (selectionPaths.Count == 0)
-                return;
+                renameTextBox = new GUITextBox(false);
+                renameTextBox.Bounds = label.Bounds;
+                info.inputOverlay.AddElement(renameTextBox);
 
 
-            DialogBox.Open("Confirm deletion", "Are you sure you want to delete the selected object(s)?",
-                DialogBox.Type.YesNo,
-                type =>
-                {
-                    if (type == DialogBox.ResultType.Yes)
-                    {
-                        foreach (var path in selectionPaths)
-                        {
-                            ProjectLibrary.Delete(path);
-                        }
+                string name = Path.GetFileNameWithoutExtension(PathEx.GetTail(path));
+                renameTextBox.Text = name;
+                renameTextBox.Focus = true;
 
 
-                        DeselectAll();
-                        Refresh();
-                    }
-                });
-        }
+                label.Visible = false;
+            }
 
 
-        private void OnSearchChanged(string newValue)
-        {
-            searchQuery = newValue;
-            Refresh();
-        }
+            public void StopRename()
+            {
+                if (renameTextBox != null)
+                {
+                    renameTextBox.Destroy();
+                    renameTextBox = null;
+                }
 
 
-        private void ClearSearch()
-        {
-            searchField.Value = "";
-            searchQuery = "";
-            Refresh();
-        }
+                label.Visible = true;
+            }
 
 
-        private void OpenOptionsWindow()
-        {
-            Vector2I openPosition;
-            Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
+            public string GetRenamedName()
+            {
+                if (renameTextBox != null)
+                    return renameTextBox.Text;
 
 
-            openPosition.x = buttonBounds.x + buttonBounds.width / 2;
-            openPosition.y = buttonBounds.y + buttonBounds.height / 2;
+                return "";
+            }
 
 
-            ProjectDropDown dropDown = DropDownWindow.Open<ProjectDropDown>(this, openPosition);
-            dropDown.SetParent(this);
-        }
+            private void ClearUnderlay()
+            {
+                if (underlay != null)
+                {
+                    underlay.Destroy();
+                    underlay = null;
+                }
 
 
-        private void Reset()
-        {
-            currentDirectory = ProjectLibrary.Root.Path;
-            selectionAnchorStart = -1;
-            selectionAnchorEnd = -1;
-            selectionPaths.Clear();
-            pingPath = "";
-            hoverHighlightPath = "";
+                underlayState = UnderlayState.None;
+            }
 
 
-            Refresh();
-        }
+            private void CreateUnderlay()
+            {
+                if (underlay == null)
+                {
+                    underlay = new GUITexture(Builtin.WhiteTexture);
+                    underlay.Bounds = Bounds;
 
 
-        private Rect2I GetScrollAreaBounds()
-        {
-            Rect2I bounds = GUI.Bounds;
-            Rect2I folderListBounds = folderListLayout.Bounds;
-            Rect2I searchBarBounds = searchBarLayout.Bounds;
+                    info.underlay.AddElement(underlay);
+                }
+            }
 
 
-            bounds.y += folderListBounds.height + searchBarBounds.height;
-            bounds.height -= folderListBounds.height + searchBarBounds.height;
+            private static SpriteTexture GetIcon(LibraryEntry entry)
+            {
+                if (entry.Type == LibraryEntryType.Directory)
+                {
+                    return EditorBuiltin.FolderIcon;
+                }
+                else
+                {
+                    FileEntry fileEntry = (FileEntry)entry;
+                    switch (fileEntry.ResType)
+                    {
+                        case ResourceType.Font:
+                            return EditorBuiltin.FontIcon;
+                        case ResourceType.Mesh:
+                            return EditorBuiltin.MeshIcon;
+                        case ResourceType.Texture:
+                            return EditorBuiltin.TextureIcon;
+                        case ResourceType.PlainText:
+                            return EditorBuiltin.PlainTextIcon;
+                        case ResourceType.ScriptCode:
+                            return EditorBuiltin.ScriptCodeIcon;
+                        case ResourceType.SpriteTexture:
+                            return EditorBuiltin.SpriteTextureIcon;
+                        case ResourceType.Shader:
+                            return EditorBuiltin.ShaderIcon;
+                        case ResourceType.Material:
+                            return EditorBuiltin.MaterialIcon;
+                        case ResourceType.Prefab:
+                            return EditorBuiltin.PrefabIcon;
+                    }
+                }
 
 
-            return bounds;
+                return null;
+            }
         }
         }
 
 
-        protected override void WindowResized(int width, int height)
+        enum MoveDirection
         {
         {
-            base.WindowResized(width, height);
-
-            Refresh();
-
-            dropTarget.Bounds = contentScrollArea.Bounds;
+            Up, Down, Left, Right
         }
         }
     }
     }
 
 

+ 13 - 1
MBansheeEngine/SceneObject.cs

@@ -5,10 +5,16 @@ namespace BansheeEngine
 {
 {
     public sealed class SceneObject : GameObject
     public sealed class SceneObject : GameObject
     {
     {
+        public string Name
+        {
+            get { return Internal_GetName(mCachedPtr); }
+            set { Internal_SetName(mCachedPtr, value); }
+        }
+
         public SceneObject Parent
         public SceneObject Parent
         {
         {
-            set { Internal_SetParent(mCachedPtr, value); }
             get { return Internal_GetParent(mCachedPtr); }
             get { return Internal_GetParent(mCachedPtr); }
+            set { Internal_SetParent(mCachedPtr, value); }
         }
         }
 
 
         public Vector3 Position
         public Vector3 Position
@@ -249,6 +255,12 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CreateInstance(SceneObject instance, string name, int flags);
         private static extern void Internal_CreateInstance(SceneObject instance, string name, int flags);
 
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetName(IntPtr nativeInstance, string name);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetName(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetParent(IntPtr nativeInstance, SceneObject parent);
         private static extern void Internal_SetParent(IntPtr nativeInstance, SceneObject parent);
 
 

+ 1 - 0
SBansheeEditor/Include/BsScriptEditorBuiltin.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 		static MonoObject* internal_getShaderIncludeIcon();
 		static MonoObject* internal_getShaderIncludeIcon();
 		static MonoObject* internal_getMaterialIcon();
 		static MonoObject* internal_getMaterialIcon();
 		static MonoObject* internal_getSpriteTextureIcon();
 		static MonoObject* internal_getSpriteTextureIcon();
+		static MonoObject* internal_getPrefabIcon();
 
 
 		ScriptEditorBuiltin(MonoObject* instance);
 		ScriptEditorBuiltin(MonoObject* instance);
 	};
 	};

+ 8 - 0
SBansheeEditor/Source/BsScriptEditorBuiltin.cpp

@@ -25,6 +25,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetShaderIncludeIcon", &ScriptEditorBuiltin::internal_getShaderIncludeIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetShaderIncludeIcon", &ScriptEditorBuiltin::internal_getShaderIncludeIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetMaterialIcon", &ScriptEditorBuiltin::internal_getMaterialIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetMaterialIcon", &ScriptEditorBuiltin::internal_getMaterialIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetSpriteTextureIcon", &ScriptEditorBuiltin::internal_getSpriteTextureIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetSpriteTextureIcon", &ScriptEditorBuiltin::internal_getSpriteTextureIcon);
+		metaData.scriptClass->addInternalCall("Internal_GetPrefabIcon", &ScriptEditorBuiltin::internal_getPrefabIcon);
 	}
 	}
 
 
 	MonoObject* ScriptEditorBuiltin::internal_getFolderIcon()
 	MonoObject* ScriptEditorBuiltin::internal_getFolderIcon()
@@ -96,4 +97,11 @@ namespace BansheeEngine
 
 
 		return ScriptSpriteTexture::toManaged(tex);
 		return ScriptSpriteTexture::toManaged(tex);
 	}
 	}
+
+	MonoObject* ScriptEditorBuiltin::internal_getPrefabIcon()
+	{
+		HSpriteTexture tex = BuiltinEditorResources::instance().getLibraryIcon(ProjectIcon::Prefab);
+
+		return ScriptSpriteTexture::toManaged(tex);
+	}
 }
 }

+ 1 - 1
SBansheeEngine/Include/BsScriptResource.h

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 {
 	enum class ScriptResourceType
 	enum class ScriptResourceType
 	{
 	{
-		Texture, SpriteTexture, Mesh, Font, Shader, Material, PlainText, ScriptCode, Undefined
+		Texture, SpriteTexture, Mesh, Font, Shader, Material, Prefab, PlainText, ScriptCode, Undefined
 	};
 	};
 
 
 	class BS_SCR_BE_EXPORT ScriptResourceBase : public PersistentScriptObjectBase
 	class BS_SCR_BE_EXPORT ScriptResourceBase : public PersistentScriptObjectBase

+ 3 - 0
SBansheeEngine/Include/BsScriptSceneObject.h

@@ -24,6 +24,9 @@ namespace BansheeEngine
 
 
 		static void internal_createInstance(MonoObject* instance, MonoString* name, UINT32 flags);
 		static void internal_createInstance(MonoObject* instance, MonoString* name, UINT32 flags);
 
 
+		static void internal_setName(ScriptSceneObject* nativeInstance, MonoString* name);
+		static MonoString* internal_getName(ScriptSceneObject* nativeInstance);
+
 		static void internal_setParent(ScriptSceneObject* nativeInstance, MonoObject* parent);
 		static void internal_setParent(ScriptSceneObject* nativeInstance, MonoObject* parent);
 		static MonoObject* internal_getParent(ScriptSceneObject* nativeInstance);
 		static MonoObject* internal_getParent(ScriptSceneObject* nativeInstance);
 
 

+ 4 - 0
SBansheeEngine/Source/BsScriptResource.cpp

@@ -36,6 +36,8 @@ namespace BansheeEngine
 			return ScriptResourceType::Material;
 			return ScriptResourceType::Material;
 		case TID_Font:
 		case TID_Font:
 			return ScriptResourceType::Font;
 			return ScriptResourceType::Font;
+		case TID_Prefab:
+			return ScriptResourceType::Prefab;
 		case TID_PlainText:
 		case TID_PlainText:
 			return ScriptResourceType::PlainText;
 			return ScriptResourceType::PlainText;
 		case TID_ScriptCode:
 		case TID_ScriptCode:
@@ -61,6 +63,8 @@ namespace BansheeEngine
 			return TID_Font;
 			return TID_Font;
 		case ScriptResourceType::Material:
 		case ScriptResourceType::Material:
 			return TID_Material;
 			return TID_Material;
+		case ScriptResourceType::Prefab:
+			return TID_Prefab;
 		case ScriptResourceType::PlainText:
 		case ScriptResourceType::PlainText:
 			return TID_PlainText;
 			return TID_PlainText;
 		case ScriptResourceType::ScriptCode:
 		case ScriptResourceType::ScriptCode:

+ 19 - 0
SBansheeEngine/Source/BsScriptSceneObject.cpp

@@ -23,6 +23,8 @@ namespace BansheeEngine
 	void ScriptSceneObject::initRuntimeData()
 	void ScriptSceneObject::initRuntimeData()
 	{
 	{
 		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptSceneObject::internal_createInstance);
 		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptSceneObject::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetName", &ScriptSceneObject::internal_getName);
+		metaData.scriptClass->addInternalCall("Internal_SetName", &ScriptSceneObject::internal_setName);
 		metaData.scriptClass->addInternalCall("Internal_GetParent", &ScriptSceneObject::internal_getParent);
 		metaData.scriptClass->addInternalCall("Internal_GetParent", &ScriptSceneObject::internal_getParent);
 		metaData.scriptClass->addInternalCall("Internal_SetParent", &ScriptSceneObject::internal_setParent);
 		metaData.scriptClass->addInternalCall("Internal_SetParent", &ScriptSceneObject::internal_setParent);
 		metaData.scriptClass->addInternalCall("Internal_GetNumChildren", &ScriptSceneObject::internal_getNumChildren);
 		metaData.scriptClass->addInternalCall("Internal_GetNumChildren", &ScriptSceneObject::internal_getNumChildren);
@@ -65,6 +67,23 @@ namespace BansheeEngine
 		ScriptGameObjectManager::instance().createScriptSceneObject(instance, sceneObject);
 		ScriptGameObjectManager::instance().createScriptSceneObject(instance, sceneObject);
 	}
 	}
 
 
+	void ScriptSceneObject::internal_setName(ScriptSceneObject* nativeInstance, MonoString* name)
+	{
+		if (checkIfDestroyed(nativeInstance))
+			return;
+
+		nativeInstance->mSceneObject->setName(MonoUtil::monoToString(name));
+	}
+
+	MonoString* ScriptSceneObject::internal_getName(ScriptSceneObject* nativeInstance)
+	{
+		if (checkIfDestroyed(nativeInstance))
+			return nullptr;
+
+		String name = nativeInstance->mSceneObject->getName();
+		return MonoUtil::stringToMono(MonoManager::instance().getDomain(), name);
+	}
+
 	void ScriptSceneObject::internal_setParent(ScriptSceneObject* nativeInstance, MonoObject* parent)
 	void ScriptSceneObject::internal_setParent(ScriptSceneObject* nativeInstance, MonoObject* parent)
 	{
 	{
 		if (checkIfDestroyed(nativeInstance))
 		if (checkIfDestroyed(nativeInstance))

+ 4 - 8
TODO.txt

@@ -42,14 +42,6 @@ TODO - How do I mark the scene as modified? I need to know if user made any modi
 		 - Should I store dirty state in Script* objects?
 		 - Should I store dirty state in Script* objects?
 		  - Probably the best
 		  - Probably the best
 
 
-Level save
- - Drag and drop to project window
-   - Automatically creates a new prefab with the same name as the root object
-    - Or creates a unique name if an asset with the same name exists
-
-Level load
- - Drag and drop from project window or double-click in project window
-
 TODO - Add Prefab buttons to Inspector (Apply, Break, Revert)
 TODO - Add Prefab buttons to Inspector (Apply, Break, Revert)
 
 
 TODO - Later - When building level for release make sure to clear all prefab diffs (possibly store them elsewhere in the first place)
 TODO - Later - When building level for release make sure to clear all prefab diffs (possibly store them elsewhere in the first place)
@@ -57,6 +49,7 @@ TODO - Later - When building level for release make sure to clear all prefab dif
 
 
  Test (likely later once I have more editor functionality working):
  Test (likely later once I have more editor functionality working):
   - If level save/load works
   - If level save/load works
+  - If drag and drop works, both ways, plus double-click to load level
   - Game object handle compare
   - Game object handle compare
   - ID restore systems 
   - ID restore systems 
   - Native+Managed diff (only the link between the two)
   - Native+Managed diff (only the link between the two)
@@ -71,6 +64,7 @@ Polish stage 1
 
 
 When elements are docked in the main window the menu bar drop down appears behind them
 When elements are docked in the main window the menu bar drop down appears behind them
 Click on empty part of the menu bar doesn't close the menu bar (ignoring NC area clicks?)
 Click on empty part of the menu bar doesn't close the menu bar (ignoring NC area clicks?)
+Clicking on a parent of a menu item just reopens that item but I would expect it to close it
 Attempting to dock a window that is not in focus will start drag instead (NC area incorrectly set up?)
 Attempting to dock a window that is not in focus will start drag instead (NC area incorrectly set up?)
 Docking problem: When I dock three windows next to each other, e.g. Hierarchy|Scene|Inspector and then try to dock another
 Docking problem: When I dock three windows next to each other, e.g. Hierarchy|Scene|Inspector and then try to dock another
  so it splits space with Hierarchy vertically the dock area appears over both hierarchy and scene, and the when docked it looks wrong
  so it splits space with Hierarchy vertically the dock area appears over both hierarchy and scene, and the when docked it looks wrong
@@ -80,6 +74,8 @@ Missing Inspector values (name + transform fields)
 Fix handles
 Fix handles
 Moving the title bar tab and then dropping it closes the window (possibly only happens when there is just one tab)
 Moving the title bar tab and then dropping it closes the window (possibly only happens when there is just one tab)
 
 
+Need a way to add scene objects and components (and remove them)
+
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Project window
 Project window