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

A lot more work on ProjectLibrary and ResourceTreeView
Started testing and bugfixing

Marko Pintera 12 лет назад
Родитель
Сommit
3bd69f2da6

+ 1 - 0
CamelotClient/Include/BsEditorPrerequisites.h

@@ -20,6 +20,7 @@ namespace BansheeEditor
 	class GUIMenuBar;
 	class GUIMenuBar;
 	class GUIDockSlider;
 	class GUIDockSlider;
 	class GUISceneTreeView;
 	class GUISceneTreeView;
+	class GUIResourceTreeView;
 	class GUITreeViewEditBox;
 	class GUITreeViewEditBox;
 	class EditorCommand;
 	class EditorCommand;
 	class ResourceMeta;
 	class ResourceMeta;

+ 6 - 8
CamelotClient/Include/BsGUIResourceTreeView.h

@@ -2,7 +2,6 @@
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "BsGUITreeView.h"
 #include "BsGUITreeView.h"
-#include "BsVirtualInput.h"
 #include "CmPath.h"
 #include "CmPath.h"
 #include <boost/signal.hpp>
 #include <boost/signal.hpp>
 
 
@@ -12,7 +11,8 @@ namespace BansheeEditor
 	{
 	{
 		struct ResourceTreeElement : public GUITreeView::TreeElement
 		struct ResourceTreeElement : public GUITreeView::TreeElement
 		{
 		{
-			CM::WPath mFullPath;
+			CM::WString mFullPath;
+			CM::WString mElementName;
 		};
 		};
 
 
 		struct DraggedResources
 		struct DraggedResources
@@ -26,7 +26,7 @@ namespace BansheeEditor
 			~InternalDraggedResources();
 			~InternalDraggedResources();
 
 
 			CM::UINT32 numObjects;
 			CM::UINT32 numObjects;
-			CM::WPath* resourcePaths;
+			CM::WString* resourcePaths;
 		};
 		};
 
 
 	public:
 	public:
@@ -76,11 +76,11 @@ namespace BansheeEditor
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
 		virtual void dragAndDropFinalize();
 
 
-		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const CM::WPath& fullPath);
+		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const CM::WString& fullPath);
 		void deleteTreeElement(ResourceTreeElement* element);
 		void deleteTreeElement(ResourceTreeElement* element);
 		void sortTreeElement(ResourceTreeElement* element);
 		void sortTreeElement(ResourceTreeElement* element);
 
 
-		ResourceTreeElement* findTreeElement(const CM::WPath& fullPath);
+		ResourceTreeElement* findTreeElement(const CM::WString& fullPath);
 
 
 		void entryAdded(const CM::WPath& path);
 		void entryAdded(const CM::WPath& path);
 		void entryRemoved(const CM::WPath& path);
 		void entryRemoved(const CM::WPath& path);
@@ -92,9 +92,7 @@ namespace BansheeEditor
 		void dropTargetDragLeave();
 		void dropTargetDragLeave();
 		void dropTargetDragDropped(CM::INT32 x, CM::INT32 y);
 		void dropTargetDragDropped(CM::INT32 x, CM::INT32 y);
 
 
-		void quicksortTreeElements(CM::Vector<TreeElement*>::type& elements, CM::INT32 first, CM::INT32 last);
-
-		CM::WPath findUniquePath(const CM::WPath& path);
+		CM::WString findUniquePath(const CM::WString& path);
 
 
 		void _changeParentWidget(BS::GUIWidget* widget);
 		void _changeParentWidget(BS::GUIWidget* widget);
 	};
 	};

+ 0 - 1
CamelotClient/Include/BsGUISceneTreeView.h

@@ -2,7 +2,6 @@
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "BsGUITreeView.h"
 #include "BsGUITreeView.h"
-#include "BsVirtualInput.h"
 #include <boost/signal.hpp>
 #include <boost/signal.hpp>
 
 
 namespace BansheeEditor
 namespace BansheeEditor

+ 0 - 1
CamelotClient/Include/BsMainEditorWindow.h

@@ -21,7 +21,6 @@ namespace BansheeEditor
 		GUIMenuBar* mMenuBar;
 		GUIMenuBar* mMenuBar;
 		DockManager* mDockManager;
 		DockManager* mDockManager;
 
 
-		void itemDropped(CM::OSDropTarget& dropTarget, CM::INT32 x, CM::INT32 y);
 		virtual void resized();
 		virtual void resized();
 
 
 		void updateAreas();
 		void updateAreas();

+ 7 - 0
CamelotClient/Include/BsProjectLibrary.h

@@ -21,20 +21,27 @@ namespace BansheeEditor
 
 
 		struct LibraryEntry
 		struct LibraryEntry
 		{
 		{
+			LibraryEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent, LibraryEntryType type);
+
 			LibraryEntryType type;
 			LibraryEntryType type;
 			CM::WPath path;
 			CM::WPath path;
+			CM::WString elementName;
 
 
 			DirectoryEntry* parent;
 			DirectoryEntry* parent;
 		};
 		};
 
 
 		struct ResourceEntry : public LibraryEntry
 		struct ResourceEntry : public LibraryEntry
 		{
 		{
+			ResourceEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent);
+
 			ResourceMetaPtr meta;
 			ResourceMetaPtr meta;
 			std::time_t lastUpdateTime;
 			std::time_t lastUpdateTime;
 		};
 		};
 
 
 		struct DirectoryEntry : public LibraryEntry
 		struct DirectoryEntry : public LibraryEntry
 		{
 		{
+			DirectoryEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent);
+
 			CM::Vector<LibraryEntry*>::type mChildren;
 			CM::Vector<LibraryEntry*>::type mChildren;
 		};
 		};
 
 

+ 1 - 0
CamelotClient/Include/CmTestTextSprite.h

@@ -20,6 +20,7 @@ namespace BansheeEditor
 		BS::GUILabel* mLabel;
 		BS::GUILabel* mLabel;
 		BS::GUIListBox* mListBox;
 		BS::GUIListBox* mListBox;
 		GUISceneTreeView* mSceneTreeView;
 		GUISceneTreeView* mSceneTreeView;
+		GUIResourceTreeView* mResourceTreeView;
 		CM::HString labelString;
 		CM::HString labelString;
 
 
 		CM::HSceneObject mDbgMainA;
 		CM::HSceneObject mDbgMainA;

+ 5 - 0
CamelotClient/Source/BsEditorApplication.cpp

@@ -24,6 +24,7 @@
 #include "BsDbgTestGameObjectRef.h"
 #include "BsDbgTestGameObjectRef.h"
 #include "BsVirtualInput.h"
 #include "BsVirtualInput.h"
 #include "CmWin32FolderMonitor.h"
 #include "CmWin32FolderMonitor.h"
+#include "BsProjectLibrary.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 using namespace BansheeEngine;
@@ -55,6 +56,8 @@ namespace BansheeEditor
 			inputConfig->registerButton("Paste", BC_V, VButtonModifier::Ctrl);
 			inputConfig->registerButton("Paste", BC_V, VButtonModifier::Ctrl);
 		}
 		}
 
 
+		ProjectLibrary::startUp(cm_new<ProjectLibrary>());
+
 		//gApplication().loadPlugin("SBansheeEditor"); // Managed part of the editor
 		//gApplication().loadPlugin("SBansheeEditor"); // Managed part of the editor
 
 
 		/************************************************************************/
 		/************************************************************************/
@@ -294,6 +297,7 @@ namespace BansheeEditor
 		/* 							END DEBUG CODE                      		*/
 		/* 							END DEBUG CODE                      		*/
 		/************************************************************************/
 		/************************************************************************/
 
 
