Explorar el Código

GUISceneTreeView elements can be deleted
GUISceneTreeView clicking on empty part of the tree view deselects the elements

Marko Pintera hace 10 años
padre
commit
b5906002ab

+ 0 - 1
BansheeEditor/BansheeEditor.vcxproj

@@ -268,7 +268,6 @@
     <ClInclude Include="Include\BsBuildDataRTTI.h" />
     <ClInclude Include="Include\BsBuildManager.h" />
     <ClInclude Include="Include\BsCmdDeleteSO.h" />
-    <ClInclude Include="Include\BsCmdEditPlainFieldGO.h" />
     <ClInclude Include="Include\BsCmdInputFieldValueChange.h" />
     <ClInclude Include="Include\BsCmdRecordSO.h" />
     <ClInclude Include="Include\BsCmdReparentSO.h" />

+ 0 - 3
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -33,9 +33,6 @@
     <ClInclude Include="Include\BsEditorCommand.h">
       <Filter>Header Files\Commands</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsCmdEditPlainFieldGO.h">
-      <Filter>Header Files\Commands</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsCmdReparentSO.h">
       <Filter>Header Files\Commands</Filter>
     </ClInclude>

+ 4 - 4
BansheeEditor/Include/BsCmdDeleteSO.h

@@ -20,10 +20,10 @@ namespace BansheeEngine
 		 * @brief	Creates and executes the command on the provided scene object.
 		 *			Automatically registers the command with undo/redo system.
 		 *
-		 * @param	inputField	Input field to modify the value on.
-		 * @param	value		New value for the field.
+		 * @param	sceneObject	Scene object to delete.
+		 * @param	description	Optional description of what exactly the command does.
 		 */
-		static void execute(const HSceneObject& sceneObject);
+		static void execute(const HSceneObject& sceneObject, const WString& description = StringUtil::WBLANK);
 
 		/**
 		 * @copydoc	EditorCommand::commit
@@ -38,7 +38,7 @@ namespace BansheeEngine
 	private:
 		friend class UndoRedo;
 
-		CmdDeleteSO(const HSceneObject& sceneObject);
+		CmdDeleteSO(const WString& description, const HSceneObject& sceneObject);
 
 		/**
 		 * @brief	Saves the state of the specified object, all of its children

+ 0 - 102
BansheeEditor/Include/BsCmdEditPlainFieldGO.h

@@ -1,102 +0,0 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsEditorCommand.h"
-#include "BsUndoRedo.h"
-
-namespace BansheeEngine
-{
-	// TODO - This is only valid for plain field types. Add something similar for pointers and/or arrays?
-	/**
-	 * @brief	A command used for undo/redo purposes. It records a value of a single RTTI field and
-	 *			using the provided interface allows you to commit a change to that field, or restore
-	 *			it to the original value.
-	 */
-	template<class T>
-	class CmdEditPlainFieldGO : public EditorCommand
-	{
-	public:
-		~CmdEditPlainFieldGO() 
-		{
-			if(mNewData != nullptr)
-				bs_free(mNewData);
-
-			if(mOldData != nullptr)
-				bs_free(mOldData);
-		}
-
-		/**
-		 * @brief	Creates and executes the command on the provided object and field.
-		 *			Automatically registers the command with undo/redo system.
-		 *
-		 * @param	gameObject	Game object to search for the field.
-		 * @param	fieldName	RTTI name of the field.
-		 * @param	fieldValue	New value for the field.
-		 */
-		static void execute(const GameObjectHandleBase& gameObject, const String& fieldName, const T& fieldValue)
-		{
-			// Register command and commit it
-			CmdEditPlainFieldGO* command = new (bs_alloc<CmdEditPlainFieldGO>()) CmdEditPlainFieldGO(gameObject, fieldName, fieldValue);
-			UndoRedo::instance().registerCommand(command);
-			command->commit();
-		}
-
-		/**
-		 * @copydoc	EditorCommand::commit
-		 */
-		void commit() override
-		{
-			if(mGameObject.isDestroyed())
-				return;
-
-			T fieldValue;
-			RTTIPlainType<T>::fromMemory(fieldValue, (char*)mNewData);
-
-			RTTITypeBase* rtti = mGameObject->getRTTI();
-			rtti->setPlainValue(mGameObject.get(), mFieldName, fieldValue);
-		}
-
-		/**
-		 * @copydoc	EditorCommand::revert
-		 */
-		void revert() override
-		{
-			if(mGameObject.isDestroyed())
-				return;
-
-			T fieldValue;
-			RTTIPlainType<T>::fromMemory(fieldValue, (char*)mOldData);
-
-			RTTITypeBase* rtti = mGameObject->getRTTI();
-			rtti->setPlainValue(mGameObject.get(), mFieldName, fieldValue);
-		}
-
-	private:
-		friend class UndoRedo;
-
-		CmdEditPlainFieldGO(const GameObjectHandleBase& gameObject, const String& fieldName, const T& fieldValue)
-			:mGameObject(gameObject), mFieldName(fieldName), mNewData(nullptr), mOldData(nullptr)
-		{
-			// Convert new value to bytes
-			UINT32 newDataNumBytes = RTTIPlainType<T>::getDynamicSize(fieldValue);
-			mNewData = bs_alloc(newDataNumBytes);
-
-			RTTIPlainType<T>::toMemory(fieldValue, (char*)mNewData);
-
-			// Get old value and also convert it to bytes
-			String oldFieldValue;
-			gameObject->getRTTI()->getPlainValue(gameObject.get(), fieldName, oldFieldValue);
-
-			UINT32 oldDataNumBytes = RTTIPlainType<T>::getDynamicSize(oldFieldValue);
-			mOldData = bs_alloc(oldDataNumBytes);
-
-			RTTIPlainType<T>::toMemory(oldFieldValue, (char*)mOldData);
-		}
-
-		GameObjectHandleBase mGameObject;
-		String mFieldName;
-
-		void* mNewData;
-		void* mOldData;
-	};
-}

