瀏覽代碼

Feature: OnSelectionChanged attribute for specifying per-component callbacks when editor selection changes

BearishSun 7 年之前
父節點
當前提交
1afb21dbab

+ 17 - 3
Source/EditorCore/Scene/BsSelection.h

@@ -55,6 +55,18 @@ namespace bs
 		 */
 		void ping(const Path& resourcePath);
 
+		/** Triggered when one or multiple scene objects is being added to the selection. */
+		Event<void(const Vector<HSceneObject>&)> onSceneObjectsAdded;
+
+		/** Triggered when one or multiple resources are being added to the selection. */
+		Event<void(const Vector<Path>&)> onResourcesAdded;
+
+		/** Triggered when one or multiple scene objects is being removed from the selection. */
+		Event<void(const Vector<HSceneObject>&)> onSceneObjectsRemoved;
+
+		/** Triggered when one or multiple resources are being removed from the selection. */
+		Event<void(const Vector<Path>&)> onResourcesRemoved;
+
 		/**
 		 * Triggered whenever scene object or resource selection changes. The provided parameters will contain the newly
 		 * selected objects/resource paths.
@@ -82,8 +94,8 @@ namespace bs
 		/**	Updates scene and resource tree views with new selection. */
 		void updateTreeViews();
 
-		/** Removes any destroyed scene objects from the selected scene object list. */
-		void pruneDestroyedSceneObjects() const;
+		/** Removes any destroyed scene objects from the provided scene object list. */
+		void pruneDestroyedSceneObjects(Vector<HSceneObject>& sceneObjects) const;
 
 		mutable Vector<HSceneObject> mSelectedSceneObjects;
 		Vector<Path> mSelectedResourcePaths;
@@ -91,7 +103,9 @@ namespace bs
 		HMessage mSceneSelectionChangedConn;
 		HMessage mResourceSelectionChangedConn;
 
-		mutable Vector<HSceneObject> mTempSO;
+		mutable Vector<HSceneObject> mTempPrune;
+		mutable Vector<HSceneObject> mTempSceneObjects;
+		mutable Vector<Path> mTempResources;
 	};
 
 	/** @} */

+ 59 - 25
Source/EditorCore/SceneView/BsSelection.cpp

@@ -9,6 +9,26 @@
 
 namespace bs
 {
+	template<class T>
+	void setDifference(const Vector<T>& a, const Vector<T>& b, Vector<T>& output)
+	{
+		for(auto& aEntry : a)
+		{
+			bool found = false;
+			for(auto& bEntry : b)
+			{
+				if(aEntry == bEntry)
+				{
+					found = true;
+					break;
+				}
+			}
+
+			if(!found)
+				output.push_back(aEntry);
+		}
+	}
+
 	Selection::Selection()
 	{
 		mSceneSelectionChangedConn = MessageHandler::instance().listen(
@@ -26,18 +46,31 @@ namespace bs
 
 	const Vector<HSceneObject>& Selection::getSceneObjects() const
 	{
-		pruneDestroyedSceneObjects();
+		pruneDestroyedSceneObjects(mSelectedSceneObjects);
 		return mSelectedSceneObjects;
 	}
 
 	void Selection::setSceneObjects(const Vector<HSceneObject>& sceneObjects)
 	{
+		setDifference(mSelectedSceneObjects, sceneObjects, mTempSceneObjects);
+		pruneDestroyedSceneObjects(mTempSceneObjects);
+		onSceneObjectsRemoved(mTempSceneObjects);
+		mTempSceneObjects.clear();
+
+		if(!mSelectedResourcePaths.empty())
+			onResourcesRemoved(mSelectedResourcePaths);
+
+		setDifference(sceneObjects, mSelectedSceneObjects, mTempSceneObjects);
+		pruneDestroyedSceneObjects(mTempSceneObjects);
+		onSceneObjectsAdded(mTempSceneObjects);
+		mTempSceneObjects.clear();
+
 		mSelectedSceneObjects = sceneObjects;
 		mSelectedResourcePaths.clear();
 
 		updateTreeViews();
 
-		pruneDestroyedSceneObjects();
+		pruneDestroyedSceneObjects(mSelectedSceneObjects);
 		onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
 	}
 
@@ -48,6 +81,17 @@ namespace bs
 
 	void Selection::setResourcePaths(const Vector<Path>& paths)
 	{
+		setDifference(mSelectedResourcePaths, paths, mTempResources);
+		onResourcesRemoved(mTempResources);
+		mTempResources.clear();
+
+		if(!mSelectedSceneObjects.empty())
+			onSceneObjectsRemoved(mSelectedSceneObjects);
+
+		setDifference(paths, mSelectedResourcePaths, mTempResources);
+		onResourcesAdded(mSelectedResourcePaths);
+		mTempResources.clear();
+
 		mSelectedResourcePaths = paths;
 		mSelectedSceneObjects.clear();
 
@@ -71,18 +115,15 @@ namespace bs
 
 	void Selection::setResourceUUIDs(const Vector<UUID>& UUIDs)
 	{
-		mSelectedResourcePaths.clear();
+		Vector<Path> paths;
 		for (auto& uuid : UUIDs)
 		{
 			Path path = gProjectLibrary().uuidToPath(uuid);
 			if (path != Path::BLANK)
-				mSelectedResourcePaths.push_back(path);
+				paths.push_back(path);
 		}
 
-		mSelectedSceneObjects.clear();
-		updateTreeViews();
-
-		onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
+		setResourcePaths(paths);
 	}
 
 	void Selection::clearSceneSelection()
@@ -92,7 +133,7 @@ namespace bs
 
 	void Selection::clearResourceSelection()
 	{
-		setResourceUUIDs({});
+		setResourcePaths({});
 	}
 
 	void Selection::ping(const HSceneObject& sceneObject)
@@ -134,11 +175,7 @@ namespace bs
 			if (!isDirty)
 				return;
 
-			mSelectedSceneObjects = newSelection;
-			mSelectedResourcePaths.clear();
-
-			pruneDestroyedSceneObjects();
-			onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
+			setSceneObjects(newSelection);
 		}
 	}
 
@@ -167,10 +204,7 @@ namespace bs
 			if (!isDirty)
 				return;
 
-			mSelectedResourcePaths = newSelection;
-			mSelectedSceneObjects.clear();
-
-			onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
+			setResourcePaths(newSelection);
 		}
 	}
 