+		ProjectLibrary::shutDown();
 		EditorGUI::shutDown();
 		EditorGUI::shutDown();
 		gBansheeApp().shutDown();
 		gBansheeApp().shutDown();
 
 
@@ -313,6 +317,7 @@ namespace BansheeEditor
 
 
 	void EditorApplication::update()
 	void EditorApplication::update()
 	{
 	{
+		ProjectLibrary::instance().update();
 		EditorWindowManager::instance().update();	
 		EditorWindowManager::instance().update();	
 	}
 	}
 
 

+ 51 - 55
CamelotClient/Source/BsGUIResourceTreeView.cpp

@@ -19,7 +19,7 @@ namespace BansheeEditor
 	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
 	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
 		:numObjects(numObjects)
 		:numObjects(numObjects)
 	{
 	{
-		resourcePaths = cm_newN<WPath>(numObjects);
+		resourcePaths = cm_newN<WString>(numObjects);
 	}
 	}
 
 
 	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
 	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
@@ -49,6 +49,8 @@ namespace BansheeEditor
 
 
 		const ProjectLibrary::LibraryEntry* rootEntry = ProjectLibrary::instance().getRootEntry();
 		const ProjectLibrary::LibraryEntry* rootEntry = ProjectLibrary::instance().getRootEntry();
 
 
+		mRootElement.mFullPath = toWString(rootEntry->path);
+		mRootElement.mElementName = PathUtil::getFilename(mRootElement.mFullPath);
 		expandElement(&mRootElement);
 		expandElement(&mRootElement);
 
 
 		Stack<StackElem>::type todo;
 		Stack<StackElem>::type todo;
@@ -57,13 +59,13 @@ namespace BansheeEditor
 		while(!todo.empty())
 		while(!todo.empty())
 		{
 		{
 			StackElem curElem = todo.top();
 			StackElem curElem = todo.top();
-			todo.top();
+			todo.pop();
 
 
 			const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
 			const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
 
 
 			for(auto& child : dirEntry->mChildren)
 			for(auto& child : dirEntry->mChildren)
 			{
 			{
-				ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, curElem.entry->path);
+				ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, toWString(child->path));
 
 
 				if(child->type == ProjectLibrary::LibraryEntryType::Directory)
 				if(child->type == ProjectLibrary::LibraryEntryType::Directory)
 					todo.push(StackElem(child, newChild));
 					todo.push(StackElem(child, newChild));
@@ -121,13 +123,13 @@ namespace BansheeEditor
 	{
 	{
 		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
 		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
 		
 		
-		WPath oldPath = resourceTreeElement->mFullPath;
-		WPath newPath = PathUtil::combine(PathUtil::parentPath(oldPath), toPath(name));
+		WString oldPath = resourceTreeElement->mFullPath;
+		WString newPath = PathUtil::combine(PathUtil::parentPath(oldPath), name);
 
 
-		ProjectLibrary::instance().moveEntry(oldPath, findUniquePath(newPath));
+		ProjectLibrary::instance().moveEntry(toPath(oldPath), toPath(findUniquePath(newPath)));
 	}
 	}
 
 
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const CM::WPath& fullPath)
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const CM::WString& fullPath)
 	{
 	{
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
 		newChild->mParent = parent;
 		newChild->mParent = parent;
@@ -135,6 +137,7 @@ namespace BansheeEditor
 		newChild->mFullPath = fullPath;
 		newChild->mFullPath = fullPath;
 		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
 		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
 		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
 		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
+		newChild->mElementName = PathUtil::getFilename(fullPath);
 
 
 		parent->mChildren.push_back(newChild);
 		parent->mChildren.push_back(newChild);
 
 
@@ -168,6 +171,9 @@ namespace BansheeEditor
 			auto iterFind = std::find(element->mParent->mChildren.begin(), element->mParent->mChildren.end(), element);
 			auto iterFind = std::find(element->mParent->mChildren.begin(), element->mParent->mChildren.end(), element);
 			if(iterFind != element->mParent->mChildren.end())
 			if(iterFind != element->mParent->mChildren.end())
 				element->mParent->mChildren.erase(iterFind);
 				element->mParent->mChildren.erase(iterFind);
+
+			sortTreeElement(static_cast<ResourceTreeElement*>(element->mParent));
+			updateElementGUI(element->mParent);
 		}
 		}
 
 
 		cm_delete(element);
 		cm_delete(element);
@@ -175,49 +181,36 @@ namespace BansheeEditor
 
 
 	void GUIResourceTreeView::sortTreeElement(ResourceTreeElement* element)
 	void GUIResourceTreeView::sortTreeElement(ResourceTreeElement* element)
 	{
 	{
-		if(element->mChildren.size() > 0)
-			quicksortTreeElements(element->mChildren, 0, (INT32)element->mChildren.size() - 1);
-	}
-
-	void GUIResourceTreeView::quicksortTreeElements(CM::Vector<TreeElement*>::type& elements, INT32 first, INT32 last)
-	{
-		if(first < last)
+		auto cmp = [&] (const TreeElement* a, const TreeElement* b)
 		{
 		{
-			int pivot = first + std::rand() % (last - first);
-
-			std::swap(elements[pivot]->mSortedIdx, elements[last]->mSortedIdx);
-			pivot = last;
-
-			int i = first;
-			for(int j = first; j < last; j++)
-			{
-				INT32 stringCompare = elements[j]->mName.compare(elements[pivot]->mName);
-				if(stringCompare < 0)
-				{
-					std::swap(elements[j]->mSortedIdx, elements[i]->mSortedIdx);
-					i++;
-				}
-			}
+			return a->mName.compare(b->mName) < 0;
+		};
 
 
-			std::swap(elements[last]->mSortedIdx, elements[pivot]->mSortedIdx);
+		std::sort(element->mChildren.begin(), element->mChildren.end(), cmp);
 
 
-			quicksortTreeElements(elements, first, i - 1);
-			quicksortTreeElements(elements, i + 1, last);
+		UINT32 idx = 0;
+		for(auto& child : element->mChildren)
+		{
+			child->mSortedIdx = idx;
+			idx++;
 		}
 		}
 	}
 	}
 
 
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const CM::WPath& fullPath)
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const CM::WString& fullPath)
 	{
 	{
-		auto pathIter = fullPath.begin();
-		auto rootIter = mRootElement.mFullPath.begin();
+		Vector<WString>::type pathElems = PathUtil::split(fullPath);
+		Vector<WString>::type rootElems = PathUtil::split(mRootElement.mFullPath);
+
+		auto pathIter = pathElems.begin();
+		auto rootIter = rootElems.begin();
 
 
-		while(*pathIter == *rootIter)
+		while(pathIter != pathElems.end() && rootIter != rootElems.end() && PathUtil::comparePathElements(*pathIter, *rootIter))
 		{
 		{
 			++pathIter;
 			++pathIter;
 			++rootIter;
 			++rootIter;
 		}
 		}
 
 
-		if(pathIter == fullPath.begin()) // Supplied path not part of the root path
+		if(pathIter == pathElems.begin()) // Supplied path not part of the root path
 			return nullptr;
 			return nullptr;
 
 
 		--pathIter;
 		--pathIter;
@@ -230,15 +223,18 @@ namespace BansheeEditor
 			ResourceTreeElement* current = todo.top();
 			ResourceTreeElement* current = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			if(*pathIter == *(--(current->mFullPath.end())))
+			if(PathUtil::comparePathElements(*pathIter, current->mElementName))
 			{
 			{
-				for(auto& child : current->mChildren)
-					todo.push(static_cast<ResourceTreeElement*>(child));
+				++pathIter;
 
 
-				if(pathIter == fullPath.end())
+				if(pathIter == pathElems.end())
 					return current;
 					return current;
 
 
-				++pathIter;
+				while(!todo.empty())
+					todo.pop();
+
+				for(auto& child : current->mChildren)
+					todo.push(static_cast<ResourceTreeElement*>(child));
 			}
 			}
 		}
 		}
 
 
