A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR
2using System.Linq;
3using UnityEditor;
4
5////TODO: support multi-object editing
6
7namespace UnityEngine.InputSystem.Samples.RebindUI
8{
9 /// <summary>
10 /// A custom inspector for <see cref="RebindActionUI"/> which provides a more convenient way for
11 /// picking the binding which to rebind.
12 /// </summary>
13 [CustomEditor(typeof(RebindActionUI))]
14 public class RebindActionUIEditor : UnityEditor.Editor
15 {
16 protected void OnEnable()
17 {
18 m_ActionProperty = serializedObject.FindProperty("m_Action");
19 m_BindingIdProperty = serializedObject.FindProperty("m_BindingId");
20 m_ActionLabelProperty = serializedObject.FindProperty("m_ActionLabel");
21 m_BindingTextProperty = serializedObject.FindProperty("m_BindingText");
22 m_RebindOverlayProperty = serializedObject.FindProperty("m_RebindOverlay");
23 m_RebindTextProperty = serializedObject.FindProperty("m_RebindText");
24 m_UpdateBindingUIEventProperty = serializedObject.FindProperty("m_UpdateBindingUIEvent");
25 m_RebindStartEventProperty = serializedObject.FindProperty("m_RebindStartEvent");
26 m_RebindStopEventProperty = serializedObject.FindProperty("m_RebindStopEvent");
27 m_DisplayStringOptionsProperty = serializedObject.FindProperty("m_DisplayStringOptions");
28
29 RefreshBindingOptions();
30 }
31
32 public override void OnInspectorGUI()
33 {
34 EditorGUI.BeginChangeCheck();
35
36 // Binding section.
37 EditorGUILayout.LabelField(m_BindingLabel, Styles.boldLabel);
38 using (new EditorGUI.IndentLevelScope())
39 {
40 EditorGUILayout.PropertyField(m_ActionProperty);
41
42 var newSelectedBinding = EditorGUILayout.Popup(m_BindingLabel, m_SelectedBindingOption, m_BindingOptions);
43 if (newSelectedBinding != m_SelectedBindingOption)
44 {
45 var bindingId = m_BindingOptionValues[newSelectedBinding];
46 m_BindingIdProperty.stringValue = bindingId;
47 m_SelectedBindingOption = newSelectedBinding;
48 }
49
50 var optionsOld = (InputBinding.DisplayStringOptions)m_DisplayStringOptionsProperty.intValue;
51 var optionsNew = (InputBinding.DisplayStringOptions)EditorGUILayout.EnumFlagsField(m_DisplayOptionsLabel, optionsOld);
52 if (optionsOld != optionsNew)
53 m_DisplayStringOptionsProperty.intValue = (int)optionsNew;
54 }
55
56 // UI section.
57 EditorGUILayout.Space();
58 EditorGUILayout.LabelField(m_UILabel, Styles.boldLabel);
59 using (new EditorGUI.IndentLevelScope())
60 {
61 EditorGUILayout.PropertyField(m_ActionLabelProperty);
62 EditorGUILayout.PropertyField(m_BindingTextProperty);
63 EditorGUILayout.PropertyField(m_RebindOverlayProperty);
64 EditorGUILayout.PropertyField(m_RebindTextProperty);
65 }
66
67 // Events section.
68 EditorGUILayout.Space();
69 EditorGUILayout.LabelField(m_EventsLabel, Styles.boldLabel);
70 using (new EditorGUI.IndentLevelScope())
71 {
72 EditorGUILayout.PropertyField(m_RebindStartEventProperty);
73 EditorGUILayout.PropertyField(m_RebindStopEventProperty);
74 EditorGUILayout.PropertyField(m_UpdateBindingUIEventProperty);
75 }
76
77 if (EditorGUI.EndChangeCheck())
78 {
79 serializedObject.ApplyModifiedProperties();
80 RefreshBindingOptions();
81 }
82 }
83
84 protected void RefreshBindingOptions()
85 {
86 var actionReference = (InputActionReference)m_ActionProperty.objectReferenceValue;
87 var action = actionReference?.action;
88
89 if (action == null)
90 {
91 m_BindingOptions = new GUIContent[0];
92 m_BindingOptionValues = new string[0];
93 m_SelectedBindingOption = -1;
94 return;
95 }
96
97 var bindings = action.bindings;
98 var bindingCount = bindings.Count;
99
100 m_BindingOptions = new GUIContent[bindingCount];
101 m_BindingOptionValues = new string[bindingCount];
102 m_SelectedBindingOption = -1;
103
104 var currentBindingId = m_BindingIdProperty.stringValue;
105 for (var i = 0; i < bindingCount; ++i)
106 {
107 var binding = bindings[i];
108 var bindingId = binding.id.ToString();
109 var haveBindingGroups = !string.IsNullOrEmpty(binding.groups);
110
111 // If we don't have a binding groups (control schemes), show the device that if there are, for example,
112 // there are two bindings with the display string "A", the user can see that one is for the keyboard
113 // and the other for the gamepad.
114 var displayOptions =
115 InputBinding.DisplayStringOptions.DontUseShortDisplayNames | InputBinding.DisplayStringOptions.IgnoreBindingOverrides;
116 if (!haveBindingGroups)
117 displayOptions |= InputBinding.DisplayStringOptions.DontOmitDevice;
118
119 // Create display string.
120 var displayString = action.GetBindingDisplayString(i, displayOptions);
121
122 // If binding is part of a composite, include the part name.
123 if (binding.isPartOfComposite)
124 displayString = $"{ObjectNames.NicifyVariableName(binding.name)}: {displayString}";
125
126 // Some composites use '/' as a separator. When used in popup, this will lead to to submenus. Prevent
127 // by instead using a backlash.
128 displayString = displayString.Replace('/', '\\');
129
130 // If the binding is part of control schemes, mention them.
131 if (haveBindingGroups)
132 {
133 var asset = action.actionMap?.asset;
134 if (asset != null)
135 {
136 var controlSchemes = string.Join(", ",
137 binding.groups.Split(InputBinding.Separator)
138 .Select(x => asset.controlSchemes.FirstOrDefault(c => c.bindingGroup == x).name));
139
140 displayString = $"{displayString} ({controlSchemes})";
141 }
142 }
143
144 m_BindingOptions[i] = new GUIContent(displayString);
145 m_BindingOptionValues[i] = bindingId;
146
147 if (currentBindingId == bindingId)
148 m_SelectedBindingOption = i;
149 }
150 }
151
152 private SerializedProperty m_ActionProperty;
153 private SerializedProperty m_BindingIdProperty;
154 private SerializedProperty m_ActionLabelProperty;
155 private SerializedProperty m_BindingTextProperty;
156 private SerializedProperty m_RebindOverlayProperty;
157 private SerializedProperty m_RebindTextProperty;
158 private SerializedProperty m_RebindStartEventProperty;
159 private SerializedProperty m_RebindStopEventProperty;
160 private SerializedProperty m_UpdateBindingUIEventProperty;
161 private SerializedProperty m_DisplayStringOptionsProperty;
162
163 private GUIContent m_BindingLabel = new GUIContent("Binding");
164 private GUIContent m_DisplayOptionsLabel = new GUIContent("Display Options");
165 private GUIContent m_UILabel = new GUIContent("UI");
166 private GUIContent m_EventsLabel = new GUIContent("Events");
167 private GUIContent[] m_BindingOptions;
168 private string[] m_BindingOptionValues;
169 private int m_SelectedBindingOption;
170
171 private static class Styles
172 {
173 public static GUIStyle boldLabel = new GUIStyle("MiniBoldLabel");
174 }
175 }
176}
177#endif