@@ -189,17 +223,17 @@ namespace bs
 		if (sceneTreeView != nullptr)
 		{
 			// Copy in case setSelection modifies the original.
-			pruneDestroyedSceneObjects();
+			pruneDestroyedSceneObjects(mSelectedSceneObjects);
 			Vector<HSceneObject> copy = mSelectedSceneObjects;
 
 			sceneTreeView->setSelection(copy);
 		}
 	}
 
-	void Selection::pruneDestroyedSceneObjects() const
+	void Selection::pruneDestroyedSceneObjects(Vector<HSceneObject>& sceneObjects) const
 	{
 		bool anyDestroyed = false;
-		for (auto& SO : mSelectedSceneObjects)
+		for (auto& SO : sceneObjects)
 		{
 			if (!SO.isDestroyed(true))
 			{
@@ -211,13 +245,13 @@ namespace bs
 		if (!anyDestroyed) // Test for quick exit for the most common case
 			return;
 
-		for(auto& SO : mSelectedSceneObjects)
+		for(auto& SO : sceneObjects)
 		{
 			if(!SO.isDestroyed(true))
-				mTempSO.push_back(SO);
+				mTempPrune.push_back(SO);
 		}
 
-		mSelectedSceneObjects.swap(mTempSO);
-		mTempSO.clear();
+		sceneObjects.swap(mTempPrune);
+		mTempPrune.clear();
 	}
 }

+ 23 - 10
Source/Scripting/MBansheeEditor/Generated/GUICurvesField.generated.cs

@@ -45,6 +45,17 @@ namespace BansheeEditor
 			Internal_create0(this, drawOptions, labelText, labelWidth, style);
 		}
 
+		/// <summary>Creates a new GUI editor field without a label.</summary>
+		/// <param name="drawOptions">Options that control which additional curve elements to draw.</param>
+		/// <param name="style">
+		/// Optional style to use for the element. Style will be retrieved from GUISkin of the GUIWidget the element is used on. 
+		/// If not specified default style is used.
+		/// </param>
+		public GUICurvesField(CurveDrawOptions drawOptions, string style = "")
+		{
+			Internal_create1(this, drawOptions, style);
+		}
+
 		/// <summary>Creates a new GUI editor field with a label.</summary>
 		/// <param name="labelContent">Content to display in the editor field label.</param>
 		/// <param name="labelWidth">Width of the label in pixels.</param>