@@ -249,10 +245,10 @@ namespace BansheeEditor
 	{
 	{
 		WPath parentPath = PathUtil::parentPath(path);
 		WPath parentPath = PathUtil::parentPath(path);
 
 
-		ResourceTreeElement* parentElement = findTreeElement(parentPath);
+		ResourceTreeElement* parentElement = findTreeElement(toWString(parentPath));
 		assert(parentElement != nullptr);
 		assert(parentElement != nullptr);
 
 
-		addTreeElement(parentElement, path);
+		addTreeElement(parentElement, toWString(path));
 		sortTreeElement(parentElement);
 		sortTreeElement(parentElement);
 
 
 		markContentAsDirty();
 		markContentAsDirty();
@@ -260,7 +256,7 @@ namespace BansheeEditor
 
 
 	void GUIResourceTreeView::entryRemoved(const WPath& path)
 	void GUIResourceTreeView::entryRemoved(const WPath& path)
 	{
 	{
-		ResourceTreeElement* treeElement = findTreeElement(path);
+		ResourceTreeElement* treeElement = findTreeElement(toWString(path));
 		
 		
 		if(treeElement != nullptr)
 		if(treeElement != nullptr)
 			deleteTreeElement(treeElement);
 			deleteTreeElement(treeElement);
@@ -344,7 +340,7 @@ namespace BansheeEditor
 
 
 			mDraggedResources = cm_new<InternalDraggedResources>((UINT32)fileList.size());
 			mDraggedResources = cm_new<InternalDraggedResources>((UINT32)fileList.size());
 			for(UINT32 i = 0; i < (UINT32)fileList.size(); i++)
 			for(UINT32 i = 0; i < (UINT32)fileList.size(); i++)
-				mDraggedResources->resourcePaths[i] = toPath(fileList[i]);
+				mDraggedResources->resourcePaths[i] = fileList[i];
 
 
 			dragAndDropEnded(treeElement);
 			dragAndDropEnded(treeElement);
 
 
@@ -359,19 +355,19 @@ namespace BansheeEditor
 		markContentAsDirty();
 		markContentAsDirty();
 	}
 	}
 
 
-	CM::WPath GUIResourceTreeView::findUniquePath(const CM::WPath& path)
+	CM::WString GUIResourceTreeView::findUniquePath(const CM::WString& path)
 	{
 	{
 		if(FileSystem::exists(path))
 		if(FileSystem::exists(path))
 		{
 		{
-			WPath noExtensionPath = path;
-			WPath extension = PathUtil::getExtension(path);
+			WString noExtensionPath = path;
+			WString extension = PathUtil::getExtension(path);
 			PathUtil::replaceExtension(noExtensionPath, L"");
 			PathUtil::replaceExtension(noExtensionPath, L"");
 
 
-			WPath newPath;
+			WString newPath;
 			UINT32 cnt = 1;
 			UINT32 cnt = 1;
 			do 
 			do 
 			{
 			{
-				newPath = PathUtil::combine(PathUtil::combine(noExtensionPath, toPath(L" " + toWString(cnt))), extension);
+				newPath = PathUtil::combine(PathUtil::combine(noExtensionPath, L" " + toWString(cnt)), extension);
 				cnt++;
 				cnt++;
 			} while (FileSystem::exists(newPath));
 			} while (FileSystem::exists(newPath));
 
 
@@ -418,16 +414,16 @@ namespace BansheeEditor
 		{
 		{
 			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
 			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
 
 
-			WPath destDir = resourceTreeElement->mFullPath;
+			WString destDir = resourceTreeElement->mFullPath;
 			if(FileSystem::isFile(destDir))
 			if(FileSystem::isFile(destDir))
 				destDir = PathUtil::parentPath(destDir);
 				destDir = PathUtil::parentPath(destDir);
 
 
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			{
 			{
-				WPath filename = PathUtil::getFilename(mDraggedResources->resourcePaths[i]);
+				WString filename = PathUtil::getFilename(mDraggedResources->resourcePaths[i]);
 
 
-				WPath newPath = PathUtil::combine(destDir, filename);
-				ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
+				WString newPath = PathUtil::combine(destDir, filename);
+				ProjectLibrary::instance().moveEntry(toPath(mDraggedResources->resourcePaths[i]), toPath(findUniquePath(newPath)));
 			}
 			}
 		}
 		}
 	}
 	}

+ 0 - 10
CamelotClient/Source/BsMainEditorWindow.cpp

@@ -76,11 +76,6 @@ namespace BansheeEditor
 		AABox dbgBox(Vector3(-300, -200, 1000), Vector3(300, 300, 1500));
 		AABox dbgBox(Vector3(-300, -200, 1000), Vector3(300, 300, 1500));
 		//DrawHelper3D::instance().drawAABox(sceneCamera, dbgBox, Color::Green, 250.0f);
 		//DrawHelper3D::instance().drawAABox(sceneCamera, dbgBox, Color::Green, 250.0f);
 
 
-		OSDropTarget& dropTarget = Platform::createDropTarget(mRenderWindow.get(), 100, 100, 400, 400);
-		dropTarget.onDrop.connect(boost::bind(&MainEditorWindow::itemDropped, this, boost::ref(dropTarget), _1, _2));
-
-		Platform::destroyDropTarget(dropTarget);
-
 		ProfilerOverlay::startUp(cm_new<ProfilerOverlay>(sceneCamera->getViewport()));
 		ProfilerOverlay::startUp(cm_new<ProfilerOverlay>(sceneCamera->getViewport()));
 		ProfilerOverlay::instance().show();
 		ProfilerOverlay::instance().show();
 	}
 	}
@@ -93,11 +88,6 @@ namespace BansheeEditor
 		cm_delete(mMenuBar);
 		cm_delete(mMenuBar);
 	}
 	}
 
 
-	void MainEditorWindow::itemDropped(OSDropTarget& dropTarget, INT32 x, INT32 y)
-	{
-		int a = 5;
-	}
-
 	void MainEditorWindow::resized()
 	void MainEditorWindow::resized()
 	{
 	{
 		EditorWindowBase::resized();
 		EditorWindowBase::resized();

+ 129 - 105
CamelotClient/Source/BsProjectLibrary.cpp

@@ -19,7 +19,19 @@ using namespace BansheeEngine;
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	const WString ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal/Resources";
+	const WString ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal\\Resources";
+
+	ProjectLibrary::LibraryEntry::LibraryEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent, LibraryEntryType type)
+		:path(path), parent(parent), type(type), elementName(name)
+	{ }
+
+	ProjectLibrary::ResourceEntry::ResourceEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent)
+		:LibraryEntry(path, name, parent, LibraryEntryType::File), lastUpdateTime(0)
+	{ }
+
+	ProjectLibrary::DirectoryEntry::DirectoryEntry(const CM::WPath& path, const CM::WString& name, DirectoryEntry* parent)
+		:LibraryEntry(path, name, parent, LibraryEntryType::Directory)
+	{ }
 
 
 	ProjectLibrary::ProjectLibrary()
 	ProjectLibrary::ProjectLibrary()
 		:mRootEntry(nullptr)
 		:mRootEntry(nullptr)
@@ -33,10 +45,15 @@ namespace BansheeEditor
 		mMonitor->onAdded.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
 		mMonitor->onAdded.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
 		mMonitor->onRemoved.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
 		mMonitor->onRemoved.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
 		mMonitor->onModified.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
 		mMonitor->onModified.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
