UnityGame/Library/PackageCache/com.unity.inputsystem/InputSystem/Editor/PropertyDrawers/InputActionPropertyDrawer.cs

199 lines
8.9 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
#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