Browse Source

Mostly finished with the project library import progress bar
Bugfixes:
- Fixed a crash that happened when window was opened and closed the same frame
- Fixed an infinite loop when a GUI element of zero width or height was placed in a layout with extra room to expand
- Fixed an issue in project library where it would try to import .meta files as resources
- Fixed an issue where editor window GUIPanel was getting deleted twice if editor window was created from script
- Fixed an issue where closing the managed modal window didn't properly destroy it
- Fixed an issue where managed modal window didn't have an instance of contents GUI panel saved

Marko Pintera 10 years ago
parent
commit
86f54d6527

+ 3 - 0
BansheeCore/Source/BsRenderWindowManager.cpp

@@ -45,6 +45,9 @@ namespace BansheeEngine
 			if(iterFind != mMovedOrResizedWindows.end())
 			if(iterFind != mMovedOrResizedWindows.end())
 				mMovedOrResizedWindows.erase(iterFind);
 				mMovedOrResizedWindows.erase(iterFind);
 
 
+			if (mNewWindowInFocus == window)
+				mNewWindowInFocus = nullptr;
+
 			mWindows.erase(window->mWindowId);
 			mWindows.erase(window->mWindowId);
 			mDirtyProperties.erase(window);
 			mDirtyProperties.erase(window);
 		}
 		}

+ 38 - 20
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -107,29 +107,44 @@ namespace BansheeEngine
 		LibraryEntry* entry = findEntry(pathToSearch);
 		LibraryEntry* entry = findEntry(pathToSearch);
 		if(entry == nullptr) // File could be new, try to find parent directory entry
 		if(entry == nullptr) // File could be new, try to find parent directory entry
 		{
 		{
-			Path parentDirPath = pathToSearch.getParent();
-			entry = findEntry(parentDirPath);
-
-			// Cannot find parent directory. Create the needed hierarchy.
-			DirectoryEntry* entryParent = nullptr;
-			DirectoryEntry* newHierarchyParent = nullptr;
-			if(entry == nullptr) 
-				createInternalParentHierarchy(pathToSearch, &newHierarchyParent, &entryParent);
-			else
-				entryParent = static_cast<DirectoryEntry*>(entry);
-
-			if(FileSystem::isFile(pathToSearch))
+			if (isMeta(pathToSearch))
 			{
 			{
-				if (import)
-					addResourceInternal(entryParent, pathToSearch);
-				
-				dirtyResources.push_back(pathToSearch);
+				Path sourceFilePath = pathToSearch;
+				sourceFilePath.setExtension(L"");
+
+				if (!FileSystem::isFile(sourceFilePath))
+				{
+					LOGWRN("Found a .meta file without a corresponding resource. Deleting.");
+
+					FileSystem::remove(pathToSearch);
+				}
 			}
 			}
-			else if(FileSystem::isDirectory(pathToSearch))
+			else
 			{
 			{
-				addDirectoryInternal(entryParent, pathToSearch);
+				Path parentDirPath = pathToSearch.getParent();
+				entry = findEntry(parentDirPath);
 
 
-				checkForModifications(pathToSearch);
+				// Cannot find parent directory. Create the needed hierarchy.
+				DirectoryEntry* entryParent = nullptr;
+				DirectoryEntry* newHierarchyParent = nullptr;
+				if (entry == nullptr)
+					createInternalParentHierarchy(pathToSearch, &newHierarchyParent, &entryParent);
+				else
+					entryParent = static_cast<DirectoryEntry*>(entry);
+
+				if (FileSystem::isFile(pathToSearch))
+				{
+					if (import)
+						addResourceInternal(entryParent, pathToSearch);
+
+					dirtyResources.push_back(pathToSearch);
+				}
+				else if (FileSystem::isDirectory(pathToSearch))
+				{
+					addDirectoryInternal(entryParent, pathToSearch);
+
+					checkForModifications(pathToSearch);
+				}
 			}
 			}
 		}
 		}
 		else if(entry->type == LibraryEntryType::File)
 		else if(entry->type == LibraryEntryType::File)
@@ -226,7 +241,10 @@ namespace BansheeEngine
 							}
 							}
 							else
 							else
 							{
 							{
-								addResourceInternal(currentDir, filePath);
+								if (import)
+									addResourceInternal(currentDir, filePath);
+
+								dirtyResources.push_back(filePath);
 							}
 							}
 						}
 						}
 					}
 					}