+
+		// TODO - Load
+		checkForModifications(EditorApplication::instance().getResourcesFolderPath());
 	}
 	}
 
 
 	ProjectLibrary::~ProjectLibrary()
 	ProjectLibrary::~ProjectLibrary()
 	{
 	{
+		// TODO - Save
+
 		mMonitor->stopMonitorAll();
 		mMonitor->stopMonitorAll();
 		cm_delete(mMonitor);
 		cm_delete(mMonitor);
 
 
@@ -56,8 +73,8 @@ namespace BansheeEditor
 
 
 		if(mRootEntry == nullptr)
 		if(mRootEntry == nullptr)
 		{
 		{
-			mRootEntry = cm_new<DirectoryEntry>();
-			mRootEntry->path = toPath(EditorApplication::instance().getResourcesFolderPath());
+			WPath resPath = toPath(EditorApplication::instance().getResourcesFolderPath());
+			mRootEntry = cm_new<DirectoryEntry>(resPath, toWString(PathUtil::getFilename(resPath)), nullptr);
 		}
 		}
 
 
 		WPath pathToSearch = toPath(fullPath);
 		WPath pathToSearch = toPath(fullPath);
@@ -103,128 +120,127 @@ namespace BansheeEditor
 		}
 		}
 		else if(entry->type == LibraryEntryType::Directory) // Check folder and all subfolders for modifications
 		else if(entry->type == LibraryEntryType::Directory) // Check folder and all subfolders for modifications
 		{
 		{
-			Stack<DirectoryEntry*>::type todo;
-			todo.push(static_cast<DirectoryEntry*>(entry));
+			if(!FileSystem::isDirectory(entry->path))
+			{
+				deleteDirectoryInternal(static_cast<DirectoryEntry*>(entry));
+			}
+			else
+			{
+				Stack<DirectoryEntry*>::type todo;
+				todo.push(static_cast<DirectoryEntry*>(entry));
 
 
-			Vector<WPath>::type childFiles;
-			Vector<WPath>::type childDirectories;
-			Vector<bool>::type existingEntries;
-			Vector<LibraryEntry*>::type toDelete;
+				Vector<WPath>::type childFiles;
+				Vector<WPath>::type childDirectories;
+				Vector<bool>::type existingEntries;
+				Vector<LibraryEntry*>::type toDelete;
 
 
-			while(!todo.empty())
-			{
-				DirectoryEntry* currentDir = todo.top();
-				todo.pop();
+				while(!todo.empty())
+				{
+					DirectoryEntry* currentDir = todo.top();
+					todo.pop();
 
 
-				existingEntries.clear();
-				existingEntries.resize(currentDir->mChildren.size());
-				for(UINT32 i = 0; i < (UINT32)currentDir->mChildren.size(); i++)
-					existingEntries[i] = false;
+					existingEntries.clear();
+					existingEntries.resize(currentDir->mChildren.size());
+					for(UINT32 i = 0; i < (UINT32)currentDir->mChildren.size(); i++)
+						existingEntries[i] = false;
 
 
-				childFiles.clear();
-				childDirectories.clear();
+					childFiles.clear();
+					childDirectories.clear();
 
 
-				FileSystem::getChildren(currentDir->path, childFiles, childDirectories);
+					FileSystem::getChildren(currentDir->path, childFiles, childDirectories);
 			
 			
-				for(auto& filePath : childFiles)
-				{
-					if(isMeta(filePath))
+					for(auto& filePath : childFiles)
 					{
 					{
-						WPath sourceFilePath = filePath;
-						PathUtil::replaceExtension(sourceFilePath, L"");
+						if(isMeta(filePath))
+						{
+							WPath sourceFilePath = filePath;
+							PathUtil::replaceExtension(sourceFilePath, L"");
+
+							if(FileSystem::isFile(sourceFilePath))
+							{
+								LOGWRN("Found a .meta file without a corresponding resource. Deleting.");
 
 
-						if(FileSystem::isFile(sourceFilePath))
+								FileSystem::remove(filePath);
+							}
+						}
+						else
 						{
 						{
-							LOGWRN("Found a .meta file without a corresponding resource. Deleting.");
+							ResourceEntry* existingEntry = nullptr;
+							UINT32 idx = 0;
+							for(auto& child : currentDir->mChildren)
+							{
+								if(child->type == LibraryEntryType::File && child->path == filePath)
+								{
+									existingEntries[idx] = true;
+									existingEntry = static_cast<ResourceEntry*>(child);
+									break;
+								}
+
+								idx++;
+							}
 
 
-							FileSystem::remove(filePath);
+							if(existingEntry != nullptr)
+							{
+								reimportResourceInternal(existingEntry);
+							}
+							else
+							{
+								addResourceInternal(currentDir, filePath);
+							}
 						}
 						}
 					}
 					}
-					else
+
+					for(auto& dirPath : childDirectories)
 					{
 					{
-						ResourceEntry* existingEntry = nullptr;
+						DirectoryEntry* existingEntry = nullptr;
 						UINT32 idx = 0;
 						UINT32 idx = 0;
 						for(auto& child : currentDir->mChildren)
 						for(auto& child : currentDir->mChildren)
 						{
 						{
-							if(child->type == LibraryEntryType::File && child->path == filePath)
+							if(child->type == LibraryEntryType::Directory && child->path == dirPath)
 							{
 							{
 								existingEntries[idx] = true;
 								existingEntries[idx] = true;
-								existingEntry = static_cast<ResourceEntry*>(child);
+								existingEntry = static_cast<DirectoryEntry*>(child);
 								break;
 								break;
 							}
 							}
 
 
 							idx++;
 							idx++;
 						}
 						}
 
 
-						if(existingEntry != nullptr)
-						{
-							reimportResourceInternal(existingEntry);
-						}
-						else
-						{
-							addResourceInternal(currentDir, filePath);
-						}
+						if(existingEntry == nullptr)
+							addDirectoryInternal(currentDir, dirPath);
 					}
 					}
-				}
 
 
-				for(auto& dirPath : childDirectories)
-				{
-					DirectoryEntry* existingEntry = nullptr;
-					UINT32 idx = 0;
-					for(auto& child : currentDir->mChildren)
 					{
 					{
-						if(child->type == LibraryEntryType::Directory && child->path == dirPath)
+						for(UINT32 i = 0; i < (UINT32)existingEntries.size(); i++)
 						{
 						{
-							existingEntries[idx] = true;
-							existingEntry = static_cast<DirectoryEntry*>(child);
-							break;
+							if(existingEntries[i])
+								continue;
+
+							toDelete.push_back(currentDir->mChildren[i]);
 						}
 						}
 
 
-						idx++;
+						for(auto& child : toDelete)
+						{
+							if(child->type == LibraryEntryType::Directory)
+								deleteDirectoryInternal(static_cast<DirectoryEntry*>(child));
+							else if(child->type == LibraryEntryType::File)
+								deleteResourceInternal(static_cast<ResourceEntry*>(child));
+						}
 					}
 					}
 
 
-					if(existingEntry == nullptr)
-						addDirectoryInternal(currentDir, dirPath);
-				}
-
-				{
-					UINT32 idx = 0;
-					toDelete.clear();
 					for(auto& child : currentDir->mChildren)
 					for(auto& child : currentDir->mChildren)
-					{
-						if(existingEntries[idx])
-							continue;
-
-						toDelete.push_back(child);
-
-						idx++;
-					}
-
-					for(auto& child : toDelete)
 					{
 					{
 						if(child->type == LibraryEntryType::Directory)
 						if(child->type == LibraryEntryType::Directory)
-							deleteDirectoryInternal(static_cast<DirectoryEntry*>(child));
-						else if(child->type == LibraryEntryType::File)
-							deleteResourceInternal(static_cast<ResourceEntry*>(child));
+							todo.push(static_cast<DirectoryEntry*>(child));
 					}
 					}
 				}
 				}
-
-				for(auto& child : currentDir->mChildren)
-				{
-					if(child->type == LibraryEntryType::Directory)
-						todo.push(static_cast<DirectoryEntry*>(child));
-				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const CM::WPath& filePath)
 	ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const CM::WPath& filePath)
 	{
 	{
-		ResourceEntry* newResource = cm_new<ResourceEntry>();
-		newResource->type = LibraryEntryType::File;
-		newResource->path = filePath;
-		newResource->parent = parent;
-
+		ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, toWString(PathUtil::getFilename(filePath)), parent);
 		parent->mChildren.push_back(newResource);
 		parent->mChildren.push_back(newResource);
 
 
 		reimportResourceInternal(newResource);
 		reimportResourceInternal(newResource);
@@ -237,11 +253,7 @@ namespace BansheeEditor
 
 
 	ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const CM::WPath& dirPath)
 	ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const CM::WPath& dirPath)
 	{
 	{
-		DirectoryEntry* newEntry = cm_new<DirectoryEntry>();
-		newEntry->type = LibraryEntryType::Directory;
-		newEntry->path = dirPath;
-		newEntry->parent = parent;
-
+		DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, toWString(PathUtil::getFilename(dirPath)), parent);
 		parent->mChildren.push_back(newEntry);
 		parent->mChildren.push_back(newEntry);
 
 
 		if(!onEntryAdded.empty())
 		if(!onEntryAdded.empty())
@@ -258,7 +270,7 @@ namespace BansheeEditor
 		{
 		{
 			if(manifest->uuidExists(resource->meta->getUUID()))
 			if(manifest->uuidExists(resource->meta->getUUID()))
 			{
 			{
-				const WPath& path = manifest->uuidToFilePath(resource->meta->getUUID());
+				const WString& path = manifest->uuidToFilePath(resource->meta->getUUID());
 				if(FileSystem::isFile(path))
 				if(FileSystem::isFile(path))
 					FileSystem::remove(path);
 					FileSystem::remove(path);
 
 
@@ -355,7 +367,7 @@ namespace BansheeEditor
 			gResources().save(importedResource, toWString(internalResourcesPath), true);
 			gResources().save(importedResource, toWString(internalResourcesPath), true);
 
 
 			ResourceManifestPtr manifest = gResources().getResourceManifest();
 			ResourceManifestPtr manifest = gResources().getResourceManifest();
-			manifest->registerResource(importedResource.getUUID(), internalResourcesPath);
+			manifest->registerResource(importedResource.getUUID(), toWString(internalResourcesPath));
 
 
 			resource->lastUpdateTime = std::time(nullptr);
 			resource->lastUpdateTime = std::time(nullptr);
 		}
 		}
@@ -371,7 +383,7 @@ namespace BansheeEditor
 		if(!manifest->uuidExists(resource->meta->getUUID()))
 		if(!manifest->uuidExists(resource->meta->getUUID()))
 			return false;
 			return false;
 
 
-		const WPath& path = manifest->uuidToFilePath(resource->meta->getUUID());
+		const WString& path = manifest->uuidToFilePath(resource->meta->getUUID());
 		if(!FileSystem::isFile(path))
 		if(!FileSystem::isFile(path))
 			return false;
 			return false;
 
 
@@ -381,20 +393,22 @@ namespace BansheeEditor
 
 
 	ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const CM::WPath& fullPath) const
 	ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const CM::WPath& fullPath) const
 	{
 	{
-		auto pathIter = fullPath.begin();
-		auto rootIter = mRootEntry->path.begin();
+		Vector<WString>::type pathElems = PathUtil::split(toWString(fullPath));
+		Vector<WString>::type rootElems = PathUtil::split(toWString(mRootEntry->path));
+
+		auto pathIter = pathElems.begin();
+		auto rootIter = rootElems.begin();
 
 
-		while(*pathIter == *rootIter)
+		while(pathIter != pathElems.end() && rootIter != rootElems.end() && PathUtil::comparePathElements(*pathIter, *rootIter))
 		{
 		{
 			++pathIter;
 			++pathIter;
 			++rootIter;
 			++rootIter;
 		}
 		}
 
 
-		if(pathIter == fullPath.begin()) // Not a single entry matches Resources path
+		if(pathIter == pathElems.begin()) // Not a single entry matches Resources path
 			return nullptr;
 			return nullptr;
 
 
 		--pathIter;
 		--pathIter;
-
 		Stack<LibraryEntry*>::type todo;
 		Stack<LibraryEntry*>::type todo;
 		todo.push(mRootEntry);
 		todo.push(mRootEntry);
 
 
@@ -403,19 +417,22 @@ namespace BansheeEditor
 			LibraryEntry* current = todo.top();
 			LibraryEntry* current = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			if(*pathIter == *(--(current->path.end())))
+			if(PathUtil::comparePathElements(*pathIter, current->elementName))
 			{
 			{
+				++pathIter;
+
+				if(pathIter == pathElems.end())
+					return current;
+
+				while(!todo.empty())
+					todo.pop();
+
 				if(current->type == LibraryEntryType::Directory)
 				if(current->type == LibraryEntryType::Directory)
 				{
 				{
 					DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
 					DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
 					for(auto& child : dirEntry->mChildren)
 					for(auto& child : dirEntry->mChildren)
 						todo.push(child);
 						todo.push(child);
 				}
 				}
-
-				if(pathIter == fullPath.end())
-					return current;
-
-				++pathIter;
 			}
 			}
 		}
 		}
 
 
@@ -473,6 +490,7 @@ namespace BansheeEditor
 				newEntryParent->mChildren.push_back(oldEntry);
 				newEntryParent->mChildren.push_back(oldEntry);
 				oldEntry->parent = newEntryParent;
 				oldEntry->parent = newEntryParent;
 				oldEntry->path = newPath;
 				oldEntry->path = newPath;
+				oldEntry->elementName = toWString(PathUtil::getFilename(newPath));
 
 
 				if(!onEntryRemoved.empty())
 				if(!onEntryRemoved.empty())
 					onEntryRemoved(oldPath);
 					onEntryRemoved(oldPath);
@@ -557,9 +575,7 @@ namespace BansheeEditor
 
 
 	WPath ProjectLibrary::getMetaPath(const CM::WPath& path) const
 	WPath ProjectLibrary::getMetaPath(const CM::WPath& path) const
 	{
 	{
-		WString ext = toWString(PathUtil::getExtension(path));
-		WPath metaPath = path;
-		PathUtil::replaceExtension(metaPath, ext + L".meta");
+		WPath metaPath = toPath(toWString(path) + L".meta");
 
 
 		return metaPath;
 		return metaPath;
 	}
 	}
@@ -571,6 +587,14 @@ namespace BansheeEditor
 
 
 	void ProjectLibrary::onMonitorFileModified(const WString& path)
 	void ProjectLibrary::onMonitorFileModified(const WString& path)
 	{
 	{
-		checkForModifications(path);
+		if(!isMeta(toPath(path)))
+			checkForModifications(path);
+		else
+		{
+			WPath resourcePath = toPath(path);
+			PathUtil::replaceExtension(resourcePath, L"");
+
+			checkForModifications(toWString(resourcePath));
+		}
 	}
 	}
 }
 }

+ 19 - 16
CamelotClient/Source/CmTestTextSprite.cpp

@@ -25,6 +25,7 @@
 #include "BsGUIContent.h"
 #include "BsGUIContent.h"
 #include "CmStringTable.h"
 #include "CmStringTable.h"
 #include "BsGUISceneTreeView.h"
 #include "BsGUISceneTreeView.h"
+#include "BsGUIResourceTreeView.h"
 #include "BsGUIScrollArea.h"
 #include "BsGUIScrollArea.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
@@ -49,7 +50,7 @@ namespace BansheeEditor
 		GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
 		GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
 
 
 		mSceneTreeView = GUISceneTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
 		mSceneTreeView = GUISceneTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
-
+		mResourceTreeView = GUIResourceTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
 		GUILayout& sceneTreeViewLayout = area->getLayout().addLayoutY();
 		GUILayout& sceneTreeViewLayout = area->getLayout().addLayoutY();
 		
 		
 		//sceneTreeViewLayout.addElement(mSceneTreeView);
 		//sceneTreeViewLayout.addElement(mSceneTreeView);
@@ -85,26 +86,27 @@ namespace BansheeEditor
 		sceneTreeViewLayout.addFlexibleSpace();
 		sceneTreeViewLayout.addFlexibleSpace();
 
 
 		scrollArea->getLayout().addElement(mSceneTreeView);
 		scrollArea->getLayout().addElement(mSceneTreeView);
+		area->getLayout().addElement(mResourceTreeView);
 
 
-		GUIButton* button = GUIButton::create(*this, HString(L"dbgBtn"));
-		button->onClick.connect(boost::bind(&TestTextSprite::dbgBtn, this));
-		area->getLayout().addElement(button);
+		//GUIButton* button = GUIButton::create(*this, HString(L"dbgBtn"));
+		//button->onClick.connect(boost::bind(&TestTextSprite::dbgBtn, this));
+		//area->getLayout().addElement(button);
 
 
-		button = GUIButton::create(*this, HString(L"Add GameObjects"));
-		button->onClick.connect(boost::bind(&TestTextSprite::dbgAdd, this));
-		area->getLayout().addElement(button);
+		//button = GUIButton::create(*this, HString(L"Add GameObjects"));
+		//button->onClick.connect(boost::bind(&TestTextSprite::dbgAdd, this));
+		//area->getLayout().addElement(button);
 
 
-		button = GUIButton::create(*this, HString(L"Rename GameObject"));
-		button->onClick.connect(boost::bind(&TestTextSprite::dbgRename, this));
-		area->getLayout().addElement(button);
+		//button = GUIButton::create(*this, HString(L"Rename GameObject"));
+		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRename, this));
+		//area->getLayout().addElement(button);
 
 
-		button = GUIButton::create(*this, HString(L"Remove child GameObjects"));
-		button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveChildren, this));
-		area->getLayout().addElement(button);
+		//button = GUIButton::create(*this, HString(L"Remove child GameObjects"));
+		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveChildren, this));
+		//area->getLayout().addElement(button);
 
 
-		button = GUIButton::create(*this, HString(L"Remove parent GameObjects"));
-		button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveParents, this));
-		area->getLayout().addElement(button);
+		//button = GUIButton::create(*this, HString(L"Remove parent GameObjects"));
+		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveParents, this));
+		//area->getLayout().addElement(button);
 
 
 		area->getLayout().addFlexibleSpace();
 		area->getLayout().addFlexibleSpace();
 
 