+ 5 - 4
BansheeEditor/Include/BsCmdInputFieldValueChange.h

@@ -21,10 +21,11 @@ namespace BansheeEngine
 		 *
 		 * @param	inputField	Input field to modify the value on.
 		 * @param	value		New value for the field.
+		 * @param	description	Optional description of what exactly the command does.
 		 */
-		static void execute(InputFieldType* inputField, const ValueType& value)
+		static void execute(InputFieldType* inputField, const ValueType& value, const WString& description = StringUtil::WBLANK)
 		{
-			CmdInputFieldValueChange* command = new (bs_alloc<CmdInputFieldValueChange>()) CmdInputFieldValueChange(inputField, value);
+			CmdInputFieldValueChange* command = new (bs_alloc<CmdInputFieldValueChange>()) CmdInputFieldValueChange(description, inputField, value);
 			UndoRedo::instance().registerCommand(command);
 			command->commit();
 		}
@@ -48,8 +49,8 @@ namespace BansheeEngine
 	private:
 		friend class UndoRedo;
 
-		CmdInputFieldValueChange(InputFieldType* inputField, const ValueType& value)
-			:mInputField(inputField), mOldValue(inputField->getValue()), mNewValue(value)
+		CmdInputFieldValueChange(const WString& description, InputFieldType* inputField, const ValueType& value)
+			:EditorCommand(description), mInputField(inputField), mOldValue(inputField->getValue()), mNewValue(value)
 		{ }
 
 		ValueType mOldValue;

+ 4 - 4
BansheeEditor/Include/BsCmdRecordSO.h

@@ -21,10 +21,10 @@ namespace BansheeEngine
 		 * @brief	Creates and executes the command on the provided scene object.
 		 *			Automatically registers the command with undo/redo system.
 		 *
-		 * @param	inputField	Input field to modify the value on.
-		 * @param	value		New value for the field.
+		 * @param	sceneObject	Scene object to record.
+		 * @param	description	Optional description of what exactly the command does.
 		 */
-		static void execute(const HSceneObject& sceneObject);
+		static void execute(const HSceneObject& sceneObject, const WString& description = StringUtil::WBLANK);
 
 		/**
 		 * @copydoc	EditorCommand::commit
@@ -39,7 +39,7 @@ namespace BansheeEngine
 	private:
 		friend class UndoRedo;
 
-		CmdRecordSO(const HSceneObject& sceneObject);
+		CmdRecordSO(const WString& description, const HSceneObject& sceneObject);
 
 		/**
 		 * @brief	Saves the state of the specified object, all of its children

+ 4 - 2
BansheeEditor/Include/BsCmdReparentSO.h

@@ -20,8 +20,10 @@ namespace BansheeEngine
 		 *
 		 * @param	sceneObjects	Object(s) to change the parent for.
 		 * @param	newParent		New parent for the provided objects.
+		 * @param	description		Optional description of what exactly the command does.
 		 */