@@ -54,7 +65,7 @@ namespace BansheeEditor
 		/// </param>
 		public GUICurvesField(GUIContent labelContent, uint labelWidth, string style = "")
 		{
-			Internal_create1(this, ref labelContent, labelWidth, style);
+			Internal_create2(this, ref labelContent, labelWidth, style);
 		}
 
 		/// <summary>Creates a new GUI editor field with a label.</summary>
@@ -65,7 +76,7 @@ namespace BansheeEditor
 		/// </param>
 		public GUICurvesField(GUIContent labelContent, string style = "")
 		{
-			Internal_create2(this, ref labelContent, style);
+			Internal_create3(this, ref labelContent, style);
 		}
 
 		/// <summary>Creates a new GUI editor field with a label.</summary>
@@ -77,7 +88,7 @@ namespace BansheeEditor
 		/// </param>
 		public GUICurvesField(LocString labelText, uint labelWidth, string style = "")
 		{
-			Internal_create3(this, labelText, labelWidth, style);
+			Internal_create4(this, labelText, labelWidth, style);
 		}
 
 		/// <summary>Creates a new GUI editor field with a label.</summary>
@@ -88,7 +99,7 @@ namespace BansheeEditor
 		/// </param>
 		public GUICurvesField(LocString labelText, string style = "")
 		{
-			Internal_create4(this, labelText, style);
+			Internal_create5(this, labelText, style);
 		}
 
 		/// <summary>Creates a new GUI editor field without a label.</summary>
@@ -98,7 +109,7 @@ namespace BansheeEditor
 		/// </param>
 		public GUICurvesField(string style = "")
 		{
-			Internal_create5(this, style);
+			Internal_create6(this, style);
 		}
 
 		/// <summary>
@@ -207,15 +218,17 @@ namespace BansheeEditor
 		[MethodImpl(MethodImplOptions.InternalCall)]
 		private static extern void Internal_create0(GUICurvesField managedInstance, CurveDrawOptions drawOptions, LocString labelText, uint labelWidth, string style);
 		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern void Internal_create1(GUICurvesField managedInstance, ref GUIContent labelContent, uint labelWidth, string style);
+		private static extern void Internal_create1(GUICurvesField managedInstance, CurveDrawOptions drawOptions, string style);
+		[MethodImpl(MethodImplOptions.InternalCall)]
+		private static extern void Internal_create2(GUICurvesField managedInstance, ref GUIContent labelContent, uint labelWidth, string style);
 		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern void Internal_create2(GUICurvesField managedInstance, ref GUIContent labelContent, string style);
+		private static extern void Internal_create3(GUICurvesField managedInstance, ref GUIContent labelContent, string style);
 		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern void Internal_create3(GUICurvesField managedInstance, LocString labelText, uint labelWidth, string style);
+		private static extern void Internal_create4(GUICurvesField managedInstance, LocString labelText, uint labelWidth, string style);
 		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern void Internal_create4(GUICurvesField managedInstance, LocString labelText, string style);
+		private static extern void Internal_create5(GUICurvesField managedInstance, LocString labelText, string style);
 		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern void Internal_create5(GUICurvesField managedInstance, string style);