+ 7 - 2
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -137,8 +137,13 @@ namespace BansheeEngine
 					processedElements[childIdx] = true;
 					processedElements[childIdx] = true;
 				else
 				else
 				{
 				{
-					numNonClampedElements++;
-					totalNonClampedSize += elementAreas[childIdx].width;
+					if (elementAreas[childIdx].width > 0)
+					{
+						numNonClampedElements++;
+						totalNonClampedSize += elementAreas[childIdx].width;
+					}
+					else
+						processedElements[childIdx] = true;
 				}
 				}
 			}
 			}
 
 

+ 7 - 2
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -137,8 +137,13 @@ namespace BansheeEngine
 					processedElements[childIdx] = true;
 					processedElements[childIdx] = true;
 				else
 				else
 				{
 				{
-					numNonClampedElements++;
-					totalNonClampedSize += elementAreas[childIdx].height;
+					if (elementAreas[childIdx].height > 0)
+					{
+						numNonClampedElements++;
+						totalNonClampedSize += elementAreas[childIdx].height;
+					}
+					else
+						processedElements[childIdx] = true;
 				}
 				}
 			}
 			}
 
 

+ 15 - 0
MBansheeEditor/EditorApplication.cs

@@ -77,6 +77,8 @@ namespace BansheeEditor
         private SceneWindow scene;
         private SceneWindow scene;
         private DebugWindow debug;
         private DebugWindow debug;
 
 
+        private FolderMonitor monitor;
+
         // DEBUG ONLY
         // DEBUG ONLY
         Debug_Component1 dbgComponent;
         Debug_Component1 dbgComponent;
         // END DEBUG ONLY
         // END DEBUG ONLY
@@ -106,6 +108,12 @@ namespace BansheeEditor
             scene = EditorWindow.OpenWindow<SceneWindow>();
             scene = EditorWindow.OpenWindow<SceneWindow>();
             debug = EditorWindow.OpenWindow<DebugWindow>();
             debug = EditorWindow.OpenWindow<DebugWindow>();
 
 
+            ProjectLibrary.Refresh();
+            monitor = new FolderMonitor(ProjectLibrary.ResourceFolder);
+            monitor.OnAdded += OnAssetModified;
+            monitor.OnRemoved += OnAssetModified;
+            monitor.OnModified += OnAssetModified;
+
             // DEBUG ONLY
             // DEBUG ONLY
 
 
             SceneObject newDbgObject = new SceneObject("NewDbgObject");
             SceneObject newDbgObject = new SceneObject("NewDbgObject");
@@ -123,8 +131,15 @@ namespace BansheeEditor
             // DEBUG ONLY END
             // DEBUG ONLY END
         }
         }
 
 
+        private void OnAssetModified(string path)
+        {
+            ProjectLibrary.Refresh(path);
+        }
+
         internal void EditorUpdate()
         internal void EditorUpdate()
         {
         {
+            ProjectLibrary.Update();
+
             // DEBUG ONLY
             // DEBUG ONLY
 
 
             if (dbgComponent != null)
             if (dbgComponent != null)

+ 61 - 3
MBansheeEditor/ProjectLibrary.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using BansheeEngine;
 using BansheeEngine;
@@ -13,9 +14,30 @@ namespace BansheeEditor
         public static event Action<string> OnEntryAdded;
         public static event Action<string> OnEntryAdded;
         public static event Action<string> OnEntryRemoved;
         public static event Action<string> OnEntryRemoved;
 
 
-        public static string[] Refresh(bool import = false)
+        private static HashSet<string> queuedForImport = new HashSet<string>();
+        private static int numImportedFiles;
+        private static int totalFilesToImport;
+
+        private const float TIME_SLICE_SECONDS = 0.030f;
+
+        public static void Refresh()
+        {
+            string[] modifiedPaths = Internal_Refresh(ResourceFolder, false);
+            foreach (var modifiedPath in modifiedPaths)
+            {
+                if (queuedForImport.Add(modifiedPath))
+                    totalFilesToImport++;
+            }
+        }
+
+        public static void Refresh(string path)
         {
         {
-            return Internal_Refresh(import);
+            string[] modifiedPaths = Internal_Refresh(path, false);
+            foreach (var modifiedPath in modifiedPaths)
+            {
+                if (queuedForImport.Add(modifiedPath))
+                    totalFilesToImport++;
+            }
         }
         }
 
 
         public static void Create(Resource resource, string path)
         public static void Create(Resource resource, string path)
@@ -89,6 +111,42 @@ namespace BansheeEditor
             Internal_Copy(source, destination, overwrite);
             Internal_Copy(source, destination, overwrite);
         }
         }
 
 