-		static void execute(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent);
+		static void execute(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent, 
+			const WString& description = StringUtil::WBLANK);
 
 		/**
 		 * @copydoc	EditorCommand::commit
@@ -36,7 +38,7 @@ namespace BansheeEngine
 	private:
 		friend class UndoRedo;
 
-		CmdReparentSO(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent);
+		CmdReparentSO(const WString& description, const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent);
 
 		Vector<HSceneObject> mSceneObjects;
 		Vector<HSceneObject> mOldParents;

+ 5 - 1
BansheeEditor/Include/BsEditorCommand.h

@@ -11,10 +11,11 @@ namespace BansheeEngine
 	class EditorCommand
 	{
 	public:
+		EditorCommand(const WString& description);
 		virtual ~EditorCommand() { }
 
 		/**
-		 * @brief	Applies the command, commiting the change.
+		 * @brief	Applies the command, committing the change.
 		 */
 		virtual void commit() { }
 
@@ -28,5 +29,8 @@ namespace BansheeEngine
 		 * @brief	Deletes the command.
 		 */
 		static void destroy(EditorCommand* command);
+
+	private:
+		WString mDescription;
 	};
 }

+ 5 - 4
BansheeEditor/Source/BsCmdDeleteSO.cpp

@@ -5,8 +5,9 @@
 
 namespace BansheeEngine
 {
-	CmdDeleteSO::CmdDeleteSO(const HSceneObject& sceneObject)
-		:mSceneObject(sceneObject), mSerializedObject(nullptr), mSerializedObjectParentId(0), mSerializedObjectSize(0)
+	CmdDeleteSO::CmdDeleteSO(const WString& description, const HSceneObject& sceneObject)
+		:EditorCommand(description), mSceneObject(sceneObject), mSerializedObject(nullptr), 
+		mSerializedObjectParentId(0), mSerializedObjectSize(0)
 	{
 
 	}
@@ -29,10 +30,10 @@ namespace BansheeEngine
 		}
 	}
 
-	void CmdDeleteSO::execute(const HSceneObject& sceneObject)
+	void CmdDeleteSO::execute(const HSceneObject& sceneObject, const WString& description)
 	{
 		// Register command and commit it
-		CmdDeleteSO* command = new (bs_alloc<CmdDeleteSO>()) CmdDeleteSO(sceneObject);
+		CmdDeleteSO* command = new (bs_alloc<CmdDeleteSO>()) CmdDeleteSO(description, sceneObject);
 		UndoRedo::instance().registerCommand(command);
 		command->commit();
 	}

+ 4 - 4
BansheeEditor/Source/BsCmdRecordSO.cpp

@@ -5,8 +5,8 @@
 
 namespace BansheeEngine
 {
-	CmdRecordSO::CmdRecordSO(const HSceneObject& sceneObject)
-		:mSceneObject(sceneObject), mSerializedObject(nullptr), mSerializedObjectParentId(0), mSerializedObjectSize(0)
+	CmdRecordSO::CmdRecordSO(const WString& description, const HSceneObject& sceneObject)
+		:EditorCommand(description), mSceneObject(sceneObject), mSerializedObject(nullptr), mSerializedObjectParentId(0), mSerializedObjectSize(0)
 	{
 
 	}
@@ -29,10 +29,10 @@ namespace BansheeEngine
 		}
 	}
 
-	void CmdRecordSO::execute(const HSceneObject& sceneObject)
+	void CmdRecordSO::execute(const HSceneObject& sceneObject, const WString& description)
 	{
 		// Register command and commit it
-		CmdRecordSO* command = new (bs_alloc<CmdRecordSO>()) CmdRecordSO(sceneObject);
+		CmdRecordSO* command = new (bs_alloc<CmdRecordSO>()) CmdRecordSO(description, sceneObject);
 		UndoRedo::instance().registerCommand(command);
 		command->commit();
 	}

+ 5 - 4
BansheeEditor/Source/BsCmdReparentSO.cpp