@@ -116,6 +118,7 @@ namespace BansheeEditor
 	{
 	{
 		labelString.setParameter(0, toWString(Input::instance().getCursorPosition().x));
 		labelString.setParameter(0, toWString(Input::instance().getCursorPosition().x));
 		mSceneTreeView->update();
 		mSceneTreeView->update();
+		mResourceTreeView->update();
 		//labelString.setParameter(1, toWString(Input::instance().getCursorPosition().y));
 		//labelString.setParameter(1, toWString(Input::instance().getCursorPosition().y));
 	}
 	}
 
 

+ 6 - 7
CamelotCore/Include/CmResourceManifest.h

@@ -2,7 +2,6 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
-#include "CmPath.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -17,18 +16,18 @@ namespace CamelotFramework
 	class CM_EXPORT ResourceManifest : public IReflectable
 	class CM_EXPORT ResourceManifest : public IReflectable
 	{
 	{
 	public:
 	public:
-		void registerResource(const String& uuid, const WPath& filePath);
+		void registerResource(const String& uuid, const WString& filePath);
 		void unregisterResource(const String& uuid);
 		void unregisterResource(const String& uuid);
 
 
-		const WPath& uuidToFilePath(const String& uuid) const;
-		const String& filePathToUUID(const WPath& filePath) const;
+		const WString& uuidToFilePath(const String& uuid) const;
+		const String& filePathToUUID(const WString& filePath) const;
 
 
 		bool uuidExists(const String& uuid) const;
 		bool uuidExists(const String& uuid) const;
-		bool filePathExists(const WPath& filePath) const;
+		bool filePathExists(const WString& filePath) const;
 
 
 	private:
 	private:
-		Map<String, WPath>::type mUUIDToFilePath;
-		Map<WPath, String>::type mFilePathToUUID;
+		Map<String, WString>::type mUUIDToFilePath;
+		Map<WString, String>::type mFilePathToUUID;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/

+ 2 - 2
CamelotCore/Include/CmResourceManifestRTTI.h

@@ -52,12 +52,12 @@ namespace CamelotFramework
 	class CM_EXPORT ResourceManifestRTTI : public RTTIType<ResourceManifest, IReflectable, ResourceManifestRTTI>
 	class CM_EXPORT ResourceManifestRTTI : public RTTIType<ResourceManifest, IReflectable, ResourceManifestRTTI>
 	{
 	{
 	private:
 	private:
-		Map<String, WPath>::type& getUUIDMap(ResourceManifest* obj) 
+		Map<String, WString>::type& getUUIDMap(ResourceManifest* obj) 
 		{ 
 		{ 
 			return obj->mUUIDToFilePath;
 			return obj->mUUIDToFilePath;
 		}
 		}
 
 
-		void setUUIDMap(ResourceManifest* obj, Map<String, WPath>::type& val) 
+		void setUUIDMap(ResourceManifest* obj, Map<String, WString>::type& val) 
 		{ 
 		{ 
 			obj->mUUIDToFilePath = val; 
 			obj->mUUIDToFilePath = val; 
 
 

+ 1 - 2
CamelotCore/Include/CmResources.h

@@ -3,7 +3,6 @@
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
 #include "CmWorkQueue.h"
 #include "CmWorkQueue.h"
-#include "CmPath.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -157,7 +156,7 @@ namespace CamelotFramework
 		HResource loadInternal(const WString& filePath, bool synchronous); 
 		HResource loadInternal(const WString& filePath, bool synchronous); 
 		ResourcePtr loadFromDiskAndDeserialize(const WString& filePath);
 		ResourcePtr loadFromDiskAndDeserialize(const WString& filePath);
 
 
-		const WPath& getPathFromUUID(const String& uuid) const;
+		const WString& getPathFromUUID(const String& uuid) const;
 		const String& getUUIDFromPath(const WString& path) const;
 		const String& getUUIDFromPath(const WString& path) const;
 
 
 		void notifyResourceLoadingFinished(HResource& handle);
 		void notifyResourceLoadingFinished(HResource& handle);

+ 1 - 0
CamelotCore/Source/CmPlatform.cpp

@@ -43,6 +43,7 @@ namespace CamelotFramework
 	{
 	{
 		_clear();
 		_clear();
 
 
+		mDropType = OSDropType::FileList;
 		mFileList = cm_new<Vector<WString>::type>();
 		mFileList = cm_new<Vector<WString>::type>();
 		*mFileList = fileList;
 		*mFileList = fileList;
 	}
 	}

+ 5 - 5
CamelotCore/Source/CmResourceManifest.cpp

@@ -3,7 +3,7 @@
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
-	void ResourceManifest::registerResource(const String& uuid, const WPath& filePath)
+	void ResourceManifest::registerResource(const String& uuid, const WString& filePath)
 	{
 	{
 		auto iterFind = mUUIDToFilePath.find(uuid);
 		auto iterFind = mUUIDToFilePath.find(uuid);
 
 
@@ -35,17 +35,17 @@ namespace CamelotFramework
 		}
 		}
 	}
 	}
 
 
-	const WPath& ResourceManifest::uuidToFilePath(const String& uuid) const
+	const WString& ResourceManifest::uuidToFilePath(const String& uuid) const
 	{
 	{
 		auto iterFind = mUUIDToFilePath.find(uuid);
 		auto iterFind = mUUIDToFilePath.find(uuid);
 
 
 		if(iterFind != mUUIDToFilePath.end())
 		if(iterFind != mUUIDToFilePath.end())
 			return iterFind->second;
 			return iterFind->second;
 		else
 		else
-			return PathUtil::BLANK;
+			return StringUtil::WBLANK;
 	}
 	}
 
 
-	const String& ResourceManifest::filePathToUUID(const WPath& filePath) const
+	const String& ResourceManifest::filePathToUUID(const WString& filePath) const
 	{
 	{
 		auto iterFind = mFilePathToUUID.find(filePath);
 		auto iterFind = mFilePathToUUID.find(filePath);
 
 
@@ -62,7 +62,7 @@ namespace CamelotFramework
 		return iterFind != mUUIDToFilePath.end();
 		return iterFind != mUUIDToFilePath.end();
 	}
 	}
 
 
-	bool ResourceManifest::filePathExists(const WPath& filePath) const
+	bool ResourceManifest::filePathExists(const WString& filePath) const
 	{
 	{
 		auto iterFind = mFilePathToUUID.find(filePath);
 		auto iterFind = mFilePathToUUID.find(filePath);
 
 

+ 6 - 6
CamelotCore/Source/CmResources.cpp

@@ -114,7 +114,7 @@ namespace CamelotFramework
 			return HResource();
 			return HResource();
 		}
 		}
 
 
-		WString filePath = toWString(getPathFromUUID(uuid));
+		WString filePath = getPathFromUUID(uuid);
 		return load(filePath);
 		return load(filePath);
 	}
 	}
 
 
@@ -126,14 +126,14 @@ namespace CamelotFramework
 			return HResource();
 			return HResource();
 		}
 		}
 
 