+		private static extern void Internal_create6(GUICurvesField managedInstance, string style);
 		private void Internal_onClicked()
 		{
 			OnClicked();

+ 2 - 0
Source/Scripting/MBansheeEditor/MBansheeEditor.csproj

@@ -53,6 +53,7 @@
     <Compile Include="Inspectors\ReflectionProbeInspector.cs" />
     <Compile Include="Inspectors\RenderSettingsInspector.cs" />
     <Compile Include="Utility\EdAnimationCurve.cs" />
+    <Compile Include="Utility\OnSelectionChanged.cs" />
     <Compile Include="Utility\SerializedSceneObject.cs" />
     <Compile Include="Utility\SerializedDiff.cs" />
     <Compile Include="Utility\SerializedObject.cs" />
@@ -118,6 +119,7 @@
     <Compile Include="Windows\LogWindow.cs" />
     <Compile Include="Windows\Scene\Gizmos\CameraGizmo.cs" />
     <Compile Include="Windows\Scene\Gizmos\LightProbeVolumeGizmo.cs" />
+    <Compile Include="Windows\Scene\Gizmos\ParticleSystemGizmos.cs" />
     <Compile Include="Windows\Scene\Gizmos\ReflectionProbeGizmo.cs" />
     <Compile Include="Windows\Scene\Handles\HandleSlider2D.cs" />
     <Compile Include="Windows\Scene\Handles\HandleSliderSphere.cs" />

+ 24 - 0
Source/Scripting/MBansheeEditor/Utility/OnSelectionChanged.cs

@@ -0,0 +1,24 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Utility-Editor
+     *  @{
+     */
+
+    /// <summary>
+    /// Notifies the runtime that the method this attribute is specified on serves as a callback for reporting when a new
+    /// scene object containing a certain component type has been selected or deselected. The method must have two
+    /// parameters. First parameter must derive from <see cref="BansheeEngine.Component"/> type and determines for which
+    /// components will be method be triggered. When callback is triggered this parameter will contain the instance of
+    /// the component that was selected or deselected. The second parameter must be a boolean which determines whether the
+    /// component as added (if true) or removed (if true) from the current selection.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Method)]
+    public sealed class OnSelectionChanged : Attribute
+    { }
+
+    /** @} */
+}

+ 2 - 2
Source/Scripting/MBansheeEditor/Windows/Scene/Gizmos/DrawGizmo.cs

@@ -28,8 +28,8 @@ namespace BansheeEditor
     /// <summary>
     /// Notifies the runtime that the method this attribute is specified on serves for gizmo drawing. All drawing in the 
     /// method should be done using the <see cref="Gizmos"/> class. The method must be static and must accept a single
-    /// parameter of type deriving from <see cref="Component"/>. Type of the parameter determines for which objects will
-    /// the gizmo be drawn for.
+    /// parameter of type deriving from <see cref="BansheeEngine.Component"/>. Type of the parameter determines for which
+    /// objects will the gizmo be drawn for.
     /// </summary>
     [AttributeUsage(AttributeTargets.Method)]
     public sealed class DrawGizmo : Attribute

+ 44 - 0
Source/Scripting/MBansheeEditor/Windows/Scene/Gizmos/ParticleSystemGizmos.cs

@@ -0,0 +1,44 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2017 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Gizmos
+     *  @{
+     */
+
+    /// <summary>
+    /// Handles drawing of gizmos and selection callback for the <see cref="ParticleSystem"/> component.
+    /// </summary>
+    internal class ParticleSystemGizmos
+    {
+        /// <summary>
+        /// Method called by the runtime when gizmos are meant to be drawn.
+        /// </summary>
+        /// <param name="component">Component to draw gizmos for.</param>
+        [DrawGizmo(DrawGizmoFlags.Selected)]
+        private static void Draw(ParticleSystem component)
+        {
+            SceneObject so = component.SceneObject;
+
+            Gizmos.Color = Color.Yellow;
+            Gizmos.Transform = Matrix4.TRS(so.Position, Quaternion.LookRotation(so.Rotation.Forward, so.Rotation.Up), Vector3.One);
+
+            // TODO
+        }
+
+        /// <summary>
+        /// Method called by the runtime when the component is selected or deselected.
+        /// </summary>
+        /// <param name="component">Component that was selected or deselected.</param>
+        /// <param name="selected">If true the provided component was selected, otherwise deselected.</param>
+        [OnSelectionChanged]
+        private static void SelectionChanged(ParticleSystem component, bool selected)
+        {
+            component.TogglePreviewMode(selected);
+        }
+    }
+
+    /** @} */
+}

+ 12 - 0
Source/Scripting/MBansheeEngine/Generated/CParticleSystem.generated.cs

@@ -81,6 +81,16 @@ namespace BansheeEngine
 			set { Internal_setLayer(mCachedPtr, value); }
 		}
 
+		/// <summary>
+		/// Enables or disabled preview mode. Preview mode allows the particle system to play while the game is not running,  
+		/// primarily for preview purposes in the editor. Returns true if the preview mode was enabled, false if it was disabled 
+		/// or enabling preview failed.
+		/// </summary>
+		internal bool TogglePreviewMode(bool enabled)
+		{
+			return Internal__togglePreviewMode(mCachedPtr, enabled);
+		}
+
 		[MethodImpl(MethodImplOptions.InternalCall)]
 		private static extern void Internal_setSettings(IntPtr thisPtr, ParticleSystemSettings settings);
 		[MethodImpl(MethodImplOptions.InternalCall)]
