#if UNITY_EDITOR using UnityEditor; namespace UnityEngine.InputSystem.Editor { /// /// A custom property drawer for . /// /// /// Selectively draws the and/or the /// underlying the property, based on whether the property is set to use a reference or not. /// The drawer also allows for drawing in different layouts, chosen through Project Settings. /// /// [CustomPropertyDrawer(typeof(InputActionProperty))] internal class InputActionPropertyDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (property == null) throw new System.ArgumentNullException(nameof(property)); var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode; switch (drawerMode) { case InputSettings.InputActionPropertyDrawerMode.Compact: default: return GetCompactHeight(property); case InputSettings.InputActionPropertyDrawerMode.MultilineEffective: case InputSettings.InputActionPropertyDrawerMode.MultilineBoth: return GetMultilineHeight(property, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective); } } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property == null) throw new System.ArgumentNullException(nameof(property)); // Using BeginProperty / EndProperty on the parent property means that // prefab override logic works on the entire property. label = EditorGUI.BeginProperty(position, label, property); var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode; switch (drawerMode) { case InputSettings.InputActionPropertyDrawerMode.Compact: default: DrawCompactGUI(position, property, label); break; case InputSettings.InputActionPropertyDrawerMode.MultilineEffective: case InputSettings.InputActionPropertyDrawerMode.MultilineBoth: DrawMultilineGUI(position, property, label, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective); break; } EditorGUI.EndProperty(); } static float GetCompactHeight(SerializedProperty property) { var useReference = property.FindPropertyRelative("m_UseReference"); var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action"); return EditorGUI.GetPropertyHeight(effectiveProperty); } static float GetMultilineHeight(SerializedProperty property, bool showEffectiveOnly) { var height = 0f; // Field label. height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; // "Use Reference" toggle. height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; // We show either the InputAction property drawer or InputActionReference drawer (default object field). var useReference = property.FindPropertyRelative("m_UseReference"); var reference = property.FindPropertyRelative("m_Reference"); var action = property.FindPropertyRelative("m_Action"); if (showEffectiveOnly) { var effectiveProperty = useReference.boolValue ? reference : action; height += EditorGUI.GetPropertyHeight(effectiveProperty); } else { height += EditorGUI.GetPropertyHeight(reference) + EditorGUI.GetPropertyHeight(action); } return height; } static void DrawCompactGUI(Rect position, SerializedProperty property, GUIContent label) { position = EditorGUI.PrefixLabel(position, label); var useReference = property.FindPropertyRelative("m_UseReference"); var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action"); // Calculate rect for configuration button var buttonRect = position; var popupStyle = Styles.popup; buttonRect.yMin += popupStyle.margin.top + 1f; buttonRect.width = popupStyle.fixedWidth + popupStyle.margin.right; buttonRect.height = EditorGUIUtility.singleLineHeight; position.xMin = buttonRect.xMax; // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; // Using BeginProperty / EndProperty on the popup button allows the user to // revert prefab overrides to Use Reference by right-clicking the configuration button. EditorGUI.BeginProperty(buttonRect, GUIContent.none, useReference); using (var check = new EditorGUI.ChangeCheckScope()) { var newPopupIndex = EditorGUI.Popup(buttonRect, GetCompactPopupIndex(useReference), Contents.compactPopupOptions, popupStyle); if (check.changed) useReference.boolValue = IsUseReference(newPopupIndex); } EditorGUI.EndProperty(); EditorGUI.PropertyField(position, effectiveProperty, GUIContent.none); // Set indent back to what it was EditorGUI.indentLevel = indent; } static void DrawMultilineGUI(Rect position, SerializedProperty property, GUIContent label, bool showEffectiveOnly) { const float kIndent = 15f; var titleRect = position; titleRect.height = EditorGUIUtility.singleLineHeight; var useReference = property.FindPropertyRelative("m_UseReference"); var useReferenceToggleRect = position; useReferenceToggleRect.x += kIndent; useReferenceToggleRect.width -= kIndent; useReferenceToggleRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; useReferenceToggleRect.height = EditorGUI.GetPropertyHeight(useReference); var firstValueRect = position; firstValueRect.x += kIndent; firstValueRect.width -= kIndent; firstValueRect.y += (titleRect.height + useReferenceToggleRect.height) + (EditorGUIUtility.standardVerticalSpacing * 2f); var reference = property.FindPropertyRelative("m_Reference"); var action = property.FindPropertyRelative("m_Action"); // Draw the Use Reference toggle. EditorGUI.LabelField(titleRect, label); EditorGUI.PropertyField(useReferenceToggleRect, useReference); if (showEffectiveOnly) { // Draw only the Reference or Action underlying the property, whichever is the effective one. var effectiveProperty = useReference.boolValue ? reference : action; firstValueRect.height = EditorGUI.GetPropertyHeight(effectiveProperty); EditorGUI.PropertyField(firstValueRect, effectiveProperty); } else { // Draw the Action followed by the Reference. firstValueRect.height = EditorGUI.GetPropertyHeight(action); var referenceRect = firstValueRect; referenceRect.y += firstValueRect.height + EditorGUIUtility.standardVerticalSpacing; referenceRect.height = EditorGUI.GetPropertyHeight(reference); EditorGUI.PropertyField(firstValueRect, action); EditorGUI.PropertyField(referenceRect, reference); } } // 0 == Use Reference, 1 == Use Action // Keep synced with Contents.compactPopupOptions. static int GetCompactPopupIndex(SerializedProperty useReference) => useReference.boolValue ? 0 : 1; static bool IsUseReference(int index) => index == 0; static class Contents { static readonly GUIContent s_UseReference = EditorGUIUtility.TrTextContent("Use Reference"); static readonly GUIContent s_UseAction = EditorGUIUtility.TrTextContent("Use Action"); public static readonly GUIContent[] compactPopupOptions = { s_UseReference, s_UseAction }; } static class Styles { public static readonly GUIStyle popup = new GUIStyle("PaneOptions") { imagePosition = ImagePosition.ImageOnly }; } } } #endif // UNITY_EDITOR