@@ -3,8 +3,8 @@
 
 namespace BansheeEngine
 {
-	CmdReparentSO::CmdReparentSO(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent)
-		:mSceneObjects(sceneObjects), mNewParent(newParent)
+	CmdReparentSO::CmdReparentSO(const WString& description, const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent)
+		:EditorCommand(description), mSceneObjects(sceneObjects), mNewParent(newParent)
 	{
 		for(auto& sceneObject : mSceneObjects)
 		{
@@ -12,10 +12,11 @@ namespace BansheeEngine
 		}
 	}
 
-	void CmdReparentSO::execute(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent)
+	void CmdReparentSO::execute(const Vector<HSceneObject>& sceneObjects, const HSceneObject& newParent,
+		const WString& description)
 	{
 		// Register command and commit it
-		CmdReparentSO* command = new (bs_alloc<CmdReparentSO>()) CmdReparentSO(sceneObjects, newParent);
+		CmdReparentSO* command = new (bs_alloc<CmdReparentSO>()) CmdReparentSO(description, sceneObjects, newParent);
 		UndoRedo::instance().registerCommand(command);
 		command->commit();
 	}

+ 4 - 0
BansheeEditor/Source/BsEditorCommand.cpp

@@ -2,6 +2,10 @@
 
 namespace BansheeEngine
 {
+	EditorCommand::EditorCommand(const WString& description)
+		:mDescription(description)
+	{ }
+
 	void EditorCommand::destroy(EditorCommand* command)
 	{
 		bs_delete(command);

+ 2 - 0
BansheeEditor/Source/BsEditorTestSuite.cpp

@@ -454,6 +454,7 @@ namespace BansheeEngine
 
 		CmdRecordSO::execute(so0_0);
 		cmpB1_1->val1 = "ModifiedValue";
+		so0_0->setName("modified");
 		UndoRedo::instance().undo();
 
 		BS_TEST_ASSERT(!so0_0.isDestroyed());
@@ -468,6 +469,7 @@ namespace BansheeEngine
 		BS_TEST_ASSERT(!cmpExternal->ref1.isDestroyed());
 		BS_TEST_ASSERT(!cmpExternal->ref2.isDestroyed());
 		BS_TEST_ASSERT(cmpB1_1->val1 == "InitialValue");
+		BS_TEST_ASSERT(so0_0->getName() == "so0_0");
 
 		so0_0->destroy();
 	}

+ 11 - 4
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -2,9 +2,10 @@
 #include "BsSceneObject.h"
 #include "BsSceneManager.h"
 #include "BsGUISkin.h"
-#include "BsCmdEditPlainFieldGO.h"
-#include "BsDragAndDropManager.h"
+#include "BsCmdRecordSO.h"
 #include "BsCmdReparentSO.h"
+#include "BsCmdDeleteSO.h"
+#include "BsDragAndDropManager.h"
 #include "BsSelection.h"
 #include "BsGUIResourceTreeView.h"
 #include "BsProjectLibrary.h"
@@ -215,12 +216,18 @@ namespace BansheeEngine
 	void GUISceneTreeView::renameTreeElement(GUITreeView::TreeElement* element, const WString& name)
 	{
 		SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(element);
-		CmdEditPlainFieldGO<String>::execute(sceneTreeElement->mSceneObject, "mName", toString(name));
+
+		HSceneObject so = sceneTreeElement->mSceneObject;
+		CmdRecordSO::execute(so, L"Renamed \"" + toWString(so->getName()) + L"\"");
+		so->setName("mName");
 	}
 
 	void GUISceneTreeView::deleteTreeElement(TreeElement* element)
 	{
-		// TODO - Actually delete the scene object
+		SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(element);
+
+		HSceneObject so = sceneTreeElement->mSceneObject;
+		CmdDeleteSO::execute(so, L"Deleted \"" + toWString(so->getName()) + L"\"");
 	}
 
 	void GUISceneTreeView::deleteTreeElementInternal(GUITreeView::TreeElement* element)

+ 58 - 49
BansheeEditor/Source/BsGUITreeView.cpp

@@ -207,80 +207,89 @@ namespace BansheeEngine
 				treeElement = element->getTreeElement();
 			}
 
-			if(treeElement != nullptr && event.getPosition().x >= treeElement->mElement->_getLayoutData().area.x)
+			if (treeElement != nullptr)
 			{
-				if(event.isCtrlDown())
+				if (event.getPosition().x >= treeElement->mElement->_getLayoutData().area.x)
 				{
-					selectElement(treeElement);
-				}
-				else if(event.isShiftDown())
-				{
-					if(isSelectionActive())
+					if (event.isCtrlDown())
 					{
-						TreeElement* selectionRoot = mSelectedElements[0].element;
-						unselectAll();
-
-						auto iterStartFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
-							[&] (const InteractableElement& x) { return x.parent == selectionRoot->mParent; } );
-
-						bool foundStart = false;
-						bool foundEnd = false;
-						for(; iterStartFind != mVisibleElements.end(); ++iterStartFind)
+						selectElement(treeElement);
+					}
+					else if (event.isShiftDown())
+					{
+						if (isSelectionActive())
 						{
-							if(!iterStartFind->isTreeElement())
-								continue;
+							TreeElement* selectionRoot = mSelectedElements[0].element;
+							unselectAll();
+
+							auto iterStartFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
+								[&](const InteractableElement& x) { return x.parent == selectionRoot->mParent; });
 
-							TreeElement* curElem = iterStartFind->getTreeElement();
-							if(curElem == selectionRoot)
+							bool foundStart = false;
+							bool foundEnd = false;
+							for (; iterStartFind != mVisibleElements.end(); ++iterStartFind)
 							{
-								foundStart = true;
-								break;
+								if (!iterStartFind->isTreeElement())
+									continue;
+
+								TreeElement* curElem = iterStartFind->getTreeElement();
+								if (curElem == selectionRoot)
+								{
+									foundStart = true;
+									break;
+								}
 							}
-						}
 
-						auto iterEndFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
-							[&] (const InteractableElement& x) { return &x == element; } );
+							auto iterEndFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
+								[&](const InteractableElement& x) { return &x == element; });
 