+        internal static void Update()
+        {
+            if (queuedForImport.Count > 0)
+            {
+                UInt64 start = Time.Precise;
+                List<string> toRemove = new List<string>();
+                foreach (var entry in queuedForImport)
+                {
+                    float pct = numImportedFiles/(float)totalFilesToImport;
+                    ProgressBar.Show("Importing (" + numImportedFiles + "/" + totalFilesToImport + ")", entry, pct);
+
+                    Internal_Refresh(entry, true);
+                    toRemove.Add(entry);
+                    numImportedFiles++;
+
+                    UInt64 end = Time.Precise;
+                    UInt64 elapsed = end - start;
+
+                    float elapsedSeconds = elapsed * Time.MicroToSecond;
+                    if (elapsedSeconds > TIME_SLICE_SECONDS)
+                        break;
+                }
+
+                foreach (var entry in toRemove)
+                    queuedForImport.Remove(entry);
+
+                if (queuedForImport.Count == 0)
+                {
+                    numImportedFiles = 0;
+                    totalFilesToImport = 0;
+
+                    ProgressBar.Hide();
+                }
+            }
+        }
+
         private static void Internal_DoOnEntryAdded(string path)
         private static void Internal_DoOnEntryAdded(string path)
         {
         {
             if (OnEntryAdded != null)
             if (OnEntryAdded != null)
@@ -102,7 +160,7 @@ namespace BansheeEditor
         }
         }
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern string[] Internal_Refresh(bool import);
+        private static extern string[] Internal_Refresh(string path, bool import);
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Create(Resource resource, string path);
         private static extern void Internal_Create(Resource resource, string path);

+ 56 - 23
MBansheeEditor/ProjectWindow.cs

@@ -62,8 +62,7 @@ namespace BansheeEditor
                         elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
                         elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
                     }
                     }
 
 
-                    labelWidth = availableWidth / elementsPerRow;
-                    labelWidth -= (elementsPerRow + 1)*MIN_HORZ_SPACING;
+                    labelWidth = (availableWidth - (elementsPerRow + 1)*MIN_HORZ_SPACING) / elementsPerRow;
                 }
                 }
 
 
                 this.window = window;
                 this.window = window;
@@ -515,12 +514,27 @@ namespace BansheeEditor
                     if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
                     if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
                         continue;
                         continue;
 
 
-                    string destination = Path.Combine(destinationFolder, Path.GetFileName(absolutePath));
+                    string pathTail = PathEx.GetTail(absolutePath);
+                    string destination = Path.Combine(destinationFolder, pathTail);
 
 
-                    if (ProjectLibrary.Exists(path))
-                        ProjectLibrary.Move(path, destination, true);
-                    else
-                        ProjectLibrary.Copy(path, destination, true);
+                    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();
                 }
                 }
             }
             }
         }
         }
@@ -783,15 +797,12 @@ namespace BansheeEditor
         {
         {
             foreach (var source in sourcePaths)
             foreach (var source in sourcePaths)
             {
             {
-                int idx = 0;
-                string destination;
-                do
-                {
-                    destination = source + "_" + idx;
-                    idx++;
-                } while (!ProjectLibrary.Exists(destination));
+                if (Directory.Exists(source))
+                    DirectoryEx.Copy(source, GetUniquePath(source));
+                else if (File.Exists(source))
+                    FileEx.Copy(source, GetUniquePath(source));
 
 
-                ProjectLibrary.Copy(source, destination);
+                ProjectLibrary.Refresh();
             }
             }
         }
         }
 
 
