using System; using System.Linq; using UnityEngine; using System.Text; using System.Collections.Generic; using System.Collections; #if UNITY_EDITOR using UnityEditor; #endif using System.Reflection; #if UNITY_EDITOR [CustomEditor(typeof (MonoBehaviour), true)] [CanEditMultipleObjects] public class EditorButton : Editor { class EditorButtonState { public bool opened; public System.Object[] parameters; public EditorButtonState(int numberOfParameters) { parameters = new System.Object[numberOfParameters]; } } EditorButtonState[] editorButtonStates; delegate object ParameterDrawer(ParameterInfo parameter, object val); Dictionary typeDrawer = new Dictionary { {typeof(float),DrawFloatParameter}, {typeof(int),DrawIntParameter}, {typeof(string),DrawStringParameter}, {typeof(bool),DrawBoolParameter}, {typeof(Color),DrawColorParameter}, {typeof(Vector3),DrawVector3Parameter}, {typeof(Vector2),DrawVector2Parameter}, {typeof(Quaternion),DrawQuaternionParameter} }; Dictionary typeDisplayName = new Dictionary { {typeof(float),"float"}, {typeof(int),"int"}, {typeof(string),"string"}, {typeof(bool),"bool"}, {typeof(Color),"Color"}, {typeof(Vector3),"Vector3"}, {typeof(Vector2),"Vector2"}, {typeof(Quaternion),"Quaternion"} }; public override void OnInspectorGUI() { base.OnInspectorGUI(); var mono = target as MonoBehaviour; var methods = mono.GetType() .GetMembers(BindingFlags.Instance | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) .Where(o => Attribute.IsDefined(o, typeof (EditorButtonAttribute))); int methodIndex = 0; if (editorButtonStates == null) { CreateEditorButtonStates (methods.Select(member => (MethodInfo)member).ToArray()); } foreach (var memberInfo in methods) { var method = memberInfo as MethodInfo; DrawButtonforMethod (targets,method,GetEditorButtonState(method,methodIndex)); methodIndex++; } } void CreateEditorButtonStates(MethodInfo[] methods) { editorButtonStates = new EditorButtonState[methods.Length]; int methodIndex = 0; foreach (var methodInfo in methods) { editorButtonStates [methodIndex] = new EditorButtonState (methodInfo.GetParameters ().Length); methodIndex++; } } EditorButtonState GetEditorButtonState(MethodInfo method,int methodIndex) { return editorButtonStates [methodIndex]; } void DrawButtonforMethod(object[] invokationTargets, MethodInfo methodInfo, EditorButtonState state) { EditorGUILayout.BeginHorizontal (); var foldoutRect = EditorGUILayout.GetControlRect (GUILayout.Width (10.0f)); state.opened = EditorGUI.Foldout (foldoutRect, state.opened, ""); bool clicked = GUILayout.Button (MethodDisplayName(methodInfo),GUILayout.ExpandWidth(true)); EditorGUILayout.EndHorizontal (); if (state.opened) { EditorGUI.indentLevel++; int paramIndex = 0; foreach (ParameterInfo parameterInfo in methodInfo.GetParameters()) { object currentVal = state.parameters [paramIndex]; state.parameters[paramIndex] = DrawParameterInfo (parameterInfo,currentVal); paramIndex++; } EditorGUI.indentLevel--; } if (clicked) { foreach (var invokationTarget in invokationTargets) { var monoTarget = invokationTarget as MonoBehaviour; object returnVal = methodInfo.Invoke (monoTarget,state.parameters); if (returnVal is IEnumerator) { monoTarget.StartCoroutine ((IEnumerator)returnVal); } else if(returnVal != null){ Debug.Log ("Method call result -> "+returnVal); } } } } object GetDefaultValue(ParameterInfo parameter) { bool hasDefaultValue = !DBNull.Value.Equals (parameter.DefaultValue); if (hasDefaultValue) return parameter.DefaultValue; Type parameterType = parameter.ParameterType; if (parameterType.IsValueType) return Activator.CreateInstance(parameterType); return null; } object DrawParameterInfo(ParameterInfo parameterInfo, object currentValue) { object paramValue = null; EditorGUILayout.BeginHorizontal (); EditorGUILayout.LabelField (parameterInfo.Name); ParameterDrawer drawer = GetParameterDrawer (parameterInfo); if (currentValue == null) currentValue = GetDefaultValue (parameterInfo); paramValue = drawer.Invoke (parameterInfo, currentValue); EditorGUILayout.EndHorizontal (); return paramValue; } ParameterDrawer GetParameterDrawer(ParameterInfo parameter) { Type parameterType = parameter.ParameterType; if (typeof(UnityEngine.Object).IsAssignableFrom(parameterType)) return DrawUnityEngineObjectParameter; ParameterDrawer drawer; if (typeDrawer.TryGetValue (parameterType, out drawer)) { return drawer; } return null; } static object DrawFloatParameter(ParameterInfo parameterInfo,object val) { //Since it is legal to define a float param with an integer default value (e.g void method(float p = 5);) //we must use Convert.ToSingle to prevent forbidden casts //because you can't cast an "int" object to float //See for http://stackoverflow.com/questions/17516882/double-casting-required-to-convert-from-int-as-object-to-float more info return EditorGUILayout.FloatField (Convert.ToSingle(val)); } static object DrawIntParameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.IntField ((int)val); } static object DrawBoolParameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.Toggle ((bool)val); } static object DrawStringParameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.TextField ((string)val); } static object DrawColorParameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.ColorField ((Color)val); } static object DrawUnityEngineObjectParameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.ObjectField ((UnityEngine.Object)val, parameterInfo.ParameterType, true); } static object DrawVector2Parameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.Vector2Field ("", (Vector2)val); } static object DrawVector3Parameter(ParameterInfo parameterInfo,object val) { return EditorGUILayout.Vector3Field ("", (Vector3)val); } static object DrawQuaternionParameter(ParameterInfo parameterInfo,object val) { return Quaternion.Euler(EditorGUILayout.Vector3Field ("", ((Quaternion)val).eulerAngles)); } string MethodDisplayName(MethodInfo method) { StringBuilder sb = new StringBuilder (); sb.Append (method.Name +"("); var methodParams = method.GetParameters (); foreach (ParameterInfo parameter in methodParams) { sb.Append (MethodParameterDisplayName (parameter)); sb.Append (","); } if(methodParams.Length > 0) sb.Remove (sb.Length - 1, 1); sb.Append (")"); return sb.ToString (); } string MethodParameterDisplayName(ParameterInfo parameterInfo) { string parameterTypeDisplayName; if (!typeDisplayName.TryGetValue (parameterInfo.ParameterType,out parameterTypeDisplayName)) { parameterTypeDisplayName = parameterInfo.ParameterType.ToString (); } return parameterTypeDisplayName + " " + parameterInfo.Name; } string MethodUID(MethodInfo method) { StringBuilder sb = new StringBuilder (); sb.Append (method.Name +"_"); foreach (ParameterInfo parameter in method.GetParameters()) { sb.Append (parameter.ParameterType.ToString ()); sb.Append ("_"); sb.Append (parameter.Name); } sb.Append (")"); return sb.ToString (); } } #endif