protected override void OnRenderProperty(Rect position, PropertyName exposedPropertyNameString, UnityEngine.Object currentReferenceValue, SerializedProperty exposedPropertyDefault, SerializedProperty exposedPropertyName, BaseExposedPropertyDrawer.ExposedPropertyMode mode, IExposedPropertyTable exposedPropertyTable) { Type objType = base.fieldInfo.FieldType.GetGenericArguments()[0]; EditorGUI.BeginChangeCheck(); UnityEngine.Object @object = EditorGUI.ObjectField(position, currentReferenceValue, objType, exposedPropertyTable != null); if (EditorGUI.EndChangeCheck()) { if (mode == BaseExposedPropertyDrawer.ExposedPropertyMode.DefaultValue) { if (!EditorUtility.IsPersistent(exposedPropertyDefault.serializedObject.targetObject) || @object == null || EditorUtility.IsPersistent(@object)) { if (!EditorGUI.CheckForCrossSceneReferencing(exposedPropertyDefault.serializedObject.targetObject, @object)) { exposedPropertyDefault.objectReferenceValue = @object; } } else { string text = GUID.Generate().ToString(); exposedPropertyNameString = new PropertyName(text); exposedPropertyName.stringValue = text; Undo.RecordObject(exposedPropertyTable as UnityEngine.Object, "Set Exposed Property"); exposedPropertyTable.SetReferenceValue(exposedPropertyNameString, @object); } } else { Undo.RecordObject(exposedPropertyTable as UnityEngine.Object, "Set Exposed Property"); exposedPropertyTable.SetReferenceValue(exposedPropertyNameString, @object); } } }
protected override void OnRenderProperty(Rect position, PropertyName exposedPropertyNameString, Object currentReferenceValue, UnityEditor.SerializedProperty exposedPropertyDefault, UnityEditor.SerializedProperty exposedPropertyName, ExposedPropertyMode mode, IExposedPropertyTable exposedPropertyTable) { var propertyType = fieldInfo.FieldType; if (propertyType.IsArrayOrList()) { propertyType = propertyType.GetArrayOrListElementType(); } var typeOfExposedReference = propertyType.GetGenericArguments()[0]; EditorGUI.BeginChangeCheck(); var newValue = EditorGUI.ObjectField(position, currentReferenceValue, typeOfExposedReference, exposedPropertyTable != null); if (EditorGUI.EndChangeCheck()) { if (mode == ExposedPropertyMode.DefaultValue) { // We can directly assign to the exposed property default value if // * asset we are modifying is in the scene // * object we are assigning to the property is also an asset if (!EditorUtility.IsPersistent(exposedPropertyDefault.serializedObject.targetObject) || newValue == null || EditorUtility.IsPersistent(newValue)) { if (!EditorGUI.CheckForCrossSceneReferencing(exposedPropertyDefault.serializedObject.targetObject, newValue)) { exposedPropertyDefault.objectReferenceValue = newValue; } } else { var guid = UnityEditor.GUID.Generate(); var str = guid.ToString(); exposedPropertyNameString = new PropertyName(str); exposedPropertyName.stringValue = str; Undo.RecordObject(exposedPropertyTable as UnityEngine.Object, "Set Exposed Property"); exposedPropertyTable.SetReferenceValue(exposedPropertyNameString, newValue); } } else { Undo.RecordObject(exposedPropertyTable as UnityEngine.Object, "Set Exposed Property"); exposedPropertyTable.SetReferenceValue(exposedPropertyNameString, newValue); } } }
static Object DoObjectField(Rect position, Rect dropRect, int id, Object obj, Object objBeingEdited, System.Type objType, SerializedProperty property, EditorGUI.ObjectFieldValidator validator, GUIStyle style, SearchContext context, SearchViewFlags searchViewFlags = SearchViewFlags.None) { if (validator == null) { validator = EditorGUI.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 && Utils.IsGUIClipEnabled() && (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 <= EditorGUI.kObjectFieldMiniThumbnailHeight && position.width <= EditorGUI.kObjectFieldMiniThumbnailWidth) { visualType = ObjectFieldVisualType.MiniPreview; } else if (hasThumbnail && position.height > EditorGUI.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) && position.Contains(Event.current.mousePosition)) { var actualObject = property != null ? property.objectReferenceValue : obj; var contextMenu = new GenericMenu(); if (EditorGUI.FillPropertyContextMenu(property, null, contextMenu) != null) { contextMenu.AddSeparator(""); } contextMenu.AddItem(Utils.GUIContentTemp("Properties..."), false, () => Utils.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, EditorGUI.ObjectFieldValidatorOptions.None); 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; ShowSearchPicker(context, searchViewFlags, property, property == null ? obj : null, id, evt, objType); } } else { Object actualTargetObject = property != null ? property.objectReferenceValue : obj; Component com = actualTargetObject as Component; if (com) { actualTargetObject = com.gameObject; } if (EditorGUI.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); 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 == k_PickerUpdatedCommand && s_LastPickerId == id && GUIUtility.keyboardControl == id && (property == null || !Utils.SerializedPropertyIsScript(property))) { return(AssignSelectedObject(property, validator, objType, evt)); } else if (commandName == k_PickerClosedCommand && s_LastPickerId == id && GUIUtility.keyboardControl == id) { if (s_LastSelectionWasCanceled) { // User canceled object selection; don't apply evt.Use(); // When we operate directly on objects, the undo system doesn't work. // We added a hack that sets the s_LastSelectedItem to the original item // when canceling with an object. if (property == null) { return(s_LastSelectedItem); } break; } // When property is script, it is not assigned on update, so assign it on close if (property != null && Utils.SerializedPropertyIsScript(property)) { return(AssignSelectedObject(property, validator, objType, evt)); } return(property != null ? property.objectReferenceValue : obj); } else if (Utils.IsCommandDelete(evt.commandName) && GUIUtility.keyboardControl == id) { if (property != null) { property.objectReferenceValue = null; } else { obj = null; } GUI.changed = true; evt.Use(); } break; case EventType.ValidateCommand: if (Utils.IsCommandDelete(evt.commandName) && 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) { 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 (Utils.MainActionKeyForControl(evt, id)) { ShowSearchPicker(context, searchViewFlags, property, property == null ? obj : null, id, evt, objType); } } break; case EventType.Repaint: GUIContent temp; if (EditorGUI.showMixedValue) { temp = EditorGUI.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 = Utils.GUIContentTemp(Utils.SerializedPropertyObjectReferenceStringValue(property)); } 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 = Utils.ObjectContent(obj, objType, property.objectReferenceInstanceIDValue); } else { temp = EditorGUIUtility.ObjectContent(obj, objType); } } if (property != null) { if (obj != null) { Object[] references = { obj }; if (EditorSceneManager.preventCrossSceneReferences && EditorGUI.CheckForCrossSceneReferencing(obj, property.serializedObject.targetObject)) { if (!EditorApplication.isPlaying) { temp = s_SceneMismatch; } else { temp.text = temp.text + string.Format(" ({0})", EditorGUI.GetGameObjectFromObject(obj).scene.name); } } else if (validator(references, objType, property, EditorGUI.ObjectFieldValidatorOptions.ExactObjectTypeValidation) == null) { temp = s_TypeMismatch; } } } } switch (visualType) { case ObjectFieldVisualType.IconAndText: EditorGUI.BeginHandleMixedValueContentColor(); style.Draw(position, temp, id, DragAndDrop.activeControlID == id, position.Contains(Event.current.mousePosition)); Rect buttonRect = Utils.objectFieldButton.margin.Remove(GetButtonRect(visualType, position)); Utils.objectFieldButton.Draw(buttonRect, GUIContent.none, id, DragAndDrop.activeControlID == id, buttonRect.Contains(Event.current.mousePosition)); EditorGUI.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); }