-		WString filePath = toWString(getPathFromUUID(uuid));
+		WString filePath = getPathFromUUID(uuid);
 		return loadAsync(filePath);
 		return loadAsync(filePath);
 	}
 	}
 
 
 	HResource Resources::loadInternal(const WString& filePath, bool synchronous)
 	HResource Resources::loadInternal(const WString& filePath, bool synchronous)
 	{
 	{
 		String uuid;
 		String uuid;
-		if(!mResourceManifest->filePathExists(toPath(filePath)))
+		if(!mResourceManifest->filePathExists(filePath))
 			uuid = UUIDGenerator::generateRandom();
 			uuid = UUIDGenerator::generateRandom();
 		else
 		else
 			uuid = getUUIDFromPath(filePath);
 			uuid = getUUIDFromPath(filePath);
@@ -260,20 +260,20 @@ namespace CamelotFramework
 				CM_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
 				CM_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
 		}
 		}
 
 
-		mResourceManifest->registerResource(resource.getUUID(), toPath(filePath));
+		mResourceManifest->registerResource(resource.getUUID(), filePath);
 
 
 		FileSerializer fs;
 		FileSerializer fs;
 		fs.encode(resource.get(), filePath);
 		fs.encode(resource.get(), filePath);
 	}
 	}
 
 