@@ -801,29 +812,51 @@ namespace BansheeEditor
             {
             {
                 for (int i = 0; i < copyPaths.Count; i++)
                 for (int i = 0; i < copyPaths.Count; i++)
                 {
                 {
-                    string cleanPath = copyPaths[i].TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
-                    string destination = Path.Combine(destinationFolder, Path.GetFileName(cleanPath));
+                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(copyPaths[i]));
 
 
-                    ProjectLibrary.Copy(copyPaths[i], destination, true);
+                    if (Directory.Exists(copyPaths[i]))
+                        DirectoryEx.Copy(copyPaths[i], GetUniquePath(destination));
+                    else if (File.Exists(copyPaths[i]))
+                        FileEx.Copy(copyPaths[i], GetUniquePath(destination));
                 }
                 }
 
 
-                Refresh();
+                ProjectLibrary.Refresh();
             }
             }
             else if (cutPaths.Count > 0)
             else if (cutPaths.Count > 0)
             {
             {
                 for (int i = 0; i < cutPaths.Count; i++)
                 for (int i = 0; i < cutPaths.Count; i++)
                 {
                 {
-                    string cleanPath = cutPaths[i].TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
-                    string destination = Path.Combine(destinationFolder, Path.GetFileName(cleanPath));
+                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(cutPaths[i]));
 
 
-                    ProjectLibrary.Move(cutPaths[i], destination, true);
+                    if (Directory.Exists(cutPaths[i]))
+                        DirectoryEx.Move(cutPaths[i], GetUniquePath(destination));
+                    else if (File.Exists(cutPaths[i]))
+                        FileEx.Move(cutPaths[i], GetUniquePath(destination));
                 }
                 }
 
 
                 cutPaths.Clear();
                 cutPaths.Clear();
-                Refresh();
+                ProjectLibrary.Refresh();
             }
             }
         }
         }
 
 
+        private string GetUniquePath(string path)
+        {
+            string extension = Path.GetExtension(path);
+            string pathNoExtension = path;
+            if (!string.IsNullOrEmpty(extension))
+                pathNoExtension = path.Remove(path.Length - extension.Length);
+
+            int idx = 0;
+            string destination;
+            do
+            {
+                destination = pathNoExtension + "_" + idx;
+                idx++;
+            } while (!ProjectLibrary.Exists(destination));
+
+            return destination + extension;
+        }
+
         private void EditorUpdate()
         private void EditorUpdate()
         {
         {
             if (HasContentFocus)
             if (HasContentFocus)

+ 48 - 0
MBansheeEngine/DirectoryEx.cs

@@ -0,0 +1,48 @@
+using System.IO;
+
+namespace BansheeEngine
+{
+    public static class DirectoryEx
+    {
+        public static void Move(string source, string destination)
+        {
+            string destParent = PathEx.GetParent(destination);
+            if (!string.IsNullOrEmpty(destParent))
+            {
+                if (!Directory.Exists(destParent))
+                    Directory.CreateDirectory(destParent);
+            }
+
+            Directory.Move(source, destination);
+        }
+
+        public static void Copy(string source, string destination)
+        {
+            DirectoryInfo dir = new DirectoryInfo(source);
+            DirectoryInfo[] dirs = dir.GetDirectories();
+
+            if (!dir.Exists)
+            {
+                throw new DirectoryNotFoundException(
+                    "Source directory does not exist or could not be found: "
+                    + source);
+            }
+
+            if (!Directory.Exists(destination))
+                Directory.CreateDirectory(destination);
+
+            FileInfo[] files = dir.GetFiles();
+            foreach (FileInfo file in files)
+            {
+                string temppath = Path.Combine(destination, file.Name);
+                file.CopyTo(temppath, false);
+            }
+
+            foreach (DirectoryInfo subdir in dirs)
+            {
+                string temppath = Path.Combine(destination, subdir.Name);
+                Copy(subdir.FullName, temppath);
+            }
+        }
+    }
+}

+ 31 - 0
MBansheeEngine/FileEx.cs

@@ -0,0 +1,31 @@
+using System.IO;
+
+namespace BansheeEngine
+{
+    public static class FileEx
+    {
+        public static void Move(string source, string destination)
+        {
+            string destParent = PathEx.GetParent(destination);
+            if (!string.IsNullOrEmpty(destParent))
+            {
+                if (!Directory.Exists(destParent))
+                    Directory.CreateDirectory(destParent);
+            }
+
+            File.Move(source, destination);
+        }
+
+        public static void Copy(string source, string destination)
+        {
+            string destParent = PathEx.GetParent(destination);
+            if (!string.IsNullOrEmpty(destParent))
+            {
+                if (!Directory.Exists(destParent))
+                    Directory.CreateDirectory(destParent);
+            }
+
+            File.Copy(source, destination);
+        }
+    }
+}

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -56,7 +56,9 @@
     <Compile Include="DbgComponent2.cs" />
     <Compile Include="DbgComponent2.cs" />
     <Compile Include="DbgSerzCls.cs" />
     <Compile Include="DbgSerzCls.cs" />
     <Compile Include="DbgSerzObj.cs" />
     <Compile Include="DbgSerzObj.cs" />
+    <Compile Include="DirectoryEx.cs" />
     <Compile Include="DontSerializeField.cs" />
     <Compile Include="DontSerializeField.cs" />
+    <Compile Include="FileEx.cs" />
     <Compile Include="Font.cs" />
     <Compile Include="Font.cs" />
     <Compile Include="GameObject.cs" />
     <Compile Include="GameObject.cs" />
     <Compile Include="GUI\GUILayoutUtility.cs" />
     <Compile Include="GUI\GUILayoutUtility.cs" />

+ 21 - 0
MBansheeEngine/PathEx.cs

@@ -13,5 +13,26 @@ namespace BansheeEngine
         {
         {
             return Path.GetFullPath(path).StartsWith(Path.GetFullPath(parent));
             return Path.GetFullPath(path).StartsWith(Path.GetFullPath(parent));
         }
         }
+
+        public static string GetTail(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+                return "";
+
+            if (path[path.Length - 1] == Path.DirectorySeparatorChar ||
+                path[path.Length - 1] == Path.AltDirectorySeparatorChar)
+            {
+                return Path.GetDirectoryName(path);
+            }
+
+            return Path.GetFileName(path);
+        }
+
+        public static string GetParent(string path)
+        {
+            string tail = GetTail(path);
+
+            return path.Remove(path.Length - tail.Length);
+        }
     }
     }
 }
 }

