#if UNITY_EDITOR using UnityEditor; using UnityEditor.IMGUI.Controls; namespace UnityEngine.InputSystem.Editor { /// /// Base class for property drawers that display input actions. /// internal abstract class InputActionDrawerBase : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { InitTreeIfNeeded(property); return m_TreeView.totalHeight; } public override bool CanCacheInspectorGUI(SerializedProperty property) { return false; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { InitTreeIfNeeded(property); EditorGUI.BeginProperty(position, label, property); SetNameIfNotSet(property); m_TreeView.OnGUI(position); EditorGUI.EndProperty(); } private void InitTreeIfNeeded(SerializedProperty property) { // NOTE: Unlike InputActionEditorWindow, we do not need to protect against the SerializedObject // changing behind our backs by undo/redo here. Being a PropertyDrawer, we will automatically // get recreated by Unity when it touches our serialized data. if (m_TreeView == null) { // Create tree and populate it. m_TreeView = new InputActionTreeView(property.serializedObject) { onBuildTree = () => BuildTree(property), onDoubleClick = OnItemDoubleClicked, title = property.displayName, // With the tree in the inspector, the foldouts are drawn too far to the left. I don't // really know where this is coming from. This works around it by adding an arbitrary offset... foldoutOffset = 14, drawActionPropertiesButton = true }; m_TreeView.Reload(); } } private void SetNameIfNotSet(SerializedProperty actionProperty) { var nameProperty = actionProperty.FindPropertyRelative("m_Name"); if (!string.IsNullOrEmpty(nameProperty.stringValue)) return; // Special case for InputActionProperty where we want to take the name not from // the m_Action property embedded in it but rather from the InputActionProperty field // itself. var name = actionProperty.displayName; var parent = actionProperty.GetParentProperty(); if (parent != null && parent.type == "InputActionProperty") name = parent.displayName; var suffix = GetSuffixToRemoveFromPropertyDisplayName(); if (name.EndsWith(suffix)) name = name.Substring(0, name.Length - suffix.Length); nameProperty.stringValue = name; nameProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo(); } private void OnItemDoubleClicked(ActionTreeItemBase item) { // Double-clicking on binding or action item opens property popup. PropertiesViewBase propertyView = null; if (item is BindingTreeItem) { if (m_ControlPickerState == null) m_ControlPickerState = new InputControlPickerState(); propertyView = new InputBindingPropertiesView(item.property, controlPickerState: m_ControlPickerState, expectedControlLayout: item.expectedControlLayout, onChange: change => m_TreeView.Reload()); } else if (item is ActionTreeItem) { propertyView = new InputActionPropertiesView(item.property, onChange: change => m_TreeView.Reload()); } if (propertyView != null) { var rect = new Rect(GUIUtility.GUIToScreenPoint(Event.current.mousePosition), Vector2.zero); PropertiesViewPopup.Show(rect, propertyView); } } protected abstract TreeViewItem BuildTree(SerializedProperty property); protected abstract string GetSuffixToRemoveFromPropertyDisplayName(); private InputActionTreeView m_TreeView; private InputControlPickerState m_ControlPickerState; internal class PropertiesViewPopup : EditorWindow { public static void Show(Rect btnRect, PropertiesViewBase view) { var window = CreateInstance(); window.m_PropertyView = view; window.ShowPopup(); window.ShowAsDropDown(btnRect, new Vector2(300, 350)); } private void OnGUI() { m_PropertyView.OnGUI(); } private PropertiesViewBase m_PropertyView; } } } #endif // UNITY_EDITOR