static Object DoObjectField(Rect position, Rect dropRect, int id, Object obj, Object objBeingEdited, System.Type objType, System.Type additionalType, SerializedProperty property, ObjectFieldValidator validator, bool allowSceneObjects, GUIStyle style, GUIStyle buttonStyle)
{
if (validator == null)
{
validator = ValidateObjectFieldAssignment;
}
if (property != null)
{
obj = property.objectReferenceValue;
}
Event evt = Event.current;
EventType eventType = evt.type;
// special case test, so we continue to ping/select objects with the object field disabled
if (!GUI.enabled && GUIClip.enabled && (Event.current.rawType == EventType.MouseDown))
{
eventType = Event.current.rawType;
}
bool hasThumbnail = EditorGUIUtility.HasObjectThumbnail(objType);
// Determine visual type
ObjectFieldVisualType visualType = ObjectFieldVisualType.IconAndText;
if (hasThumbnail && position.height <= kObjectFieldMiniThumbnailHeight && position.width <= kObjectFieldMiniThumbnailWidth)
{
visualType = ObjectFieldVisualType.MiniPreview;
}
else if (hasThumbnail && position.height > kSingleLineHeight)
{
visualType = ObjectFieldVisualType.LargePreview;
}
Vector2 oldIconSize = EditorGUIUtility.GetIconSize();
if (visualType == ObjectFieldVisualType.IconAndText)
{
EditorGUIUtility.SetIconSize(new Vector2(12, 12)); // Have to be this small to fit inside a single line height ObjectField
}
else if (visualType == ObjectFieldVisualType.LargePreview)
{
EditorGUIUtility.SetIconSize(new Vector2(64, 64));
}
if ((eventType == EventType.MouseDown && Event.current.button == 1 ||
(eventType == EventType.ContextClick && visualType == ObjectFieldVisualType.IconAndText)) &&
position.Contains(Event.current.mousePosition))
{
var actualObject = property != null ? property.objectReferenceValue : obj;
var contextMenu = new GenericMenu();
if (FillPropertyContextMenu(property, null, contextMenu) != null)
{
contextMenu.AddSeparator("");
}
contextMenu.AddItem(GUIContent.Temp("Properties..."), false, () => PropertyEditor.OpenPropertyEditor(actualObject));
contextMenu.DropDown(position);
Event.current.Use();
}
switch (eventType)
{
case EventType.DragExited:
if (GUI.enabled)
{
HandleUtility.Repaint();
}
break;
case EventType.DragUpdated:
case EventType.DragPerform:
if (eventType == EventType.DragPerform)
{
string errorString;
if (!ValidDroppedObject(DragAndDrop.objectReferences, objType, out errorString))
{
Object reference = DragAndDrop.objectReferences[0];
EditorUtility.DisplayDialog("Can't assign script", errorString, "OK");
break;
}
}
if (dropRect.Contains(Event.current.mousePosition) && GUI.enabled)
{
Object[] references = DragAndDrop.objectReferences;
Object validatedObject = validator(references, objType, property, ObjectFieldValidatorOptions.None);
if (validatedObject != null)
{
// If scene objects are not allowed and object is a scene object then clear
if (!allowSceneObjects && !EditorUtility.IsPersistent(validatedObject))
{
validatedObject = null;
}
}
if (validatedObject != null)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
if (eventType == EventType.DragPerform)
{
if (property != null)
{
property.objectReferenceValue = validatedObject;
}
else
{
obj = validatedObject;
}
GUI.changed = true;
DragAndDrop.AcceptDrag();
DragAndDrop.activeControlID = 0;
}
else
{
DragAndDrop.activeControlID = id;
}
Event.current.Use();
}
}
break;
case EventType.MouseDown:
if (position.Contains(Event.current.mousePosition) && Event.current.button == 0)
{
// Get button rect for Object Selector
Rect buttonRect = GetButtonRect(visualType, position);
EditorGUIUtility.editingTextField = false;
if (buttonRect.Contains(Event.current.mousePosition))
{
if (GUI.enabled)
{
GUIUtility.keyboardControl = id;
var types = additionalType == null ? new Type[] { objType } : new Type[] { objType, additionalType };
if (property != null)
{
ObjectSelector.get.Show(types, property, allowSceneObjects);
}
else
{
ObjectSelector.get.Show(obj, types, objBeingEdited, allowSceneObjects);
}
ObjectSelector.get.objectSelectorID = id;
evt.Use();
GUIUtility.ExitGUI();
}
}
else
{
Object actualTargetObject = property != null ? property.objectReferenceValue : obj;
Component com = actualTargetObject as Component;
if (com)
{
actualTargetObject = com.gameObject;
}
if (showMixedValue)
{
actualTargetObject = null;
}
// One click shows where the referenced object is, or pops up a preview
if (Event.current.clickCount == 1)
{
GUIUtility.keyboardControl = id;
PingObjectOrShowPreviewOnClick(actualTargetObject, position);
var selectedMaterial = actualTargetObject as Material;
if (selectedMaterial != null)
{
PingObjectInSceneViewOnClick(selectedMaterial);
}
evt.Use();
}
// Double click opens the asset in external app or changes selection to referenced object
else if (Event.current.clickCount == 2)
{
if (actualTargetObject)
{
AssetDatabase.OpenAsset(actualTargetObject);
evt.Use();
GUIUtility.ExitGUI();
}
}
}
}
break;
case EventType.ExecuteCommand:
string commandName = evt.commandName;
if (commandName == ObjectSelector.ObjectSelectorUpdatedCommand && ObjectSelector.get.objectSelectorID == id && GUIUtility.keyboardControl == id && (property == null || !property.isScript))
{
return(AssignSelectedObject(property, validator, objType, evt));
}
else if (commandName == ObjectSelector.ObjectSelectorClosedCommand && ObjectSelector.get.objectSelectorID == id && GUIUtility.keyboardControl == id && property != null && property.isScript)
{
if (ObjectSelector.get.GetInstanceID() == 0)
{
// User canceled object selection; don't apply
evt.Use();
break;
}
return(AssignSelectedObject(property, validator, objType, evt));
}
else if ((evt.commandName == EventCommandNames.Delete || evt.commandName == EventCommandNames.SoftDelete) && GUIUtility.keyboardControl == id)
{
if (property != null)
{
property.objectReferenceValue = null;
}
else
{
obj = null;
}
GUI.changed = true;
evt.Use();
}
break;
case EventType.ValidateCommand:
if ((evt.commandName == EventCommandNames.Delete || evt.commandName == EventCommandNames.SoftDelete) && GUIUtility.keyboardControl == id)
{
evt.Use();
}
break;
case EventType.KeyDown:
if (GUIUtility.keyboardControl == id)
{
if (evt.keyCode == KeyCode.Backspace || (evt.keyCode == KeyCode.Delete && (evt.modifiers & EventModifiers.Shift) == 0))
{
if (property != null)
{
if (property.propertyPath.EndsWith("]"))
{
var parentArrayPropertyPath = property.propertyPath.Substring(0, property.propertyPath.LastIndexOf(".Array.data[", StringComparison.Ordinal));
var parentArrayProperty = property.serializedObject.FindProperty(parentArrayPropertyPath);
bool isReorderableList = PropertyHandler.s_reorderableLists.ContainsKey(ReorderableListWrapper.GetPropertyIdentifier(parentArrayProperty));
// If it's an element of an non-orderable array, remove that element from the array
if (!isReorderableList)
{
TargetChoiceHandler.DeleteArrayElement(property);
}
else
{
property.objectReferenceValue = null;
}
}
else
{
property.objectReferenceValue = null;
}
}
else
{
obj = null;
}
GUI.changed = true;
evt.Use();
}
// Apparently we have to check for the character being space instead of the keyCode,
// otherwise the Inspector will maximize upon pressing space.
if (evt.MainActionKeyForControl(id))
{
var types = additionalType == null ? new Type[] { objType } : new Type[] { objType, additionalType };
if (property != null)
{
ObjectSelector.get.Show(types, property, allowSceneObjects);
}
else
{
ObjectSelector.get.Show(obj, types, objBeingEdited, allowSceneObjects);
}
ObjectSelector.get.objectSelectorID = id;
evt.Use();
GUIUtility.ExitGUI();
}
}
break;
case EventType.Repaint:
GUIContent temp;
if (showMixedValue)
{
temp = s_MixedValueContent;
}
else
{
// If obj or objType are both null, we have to rely on
// property.objectReferenceStringValue to display None/Missing and the
// correct type. But if not, EditorGUIUtility.ObjectContent is more reliable.
// It can take a more specific object type specified as argument into account,
// and it gets the icon at the same time.
if (obj == null && objType == null && property != null)
{
temp = EditorGUIUtility.TempContent(property.objectReferenceStringValue);
}
else
{
// In order for ObjectContext to be able to distinguish between None/Missing,
// we need to supply an instanceID. For some reason, getting the instanceID
// from property.objectReferenceValue is not reliable, so we have to
// explicitly check property.objectReferenceInstanceIDValue if a property exists.
if (property != null)
{
temp = EditorGUIUtility.ObjectContent(obj, objType, property.objectReferenceInstanceIDValue);
}
else
{
temp = EditorGUIUtility.ObjectContent(obj, objType);
}
}
if (property != null)
{
if (obj != null)
{
Object[] references = { obj };
if (EditorSceneManager.preventCrossSceneReferences && CheckForCrossSceneReferencing(obj, property.serializedObject.targetObject))
{
if (!EditorApplication.isPlaying)
{
temp = s_SceneMismatch;
}
else
{
temp.text = temp.text + string.Format(" ({0})", GetGameObjectFromObject(obj).scene.name);
}
}
else if (validator(references, objType, property, ObjectFieldValidatorOptions.ExactObjectTypeValidation) == null)
{
temp = s_TypeMismatch;
}
}
}
}
switch (visualType)
{
case ObjectFieldVisualType.IconAndText:
BeginHandleMixedValueContentColor();
style.Draw(position, temp, id, DragAndDrop.activeControlID == id, position.Contains(Event.current.mousePosition));
Rect buttonRect = buttonStyle.margin.Remove(GetButtonRect(visualType, position));
buttonStyle.Draw(buttonRect, GUIContent.none, id, DragAndDrop.activeControlID == id, buttonRect.Contains(Event.current.mousePosition));
EndHandleMixedValueContentColor();
break;
case ObjectFieldVisualType.LargePreview:
DrawObjectFieldLargeThumb(position, id, obj, temp);
break;
case ObjectFieldVisualType.MiniPreview:
DrawObjectFieldMiniThumb(position, id, obj, temp);
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
}
EditorGUIUtility.SetIconSize(oldIconSize);
return(obj);
}