+ 14 - 12
MBansheeEngine/Time.cs

@@ -10,28 +10,27 @@ namespace BansheeEngine
     {
     {
         public static float Elapsed
         public static float Elapsed
         {
         {
-            get
-            {
-                return Internal_GetElapsed();
-            }
+            get { return Internal_GetElapsed(); }
         }
         }
 
 
         public static float FrameDelta
         public static float FrameDelta
         {
         {
-            get
-            {
-                return Internal_GetFrameDelta();
-            }
+            get { return Internal_GetFrameDelta(); }
         }
         }
 
 
         public static int FrameNumber
         public static int FrameNumber
         {
         {
-            get
-            {
-                return Internal_GetFrameNumber();
-            }
+            get { return Internal_GetFrameNumber(); }
         }
         }
 
 
+        public static UInt64 Precise
+        {
+            get { return Internal_GetPrecise(); }
+        }
+
+        public const float MicroToSecond = 1.0f/1000000.0f;
+        public const float SecondToMicro = 1000000.0f;
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern float Internal_GetElapsed();
         private static extern float Internal_GetElapsed();
 
 
@@ -40,5 +39,8 @@ namespace BansheeEngine
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern int Internal_GetFrameNumber();
         private static extern int Internal_GetFrameNumber();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern UInt64 Internal_GetPrecise();
     }
     }
 }
 }

+ 2 - 2
SBansheeEditor/Include/BsScriptModalWindow.h

@@ -42,7 +42,7 @@ namespace BansheeEngine
 		ScriptObjectBackup beginRefresh();
 		ScriptObjectBackup beginRefresh();
 		void endRefresh(const ScriptObjectBackup& backupData);
 		void endRefresh(const ScriptObjectBackup& backupData);
 		MonoObject* _createManagedInstance(bool construct);
 		MonoObject* _createManagedInstance(bool construct);
-		void closeWindow();
+		void notifyWindowDestroyed();
 
 
 		ManagedModalWindow* mModalWindow;
 		ManagedModalWindow* mModalWindow;
 		HEvent mOnAssemblyRefreshStartedConn;
 		HEvent mOnAssemblyRefreshStartedConn;
@@ -60,7 +60,7 @@ namespace BansheeEngine
 		bool createManagedInstance();
 		bool createManagedInstance();
 		void releaseManagedInstance();
 		void releaseManagedInstance();
 
 
-		void initialize(ScriptModalWindow* parent);
+		void setParent(ScriptModalWindow* parent);
 		void update();
 		void update();
 		void reloadMonoTypes(MonoClass* windowClass);
 		void reloadMonoTypes(MonoClass* windowClass);
 		void triggerOnInitialize();
 		void triggerOnInitialize();

+ 1 - 1
SBansheeEditor/Include/BsScriptProjectLibrary.h

@@ -16,7 +16,7 @@ namespace BansheeEngine
 		void static shutDown();
 		void static shutDown();
 
 
 	private:
 	private:
-		static MonoArray* internal_Refresh(bool import);
+		static MonoArray* internal_Refresh(MonoString* path, bool import);
 		static void internal_Create(MonoObject* resource, MonoString* path);
 		static void internal_Create(MonoObject* resource, MonoString* path);
 		static MonoObject* internal_Load(MonoString* path);
 		static MonoObject* internal_Load(MonoString* path);
 		static void internal_Save(MonoObject* resource);
 		static void internal_Save(MonoObject* resource);