@@ -101,6 +111,8 @@ namespace BansheeEngine
 		private static extern void Internal_setLayer(IntPtr thisPtr, ulong layer);
 		[MethodImpl(MethodImplOptions.InternalCall)]
 		private static extern ulong Internal_getLayer(IntPtr thisPtr);
+		[MethodImpl(MethodImplOptions.InternalCall)]
+		private static extern bool Internal__togglePreviewMode(IntPtr thisPtr, bool enabled);
 	}
 
 	/** @} */

+ 99 - 7
Source/Scripting/SBansheeEditor/BsScriptGizmoManager.cpp

@@ -16,20 +16,28 @@
 #include "BsScriptObjectManager.h"
 #include "BsScriptGameObjectManager.h"
 #include "Wrappers/BsScriptComponent.h"
+#include "Wrappers/BsScriptSelection.h"
 
 using namespace std::placeholders;
 
 namespace bs
 {
 	ScriptGizmoManager::ScriptGizmoManager(ScriptAssemblyManager& scriptObjectManager)
-		:mScriptObjectManager(scriptObjectManager), mDrawGizmoAttribute(nullptr), mFlagsField(nullptr)
+		:mScriptObjectManager(scriptObjectManager)
 	{
 		mDomainLoadedConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&ScriptGizmoManager::reloadAssemblyData, this));
+		mSelectionSOAddedConn = Selection::instance().onSceneObjectsAdded.connect(
+			[this](const Vector<HSceneObject>& objects) { onSOSelectionChanged(objects, true); });
+		mSelectionSORemovedConn = Selection::instance().onSceneObjectsRemoved.connect(
+			[this](const Vector<HSceneObject>& objects) { onSOSelectionChanged(objects, false); });
+
 		reloadAssemblyData();
 	}
 
 	ScriptGizmoManager::~ScriptGizmoManager()
 	{
+		mSelectionSOAddedConn.disconnect();
+		mSelectionSORemovedConn.disconnect();
 		mDomainLoadedConn.disconnect();
 	}
 
@@ -116,7 +124,7 @@ namespace bs
 						GizmoManager::instance().setPickable(pickable);
 
 						void* params[1] = { managedInstance };
-						iterFind->second.drawGizmosMethod->invoke(nullptr, params);
+						iterFind->second.method->invoke(nullptr, params);
 
 						GizmoManager::instance().endGizmo();
 					}
@@ -138,12 +146,16 @@ namespace bs
 
 		mFlagsField = mDrawGizmoAttribute->getField("flags");
 
+		mOnSelectionChangedAttribute = editorAssembly->getClass("BansheeEditor", "OnSelectionChanged");
+		if (mOnSelectionChangedAttribute == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find OnSelectionChanged managed class.");
+
 		Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
 		for (auto& assemblyName : scriptAssemblyNames)
 		{
 			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);
 
-			// Find new gizmo drawer methods
+			// Find new gizmo drawer & selection changed methods
 			const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
 			for (auto curClass : allClasses)
 			{
@@ -155,13 +167,65 @@ namespace bs
 					if (isValidDrawGizmoMethod(curMethod, componentType, drawGizmoFlags))
 					{
 						String fullComponentName = componentType->getFullName();
-						GizmoData& newGizmoData = mGizmoDrawers[fullComponentName];
+						GizmoData& data = mGizmoDrawers[fullComponentName];
+
+						data.type = componentType;
+						data.method = curMethod;
+						data.flags = drawGizmoFlags;
+					}
+					else if(isValidOnSelectionChangedMethod(curMethod, componentType))
+					{
+						String fullComponentName = componentType->getFullName();
+						SelectionChangedData& data = mSelectionChangedCallbacks[fullComponentName];
+
+						data.type = componentType;
+						data.method = curMethod;
+					}
+				}
+			}
+		}
+	}
+
+	void ScriptGizmoManager::onSOSelectionChanged(const Vector<HSceneObject>& sceneObjects, bool added)
+	{
+		for(auto& sceneObject : sceneObjects)
+		{
+			Vector<HComponent> components = sceneObject->getComponents();
+			for(auto& component : components)
+			{
+				String componentName;
+				MonoObject* managedInstance = nullptr;
+				if (rtti_is_of_type<ManagedComponent>(component.get()))
+				{
+					ManagedComponent* managedComponent = static_cast<ManagedComponent*>(component.get());
+					componentName = managedComponent->getManagedFullTypeName();
+					managedInstance = managedComponent->getManagedInstance();
+				}
+				else
+				{
+					ScriptGameObjectManager& sgoManager = ScriptGameObjectManager::instance();
+					ScriptComponentBase* scriptComponent = sgoManager.getBuiltinScriptComponent(component, false);
+
+					if (scriptComponent)
+					{
+						managedInstance = scriptComponent->getManagedInstance();
+
+						String ns, typeName;
+						MonoUtil::getClassName(managedInstance, ns, typeName);
 
-						newGizmoData.componentType = componentType;
-						newGizmoData.drawGizmosMethod = curMethod;
-						newGizmoData.flags = drawGizmoFlags;
+						componentName = ns + "." + typeName;
 					}
 				}
+
+				if (componentName.empty())
+					continue;
+
+				auto iterFind = mSelectionChangedCallbacks.find(componentName);
+				if (iterFind != mSelectionChangedCallbacks.end())
+				{
+					void* params[2] = { managedInstance, &added };
+					iterFind->second.method->invoke(nullptr, params);
+				}
 			}
 		}
 	}
