ソースを参照

TreeView reparenting

Marko Pintera 12 年 前
コミット
278c8d4803

+ 3 - 0
BansheeEngine/Include/BsGUIScrollArea.h

@@ -29,6 +29,9 @@ namespace BansheeEngine
 		static GUIScrollArea* create(GUIWidget& parent, const GUIOptions& layoutOptions, const GUIElementStyle* scrollBarStyle = nullptr, 
 			const GUIElementStyle* scrollAreaStyle = nullptr);
 
+		void scrollVertical(float pct);
+		void scrollHorizontal(float pct);
+
 		GUILayout& getLayout() const { return *mContentLayout; }
 	protected:
 		~GUIScrollArea();

+ 13 - 3
BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -240,17 +240,27 @@ namespace BansheeEngine
 	}
 
 	void GUIScrollArea::vertScrollUpdate(float scrollPos)
+	{
+		scrollVertical(scrollPos);
+	}
+
+	void GUIScrollArea::horzScrollUpdate(float scrollPos)
+	{
+		scrollHorizontal(scrollPos);
+	}
+
+	void GUIScrollArea::scrollVertical(float pct)
 	{
 		UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentHeight) - INT32(mClippedContentHeight));
-		mVertOffset = scrollableHeight * scrollPos;
+		mVertOffset = scrollableHeight * Math::clamp01(pct);
 
 		markContentAsDirty();
 	}
 
-	void GUIScrollArea::horzScrollUpdate(float scrollPos)
+	void GUIScrollArea::scrollHorizontal(float pct)
 	{
 		UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentWidth) - INT32(mClippedContentWidth));
-		mHorzOffset = scrollableWidth * scrollPos;
+		mHorzOffset = scrollableWidth * Math::clamp01(pct);
 
 		markContentAsDirty();
 	}

+ 2 - 0
CamelotClient/CamelotClient.vcxproj

@@ -256,6 +256,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsCmdEditPlainFieldGO.h" />
+    <ClInclude Include="Include\BsCmdReparentSO.h" />
     <ClInclude Include="Include\BsDockManager.h" />
     <ClInclude Include="Include\BsEditorApplication.h" />
     <ClInclude Include="Include\BsEditorCommand.h" />
@@ -286,6 +287,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="CamelotClient.cpp" />
+    <ClCompile Include="Source\BsCmdReparentSO.cpp" />
     <ClCompile Include="Source\BsDockManager.cpp" />
     <ClCompile Include="Source\BsEditorCommand.cpp" />
     <ClCompile Include="Source\BsEditorGUI.cpp" />

+ 6 - 0
CamelotClient/CamelotClient.vcxproj.filters

@@ -114,6 +114,9 @@
     <ClInclude Include="Include\BsCmdEditPlainFieldGO.h">
       <Filter>Header Files\Editor\Commands</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsCmdReparentSO.h">
+      <Filter>Header Files\Editor\Commands</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
@@ -194,5 +197,8 @@
     <ClCompile Include="Source\BsUndoRedo.cpp">
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsCmdReparentSO.cpp">
+      <Filter>Source Files\Editor\Command</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 26 - 0
CamelotClient/Include/BsCmdReparentSO.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsEditorCommand.h"
+#include "BsUndoRedo.h"
+
+namespace BansheeEditor
+{
+	class CmdReparentSO : public EditorCommand
+	{
+	public:
+		static void execute(const CM::Vector<CM::HSceneObject>::type& sceneObjects, const CM::HSceneObject& newParent);
+
+		void commit();
+		void revert();
+
+	private:
+		friend class UndoRedo;
+
+		CmdReparentSO(const CM::Vector<CM::HSceneObject>::type& sceneObjects, const CM::HSceneObject& newParent);
+
+		CM::Vector<CM::HSceneObject>::type mSceneObjects;
+		CM::Vector<CM::HSceneObject>::type mOldParents;
+		CM::HSceneObject mNewParent;
+	};
+}

+ 52 - 0
CamelotClient/Source/BsCmdReparentSO.cpp