-	const WPath& Resources::getPathFromUUID(const String& uuid) const
+	const WString& Resources::getPathFromUUID(const String& uuid) const
 	{
 	{
 		return mResourceManifest->uuidToFilePath(uuid);
 		return mResourceManifest->uuidToFilePath(uuid);
 	}
 	}
 
 
 	const String& Resources::getUUIDFromPath(const WString& path) const
 	const String& Resources::getUUIDFromPath(const WString& path) const
 	{
 	{
-		return mResourceManifest->filePathToUUID(toPath(path));
+		return mResourceManifest->filePathToUUID(path);
 	}
 	}
 
 
 	void Resources::notifyResourceLoadingFinished(HResource& handle)
 	void Resources::notifyResourceLoadingFinished(HResource& handle)

+ 70 - 53
CamelotUtility/Include/CmPath.h

@@ -43,6 +43,11 @@ namespace CamelotFramework
 			path.replace_extension(newExtension.c_str());
 			path.replace_extension(newExtension.c_str());
 		}
 		}
 
 
+		static void replaceExtension(WString& path, const WString& newExtension)
+		{
+			path = toWString(toPath(path).replace_extension(newExtension.c_str()));
+		}
+
 		static WString parentPath(const WString& path)
 		static WString parentPath(const WString& path)
 		{
 		{
 			return WPath(path.c_str()).parent_path().c_str();
 			return WPath(path.c_str()).parent_path().c_str();
@@ -59,21 +64,29 @@ namespace CamelotFramework
 		 */
 		 */
 		static bool includes(const WString& child, const WString& parent)
 		static bool includes(const WString& child, const WString& parent)
 		{
 		{
-			boost::filesystem3::wpath childPath = child.c_str();
-			boost::filesystem3::wpath parentPath = parent.c_str();
+			Vector<WString>::type childPathElems = split(child);
+			Vector<WString>::type parentPathElems = split(parent);
 
 
-			auto iterChild = childPath.begin();
-			auto iterParent = parentPath.begin();
+			auto iterChild = childPathElems.begin();
+			auto iterParent = parentPathElems.begin();
 
 
-			for(; iterChild != childPath.end(); ++iterChild, ++iterParent)
+			for(; iterParent != parentPathElems.end(); ++iterChild, ++iterParent)
 			{
 			{
-				if(*iterChild != *iterParent)
+				if(!comparePathElements(*iterChild, *iterParent))
 					return false;
 					return false;
 			}
 			}
 
 
 			return true;
 			return true;
 		}
 		}
 
 
+		static Vector<WString>::type split(const WString& path)
+		{
+			Vector<WString>::type splitPath;
+
+			WString standardizedPath = standardisePath(path);
+			return StringUtil::split(standardizedPath, L"/");
+		}
+
 		static WString combine(const WString& base, const WString& name)
 		static WString combine(const WString& base, const WString& name)
 		{
 		{
 			if (base.empty())
 			if (base.empty())
@@ -87,74 +100,78 @@ namespace CamelotFramework
 			return base / name;
 			return base / name;
 		}
 		}
 
 
-		static WPath getFilename(const WPath& path)
-		{
-			return path.filename();
-		}
-
 		/**
 		/**
-		 * @brief	Method for standardizing paths - use forward slashes only, end with slash.
+		 * @brief	Compares two path elements for equality. 
+		 * 			
+		 * @note	Should not be used for comparing entire paths. First you need to split your
+		 * 			path into sub-elements using some other method and then send those sub-elements to
+		 * 			this method. 
 		 */
 		 */
-		static WString standardisePath(const WString& inPath)
+		static bool comparePathElements(const WString& left, const WString& right)
 		{
 		{
-			WString path = inPath;
+			if(left.size() != right.size())
+				return false;
 
 
-			std::replace(path.begin(), path.end(), L'\\', L'/');
-			if(path[path.length() - 1] != L'/')
-				path += L'/';
+			for(UINT32 i = 0; i < (UINT32)left.size(); i++)
+			{
+#if CM_PLATFORM == CM_PLATFORM_WIN32 // Compare case insensitive
+				if(tolower(left[i]) != tolower(right[i]))
+					return false;
+#else
+				assert(false); // Implement case sensitive or insensitive comparison, depending on platform
+#endif
+			}
 
 
-			return path;
+			return true;
 		}
 		}
 
 
 		/**
 		/**
-		 * @brief	Method for splitting a fully qualified filename into the base name and path.
+		 * @see		comparePathElements(const WString&, const WString&)
 		 */
 		 */
-		static void splitFilename(const WString& qualifiedName, WString& outBasename, WString& outPath)
+		static bool comparePathElements(const WPath& left, const WPath& right)
 		{
 		{
-			WString path = qualifiedName;
-			// Replace \ with / first
-			std::replace( path.begin(), path.end(), L'\\', L'/' );
-			// split based on final /
-			size_t i = path.find_last_of(L'/');
+			if(left.native().size() != right.native().size())
+				return false;
 
 
-			if (i == String::npos)
-			{
-				outPath.clear();
-				outBasename = qualifiedName;
-			}
-			else
+			for(UINT32 i = 0; i < (UINT32)left.native().size(); i++)
 			{
 			{
-				outBasename = path.substr(i+1, path.size() - i - 1);
-				outPath = path.substr(0, i+1);
+#if CM_PLATFORM == CM_PLATFORM_WIN32 // Compare case insensitive
+				if(tolower(left.native()[i]) != tolower(right.native()[i]))
+					return false;
+#else
+				assert(false); // Implement case sensitive or insensitive comparison, depending on platform
+#endif
 			}
 			}
+
+			return true;
 		}
 		}
 
 
-		/**
-		 * @brief	Method for splitting a filename into the base name and extension.
-		 */
-		static void splitBaseFilename(const WString& fullName, WString& outBasename, WString& outExtension)
+		static WString getFilename(const WString& path)
 		{
 		{
-			size_t i = fullName.find_last_of(L".");
-			if (i == CamelotFramework::WString::npos)
-			{
-				outExtension.clear();
-				outBasename = fullName;
-			}
-			else
-			{
-				outExtension = fullName.substr(i+1);
-				outBasename = fullName.substr(0, i);
-			}
+			return toWString(toPath(path).filename());
+		}
+
+		static WPath getFilename(const WPath& path)
+		{
+			return path.filename();
 		}
 		}
 
 
 		/**
 		/**
-		 * @brief	Method for splitting a fully qualified filename into the base name, extension and path.
+		 * @brief	Method for standardizing paths - use forward slashes only, end with slash.
 		 */
 		 */
-		static void splitFullFilename(const WString& qualifiedName, WString& outBasename, WString& outExtention, WString& outPath)
+		static WString standardisePath(const WString& inPath)
 		{
 		{
-			WString fullName;
-			splitFilename(qualifiedName, fullName, outPath);
-			splitBaseFilename(fullName, outBasename, outExtention);
+			WString path = inPath;
+
+			std::replace(path.begin(), path.end(), L'\\', L'/');
+
+			if(path.length() > 0)
+			{
+				if(path[path.length() - 1] != L'/')
+					path += L'/';
+			}
+
+			return path;
 		}
 		}
 	};
 	};
 
 

