Browse Source

Feature: Added a way to retrieve and set expand/collapse state of the scene hierarchy view

BearishSun 6 years ago
parent
commit
ec9bc3160e

+ 43 - 0
Source/EditorCore/GUI/BsGUISceneTreeView.cpp

@@ -611,6 +611,49 @@ namespace bs
 		_markLayoutAsDirty();
 	}
 
+	SPtr<SceneTreeViewState> GUISceneTreeView::getState() const
+	{
+		const TreeElement* root = &mRootElement;
+
+		SPtr<SceneTreeViewState> state;
+		recurse(static_cast<SceneTreeElement*>(const_cast<TreeElement*>(root)), [state](SceneTreeElement* element)
+		{
+			if(!element->mSceneObject.isDestroyed())
+				state->elements.emplace_back(element->mSceneObject, element->mIsExpanded);
+		});
+
+		return state;
+	}
+
+	void GUISceneTreeView::setState(const SPtr<SceneTreeViewState>& state)
+	{
+		UnorderedMap<UINT64, bool> lookup;
+		for(auto& entry : state->elements)
+		{
+			if(entry.sceneObject.isDestroyed())
+				continue;
+
+			lookup[entry.sceneObject->getInstanceId()] = entry.isExpanded;
+		}
+
+		recurse(static_cast<SceneTreeElement*>(&mRootElement), [this, &lookup](SceneTreeElement* element)
+		{
+			if(element->mSceneObject.isDestroyed())
+				return;
+
+			UINT64 instanceId = element->mSceneObject->getInstanceId();
+
+			auto iterFind = lookup.find(instanceId);
+			if(iterFind != lookup.end())
+			{
+				if(iterFind->second)
+					expandElement(element);
+				else
+					collapseElement(element);
+			}
+		});
+	}
+
 	void GUISceneTreeView::createNewSO()
 	{
 		HSceneObject newSO = CmdCreateSO::execute("New", 0, "Created a new SceneObject");

+ 33 - 0
Source/EditorCore/GUI/BsGUISceneTreeView.h

@@ -23,6 +23,20 @@ namespace bs
 		HSceneObject* objects;
 	};
 
