#if UNITY_EDITOR using UnityEditor; using UnityEditor.UIElements; using UnityEditor.Search; using ObjectField = UnityEditor.Search.ObjectField; namespace UnityEngine.InputSystem.Editor { /// /// Custom property drawer in order to use the "Advanced Picker" from UnityEditor.Search. /// [CustomPropertyDrawer(typeof(InputActionReference))] internal sealed class InputActionReferencePropertyDrawer : PropertyDrawer { // Custom search providers for asset-based, and project-wide actions input action reference sub-assets. private readonly SearchContext m_Context = UnityEditor.Search.SearchService.CreateContext(new[] { InputActionReferenceSearchProviders.CreateInputActionReferenceSearchProviderForAssets(), InputActionReferenceSearchProviders.CreateInputActionReferenceSearchProviderForProjectWideActions(), }, string.Empty, SearchConstants.PickerSearchFlags); public void OnGUI(Rect position, SerializedProperty property, GUIContent label, System.Func doField = null) { EditorGUI.BeginProperty(position, label, property); EditorGUI.BeginChangeCheck(); var current = property.objectReferenceValue; // If the reference is set but cannot be resolved, we want to be consistent with standard unity objects // which resolve to display "Missing (Type)". This isn't really feasible since our SO isn't destroyed // directly if referenced from other assets and we have two-layer indirection (InputAction isn't an asset). // Hence, the next best thing we can do is pass null to object field to show "None (Type)" to indicate // a broken reference that need to be replaced. If however, other code would manage to delete the SO, // "Missing (Type)" should be the result. var obj = current; var currentReference = current as InputActionReference; if (currentReference && currentReference.action == null) obj = null; // none/missing // Pick an InputActionReference using custom picker. We need to use this overload taking an object // in order to be in control of the actual assignment to the serialized property so we can substitute. // We allow substituting the object field here to at least enable some test coverage. var candidate = doField != null ? doField(position, obj, typeof(InputActionReference), label) : ObjectField.DoObjectField(position, obj, typeof(InputActionReference), label, m_Context, SearchConstants.PickerViewFlags); // Only assign the value was actually changed by the user. if (EditorGUI.EndChangeCheck() && !Equals(candidate, current)) { var reference = candidate as InputActionReference; property.objectReferenceValue = reference ? InputActionReference.Create(reference.action) : null; } EditorGUI.EndProperty(); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { OnGUI(position, property, label); } } } #endif