Rasagar/Library/PackageCache/com.unity.visualeffectgraph/Editor/Utilities/PropertyBinding/VFXPropertyBinderEditor.cs
2024-08-26 23:07:20 +03:00

272 lines
9.8 KiB
C#

using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
using UnityEngine.VFX.Utility;
using UnityEditor.VFX;
using UnityEditor;
using UnityEditorInternal;
namespace UnityEditor.Experimental.VFX.Utility
{
[CustomEditor(typeof(VFXPropertyBinder))]
class VFXPropertyBinderEditor : Editor
{
[MenuItem("CONTEXT/VFXPropertyBinder/Remove Component", false, 5000)]
public static void RemoveComponent(MenuCommand command)
{
var propertyBinder = (VFXPropertyBinder)command.context;
propertyBinder.ClearPropertyBinders();
Undo.DestroyObjectImmediate(propertyBinder);
}
ReorderableList m_List;
SerializedProperty m_Elements;
SerializedProperty m_Component;
SerializedProperty m_ExecuteInEditor;
GenericMenu m_Menu;
VFXBinderEditor m_ElementEditor;
static readonly Color validColor = new Color(0.5f, 1.0f, 0.2f);
static readonly Color invalidColor = new Color(1.0f, 0.5f, 0.2f);
static readonly Color errorColor = new Color(1.0f, 0.2f, 0.2f);
static class Styles
{
public static GUIStyle labelStyle;
static Styles()
{
labelStyle = new GUIStyle(EditorStyles.label) { padding = new RectOffset(20, 0, 2, 0), richText = true };
}
}
private void OnEnable()
{
BuildMenu();
m_Elements = serializedObject.FindProperty("m_Bindings");
m_Component = serializedObject.FindProperty("m_VisualEffect");
m_ExecuteInEditor = serializedObject.FindProperty("m_ExecuteInEditor");
m_List = new ReorderableList(serializedObject, m_Elements, false, true, true, true);
m_List.drawHeaderCallback = DrawHeader;
m_List.drawElementCallback = DrawElement;
m_List.onRemoveCallback = RemoveElement;
m_List.onAddCallback = AddElement;
m_List.onSelectCallback = SelectElement;
}
private void OnDisable()
{
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_ExecuteInEditor);
EditorGUILayout.Space();
m_List.DoLayoutList();
EditorGUILayout.Space();
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (m_ElementEditor != null && m_ElementEditor.target != null && m_ElementEditor.serializedObject.targetObject != null)
{
m_ElementEditor.serializedObject.Update();
EditorGUI.BeginChangeCheck();
var fieldAttribute = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
var binding = m_ElementEditor.serializedObject.targetObject;
var type = binding.GetType();
var fields = type.GetFields(fieldAttribute);
foreach (var field in fields)
{
var property = m_ElementEditor.serializedObject.FindProperty(field.Name);
if (property == null) continue;
using (new GUILayout.HorizontalScope())
{
var attrib = field.GetCustomAttributes(true).OfType<VFXPropertyBindingAttribute>().FirstOrDefault<VFXPropertyBindingAttribute>();
if (attrib != null)
{
var parameter = property.FindPropertyRelative("m_Name");
string parm = parameter.stringValue;
parm = EditorGUILayout.TextField(ObjectNames.NicifyVariableName(property.name), parm);
if (parm != parameter.stringValue)
{
parameter.stringValue = parm;
serializedObject.ApplyModifiedProperties();
}
if (GUILayout.Button("v", EditorStyles.toolbarButton, GUILayout.Width(14)))
CheckTypeMenu(property, attrib, (m_Component.objectReferenceValue as VisualEffect).visualEffectAsset);
}
else
{
EditorGUILayout.PropertyField(property, true);
}
}
}
if (EditorGUI.EndChangeCheck())
m_ElementEditor.serializedObject.ApplyModifiedProperties();
var component = (m_Component.objectReferenceValue as VisualEffect);
bool valid = (binding as VFXBinderBase).IsValid(component);
if (!valid)
{
EditorGUILayout.HelpBox("This binding is not correctly configured, please ensure Property is valid and/or objects are not null", MessageType.Warning);
}
}
}
private class MenuPropertySetName
{
public SerializedProperty property;
public string value;
}
public void CheckTypeMenu(SerializedProperty property, VFXPropertyBindingAttribute attribute, VisualEffectAsset asset)
{
VFXGraph graph = null;
if (asset != null)
{
var resource = asset.GetResource();
if (resource != null) //If VisualEffectGraph is store in asset bundle, we can't use this following code
{
graph = resource.graph as VFXGraph;
}
}
if (graph == null)
return;
var menu = new GenericMenu();
var parameters = graph.children.OfType<UnityEditor.VFX.VFXParameter>();
foreach (var param in parameters)
{
string typeName = param.type.ToString();
if (attribute.EditorTypes.Contains(typeName))
{
MenuPropertySetName set = new MenuPropertySetName
{
property = property,
value = param.exposedName
};
menu.AddItem(new GUIContent(param.exposedName), false, SetFieldName, set);
}
}
menu.ShowAsContext();
}
public void SetFieldName(object o)
{
var set = o as MenuPropertySetName;
set.property.FindPropertyRelative("m_Name").stringValue = set.value;
m_ElementEditor.serializedObject.ApplyModifiedProperties();
}
private static Type[] s_ConcreteBinders = null;
public void BuildMenu()
{
m_Menu = new GenericMenu();
if (s_ConcreteBinders == null)
s_ConcreteBinders = VFXLibrary.FindConcreteSubclasses(typeof(VFXBinderBase), typeof(VFXBinderAttribute)).ToArray();
foreach (var type in s_ConcreteBinders)
{
string name = type.ToString();
var attrib = type.GetCustomAttributes(true).OfType<VFXBinderAttribute>().First();
name = attrib.MenuPath;
m_Menu.AddItem(new GUIContent(name), false, AddBinding, type);
}
}
public void AddBinding(object type)
{
Type t = type as Type;
var obj = (serializedObject.targetObject as VFXPropertyBinder).gameObject;
Undo.AddComponent(obj, t);
}
public void SelectElement(ReorderableList list)
{
UpdateSelection(list.index);
}
public void UpdateSelection(int selected)
{
if (selected >= 0)
{
Editor editor = null;
CreateCachedEditor(m_Elements.GetArrayElementAtIndex(selected).objectReferenceValue, typeof(VFXBinderEditor), ref editor);
m_ElementEditor = editor as VFXBinderEditor;
}
else
m_ElementEditor = null;
}
public void AddElement(ReorderableList list)
{
m_Menu.ShowAsContext();
}
public void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
var target = m_Elements.GetArrayElementAtIndex(index).objectReferenceValue as VFXBinderBase;
Rect iconRect = new Rect(rect.xMin + 4, rect.yMin + 4, 8, 8);
if (target != null)
{
var element = target.ToString();
GUI.Label(rect, new GUIContent(element), Styles.labelStyle);
var component = (m_Component.objectReferenceValue as VisualEffect);
bool valid = target.IsValid(component);
EditorGUI.DrawRect(iconRect, valid ? validColor : invalidColor);
}
else
{
EditorGUI.DrawRect(iconRect, errorColor);
GUI.Label(rect, "<color=red>(Missing or Null Property Binder)</color>", Styles.labelStyle);
}
}
public void RemoveElement(ReorderableList list)
{
int index = m_List.index;
var element = m_Elements.GetArrayElementAtIndex(index).objectReferenceValue;
if (element != null)
{
Undo.DestroyObjectImmediate(element);
}
else
{
Undo.RecordObject(serializedObject.targetObject, "Remove null entry");
}
m_Elements.DeleteArrayElementAtIndex(index); // Remove list entry
UpdateSelection(-1);
}
public void DrawHeader(Rect rect)
{
GUI.Label(rect, "Property Bindings");
}
}
}