Tanoda
InteractionBehaviourEditor.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using Leap.Unity.Query;
10using UnityEditor;
11using UnityEngine;
12
13namespace Leap.Unity.Interaction {
14
15 [CanEditMultipleObjects]
16 [CustomEditor(typeof(InteractionBehaviour), editorForChildClasses: true)]
17 public class InteractionBehaviourEditor : CustomEditorBase<InteractionBehaviour> {
18
19 private EnumEventTableEditor _tableEditor;
20
21 protected override void OnEnable() {
22 base.OnEnable();
23
24 // Interaction Manager hookup.
25 specifyCustomDecorator("_manager", drawInteractionManagerDecorator);
26
27 deferProperty("_eventTable");
28 specifyCustomDrawer("_eventTable", drawEventTable);
29
30 specifyConditionalDrawing(() => !targets.Query().All(intObj => intObj.ignoreContact),
31 "_contactForceMode");
32
33 specifyConditionalDrawing(() => !targets.Query().All(intObj => intObj.ignoreGrasping),
34 "_allowMultiGrasp",
35 "_moveObjectWhenGrasped",
36 "graspedMovementType");
37
38 // Layer Overrides
39 specifyConditionalDrawing(() => targets.Query().Any(intObj => intObj.overrideInteractionLayer),
40 "_interactionLayer");
41 specifyCustomDecorator("_interactionLayer", drawInteractionLayerDecorator);
42 specifyConditionalDrawing(() => targets.Query().Any(intObj => intObj.overrideNoContactLayer),
43 "_noContactLayer");
44 specifyCustomDecorator("_noContactLayer", drawNoContactLayerDecorator);
45 }
46
47 private void drawInteractionManagerDecorator(SerializedProperty property) {
48 bool shouldDrawInteractionManagerNotSetWarning = false;
49 foreach (var target in targets) {
50 if (Utils.IsObjectPartOfPrefabAsset(target)) continue;
51
52 if (target.manager == null) {
53 shouldDrawInteractionManagerNotSetWarning = true;
54 break;
55 }
56 }
57 if (shouldDrawInteractionManagerNotSetWarning) {
58 bool pluralTargets = targets.Length > 1;
59 string noManagerSetWarningMessage = "";
60 if (pluralTargets) {
61 noManagerSetWarningMessage = "One or more of the currently selected interaction "
62 + "objects doesn't have its Interaction Manager set. ";
63 }
64 else {
65 noManagerSetWarningMessage = "The currently selected interaction object doesn't "
66 + "have its Interaction Manager set. ";
67 }
68 noManagerSetWarningMessage += " Object validation requires a configured manager "
69 + "property.";
70
71 drawSetManagerWarningBox(noManagerSetWarningMessage, MessageType.Error);
72 }
73 }
74
75 private void drawSetManagerWarningBox(string warningMessage, MessageType messageType) {
76 EditorGUILayout.BeginHorizontal();
77
78 EditorGUILayout.HelpBox(warningMessage, messageType);
79
80 Rect buttonRect = EditorGUILayout.GetControlRect(GUILayout.MaxWidth(100F),
81 GUILayout.ExpandHeight(true),
82 GUILayout.MaxHeight(40F));
83 InteractionManager manager = InteractionManager.instance;
84 EditorGUI.BeginDisabledGroup(manager == null);
85 if (GUI.Button(buttonRect, new GUIContent("Auto-Fix",
86 manager == null ? "Please add an Interaction Manager to "
87 + "your scene."
88 : "Use InteractionManager.instance to "
89 + "automatically set the manager of the "
90 + "selected interaction objects."))) {
91 if (manager == null) {
92 Debug.LogError("Attempt to find an InteractionManager instance failed. Is there "
93 + "an InteractionManager in your scene?");
94 }
95 else {
96 foreach (var target in targets) {
97 if (Utils.IsObjectPartOfPrefabAsset(target)) continue;
98
99 Undo.RecordObject(target, "Auto-set Interaction Manager");
100 target.manager = manager;
101 }
102 }
103 }
104 EditorGUI.EndDisabledGroup();
105
106 EditorGUILayout.EndHorizontal();
107
108 EditorGUILayout.Space();
109 }
110
111 private void drawInteractionLayerDecorator(SerializedProperty property) {
112 bool shouldDrawWarning = false;
113 foreach (var target in targets) {
114 if (target.manager == null) continue; // Can't check.
115
116 if (target.overrideInteractionLayer
117 && !target.manager.autoGenerateLayers
118 && Physics.GetIgnoreLayerCollision(target.interactionLayer.layerIndex,
119 target.manager.contactBoneLayer.layerIndex)) {
120
121 shouldDrawWarning = true;
122 break;
123 }
124 }
125
126 if (shouldDrawWarning) {
127 bool pluralTargets = targets.Length > 1;
128 string message;
129 if (pluralTargets) {
130 message = "One or more of the selected interaction objects has its "
131 + "Interaction layer set NOT to collide with the contact bone "
132 + "layer. ";
133 }
134 else {
135 message = "The selected interaction object has its Interaction layer set "
136 + "NOT to collide with the contact bone layer. ";
137 }
138 message += "This will prevent an interaction object from supporting contact with "
139 + "any hands or controllers.";
140
141 EditorGUILayout.HelpBox(message, MessageType.Warning);
142 }
143 }
144
145 private void drawNoContactLayerDecorator(SerializedProperty property) {
146 bool shouldDrawCollisionWarning = false;
147 foreach (var target in targets) {
148 if (target.manager == null) continue; // Can't check.
149
150 if (target.overrideNoContactLayer
151 && !target.manager.autoGenerateLayers
152 && !Physics.GetIgnoreLayerCollision(target.noContactLayer.layerIndex,
153 target.manager.contactBoneLayer.layerIndex)) {
154 shouldDrawCollisionWarning = true;
155 break;
156 }
157 }
158
159 if (shouldDrawCollisionWarning) {
160 bool pluralTargets = targets.Length > 1;
161 string noContactErrorMessage;
162 if (pluralTargets) {
163 noContactErrorMessage = "One or more selected interaction objects has its No "
164 + "Contact layer set to collide with the contact bone "
165 + "layer. ";
166 }
167 else {
168 noContactErrorMessage = "This interaction object has its No Contact layer set "
169 + "to collide with the contact bone layer. ";
170 }
171
172 noContactErrorMessage += "Please ensure the Interaction Manager's contact bone "
173 + "layer is set not to collide with any interaction "
174 + "object's No Contact layer.";
175
176 EditorGUILayout.HelpBox(noContactErrorMessage, MessageType.Error);
177 }
178 }
179
180 public override void OnInspectorGUI() {
181 checkHasColliders();
182
183 base.OnInspectorGUI();
184 }
185
186 private void checkHasColliders() {
187 bool anyMissingColliders = false;
188 foreach (var singleTarget in targets) {
189 if (singleTarget.GetComponentsInChildren<Collider>().Length == 0) {
190 anyMissingColliders = true; break;
191 }
192 }
193
194 if (anyMissingColliders) {
195 bool pluralObjects = targets.Length > 1;
196
197 string message;
198 if (pluralObjects) {
199 message = "One or more of the currently selected interaction objects have no "
200 + "colliders. Interaction objects without any Colliders cannot be "
201 + "interacted with.";
202 }
203 else {
204 message = "This interaction object has no Colliders. Interaction objects "
205 + "without any Colliders cannot be interacted with.";
206 }
207
208 EditorGUILayout.HelpBox(message, MessageType.Warning);
209 }
210 }
211
212 private void drawEventTable(SerializedProperty property) {
213 if (_tableEditor == null) {
214 _tableEditor = new EnumEventTableEditor(property, typeof(InteractionBehaviour.EventType));
215 }
216
217 _tableEditor.DoGuiLayout();
218 }
219 }
220}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
void specifyConditionalDrawing(string conditionalName, params string[] dependantProperties)
Specify a list of properties that should only be displayed if the conditional property has a value of...
void deferProperty(string propertyName)
Defer rendering of a property until the end of the inspector. Deferred properties are drawn in the RE...
void specifyCustomDrawer(string propertyName, Action< SerializedProperty > propertyDrawer)
Specify a callback to be used to draw a specific named property. Should be called in OnEnable.
void specifyCustomDecorator(string propertyName, Action< SerializedProperty > decoratorDrawer)
Specify a callback to be used to draw a decorator for a specific named property. Should be called in ...