+ 4 - 1
SBansheeEditor/Source/BsScriptDropDownWindow.cpp

@@ -145,7 +145,10 @@ namespace BansheeEngine
 
 
 	ManagedDropDownWindow::~ManagedDropDownWindow()
 	ManagedDropDownWindow::~ManagedDropDownWindow()
 	{
 	{
-		mContentsPanel->destroy();
+		mContentsPanel->destroyChildren();
+		mContentsPanel->markAsDestroyed();
+		mContentsPanel = nullptr;
+
 		triggerOnDestroy();
 		triggerOnDestroy();
 		mScriptParent->notifyWindowClosed();
 		mScriptParent->notifyWindowClosed();
 
 

+ 2 - 1
SBansheeEditor/Source/BsScriptEditorWindow.cpp

@@ -299,7 +299,8 @@ namespace BansheeEngine
 		mScriptOwner->mIsDestroyed = true;
 		mScriptOwner->mIsDestroyed = true;
 		mScriptOwner->mEditorWidget = nullptr;
 		mScriptOwner->mEditorWidget = nullptr;
 
 
-		mContentsPanel->destroy();
+		mContentsPanel->destroyChildren();
+		mContentsPanel->markAsDestroyed();
 		mContentsPanel = nullptr;
 		mContentsPanel = nullptr;
 
 
 		triggerOnDestroy();
 		triggerOnDestroy();

+ 17 - 11
SBansheeEditor/Source/BsScriptModalWindow.cpp

@@ -47,13 +47,14 @@ namespace BansheeEngine
 	{
 	{
 		ManagedModalWindow* modalWindow = bs_new<ManagedModalWindow>(allowCloseButton, instance);
 		ManagedModalWindow* modalWindow = bs_new<ManagedModalWindow>(allowCloseButton, instance);
 		ScriptModalWindow* nativeInstance = new (bs_alloc<ScriptModalWindow>()) ScriptModalWindow(modalWindow);
 		ScriptModalWindow* nativeInstance = new (bs_alloc<ScriptModalWindow>()) ScriptModalWindow(modalWindow);
-		modalWindow->initialize(nativeInstance);
+		modalWindow->setParent(nativeInstance);
 		modalWindow->triggerOnInitialize();
 		modalWindow->triggerOnInitialize();
 	}
 	}
 
 
 	void ScriptModalWindow::internal_close(ScriptModalWindow* thisPtr)
 	void ScriptModalWindow::internal_close(ScriptModalWindow* thisPtr)
 	{
 	{
-		thisPtr->closeWindow();
+		if (thisPtr->mModalWindow != nullptr)
+			thisPtr->mModalWindow->close();
 	}
 	}
 
 
 	void ScriptModalWindow::internal_setTitle(ScriptModalWindow* thisPtr, MonoObject* title)
 	void ScriptModalWindow::internal_setTitle(ScriptModalWindow* thisPtr, MonoObject* title)
@@ -68,14 +69,8 @@ namespace BansheeEngine
 		thisPtr->mModalWindow->setTitle(titleStr);
 		thisPtr->mModalWindow->setTitle(titleStr);
 	}
 	}
 
 
-	void ScriptModalWindow::closeWindow()
+	void ScriptModalWindow::notifyWindowDestroyed()
 	{
 	{
-		if (mModalWindow == nullptr)
-			return;
-
-		mModalWindow->mContentsPanel->destroy();
-		mModalWindow->triggerOnDestroy();
-		mModalWindow->releaseManagedInstance();
 		mModalWindow = nullptr;
 		mModalWindow = nullptr;
 	}
 	}
 
 
@@ -193,6 +188,7 @@ namespace BansheeEngine
 		mGCHandle = mono_gchandle_new(mManagedInstance, false);
 		mGCHandle = mono_gchandle_new(mManagedInstance, false);
 
 
 		MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContents);
 		MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContents);
+		mContentsPanel = ScriptGUILayout::toNative(guiPanel);
 		ScriptModalWindow::guiPanelField->setValue(mManagedInstance, guiPanel);
 		ScriptModalWindow::guiPanelField->setValue(mManagedInstance, guiPanel);
 
 
 		::MonoClass* rawMonoClass = mono_object_get_class(mManagedInstance);
 		::MonoClass* rawMonoClass = mono_object_get_class(mManagedInstance);
