A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
2using System.Linq;
3using UnityEditor;
4using UnityEngine.UIElements;
5using UnityEngine.InputSystem.Layouts;
6using UnityEngine.InputSystem.Utilities;
7using System.Collections.Generic;
8
9namespace UnityEngine.InputSystem.Editor
10{
11 internal class BindingPropertiesView : ViewBase<BindingPropertiesView.ViewState>
12 {
13 private readonly Foldout m_ParentFoldout;
14 private CompositeBindingPropertiesView m_CompositeBindingPropertiesView;
15 private CompositePartBindingPropertiesView m_CompositePartBindingPropertiesView;
16
17 public BindingPropertiesView(VisualElement root, Foldout foldout, StateContainer stateContainer)
18 : base(root, stateContainer)
19 {
20 m_ParentFoldout = foldout;
21
22 CreateSelector(state => state.selectedBindingIndex,
23 s => new ViewStateCollection<InputControlScheme>(Selectors.GetControlSchemes(s)),
24 (_, controlSchemes, s) => new ViewState
25 {
26 controlSchemes = controlSchemes,
27 currentControlScheme = s.selectedControlScheme,
28 selectedBinding = Selectors.GetSelectedBinding(s),
29 selectedBindingIndex = s.selectedBindingIndex,
30 selectedBindingPath = Selectors.GetSelectedBindingPath(s),
31 selectedInputAction = Selectors.GetSelectedAction(s)
32 });
33 }
34
35 public override void RedrawUI(ViewState viewState)
36 {
37 var selectedBindingIndex = viewState.selectedBindingIndex;
38 if (selectedBindingIndex == -1)
39 return;
40
41 rootElement.Clear();
42
43 var binding = viewState.selectedBinding;
44 if (!binding.HasValue)
45 return;
46
47 m_ParentFoldout.text = "Binding";
48 if (binding.Value.isComposite)
49 {
50 m_ParentFoldout.text = "Composite";
51 m_CompositeBindingPropertiesView = CreateChildView(new CompositeBindingPropertiesView(rootElement, stateContainer));
52 }
53 else if (binding.Value.isPartOfComposite)
54 {
55 m_CompositePartBindingPropertiesView = CreateChildView(new CompositePartBindingPropertiesView(rootElement, stateContainer));
56 DrawMatchingControlPaths(viewState);
57 DrawControlSchemeToggles(viewState, binding.Value);
58 }
59 else
60 {
61 var controlPathEditor = new InputControlPathEditor(viewState.selectedBindingPath, new InputControlPickerState(),
62 () => { Dispatch(Commands.ApplyModifiedProperties()); });
63 controlPathEditor.SetControlPathsToMatch(viewState.currentControlScheme.deviceRequirements.Select(x => x.controlPath));
64
65 var inputAction = viewState.selectedInputAction;
66 controlPathEditor.SetExpectedControlLayout(inputAction?.expectedControlType ?? "");
67
68 var controlPathContainer = new IMGUIContainer(controlPathEditor.OnGUI);
69 rootElement.Add(controlPathContainer);
70
71 DrawMatchingControlPaths(viewState);
72 DrawControlSchemeToggles(viewState, binding.Value);
73 }
74 }
75
76 static bool s_showMatchingLayouts = false;
77 internal void DrawMatchingControlPaths(ViewState viewState)
78 {
79 bool controlPathUsagePresent = false;
80 bool showPaths = s_showMatchingLayouts;
81 List<MatchingControlPath> matchingControlPaths = MatchingControlPath.CollectMatchingControlPaths(viewState.selectedBindingPath.stringValue, showPaths, ref controlPathUsagePresent);
82
83 var parentElement = rootElement;
84 if (matchingControlPaths == null || matchingControlPaths.Count != 0)
85 {
86 var controllingElement = new Foldout()
87 {
88 text = $"Show Derived Bindings",
89 value = showPaths
90 };
91 rootElement.Add(controllingElement);
92
93 controllingElement.RegisterValueChangedCallback(changeEvent =>
94 {
95 if (changeEvent.target == controllingElement) // only react to foldout and not tree elements
96 s_showMatchingLayouts = changeEvent.newValue;
97 });
98
99 parentElement = controllingElement;
100 }
101
102 if (matchingControlPaths == null)
103 {
104 var messageString = controlPathUsagePresent ? "No registered controls match this current binding. Some controls are only registered at runtime." :
105 "No other registered controls match this current binding. Some controls are only registered at runtime.";
106
107 var helpBox = new HelpBox(messageString, HelpBoxMessageType.Warning);
108 helpBox.AddToClassList("matching-controls");
109 parentElement.Add(helpBox);
110 }
111 else if (matchingControlPaths.Count > 0)
112 {
113 List<TreeViewItemData<MatchingControlPath>> treeViewMatchingControlPaths = MatchingControlPath.BuildMatchingControlPathsTreeData(matchingControlPaths);
114
115 var treeView = new TreeView();
116 parentElement.Add(treeView);
117 treeView.selectionType = UIElements.SelectionType.None;
118 treeView.AddToClassList("matching-controls");
119 treeView.fixedItemHeight = 20;
120 treeView.SetRootItems(treeViewMatchingControlPaths);
121
122 // Set TreeView.makeItem to initialize each node in the tree.
123 treeView.makeItem = () =>
124 {
125 var label = new Label();
126 label.AddToClassList("matching-controls-labels");
127 return label;
128 };
129
130 // Set TreeView.bindItem to bind an initialized node to a data item.
131 treeView.bindItem = (VisualElement element, int index) =>
132 {
133 var label = (element as Label);
134 var matchingControlPath = treeView.GetItemDataForIndex<MatchingControlPath>(index);
135 label.text = $"{matchingControlPath.deviceName} > {matchingControlPath.controlName}";
136 };
137
138 treeView.ExpandRootItems();
139 }
140 }
141
142 public override void DestroyView()
143 {
144 m_CompositeBindingPropertiesView?.DestroyView();
145 m_CompositePartBindingPropertiesView?.DestroyView();
146 }
147
148 private void DrawControlSchemeToggles(ViewState viewState, SerializedInputBinding binding)
149 {
150 if (!viewState.controlSchemes.Any()) return;
151
152 var useInControlSchemeLabel = new Label("Use in control scheme")
153 {
154 name = "control-scheme-usage-title"
155 };
156
157 rootElement.Add(useInControlSchemeLabel);
158
159 foreach (var controlScheme in viewState.controlSchemes)
160 {
161 var checkbox = new Toggle(controlScheme.name)
162 {
163 value = binding.controlSchemes.Any(scheme => controlScheme.name == scheme)
164 };
165 rootElement.Add(checkbox);
166 checkbox.RegisterValueChangedCallback(changeEvent =>
167 {
168 Dispatch(ControlSchemeCommands.ChangeSelectedBindingsControlSchemes(controlScheme.name, changeEvent.newValue));
169 });
170 }
171 }
172
173 internal class ViewState
174 {
175 public int selectedBindingIndex;
176 public SerializedInputBinding? selectedBinding;
177 public ViewStateCollection<InputControlScheme> controlSchemes;
178 public InputControlScheme currentControlScheme;
179 public SerializedProperty selectedBindingPath;
180 public SerializedInputAction? selectedInputAction;
181 }
182 }
183}
184
185#endif