Files
trail-into-darkness/Packages/com.jovian.inspector/Editor/Attributes/ButtonMethodAttribute.cs
2026-03-29 18:59:24 +02:00

199 lines
7.5 KiB
C#

// ----------------------------------------------------------------------------
// Author: Kaynn, Yeo Wen Qin
// https://github.com/Kaynn-Cahya
// Date: 26/02/2019
// ----------------------------------------------------------------------------
using System;
using Jovian.Utilities;
using UnityEngine;
using Object = UnityEngine.Object;
namespace InspectorToolkit {
[AttributeUsage(AttributeTargets.Method)]
public class ButtonMethodAttribute : PropertyAttribute {
public readonly ButtonMethodDrawOrder DrawOrder;
public readonly PlayModeVisibility Visibility;
public ButtonMethodAttribute(PlayModeVisibility visibility, ButtonMethodDrawOrder drawOrder = ButtonMethodDrawOrder.AfterInspector) {
Visibility = visibility;
DrawOrder = drawOrder;
}
public ButtonMethodAttribute(ButtonMethodDrawOrder drawOrder = ButtonMethodDrawOrder.AfterInspector) {
DrawOrder = drawOrder;
Visibility = PlayModeVisibility.Always;
}
}
public enum ButtonMethodDrawOrder {
BeforeInspector,
AfterInspector
}
}
#if UNITY_EDITOR
namespace InspectorToolkit.Internal {
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
public class ButtonMethodHandler {
public class MethodData {
public MethodInfo methodInfo;
public ParameterData[] parameterDatas;
public string niceName;
public PlayModeVisibility visibility;
public ButtonMethodDrawOrder order;
}
public class ParameterData {
public ParameterInfo parameterInfo;
public string niceName;
public object value;
}
// TODO - replace with MethodDatas;
public readonly List<(MethodInfo Method, string Name, PlayModeVisibility visibility, ButtonMethodDrawOrder order)> TargetMethods;
public int Amount => TargetMethods?.Count ?? 0;
public readonly List<MethodData> MethodDatas;
public bool HasMethods => MethodDatas?.Count > 0;
private readonly Object _target;
public Object Target => _target;
public ButtonMethodHandler(Object target) {
_target = target;
Type type = target.GetType();
BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
IEnumerable<MemberInfo> members = type.GetMembers(bindings).Where(IsButtonMethod);
foreach(MemberInfo member in members) {
MethodInfo method = member as MethodInfo;
if(method == null) continue;
if(IsValidMember(method, member)) {
ButtonMethodAttribute attribute = (ButtonMethodAttribute)Attribute.GetCustomAttribute(method, typeof(ButtonMethodAttribute));
TargetMethods ??= new List<(MethodInfo, string, PlayModeVisibility, ButtonMethodDrawOrder)>();
TargetMethods.Add((method, ObjectNames.NicifyVariableName(method.Name), attribute.Visibility, attribute.DrawOrder));
MethodDatas ??= new();
ParameterInfo[] parameterInfos = method.GetParameters();
ParameterData[] parameterDatas = new ParameterData[parameterInfos.Length];
for(int i = 0; i < parameterInfos.Length; i++) {
ParameterInfo info = parameterInfos[i];
object value;
if(info.HasDefaultValue) {
value = info.DefaultValue;
}
else if(info.ParameterType == typeof(string)) {
value = "String";
}
else if(info.ParameterType == typeof(Object) || info.ParameterType.IsSubclassOf(typeof(Object))) {
value = null;
}
else {
value = Activator.CreateInstance(info.ParameterType);
}
parameterDatas[i] = new ParameterData() {
niceName = ObjectNames.NicifyVariableName(info.Name),
parameterInfo = info,
value = value
};
}
MethodData methodData = new MethodData() {
methodInfo = method,
niceName = ObjectNames.NicifyVariableName(method.Name),
visibility = attribute.Visibility,
order = attribute.DrawOrder,
parameterDatas = parameterDatas
};
MethodDatas.Add(methodData);
}
}
}
public bool HasAnyVisibleMethods() {
if(MethodDatas == null || MethodDatas.Count == 0) return false;
foreach (MethodData methodData in MethodDatas) {
if (methodData.visibility.IsVisible()) {
return true;
}
}
return false;
}
public void OnBeforeInspectorGUI() {
if(MethodDatas == null || MethodDatas.Count == 0) return;
DrawButtonMethods(ButtonMethodDrawOrder.BeforeInspector);
}
private void DrawButtonMethods(ButtonMethodDrawOrder drawOrder) {
foreach(MethodData method in MethodDatas) {
if(method.order != drawOrder) continue;
if(!method.visibility.IsVisible()) continue;
if(method.parameterDatas.Length > 0) {
GUILayout.BeginVertical(EditorStyles.helpBox);
}
if(GUILayout.Button(method.niceName)) {
object result = method.methodInfo.Invoke(_target, method.parameterDatas.Select(p=>p.value).ToArray());
if(result != null) {
Debug.Log($"{method.niceName} => {result}");
}
}
foreach (ParameterData p in method.parameterDatas) {
p.value = InspectorGUIUtility.DrawField(p.niceName, p.parameterInfo.ParameterType, p.value);
}
if(method.parameterDatas.Length > 0) {
GUILayout.EndVertical();
}
}
}
public void OnAfterInspectorGUI() {
if(MethodDatas == null || MethodDatas.Count == 0) return;
DrawButtonMethods(ButtonMethodDrawOrder.AfterInspector);
}
public void Invoke(MethodInfo method) => InvokeMethod(_target, method);
private void InvokeMethod(Object target, MethodInfo method) {
object result = method.Invoke(target, null);
if(result != null) {
string message = $"{result} \nResult of Method '{method.Name}' invocation on object {target.name}";
Debug.Log(message, target);
}
}
private bool IsButtonMethod(MemberInfo memberInfo) {
return Attribute.IsDefined(memberInfo, typeof(ButtonMethodAttribute));
}
private bool IsValidMember(MethodInfo method, MemberInfo member) {
if(method == null) {
Debug.LogWarning(
$"Property <color=brown>{member.Name}</color>.Reason: Member is not a method but has EditorButtonAttribute!");
return false;
}
return true;
}
}
}
#endif