@@ -268,7 +264,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void ManagedModalWindow::initialize(ScriptModalWindow* parent)
+	void ManagedModalWindow::setParent(ScriptModalWindow* parent)
 	{
 	{
 		mScriptParent = parent;
 		mScriptParent = parent;
 	}
 	}
@@ -303,7 +299,17 @@ namespace BansheeEngine
 
 
 	void ManagedModalWindow::close()
 	void ManagedModalWindow::close()
 	{
 	{
-		mScriptParent->closeWindow();
+		triggerOnDestroy();
+
+		mContentsPanel->destroyChildren();
+		mContentsPanel->markAsDestroyed();
+		mContentsPanel = nullptr;
+
+		releaseManagedInstance();
+
+		mScriptParent->notifyWindowDestroyed();
+
+		ModalWindow::close();
 	}
 	}
 
 
 	void ManagedModalWindow::reloadMonoTypes(MonoClass* windowClass)
 	void ManagedModalWindow::reloadMonoTypes(MonoClass* windowClass)

+ 4 - 2
SBansheeEditor/Source/BsScriptProjectLibrary.cpp

@@ -52,10 +52,12 @@ namespace BansheeEngine
 		OnEntryRemovedThunk = (OnEntryChangedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnEntryRemoved", 1)->getThunk();
 		OnEntryRemovedThunk = (OnEntryChangedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnEntryRemoved", 1)->getThunk();
 	}
 	}
 
 
-	MonoArray* ScriptProjectLibrary::internal_Refresh(bool import)
+	MonoArray* ScriptProjectLibrary::internal_Refresh(MonoString* path, bool import)
 	{
 	{
+		Path nativePath = MonoUtil::monoToWString(path);
+
 		Vector<Path> dirtyResources;
 		Vector<Path> dirtyResources;
-		ProjectLibrary::instance().checkForModifications(ProjectLibrary::instance().getResourcesFolder(), import, dirtyResources);
+		ProjectLibrary::instance().checkForModifications(nativePath, import, dirtyResources);
 
 
 		ScriptArray output = ScriptArray::create<WString>((UINT32)dirtyResources.size());
 		ScriptArray output = ScriptArray::create<WString>((UINT32)dirtyResources.size());
 		for (UINT32 i = 0; i < (UINT32)dirtyResources.size(); i++)
 		for (UINT32 i = 0; i < (UINT32)dirtyResources.size(); i++)

+ 2 - 2
SBansheeEngine/Include/BsScriptGUILayout.h

@@ -24,7 +24,8 @@ namespace BansheeEngine
 		void removeChild(ScriptGUIElementBaseTBase* element);
 		void removeChild(ScriptGUIElementBaseTBase* element);
 
 
 		void destroy() override;
 		void destroy() override;
-
+		void destroyChildren();
+		void markAsDestroyed();
 	private:
 	private:
 		friend class ScriptGUIPanel;
 		friend class ScriptGUIPanel;
 
 
@@ -52,7 +53,6 @@ namespace BansheeEngine
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GUIPanel")
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GUIPanel")
 
 
 		static MonoObject* createFromExisting(GUIPanel* panel);
 		static MonoObject* createFromExisting(GUIPanel* panel);
-
 	private:
 	private:
 		ScriptGUIPanel(MonoObject* instance);
 		ScriptGUIPanel(MonoObject* instance);
 	};
 	};

+ 1 - 0
SBansheeEngine/Include/BsScriptTime.h

@@ -14,6 +14,7 @@ namespace BansheeEngine
 		static float internal_getElapsed();
 		static float internal_getElapsed();
 		static float internal_getFrameDelta();
 		static float internal_getFrameDelta();
 		static UINT32 internal_getFrameNumber();
 		static UINT32 internal_getFrameNumber();
+		static UINT64 internal_getPrecise();
 
 
 		ScriptTime(MonoObject* instance);
 		ScriptTime(MonoObject* instance);
 	};
 	};

+ 16 - 5
SBansheeEngine/Source/BsScriptGUILayout.cpp

@@ -37,11 +37,7 @@ namespace BansheeEngine
 			if (mParent != nullptr)
 			if (mParent != nullptr)
 				mParent->removeChild(this);
 				mParent->removeChild(this);
 
 
-			while (mChildren.size() > 0)
-			{
-				ChildInfo childInfo = mChildren[0];
-				childInfo.element->destroy();
-			}
+			destroyChildren();
 
 
 			GUILayout::destroy(mLayout);
 			GUILayout::destroy(mLayout);
 
 
