/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using System; using System.Reflection; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; using UnityObject = UnityEngine.Object; namespace Leap.Unity.Attributes { /// /// Use the OnChange attribute to recieve a callback whenever a field /// is changed. The callback can be in the form of: /// - A method accepting zero arguments /// - A method accepting a single argument matching the field type /// (new value is passed in as the argument) /// - A property matching the type of the field /// (the setter is called with the new value) /// public class OnEditorChangeAttribute : CombinablePropertyAttribute { public readonly string methodName; public OnEditorChangeAttribute(string methodName) { this.methodName = methodName; } #if UNITY_EDITOR private Action _cachedDelegate; public override void OnPropertyChanged(SerializedProperty property) { base.OnPropertyChanged(property); if (_cachedDelegate == null) { Type type = targets[0].GetType(); PropertyInfo propertyInfo = type.GetProperty(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ); if (propertyInfo != null) { _cachedDelegate = (obj, arg) => propertyInfo.SetValue(obj, arg, null); } else { MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy ); if (method == null) { Debug.LogWarning("Could not find a property or method of the name " + methodName + " " + "to invoke for the OnChange attribute."); return; } int paramCount = method.GetParameters().Length; if (paramCount == 0) { _cachedDelegate = (obj, arg) => method.Invoke(obj, null); } else if (paramCount == 1) { object[] argArray = new object[1]; _cachedDelegate = (obj, arg) => { argArray[0] = arg; method.Invoke(obj, argArray); }; } else { Debug.LogWarning("Could not invoke the method " + methodName + " from OnChange because the method had more than 1 argument."); } } } property.serializedObject.ApplyModifiedProperties(); foreach (var target in targets) { object newValue = fieldInfo.GetValue(target); _cachedDelegate(target, newValue); } } #endif } }