+	/** Information about a single element in GUISceneTreeView. */
+	struct BS_SCRIPT_EXPORT(pl:true,api:bed) SceneTreeViewElement
+	{
+		HSceneObject sceneObject;
+		bool isExpanded;
+	};
+
+	/** Information about all elements displayed in a GUISceneTreeView. */
+	struct BS_SCRIPT_EXPORT(api:bed) SceneTreeViewState
+	{
+		BS_SCRIPT_EXPORT()
+		Vector<SceneTreeViewElement> elements;
+	};
+
 	/** GUI element that displays all SceneObject%s in the current scene in the active project in a tree view. */
 	class BS_ED_EXPORT GUISceneTreeView : public GUITreeView
 	{
@@ -103,6 +117,12 @@ namespace bs
 		/** @copydoc GUITreeView::paste */
 		void paste() override;
 
+		/** Returns the expand/collapse state of the elements in the tree view, allowing it to be restored later. */
+		SPtr<SceneTreeViewState> getState() const;
+
+		/** Sets the expand/collapse state of the elements in the tree view. */
+		void setState(const SPtr<SceneTreeViewState>& state);
+
 		/** Triggered whenever the selection changes. Call getSelection() to retrieve new selection. */
 		Event<void()> onSelectionChanged; 
 
@@ -182,6 +202,19 @@ namespace bs
 		/**	Removes all elements from the list used for copy/cut operations. */
 		void clearCopyList();
 
+		/** Iterates over the tree element hierarchy, starting with the provided element and calls @p predicate. */
+		template<class T>
+		void recurse(SceneTreeElement* element, T predicate) const
+		{
+			predicate(element);
+
+			for(UINT32 j = 0; j < element->mChildren.size(); j++)
+			{
+				SceneTreeElement* currentChild = static_cast<SceneTreeElement*>(element->mChildren[j]);
+				recurse(element, predicate);
+			}
+		}
+
 		/**
 		 * Cleans duplicate objects from the provided scene object list. This involves removing child elements if their
 		 * parents are already part of the list.

+ 15 - 0
Source/EditorManaged/GUI/GUISceneTreeView.cs

@@ -17,6 +17,15 @@ namespace bs.Editor
     /// </summary>
     public sealed class GUISceneTreeView : GUIElement
     {
+        /// <summary>
+        /// State of the tree view, containing the expand/collapse state of all the elements in the view.
+        /// </summary>
+        public SceneTreeViewState State
+        {
+            get { return Internal_GetState(mCachedPtr); }
+            set { Internal_SetState(mCachedPtr, value);}
+        }
+
         /// <summary>
         /// Creates a new scene tree view element.
         /// </summary>
@@ -180,6 +189,12 @@ namespace bs.Editor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_RenameSelection(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneTreeViewState Internal_GetState(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetState(IntPtr thisPtr, SceneTreeViewState state);
     }
 
     /** @} */

+ 17 - 0
Source/EditorManaged/Generated/SceneTreeViewElement.generated.cs

@@ -0,0 +1,17 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using bs;
+
+namespace bs.Editor
+{
+	/// <summary>Information about a single element in GUISceneTreeView.</summary>
+	[StructLayout(LayoutKind.Sequential), SerializeObject]
+	public partial struct SceneTreeViewElement
+	{
+		public SceneObject sceneObject;
+		public bool isExpanded;
+	}
+}

+ 30 - 0
Source/EditorManaged/Generated/SceneTreeViewState.generated.cs

@@ -0,0 +1,30 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using bs;
+
+namespace bs.Editor
+{
+	/// <summary>Information about all elements displayed in a GUISceneTreeView.</summary>
+	[ShowInInspector]
+	public partial class SceneTreeViewState : ScriptObject
+	{
+		private SceneTreeViewState(bool __dummy0) { }
+		protected SceneTreeViewState() { }
+
+		[ShowInInspector]
+		[NativeWrapper]
+		public SceneTreeViewElement[] Elements
+		{
+			get { return Internal_getelements(mCachedPtr); }
+			set { Internal_setelements(mCachedPtr, value); }
+		}
+
+		[MethodImpl(MethodImplOptions.InternalCall)]
+		private static extern SceneTreeViewElement[] Internal_getelements(IntPtr thisPtr);
+		[MethodImpl(MethodImplOptions.InternalCall)]
+		private static extern void Internal_setelements(IntPtr thisPtr, SceneTreeViewElement[] value);
+	}
+}

+ 61 - 0
Source/EditorScript/Generated/BsScriptSceneTreeViewElement.generated.cpp

@@ -0,0 +1,61 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+#include "BsScriptSceneTreeViewElement.generated.h"
+#include "BsMonoMethod.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+#include "BsScriptGameObjectManager.h"
+#include "Scene/BsSceneObject.h"
+#include "Wrappers/BsScriptSceneObject.h"
+
+namespace bs
+{
+	ScriptSceneTreeViewElement::ScriptSceneTreeViewElement(MonoObject* managedInstance)
+		:ScriptObject(managedInstance)
+	{ }
+
+	void ScriptSceneTreeViewElement::initRuntimeData()
+	{ }
+
+	MonoObject*ScriptSceneTreeViewElement::box(const __SceneTreeViewElementInterop& value)
+	{
+		return MonoUtil::box(metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	__SceneTreeViewElementInterop ScriptSceneTreeViewElement::unbox(MonoObject* value)
+	{
+		return *(__SceneTreeViewElementInterop*)MonoUtil::unbox(value);
+	}
+
+	SceneTreeViewElement ScriptSceneTreeViewElement::fromInterop(const __SceneTreeViewElementInterop& value)
+	{
+		SceneTreeViewElement output;
+		GameObjectHandle<SceneObject> tmpsceneObject;
+		ScriptSceneObject* scriptsceneObject;
+		scriptsceneObject = ScriptSceneObject::toNative(value.sceneObject);
+		if(scriptsceneObject != nullptr)
+			tmpsceneObject = scriptsceneObject->getHandle();
+		output.sceneObject = tmpsceneObject;
+		output.isExpanded = value.isExpanded;
+
+		return output;
+	}
+
+	__SceneTreeViewElementInterop ScriptSceneTreeViewElement::toInterop(const SceneTreeViewElement& value)
+	{
+		__SceneTreeViewElementInterop output;
+		ScriptSceneObject* scriptsceneObject = nullptr;
+		if(value.sceneObject)
+		scriptsceneObject = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(value.sceneObject);
+		MonoObject* tmpsceneObject;
+		if(scriptsceneObject != nullptr)
+			tmpsceneObject = scriptsceneObject->getManagedInstance();
+		else
+			tmpsceneObject = nullptr;
+		output.sceneObject = tmpsceneObject;
+		output.isExpanded = value.isExpanded;
+
+		return output;
+	}
+
+}

+ 31 - 0
Source/EditorScript/Generated/BsScriptSceneTreeViewElement.generated.h

@@ -0,0 +1,31 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+#include "../../EditorCore/GUI/BsGUISceneTreeView.h"
+
+namespace bs
+{
+	struct __SceneTreeViewElementInterop
+	{
+		MonoObject* sceneObject;
+		bool isExpanded;
+	};
+
+	class BS_SCR_BED_EXPORT ScriptSceneTreeViewElement : public ScriptObject<ScriptSceneTreeViewElement>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, EDITOR_NS, "SceneTreeViewElement")
+
+		static MonoObject* box(const __SceneTreeViewElementInterop& value);
+		static __SceneTreeViewElementInterop unbox(MonoObject* value);
+		static SceneTreeViewElement fromInterop(const __SceneTreeViewElementInterop& value);
+		static __SceneTreeViewElementInterop toInterop(const SceneTreeViewElement& value);
+
+	private:
+		ScriptSceneTreeViewElement(MonoObject* managedInstance);
+
+	};
+}

+ 67 - 0
Source/EditorScript/Generated/BsScriptSceneTreeViewState.generated.cpp

@@ -0,0 +1,67 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+#include "BsScriptSceneTreeViewState.generated.h"
+#include "BsMonoMethod.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+#include "../../EditorCore/GUI/BsGUISceneTreeView.h"
+#include "BsScriptSceneTreeViewElement.generated.h"
+
+namespace bs
+{
+	ScriptSceneTreeViewState::ScriptSceneTreeViewState(MonoObject* managedInstance, const SPtr<SceneTreeViewState>& value)
+		:ScriptObject(managedInstance), mInternal(value)
+	{
+	}
+
+	void ScriptSceneTreeViewState::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_getelements", (void*)&ScriptSceneTreeViewState::Internal_getelements);
+		metaData.scriptClass->addInternalCall("Internal_setelements", (void*)&ScriptSceneTreeViewState::Internal_setelements);
+
+	}
+
+	MonoObject* ScriptSceneTreeViewState::create(const SPtr<SceneTreeViewState>& value)
+	{
+		if(value == nullptr) return nullptr; 
+
+		bool dummy = false;
+		void* ctorParams[1] = { &dummy };
+
+		MonoObject* managedInstance = metaData.scriptClass->createInstance("bool", ctorParams);
+		new (bs_alloc<ScriptSceneTreeViewState>()) ScriptSceneTreeViewState(managedInstance, value);
+		return managedInstance;
+	}
+	MonoArray* ScriptSceneTreeViewState::Internal_getelements(ScriptSceneTreeViewState* thisPtr)
+	{
+		Vector<SceneTreeViewElement> vec__output;
+		vec__output = thisPtr->getInternal()->elements;
+
+		MonoArray* __output;
+		int arraySize__output = (int)vec__output.size();
+		ScriptArray array__output = ScriptArray::create<ScriptSceneTreeViewElement>(arraySize__output);
+		for(int i = 0; i < arraySize__output; i++)
+		{
+			array__output.set(i, ScriptSceneTreeViewElement::toInterop(vec__output[i]));
+		}
+		__output = array__output.getInternal();
+
+		return __output;
+	}
+
+	void ScriptSceneTreeViewState::Internal_setelements(ScriptSceneTreeViewState* thisPtr, MonoArray* value)
+	{
+		Vector<SceneTreeViewElement> vecvalue;
+		if(value != nullptr)
+		{
+			ScriptArray arrayvalue(value);
+			vecvalue.resize(arrayvalue.size());
+			for(int i = 0; i < (int)arrayvalue.size(); i++)
+			{
+				vecvalue[i] = ScriptSceneTreeViewElement::fromInterop(arrayvalue.get<__SceneTreeViewElementInterop>(i));
+			}
+
+		}
+		thisPtr->getInternal()->elements = vecvalue;
+	}
+}