@@ -193,4 +257,32 @@ namespace bs
 
 		return true;
 	}
+
+	bool ScriptGizmoManager::isValidOnSelectionChangedMethod(class MonoMethod* method, MonoClass*& componentType)
+	{
+		componentType = nullptr;
+
+		if (!method->hasAttribute(mOnSelectionChangedAttribute))
+			return false;
+
+		if (method->getNumParameters() != 2)
+			return false;
+
+		if (!method->isStatic())
+			return false;
+
+		MonoClass* param0Type = method->getParameterType(0);
+		MonoClass* componentClass = mScriptObjectManager.getBuiltinClasses().componentClass;
+
+		if (!param0Type->isSubClassOf(componentClass))
+			return false;
+
+		MonoClass* param1Type = method->getParameterType(1);
+		if(param1Type->_getInternalClass() != MonoUtil::getBoolClass())
+			return false;
+
+		componentType = param0Type;
+
+		return true;
+	}
 }

+ 35 - 5
Source/Scripting/SBansheeEditor/BsScriptGizmoManager.h

@@ -25,14 +25,21 @@ namespace bs
 	 */
 	class BS_SCR_BED_EXPORT ScriptGizmoManager : public Module<ScriptGizmoManager>
 	{
-		/**	Data about a managed gizmo method. */
+		/**	Data about a managed gizmo drawing method. */
 		struct GizmoData
 		{
-			MonoClass* componentType; /**< Component the gizmo method belongs to. */
-			MonoMethod* drawGizmosMethod; /**< Method that displays the gizmo. */
+			MonoClass* type; /**< Component the gizmo method belongs to. */
+			MonoMethod* method; /**< Method that displays the gizmo. */
 			UINT32 flags; /**< Gizmo flags of type DrawGizmoFlags that control gizmo properties. */
 		};
 
+		/** Data about a managed selection changed callback method. */
+		struct SelectionChangedData
+		{
+			MonoClass* type; /**< Component or resource the selection method should trigger on. */
+			MonoMethod* method; /**< Method that receives the selection changed callback. */
+		};
+
 	public:
 		ScriptGizmoManager(ScriptAssemblyManager& scriptObjectManager);
 		~ScriptGizmoManager();
@@ -46,6 +53,15 @@ namespace bs
 		/**	Finds all gizmo methods (marked with the DrawGizmo attribute). Clears any previously found methods. */
 		void reloadAssemblyData();
 
+		/**
+		 * Triggered when entries are added or removed from the selection.
+		 *
+		 * @param[in]	sceneObjects	Newly selected or deselected scene objects. 
+		 * @param[in]	added			If true, the provided objects were added to the selection. If false, the provided
+		 *								objects were removed from the selection.
+		 */
+		void onSOSelectionChanged(const Vector<HSceneObject>& sceneObjects, bool added);
+
 		/**
 		 * Checks is the provided method a valid gizmo draw method and if it is, returns properties of that method.
 		 *
@@ -58,12 +74,26 @@ namespace bs
 		 */
 		bool isValidDrawGizmoMethod(MonoMethod* method, MonoClass*& componentType, UINT32& drawGizmoFlags);
 
+		/**
+		 * Checks is the provided method a valid selection changed callback method.
+		 *
+		 * @param[in]	method			Method to check.
+		 * @param[in]	componentType	Output parameter containing the component the method is part of. Only valid if this
+		 *								method returns true.
+		 * @return						True if the method is a valid selection changed callback method.
+		 */
+		bool isValidOnSelectionChangedMethod(MonoMethod* method, MonoClass*& componentType);
+
 		ScriptAssemblyManager& mScriptObjectManager;
 		HEvent mDomainLoadedConn;
+		HEvent mSelectionSOAddedConn;
+		HEvent mSelectionSORemovedConn;
 
-		MonoClass* mDrawGizmoAttribute;
-		MonoField* mFlagsField;
+		MonoClass* mDrawGizmoAttribute = nullptr;
+		MonoField* mFlagsField = nullptr;
+		MonoClass* mOnSelectionChangedAttribute = nullptr;
 		Map<String, GizmoData> mGizmoDrawers;
+		Map<String, SelectionChangedData> mSelectionChangedCallbacks;
 	};
 
 	/** @} */