-						if(iterEndFind != mVisibleElements.end())
-							foundEnd = true;
+							if (iterEndFind != mVisibleElements.end())
+								foundEnd = true;
 
-						if(foundStart && foundEnd)
-						{
-							if(iterStartFind < iterEndFind)
+							if (foundStart && foundEnd)
 							{
-								for(;iterStartFind != (iterEndFind + 1); ++iterStartFind)
+								if (iterStartFind < iterEndFind)
 								{
-									if(iterStartFind->isTreeElement())
-										selectElement(iterStartFind->getTreeElement());
+									for (; iterStartFind != (iterEndFind + 1); ++iterStartFind)
+									{
+										if (iterStartFind->isTreeElement())
+											selectElement(iterStartFind->getTreeElement());
+									}
 								}
-							}
-							else if(iterEndFind < iterStartFind)
-							{
-								for(;iterEndFind != (iterStartFind + 1); ++iterEndFind)
+								else if (iterEndFind < iterStartFind)
 								{
-									if(iterEndFind->isTreeElement())
-										selectElement(iterEndFind->getTreeElement());
+									for (; iterEndFind != (iterStartFind + 1); ++iterEndFind)
+									{
+										if (iterEndFind->isTreeElement())
+											selectElement(iterEndFind->getTreeElement());
+									}
 								}
+								else
+									selectElement(treeElement);
 							}
-							else
+
+							if (!foundStart || !foundEnd)
 								selectElement(treeElement);
 						}
-
-						if(!foundStart || !foundEnd)
+						else
+						{
 							selectElement(treeElement);
+						}
 					}
 					else
 					{
+						unselectAll();
 						selectElement(treeElement);
 					}
-				}
-				else
-				{
-					unselectAll();
-					selectElement(treeElement);
-				}
 
-				_markLayoutAsDirty();
+					_markLayoutAsDirty();
+
+					return true;
+				}
+			}
+			else
+			{
+				unselectAll();
 
 				return true;
 			}

+ 3 - 0
TODO.txt

@@ -60,6 +60,9 @@ SceneTreeView
   - Delete + rename should be undoable
  - ELement cant be deselected by clicking on empty space
  - Clicking on an already selected element should start rename
+ - Also add context with "New SceneObject" & "New SceneObject (Child)"
+ - ping() method (scrolls to element and displays a bg for it until user clicks elsewhere)
+ - Elements in SceneTreeView aren't ordered properly
 
 Ribek use:
  - Camera, Renderable, Material, Texture inspector