+ 24 - 2
CamelotUtility/Source/CmFileSystem.cpp

@@ -149,12 +149,34 @@ namespace CamelotFramework
 
 
 	void FileSystem::createDir(const WString& fullPath)
 	void FileSystem::createDir(const WString& fullPath)
 	{
 	{
-		create_directory(fullPath.c_str());
+		createDir(WPath(fullPath.c_str()));
 	}
 	}
 
 
 	void FileSystem::createDir(const WPath& fullPath)
 	void FileSystem::createDir(const WPath& fullPath)
 	{
 	{
-		create_directory(fullPath);
+		if(fullPath.empty())
+			return;
+
+		WPath parentPath = fullPath;
+		auto pathEnd = fullPath.end();
+
+		while(!exists(parentPath))
+		{
+			if(pathEnd == fullPath.begin())
+				break;
+
+			parentPath = parentPath.parent_path();
+			pathEnd--;
+		}
+
+		for(; pathEnd != fullPath.end(); ++pathEnd)
+		{
+			create_directory(parentPath);
+
+			parentPath /= *pathEnd;
+		}
+
+		create_directory(parentPath);
 	}
 	}
 
 
 	void FileSystem::getChildren(const WPath& dirPath, Vector<WPath>::type& files, Vector<WPath>::type& directories)
 	void FileSystem::getChildren(const WPath& dirPath, Vector<WPath>::type& files, Vector<WPath>::type& directories)

+ 25 - 23
ProjectLibrary.txt

@@ -1,37 +1,39 @@
 
 
-Today:
- - Fix TreeView issues with expand
-
-Tomorrow:
- - Attempt to add ResourceTreeView to scene (and initialize ProjectLibrary)
- - Project library save/load
- - Figure out how to deal with import queue
- 
- 
- ProjectLibrary
-  - Save/Load - saves/loads the hierarchy of ResourceEntries
+TODO
+ - ResourceManifest filePathToUUID wont work as intended as file-path comparison is case sensitive plus it wont deal with slashes properly
+ - Remove WPath. In general, but specifically from CmPath.h, CmFileSystem.h and Projectlibrary
+ - ResourceTreeView - Element sorting doesn't work
+ - ProjectLibrary Save/Load - saves/loads the hierarchy of ResourceEntries
+    - ResourceManifest needs to store relative locations when I save it, so that user can move Project folder safely
+ - Resource import queue (ability to display progress bar for resources that are importing)
+ - Implement Delete command for ResourceTreeView
 
 
 --------------------
 --------------------
 
 
-Imported resources should get queued. Since I want to display a progress bar with % of resources imported.
- - Plus importers should work on separate threads (Will likely make Resources worker threads global and re-use them for importer)
+Test:
+ - OSDropTarget
+    - Drag and drop one file from Explorer into TreeView
+    - Drag and drop multiple files from Explorer into TreeView
+    - Drag and drop entire folders from Explorer into TreeView
+    - Dragging folders or files from within Resources to another sub-folder in Resources
 
 
--------------------
+ - File monitoring
+    - Add a file and ensure it is imported
+    - Delete a file and ensure it has been cleaned up
+    - Add a whole folder hierarchy with files and see if it is constructed properly
+    - Delete a folder hierarcha and ensure it has been cleaned up
+
+ - Start-up
+     - Load up ProjectLibrary with a complex hierarchy already existing, with multiple files to import
 
 
-TOMORROW:
-mIsVisible seems to get set in updateTreeElement? Which means expanding/closing wont work without it
- - I should probably move those so they are changed whenever mIsExpanded is toggled
- - I might want to move stuff from TreeView::update in general to an event-based system. Only in case of Scene those events would be generated internally.
+ - Save/Load (After it is implemented)
+     - Ensure that leaving application and then reloading will still recognize previously saved assets and will not reimport them
+       - Also ensure that UUIDs will be properly read from .meta files
 
 
-Later: Projectlibrary add (tracking drag and drop using Win32DragAndDropManager)
 -------------------
 -------------------
 
 
 LOW PRIORITY
 LOW PRIORITY
 
 
-ResourceManifest contains absolute file locations. What happens when the project moves?
- - When saving ResourceManifest make sure to process all paths and make them relative.
- - Then reverse that process on load
-
 What happens when importer fails importing a file?
 What happens when importer fails importing a file?
  - This can be one of the lasts steps, but I will likely need to go through all importers manually and set them up so they return proper error codes
  - This can be one of the lasts steps, but I will likely need to go through all importers manually and set them up so they return proper error codes
     and clean up properly on error.
     and clean up properly on error.