+ 30 - 0
Source/EditorScript/Generated/BsScriptSceneTreeViewState.generated.h

@@ -0,0 +1,30 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//************** Copyright (c) 2016-2019 Marko Pintera ([email protected]). All rights reserved. *******************//
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+#include "../../EditorCore/GUI/BsGUISceneTreeView.h"
+
+namespace bs
+{
+	struct SceneTreeViewState;
+	struct __SceneTreeViewElementInterop;
+
+	class BS_SCR_BED_EXPORT ScriptSceneTreeViewState : public ScriptObject<ScriptSceneTreeViewState>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, EDITOR_NS, "SceneTreeViewState")
+
+		ScriptSceneTreeViewState(MonoObject* managedInstance, const SPtr<SceneTreeViewState>& value);
+
+		SPtr<SceneTreeViewState> getInternal() const { return mInternal; }
+		static MonoObject* create(const SPtr<SceneTreeViewState>& value);
+
+	private:
+		SPtr<SceneTreeViewState> mInternal;
+
+		static MonoArray* Internal_getelements(ScriptSceneTreeViewState* thisPtr);
+		static void Internal_setelements(ScriptSceneTreeViewState* thisPtr, MonoArray* value);
+	};
+}

+ 27 - 0
Source/EditorScript/Wrappers/GUI/BsScriptGUISceneTreeView.cpp

