199 lines
8.9 KiB
C#
199 lines
8.9 KiB
C#
|
#if UNITY_EDITOR
|
||
|
using UnityEditor;
|
||
|
|
||
|
namespace UnityEngine.InputSystem.Editor
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// A custom property drawer for <see cref="InputActionProperty"/>.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Selectively draws the <see cref="InputActionReference"/> and/or the <see cref="InputAction"/>
|
||
|
/// 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.
|
||
|
/// </remarks>
|
||
|
/// <seealso cref="InputSettings.InputActionPropertyDrawerMode"/>
|
||
|
[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
|