@@ -50,6 +46,21 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	void ScriptGUILayout::destroyChildren()
+	{
+		while (mChildren.size() > 0)
+		{
+			ChildInfo childInfo = mChildren[0];
+			childInfo.element->destroy();
+		}
+	}
+
+	void ScriptGUILayout::markAsDestroyed()
+	{
+		mLayout = nullptr;
+		mIsDestroyed = true;
+	}
+
 	void ScriptGUILayout::addChild(ScriptGUIElementBaseTBase* element)
 	void ScriptGUILayout::addChild(ScriptGUIElementBaseTBase* element)
 	{
 	{
 		ChildInfo childInfo;
 		ChildInfo childInfo;

+ 6 - 0
SBansheeEngine/Source/BsScriptTime.cpp

@@ -16,6 +16,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetElapsed", &ScriptTime::internal_getElapsed);
 		metaData.scriptClass->addInternalCall("Internal_GetElapsed", &ScriptTime::internal_getElapsed);
 		metaData.scriptClass->addInternalCall("Internal_GetFrameDelta", &ScriptTime::internal_getFrameDelta);
 		metaData.scriptClass->addInternalCall("Internal_GetFrameDelta", &ScriptTime::internal_getFrameDelta);
 		metaData.scriptClass->addInternalCall("Internal_GetFrameNumber", &ScriptTime::internal_getFrameNumber);
 		metaData.scriptClass->addInternalCall("Internal_GetFrameNumber", &ScriptTime::internal_getFrameNumber);
+		metaData.scriptClass->addInternalCall("Internal_GetPrecise", &ScriptTime::internal_getPrecise);
 	}
 	}
 
 
 	float ScriptTime::internal_getElapsed()
 	float ScriptTime::internal_getElapsed()
@@ -32,4 +33,9 @@ namespace BansheeEngine
 	{
 	{
 		return gTime().getFrameNumber();
 		return gTime().getFrameNumber();
 	}
 	}
+
+	UINT64 ScriptTime::internal_getPrecise()
+	{
+		return gTime().getTimePrecise();
+	}
 }
 }

+ 10 - 15
TODO.txt

@@ -17,17 +17,14 @@ TODO - Setting Material array parameters isn't possible from C#
 GUIResourceField doesn't distinguish between tex2d, tex3d and texcube.
 GUIResourceField doesn't distinguish between tex2d, tex3d and texcube.
 
 
 ---------------------------------------------------------------------
 ---------------------------------------------------------------------
-Extend ProjectLibrary.Refresh
- - Called in EditorApplication on start or assembly refresh
- - Calls checkForModifications(false) internally, retrieves dirty resources and adds them to a HashSet (if they're not already there)
- - EditorApplication also subscribes to FolderMonitor and when it triggers asset modification call Refresh(false)
- - In Update() go over all dirty resources and call checkForModifications(true) on that specific path
-   - Time-slice the import so UI has time to update
-   - Open/Close/Update the progress bar as necessary
-   - Update is called every frame by EditorApplication
-
-Modify ProjectWindow so it only does file-system copy/move operations for copy/paste
-and drag and drop. After which it calls ProjectLibrary.Refresh.
+
+When windows first open they show up as all black. This is problematic with progress bar window since it may appear for just one frame and it only shows up as black square during that time.
+ - Later on after I fix this issue I should probably just make a special case and not open the progress bar if all import is done in one go
+
+Test DoOnDragDropped with a folder. I feel the copy/move methods might break because they don't properly retrieve folder name.
+
+I'm not sure if queued dependencies are handled properly. They're handled on an internal ProjectLibrary loop but perhaps I should
+return them in checkForModifications?
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Project window
 Project window
@@ -40,10 +37,8 @@ Later:
   - Add ping to SceneTreeView
   - Add ping to SceneTreeView
  - Consider delaying search until user stops pressing keys
  - Consider delaying search until user stops pressing keys
  - Save & restore scroll position when Refresh happens
  - Save & restore scroll position when Refresh happens
- - Might need to handle overwritting better when importing/moving
-   - When pasting generate a unique filename if the same one already exists
-   - Do the same when drag and dropping (either internal, or OS)
-
+ - F2 and context menu for renaming assets (or when clicking on a solo selected asset)
+   - Also make sure the names contain only valid path characters
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Resources
 Resources
  - Load/Unload/UnloadUnused
  - Load/Unload/UnloadUnused