private static void DrawObjectFieldMiniThumb(Rect position, int id, Object obj, GUIContent content) { GUIStyle thumbStyle = EditorStyles.objectFieldMiniThumb; position.width = EditorGUI.kObjectFieldMiniThumbnailWidth; EditorGUI.BeginHandleMixedValueContentColor(); bool hover = obj != null; // we use hover texture for enhancing the border if we have a reference bool on = DragAndDrop.activeControlID == id; bool keyFocus = GUIUtility.keyboardControl == id; thumbStyle.Draw(position, hover, false, on, keyFocus); EditorGUI.EndHandleMixedValueContentColor(); if (obj != null && !EditorGUI.showMixedValue) { Rect thumbRect = new Rect(position.x + 1, position.y + 1, position.height - 2, position.height - 2); // subtract 1 px border Texture2D t2d = content.image as Texture2D; if (t2d != null && t2d.alphaIsTransparency) { EditorGUI.DrawTextureTransparent(thumbRect, t2d); } else { EditorGUI.DrawPreviewTexture(thumbRect, content.image); } // Tooltip if (thumbRect.Contains(Event.current.mousePosition)) { GUI.Label(thumbRect, Search.Utils.GUIContentTemp(string.Empty, "Ctrl + Click to show preview")); } } }
private static void DrawObjectFieldLargeThumb(Rect position, int id, Object obj, GUIContent content) { GUIStyle thumbStyle = EditorStyles.objectFieldThumb; thumbStyle.Draw(position, GUIContent.none, id, DragAndDrop.activeControlID == id, position.Contains(Event.current.mousePosition)); if (obj != null && !EditorGUI.showMixedValue) { Matrix4x4 guiMatrix = GUI.matrix; // Initial matrix is saved in order to be able to reset it to default bool isSprite = obj is Sprite; bool alphaIsTransparencyTex2D = (obj is Texture2D && (obj as Texture2D).alphaIsTransparency); Rect thumbRect = thumbStyle.padding.Remove(position); Texture2D t2d = AssetPreview.GetAssetPreview(obj); if (t2d != null) { // A checkerboard background is drawn behind transparent textures (for visibility) if (isSprite || t2d.alphaIsTransparency || alphaIsTransparencyTex2D) { GUI.DrawTexture(thumbRect, EditorGUI.transparentCheckerTexture, ScaleMode.StretchToFill, false); } // Draw asset preview (scaled to fit inside the frame) GUIUtility.ScaleAroundPivot(thumbRect.size / position.size, thumbRect.position); GUIStyle.none.Draw(thumbRect, t2d, false, false, false, false); GUI.matrix = guiMatrix; } else { // Preview not loaded -> Draw icon if (isSprite || alphaIsTransparencyTex2D) { // A checkerboard background is drawn behind transparent textures (for visibility) GUI.DrawTexture(thumbRect, EditorGUI.transparentCheckerTexture, ScaleMode.StretchToFill, false); GUI.DrawTexture(thumbRect, content.image, ScaleMode.StretchToFill, true); } else { EditorGUI.DrawPreviewTexture(thumbRect, content.image); } // Keep repainting until the object field has a proper preview HandleUtility.Repaint(); } } else { GUIStyle s2 = thumbStyle.name + "Overlay"; EditorGUI.BeginHandleMixedValueContentColor(); s2.Draw(position, content, id); EditorGUI.EndHandleMixedValueContentColor(); } GUIStyle s3 = thumbStyle.name + "Overlay2"; s3.Draw(position, s_Select, id); }
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); }