@@ -11,6 +11,8 @@
 #include "BsScriptGameObjectManager.h"
 #include "Wrappers/BsScriptSceneObject.h"
 
+#include "Generated/BsScriptSceneTreeViewState.generated.h"
+
 using namespace std::placeholders;
 
 namespace bs
@@ -42,6 +44,8 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_DuplicateSelection", (void*)&ScriptGUISceneTreeView::internal_duplicateSelection);
 		metaData.scriptClass->addInternalCall("Internal_DeleteSelection", (void*)&ScriptGUISceneTreeView::internal_deleteSelection);
 		metaData.scriptClass->addInternalCall("Internal_RenameSelection", (void*)&ScriptGUISceneTreeView::internal_renameSelection);
+		metaData.scriptClass->addInternalCall("Internal_GetState", (void*)&ScriptGUISceneTreeView::internal_getState);
+		metaData.scriptClass->addInternalCall("Internal_SetState", (void*)&ScriptGUISceneTreeView::internal_setState);
 
 		onModifiedThunk = (OnModifiedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnModified", 0)->getThunk();
 		onResourceDroppedThunk = (OnResourceDroppedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnResourceDropped", 2)->getThunk();
@@ -129,4 +133,27 @@ namespace bs
 		GUISceneTreeView* treeView = static_cast<GUISceneTreeView*>(thisPtr->getGUIElement());
 		treeView->renameSelected();
 	}
+
+	MonoObject* ScriptGUISceneTreeView::internal_getState(ScriptGUISceneTreeView* thisPtr)
+	{
+		GUISceneTreeView* treeView = static_cast<GUISceneTreeView*>(thisPtr->getGUIElement());
+		return ScriptSceneTreeViewState::create(treeView->getState());
+	}
+
+	void ScriptGUISceneTreeView::internal_setState(ScriptGUISceneTreeView* thisPtr, MonoObject* obj)
+	{
+		SPtr<SceneTreeViewState> state;
+		if(obj)
+		{
+			ScriptSceneTreeViewState* scriptState = ScriptSceneTreeViewState::toNative(obj);
+			if(scriptState)
+				state = scriptState->getInternal();
+		}
+
+		if(state)
+		{
+			GUISceneTreeView* treeView = static_cast<GUISceneTreeView*>(thisPtr->getGUIElement());
+			treeView->setState(state);
+		}
+	}
 }

+ 2 - 0
Source/EditorScript/Wrappers/GUI/BsScriptGUISceneTreeView.h

@@ -41,6 +41,8 @@ namespace bs
 		static void internal_duplicateSelection(ScriptGUISceneTreeView* thisPtr);
 		static void internal_deleteSelection(ScriptGUISceneTreeView* thisPtr);
 		static void internal_renameSelection(ScriptGUISceneTreeView* thisPtr);
+		static MonoObject* internal_getState(ScriptGUISceneTreeView* thisPtr);
+		static void internal_setState(ScriptGUISceneTreeView* thisPtr, MonoObject* obj);
 
 		typedef void(BS_THUNKCALL *OnModifiedThunkDef) (MonoObject*, MonoException**);
 		typedef void(BS_THUNKCALL *OnResourceDroppedThunkDef) (MonoObject*, MonoObject*, MonoArray*, MonoException**);