Skip to content

Instantly share code, notes, and snippets.

@GhatSmith
Created September 15, 2018 23:22
Show Gist options
  • Save GhatSmith/2da8a581bcc6750300d718562f31e63f to your computer and use it in GitHub Desktop.
Save GhatSmith/2da8a581bcc6750300d718562f31e63f to your computer and use it in GitHub Desktop.
// Based on : http://baba-s.hatenablog.com/entry/2014/07/30/152826
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary> Example of use : [ButtonAttribute ("MethodName", "ButtonNameInInspector", "TooltipInInspector", true, true, "param1", 10, "param3")] </summary>
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = true)]
public sealed class ButtonAttribute : PropertyAttribute
{
public string Function { get; private set; }
public string ButtonName { get; private set; }
public object[] Parameters { get; private set; }
public bool OnlyInPlayMode { get; private set; }
public string Tooltip { get; private set; }
public bool DisplayVariable { get; private set; }
/// <summary> WARNING : not working with overloaded functions </summary>
public ButtonAttribute(string function, string name, string tooltip, bool onlyInPlayMode, bool displayVariable, params object[] parameters)
{
Function = function;
ButtonName = name;
OnlyInPlayMode = onlyInPlayMode;
Tooltip = tooltip;
DisplayVariable = displayVariable;
Parameters = parameters;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(ButtonAttribute))]
public sealed class ButtonDrawer : PropertyDrawer
{
private ButtonAttribute typedAttribute;
public ButtonAttribute TypedAttribute
{
get
{
if (typedAttribute == null) typedAttribute = attribute as ButtonAttribute;
return typedAttribute;
}
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (TypedAttribute.DisplayVariable)
{
EditorGUI.PropertyField(position, property, label, true);
position.y += EditorGUI.GetPropertyHeight(property, label, true);
position.y += 2; // add little space above helpbox
}
string tooltip = TypedAttribute.Tooltip;
if (TypedAttribute.OnlyInPlayMode && !Application.isPlaying)
{
EditorGUI.BeginDisabledGroup(true);
if (string.IsNullOrEmpty(tooltip)) tooltip = "Button only available in play mode";
else tooltip = TypedAttribute.Tooltip + " (button only available in play mode)";
}
position.height = EditorGUI.GetPropertyHeight(property, label, true);
if (GUI.Button(position, new GUIContent(TypedAttribute.ButtonName, tooltip)))
{
var objectReferenceValue = property.serializedObject.targetObject;
var type = objectReferenceValue.GetType();
var bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
try
{
var method = type.GetMethod(TypedAttribute.Function, bindingAttr);
method.Invoke(objectReferenceValue, TypedAttribute.Parameters);
}
catch (AmbiguousMatchException)
{
var format = @"{0}.{1} : AmbiguousMatchException. Unable to determine which overloaded function is called for {0}.{1}. Please delete overloading function";
var message = string.Format(format, type.Name, TypedAttribute.Function);
Debug.LogError(message, objectReferenceValue);
}
catch (ArgumentException)
{
var parameters = string.Join(", ", TypedAttribute.Parameters.Select(c => c.ToString()).ToArray());
var format = @"{0}.{1} : ArgumentException. You can't pass argument {2} to the function {0}.{1}. Please verify the types of the arguments";
var message = string.Format(format, type.Name, TypedAttribute.Function, parameters);
Debug.LogError(message, objectReferenceValue);
}
catch (NullReferenceException)
{
var format = @"{0}.{1} : NullReferenceException. Undefined function. Please verify if function is defined in {0}.{1}";
var message = string.Format(format, type.Name, TypedAttribute.Function);
Debug.LogError(message, objectReferenceValue);
}
catch (TargetParameterCountException)
{
var parameters = string.Join(", ", TypedAttribute.Parameters.Select(c => c.ToString()).ToArray());
var format = @"{0}.{1} : TargetParameterCountException. You can't pass argument {2} to the function {0}.{1}. Please verify the number of the parameters given to the function ";
var message = string.Format(format, type.Name, TypedAttribute.Function, parameters);
Debug.LogError(message, objectReferenceValue);
}
}
if (TypedAttribute.OnlyInPlayMode && !Application.isPlaying) EditorGUI.EndDisabledGroup();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (TypedAttribute.DisplayVariable) return EditorGUI.GetPropertyHeight(property, label, true) + GetButtonHeight();
else return GetButtonHeight();
}
public float GetButtonHeight()
{
GUIContent content = new GUIContent(TypedAttribute.ButtonName);
GUIStyle style = GUI.skin.box;
style.alignment = TextAnchor.MiddleCenter;
// Compute how large the button needs to be.
Vector2 size = style.CalcSize(content);
return size.y;
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment