暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InputActionPropertyDrawer.cs 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #if UNITY_EDITOR
  2. using UnityEditor;
  3. namespace UnityEngine.InputSystem.Editor
  4. {
  5. /// <summary>
  6. /// A custom property drawer for <see cref="InputActionProperty"/>.
  7. /// </summary>
  8. /// <remarks>
  9. /// Selectively draws the <see cref="InputActionReference"/> and/or the <see cref="InputAction"/>
  10. /// underlying the property, based on whether the property is set to use a reference or not.
  11. /// The drawer also allows for drawing in different layouts, chosen through Project Settings.
  12. /// </remarks>
  13. /// <seealso cref="InputSettings.InputActionPropertyDrawerMode"/>
  14. [CustomPropertyDrawer(typeof(InputActionProperty))]
  15. internal class InputActionPropertyDrawer : PropertyDrawer
  16. {
  17. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  18. {
  19. if (property == null)
  20. throw new System.ArgumentNullException(nameof(property));
  21. var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode;
  22. switch (drawerMode)
  23. {
  24. case InputSettings.InputActionPropertyDrawerMode.Compact:
  25. default:
  26. return GetCompactHeight(property);
  27. case InputSettings.InputActionPropertyDrawerMode.MultilineEffective:
  28. case InputSettings.InputActionPropertyDrawerMode.MultilineBoth:
  29. return GetMultilineHeight(property, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective);
  30. }
  31. }
  32. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  33. {
  34. if (property == null)
  35. throw new System.ArgumentNullException(nameof(property));
  36. // Using BeginProperty / EndProperty on the parent property means that
  37. // prefab override logic works on the entire property.
  38. label = EditorGUI.BeginProperty(position, label, property);
  39. var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode;
  40. switch (drawerMode)
  41. {
  42. case InputSettings.InputActionPropertyDrawerMode.Compact:
  43. default:
  44. DrawCompactGUI(position, property, label);
  45. break;
  46. case InputSettings.InputActionPropertyDrawerMode.MultilineEffective:
  47. case InputSettings.InputActionPropertyDrawerMode.MultilineBoth:
  48. DrawMultilineGUI(position, property, label, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective);
  49. break;
  50. }
  51. EditorGUI.EndProperty();
  52. }
  53. static float GetCompactHeight(SerializedProperty property)
  54. {
  55. var useReference = property.FindPropertyRelative("m_UseReference");
  56. var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action");
  57. return EditorGUI.GetPropertyHeight(effectiveProperty);
  58. }
  59. static float GetMultilineHeight(SerializedProperty property, bool showEffectiveOnly)
  60. {
  61. var height = 0f;
  62. // Field label.
  63. height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
  64. // "Use Reference" toggle.
  65. height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
  66. // We show either the InputAction property drawer or InputActionReference drawer (default object field).
  67. var useReference = property.FindPropertyRelative("m_UseReference");
  68. var reference = property.FindPropertyRelative("m_Reference");
  69. var action = property.FindPropertyRelative("m_Action");
  70. if (showEffectiveOnly)
  71. {
  72. var effectiveProperty = useReference.boolValue ? reference : action;
  73. height += EditorGUI.GetPropertyHeight(effectiveProperty);
  74. }
  75. else
  76. {
  77. height += EditorGUI.GetPropertyHeight(reference) + EditorGUI.GetPropertyHeight(action);
  78. }
  79. return height;
  80. }
  81. static void DrawCompactGUI(Rect position, SerializedProperty property, GUIContent label)
  82. {
  83. position = EditorGUI.PrefixLabel(position, label);
  84. var useReference = property.FindPropertyRelative("m_UseReference");
  85. var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action");
  86. // Calculate rect for configuration button
  87. var buttonRect = position;
  88. var popupStyle = Styles.popup;
  89. buttonRect.yMin += popupStyle.margin.top + 1f;
  90. buttonRect.width = popupStyle.fixedWidth + popupStyle.margin.right;
  91. buttonRect.height = EditorGUIUtility.singleLineHeight;
  92. position.xMin = buttonRect.xMax;
  93. // Don't make child fields be indented
  94. var indent = EditorGUI.indentLevel;
  95. EditorGUI.indentLevel = 0;
  96. // Using BeginProperty / EndProperty on the popup button allows the user to
  97. // revert prefab overrides to Use Reference by right-clicking the configuration button.
  98. EditorGUI.BeginProperty(buttonRect, GUIContent.none, useReference);
  99. using (var check = new EditorGUI.ChangeCheckScope())
  100. {
  101. var newPopupIndex = EditorGUI.Popup(buttonRect, GetCompactPopupIndex(useReference), Contents.compactPopupOptions, popupStyle);
  102. if (check.changed)
  103. useReference.boolValue = IsUseReference(newPopupIndex);
  104. }
  105. EditorGUI.EndProperty();
  106. EditorGUI.PropertyField(position, effectiveProperty, GUIContent.none);
  107. // Set indent back to what it was
  108. EditorGUI.indentLevel = indent;
  109. }
  110. static void DrawMultilineGUI(Rect position, SerializedProperty property, GUIContent label, bool showEffectiveOnly)
  111. {
  112. const float kIndent = 15f;
  113. var titleRect = position;
  114. titleRect.height = EditorGUIUtility.singleLineHeight;
  115. var useReference = property.FindPropertyRelative("m_UseReference");
  116. var useReferenceToggleRect = position;
  117. useReferenceToggleRect.x += kIndent;
  118. useReferenceToggleRect.width -= kIndent;
  119. useReferenceToggleRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
  120. useReferenceToggleRect.height = EditorGUI.GetPropertyHeight(useReference);
  121. var firstValueRect = position;
  122. firstValueRect.x += kIndent;
  123. firstValueRect.width -= kIndent;
  124. firstValueRect.y += (titleRect.height + useReferenceToggleRect.height) + (EditorGUIUtility.standardVerticalSpacing * 2f);
  125. var reference = property.FindPropertyRelative("m_Reference");
  126. var action = property.FindPropertyRelative("m_Action");
  127. // Draw the Use Reference toggle.
  128. EditorGUI.LabelField(titleRect, label);
  129. EditorGUI.PropertyField(useReferenceToggleRect, useReference);
  130. if (showEffectiveOnly)
  131. {
  132. // Draw only the Reference or Action underlying the property, whichever is the effective one.
  133. var effectiveProperty = useReference.boolValue ? reference : action;
  134. firstValueRect.height = EditorGUI.GetPropertyHeight(effectiveProperty);
  135. EditorGUI.PropertyField(firstValueRect, effectiveProperty);
  136. }
  137. else
  138. {
  139. // Draw the Action followed by the Reference.
  140. firstValueRect.height = EditorGUI.GetPropertyHeight(action);
  141. var referenceRect = firstValueRect;
  142. referenceRect.y += firstValueRect.height + EditorGUIUtility.standardVerticalSpacing;
  143. referenceRect.height = EditorGUI.GetPropertyHeight(reference);
  144. EditorGUI.PropertyField(firstValueRect, action);
  145. EditorGUI.PropertyField(referenceRect, reference);
  146. }
  147. }
  148. // 0 == Use Reference, 1 == Use Action
  149. // Keep synced with Contents.compactPopupOptions.
  150. static int GetCompactPopupIndex(SerializedProperty useReference) => useReference.boolValue ? 0 : 1;
  151. static bool IsUseReference(int index) => index == 0;
  152. static class Contents
  153. {
  154. static readonly GUIContent s_UseReference = EditorGUIUtility.TrTextContent("Use Reference");
  155. static readonly GUIContent s_UseAction = EditorGUIUtility.TrTextContent("Use Action");
  156. public static readonly GUIContent[] compactPopupOptions = { s_UseReference, s_UseAction };
  157. }
  158. static class Styles
  159. {
  160. public static readonly GUIStyle popup = new GUIStyle("PaneOptions") { imagePosition = ImagePosition.ImageOnly };
  161. }
  162. }
  163. }
  164. #endif // UNITY_EDITOR