@@ -0,0 +1,52 @@
+#include "BsCmdReparentSO.h"
+#include "CmSceneObject.h"
+
+using namespace BansheeEngine;
+using namespace CamelotFramework;
+
+namespace BansheeEditor
+{
+	CmdReparentSO::CmdReparentSO(const CM::Vector<CM::HSceneObject>::type& sceneObjects, const CM::HSceneObject& newParent)
+		:mSceneObjects(sceneObjects), mNewParent(newParent)
+	{
+		for(auto& sceneObject : mSceneObjects)
+		{
+			mOldParents.push_back(sceneObject->getParent());
+		}
+	}
+
+	void CmdReparentSO::execute(const CM::Vector<CM::HSceneObject>::type& sceneObjects, const CM::HSceneObject& newParent)
+	{
+		// Register command and commit it
+		CmdReparentSO* command = new (cm_alloc<CmdReparentSO>()) CmdReparentSO(sceneObjects, newParent);
+		UndoRedo::instance().registerCommand(command);
+		command->commit();
+	}
+
+	void CmdReparentSO::commit()
+	{
+		if(mNewParent.isDestroyed())
+			return;
+
+		UINT32 cnt = 0;
+		for(auto& sceneObject : mSceneObjects)
+		{
+			if(!sceneObject.isDestroyed())
+				sceneObject->setParent(mNewParent);
+
+			cnt++;
+		}
+	}
+
+	void CmdReparentSO::revert()
+	{
+		UINT32 cnt = 0;
+		for(auto& sceneObject : mSceneObjects)
+		{
+			if(!sceneObject.isDestroyed() && !mOldParents[cnt].isDestroyed())
+				sceneObject->setParent(mOldParents[cnt]);
+
+			cnt++;
+		}
+	}
+}

+ 31 - 3
CamelotClient/Source/BsGUISceneTreeView.cpp

@@ -15,6 +15,7 @@
 #include "CmSceneManager.h"
 #include "BsCmdEditPlainFieldGO.h"
 #include "BsDragAndDropManager.h"
+#include "BsCmdReparentSO.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
@@ -184,7 +185,10 @@ namespace BansheeEditor
 				{
 					Vector<TreeElement*>::type newChildren;
 
-					mTempToDelete.resize(current->mChildren.size(), true);
+					mTempToDelete.resize(current->mChildren.size());
+					for(UINT32 i = 0; i < (UINT32)current->mChildren.size(); i++)
+						mTempToDelete[i] = true;
+
 					for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
 					{
 						HSceneObject currentSOChild = currentSO->getChild(i);
@@ -493,9 +497,33 @@ namespace BansheeEditor
 			if(DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject)
 			{
 				DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
+				const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(event.getPosition());
+
+				TreeElement* treeElement = nullptr;
+				if(element != nullptr)
+				{
+					if(element->isTreeElement())
+						treeElement = interactableToRealElement(*element);
+					else
+						treeElement = element->parent;
+				}
+
+				if(treeElement != nullptr)
+				{
+					Vector<HSceneObject>::type sceneObjects;
+					HSceneObject newParent = treeElement->mSceneObject;
+
+					for(UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
+					{
+						if(draggedSceneObjects->objects[i] != newParent)
+							sceneObjects.push_back(draggedSceneObjects->objects[i]);
+					}
+
+					CmdReparentSO::execute(sceneObjects, newParent);
+				}
+
+				unselectAll();
 
-				// TODO - Actually perform parent change
-				
 				return true;
 			}
 		}

+ 9 - 6
TreeView.txt

@@ -4,17 +4,20 @@ TODO:
     - Will likely need some kind of check to ignore double-clicks?
  - Context menu with rename/copy/paste/duplicate
  - Delete with Undo/Redo support
- - Drag and drop
-   - If a mouse drag is detected DragAndDropManager is activated
-   - Element is not removed from its original position until drag is complete
-   - Dragging over an element will make a highlight box appear around it
-   - Dragging between elements will make a thick line appear between them
-   - Releasing the drag changes the element parents
  - Auto scroll
     - Sliding over top or bottom of the tree view while dragging an element will search GUIElement parents to find a ScrollArea. If it finds one it will attempt to scroll up or down.
  - Support for icons next to tree elements
  - Ability to move selection via arrow keys
 
+Drag and drop problem:
+ - Test it properly
+ If I make three element deep tree
+  A
+  --B
+  ----C
+
+And the move C to have parent A, nothing will happen when I first do it. And when I do it next time element will move properly but a ghost element will remain.
+
 MenuBar problems:
  - Clicking the top menu item closes and immediately opens the menu again (it should only close it)
    - Something similar probably also happens with ListBox