+ 14 - 5
Source/Scripting/SBansheeEditor/Generated/BsScriptGUICurvesField.generated.cpp

@@ -37,6 +37,7 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_create3", (void*)&ScriptGUICurvesField::Internal_create3);
 		metaData.scriptClass->addInternalCall("Internal_create4", (void*)&ScriptGUICurvesField::Internal_create4);
 		metaData.scriptClass->addInternalCall("Internal_create5", (void*)&ScriptGUICurvesField::Internal_create5);
+		metaData.scriptClass->addInternalCall("Internal_create6", (void*)&ScriptGUICurvesField::Internal_create6);
 
 		onClickedThunk = (onClickedThunkDef)metaData.scriptClass->getMethodExact("Internal_onClicked", "")->getThunk();
 	}
@@ -146,7 +147,15 @@ namespace bs
 		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
 	}
 
-	void ScriptGUICurvesField::Internal_create1(MonoObject* managedInstance, __GUIContentInterop* labelContent, uint32_t labelWidth, MonoString* style)
+	void ScriptGUICurvesField::Internal_create1(MonoObject* managedInstance, CurveDrawOption drawOptions, MonoString* style)
+	{
+		String tmpstyle;
+		tmpstyle = MonoUtil::monoToString(style);
+		GUICurvesField* instance = GUICurvesField::create(drawOptions, tmpstyle);
+		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
+	}
+
+	void ScriptGUICurvesField::Internal_create2(MonoObject* managedInstance, __GUIContentInterop* labelContent, uint32_t labelWidth, MonoString* style)
 	{
 		GUIContent tmplabelContent;
 		tmplabelContent = ScriptGUIContent::fromInterop(*labelContent);
@@ -156,7 +165,7 @@ namespace bs
 		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
 	}
 
-	void ScriptGUICurvesField::Internal_create2(MonoObject* managedInstance, __GUIContentInterop* labelContent, MonoString* style)
+	void ScriptGUICurvesField::Internal_create3(MonoObject* managedInstance, __GUIContentInterop* labelContent, MonoString* style)
 	{
 		GUIContent tmplabelContent;
 		tmplabelContent = ScriptGUIContent::fromInterop(*labelContent);
@@ -166,7 +175,7 @@ namespace bs
 		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
 	}
 
-	void ScriptGUICurvesField::Internal_create3(MonoObject* managedInstance, MonoObject* labelText, uint32_t labelWidth, MonoString* style)
+	void ScriptGUICurvesField::Internal_create4(MonoObject* managedInstance, MonoObject* labelText, uint32_t labelWidth, MonoString* style)
 	{
 		SPtr<HString> tmplabelText;
 		ScriptHString* scriptlabelText;
@@ -179,7 +188,7 @@ namespace bs
 		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
 	}
 
-	void ScriptGUICurvesField::Internal_create4(MonoObject* managedInstance, MonoObject* labelText, MonoString* style)
+	void ScriptGUICurvesField::Internal_create5(MonoObject* managedInstance, MonoObject* labelText, MonoString* style)
 	{
 		SPtr<HString> tmplabelText;
 		ScriptHString* scriptlabelText;
@@ -192,7 +201,7 @@ namespace bs
 		new (bs_alloc<ScriptGUICurvesField>())ScriptGUICurvesField(managedInstance, instance);
 	}
 
