Reputation: 90789
I'm just asking if there is any possibility to hide the "Object Picker" (The little knob/menu next to an ObjectField) in a custom Inspector. I have some cases where changes are disabled (DisableGroup) and I would like to also hide the knob while the content can not be changed anyway.
Also to make things easier for users I think about making the field higher (EditorGUIUtility.SingleLineHeight * 2
) -> the picker gets stretched as well what looks kind of shitty ^^
example:
using UnityEditor;
using UnityEngine;
public class Bla : MonoBehaviour {
[CustomEditor(typeof(Bla))]
public class BlaEditor : Editor
{
private AudioClip _clip;
public override void OnInspectorGUI()
{
EditorGUI.BeginDisabledGroup(true);
// do some magic to hide the object picker
_clip = (AudioClip) EditorGUILayout.ObjectField("some label", _clip, typeof(AudioClip), false);
EditorGUI.EndDisabledGroup();
}
}
}
I want to stick with an ObjectField
rather than a simple Label for two reasons:
Upvotes: 2
Views: 5298
Reputation: 1
Thanks for the answers. Tried a little more work to make it more like the unity built-in one.
using UnityEngine;
using UnityEditor;
static partial class EditorGUIUtils {
public static void ObjectDisplayFieldLayout(Object obj, params GUILayoutOption[] options) =>
ObjectDisplayFieldLayout(obj, (GUIContent)null, options);
public static void ObjectDisplayFieldLayout(Object obj, string label, params GUILayoutOption[] options) =>
ObjectDisplayFieldLayout(obj, new GUIContent(label), options);
public static void ObjectDisplayFieldLayout(Object obj, GUIContent label, params GUILayoutOption[] options) {
EditorGUILayout.BeginVertical();
GUILayout.Space(2);
EditorGUILayout.BeginHorizontal();
GUILayout.Space(2);
GUILayout.Space(EditorGUI.indentLevel * 15);
GUIStyle style = new GUIStyle(GUI.skin.textField);
style.fixedHeight = EditorGUIUtility.singleLineHeight;
style.imagePosition = obj != null ? ImagePosition.ImageLeft : ImagePosition.TextOnly;
style.alignment = TextAnchor.MiddleLeft;
GUIContent content = EditorGUIUtility.ObjectContent(obj, obj.GetType());
Rect rect = GUILayoutUtility.GetRect(4, EditorGUIUtility.singleLineHeight, options);
Rect objRect = rect;
if (label != null) {
Rect labelRect = rect;
labelRect.width = rect.width / 2f - 1f;
if (labelRect.width >= 1f) {
EditorGUI.PrefixLabel(labelRect, label);
objRect = labelRect;
objRect.x = labelRect.xMax + 2f;
objRect.width = Mathf.Max(4f, rect.xMax - objRect.x);
}
}
var e = Event.current;
if (e.type == EventType.MouseDown && e.button == 0 && objRect.Contains(e.mousePosition)) {
if (obj != null)
EditorGUIUtility.PingObject(obj);
e.Use();
}
GUI.Button(objRect, content, style);
GUILayout.Space(1);
EditorGUILayout.EndHorizontal();
GUILayout.Space(1);
EditorGUILayout.EndVertical();
}
}
Use it like
EditorGUILayout.LabelField("Base Texture Reference", EditorStyles.boldLabel);
if (BaseTextureList.arraySize <= 0) {
EditorGUILayout.LabelField("not exist", EditorStyles.miniLabel);
}
else {
EditorGUI.indentLevel++;
for (int i = 0; i < BaseTextureList.arraySize; i++) {
EditorGUIUtils.ObjectDisplayFieldLayout(BaseTextureList.GetArrayElementAtIndex(i).objectReferenceValue, $"Texture {i}");
}
EditorGUI.indentLevel--;
}
Upvotes: 0
Reputation: 1
I needed to do something similar and found a way to do this by stepping through the ObjectField in the UIToolkit Debugger. The type of the little object selector button is hidden, so we cant really work with the class itself.
This solution is using UIToolkit, so unfortunately it won't work with Unity Editor IMGUI, but hopefully it will be helpful to someone.
The Solution in easy steps:
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomPropertyDrawer(typeof(MyClass))]
public class MyClassDrawer: PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var field = new ObjectField(property.displayName);
field.objectType = typeof(MyClass);
var button = FindChild(field, "unity-object-field__selector");
button.visible = false;
return field;
}
private VisualElement FindChild(VisualElement parent, string ussClass)
{
foreach(var child in parent.Children())
{
if (child.ClassListContains(ussClass))
return child;
var subChild = FindChild(child, ussClass);
if (subChild != null)
return subChild;
}
return null;
}
}
Upvotes: 0
Reputation: 307
I've got another solution: Ignore the pick result of this object picker, and although the picker is still here and can show the picker window, pick up will not work.
(I still don't know how to hide this button and the pickerwindow, > <), and this answer was posted at unity answers as well.
Here is the code:
// Register another callback of this object field
myObjectField.RegisterValueChangedCallback(DefaultObjectFieldCallback);
// In this callback, is a trick
private void DefaultAssetFieldCallback(ChangeEvent<UnityEngine.Object> evt) {
// unregister the callback first
myObjectField.UnregisterValueChangedCallback(DefaultAssetFieldCallback);
// trick: set back to the old value
m_ConfigAssetField.value = evt.previousValue;
// register the callback again
myObjectField.RegisterValueChangedCallback(DefaultObjectFieldCallback);
}
Upvotes: 0
Reputation: 6702
You might find a solution to hide the object picker by usage of stylesheets.
If all you want is just to display some reference, you can use a simple button basically styled as text field, adding an image and ping the object from code yourself.
using UnityEngine;
namespace Test
{
public class TestBehaviour : MonoBehaviour
{
[SerializeField] private bool _audioEnabled;
[SerializeField] private AudioClip _audioClip;
}
}
editor:
using System.Reflection;
using UnityEditor;
using UnityEditor.Experimental.UIElements;
using UnityEngine;
namespace Test
{
[CustomEditor(typeof(TestBehaviour))]
public class TestBehaviourEditor : Editor
{
private SerializedProperty _clipProp;
private SerializedProperty _audioEnabledProp;
private ObjectField m_ObjectField;
private const BindingFlags FIELD_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private void OnEnable()
{
_clipProp = serializedObject.FindProperty("_audioClip");
_audioEnabledProp = serializedObject.FindProperty("_audioEnabled");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(_audioEnabledProp);
if(_audioEnabledProp.boolValue)
EditorGUILayout.PropertyField(_clipProp);
else
{
//TODO: calculate proper layout
var type = target.GetType().GetField(_clipProp.propertyPath, FIELD_BINDING_FLAGS).FieldType;
var clip = _clipProp.objectReferenceValue;
var guiContent = EditorGUIUtility.ObjectContent(clip, type);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Fake ObjectField Button");
var style = new GUIStyle("TextField");
style.fixedHeight = 16;
style.imagePosition = clip ? ImagePosition.ImageLeft : ImagePosition.TextOnly;
if (GUILayout.Button(guiContent, style ) && clip)
EditorGUIUtility.PingObject(clip);
EditorGUILayout.EndHorizontal();
}
serializedObject.ApplyModifiedProperties();
}
}
}
Upvotes: 2