-	void ScriptGUICurvesField::Internal_create5(MonoObject* managedInstance, MonoString* style)
+	void ScriptGUICurvesField::Internal_create6(MonoObject* managedInstance, MonoString* style)
 	{
 		String tmpstyle;
 		tmpstyle = MonoUtil::monoToString(style);

+ 6 - 5
Source/Scripting/SBansheeEditor/Generated/BsScriptGUICurvesField.generated.h

@@ -36,10 +36,11 @@ namespace bs
 		static void Internal_setPadding(ScriptGUICurvesField* thisPtr, uint32_t padding);
 		static void Internal_create(MonoObject* managedInstance, CurveDrawOption drawOptions, __GUIContentInterop* labelContent, uint32_t labelWidth, MonoString* style);
 		static void Internal_create0(MonoObject* managedInstance, CurveDrawOption drawOptions, MonoObject* labelText, uint32_t labelWidth, MonoString* style);
-		static void Internal_create1(MonoObject* managedInstance, __GUIContentInterop* labelContent, uint32_t labelWidth, MonoString* style);
-		static void Internal_create2(MonoObject* managedInstance, __GUIContentInterop* labelContent, MonoString* style);
-		static void Internal_create3(MonoObject* managedInstance, MonoObject* labelText, uint32_t labelWidth, MonoString* style);
-		static void Internal_create4(MonoObject* managedInstance, MonoObject* labelText, MonoString* style);
-		static void Internal_create5(MonoObject* managedInstance, MonoString* style);
+		static void Internal_create1(MonoObject* managedInstance, CurveDrawOption drawOptions, MonoString* style);
+		static void Internal_create2(MonoObject* managedInstance, __GUIContentInterop* labelContent, uint32_t labelWidth, MonoString* style);
+		static void Internal_create3(MonoObject* managedInstance, __GUIContentInterop* labelContent, MonoString* style);
+		static void Internal_create4(MonoObject* managedInstance, MonoObject* labelText, uint32_t labelWidth, MonoString* style);
+		static void Internal_create5(MonoObject* managedInstance, MonoObject* labelText, MonoString* style);
+		static void Internal_create6(MonoObject* managedInstance, MonoString* style);
 	};
 }

+ 12 - 0
Source/Scripting/SBansheeEngine/Generated/BsScriptCParticleSystem.generated.cpp

@@ -46,6 +46,7 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_getEvolvers", (void*)&ScriptCParticleSystem::Internal_getEvolvers);
 		metaData.scriptClass->addInternalCall("Internal_setLayer", (void*)&ScriptCParticleSystem::Internal_setLayer);
 		metaData.scriptClass->addInternalCall("Internal_getLayer", (void*)&ScriptCParticleSystem::Internal_getLayer);
+		metaData.scriptClass->addInternalCall("Internal__togglePreviewMode", (void*)&ScriptCParticleSystem::Internal__togglePreviewMode);
 
 	}
 
@@ -204,4 +205,15 @@ namespace bs
 
 		return __output;
 	}
+
+	bool ScriptCParticleSystem::Internal__togglePreviewMode(ScriptCParticleSystem* thisPtr, bool enabled)
+	{
+		bool tmp__output;
+		tmp__output = thisPtr->getHandle()->_togglePreviewMode(enabled);
+
+		bool __output;
+		__output = tmp__output;
+
+		return __output;
+	}
 }

+ 1 - 0
Source/Scripting/SBansheeEngine/Generated/BsScriptCParticleSystem.generated.h

@@ -27,5 +27,6 @@ namespace bs
 		static MonoArray* Internal_getEvolvers(ScriptCParticleSystem* thisPtr);
 		static void Internal_setLayer(ScriptCParticleSystem* thisPtr, uint64_t layer);
 		static uint64_t Internal_getLayer(ScriptCParticleSystem* thisPtr);
+		static bool Internal__togglePreviewMode(ScriptCParticleSystem* thisPtr, bool enabled);
 	};
 }

+ 1 - 1
Source/bsf

@@ -1 +1 @@
-Subproject commit bf1c2fe0b31578128ab818df4a3f07196195e885
+Subproject commit 722e709baa4f3356b7d6e2204cc8d9c90e922e3a