- Home /
How to configure a PropertyField so it won't allow scene objects
My MonoBehaviour has a field
public GameObject targetPrefab;
I am writing a custom inspector and would like the user to only be able to drag assets to this field, NOT scene objects. I EditorGUILayout has ObjectField which has a flag for disallowing scene objects:
target.targetPrefab = (GameObject) EditorGUILayout.ObjectField("Target Prefab", target.targetPrefab, ` `typeof(GameObject), false);
I would like to use:
so = new SerializedObject(target);
targ = so.FindProperty("targetPrefab");
EditorGUILayout.PropertyField(targ);
However I can't find a way of disallowing scene objects from being dragged to the PropertyField. Is there a way?
Thanks.
Answer by vexe · Feb 20, 2014 at 12:35 PM
Unity 4.3.4 is here, and there's still no parameter you could pass to PropertyField to disallow dropping scene objects.
If you have ILSpy or .NET reflector, you could inspect PropertyField
yourself to see how it's implemented. As you might have guessed, PropertyField
has a switch statement internally so that it picks the right field type to use, based on your property. Here's the part related to when the property's type is a reference type:
case SerializedPropertyType.ObjectReference:
ObjectField(position, property, label);
Here's that ObjectField
:
internal static void ObjectField(Rect position, SerializedProperty property, GUIContent label)
{
ObjectField(position, property, label, EditorStyles.objectField);
}
Follow along:
internal static void ObjectField(Rect position, SerializedProperty property, GUIContent label, GUIStyle style)
{
int id = GUIUtility.GetControlID(s_PPtrHash, EditorGUIUtility.native, position);
position = PrefixLabel(position, id, label);
bool allowSceneObjects = false;
if (property != null)
{
Object targetObject = property.serializedObject.targetObject;
if ((targetObject != null) && !EditorUtility.IsPersistent(targetObject))
{
allowSceneObjects = true;
}
}
DoObjectField(position, position, id, null, null, property, null, allowSceneObjects, style);
}
So at the end it's using that DoObjectField
, which is essentially the same method used in EditorGUILayout.ObjectField
(if you follow that along, you'll end up with DoObjectField
as well) - As you can see allowSceneObjects
is being set internally which sucks :(
You could always fallback and use EditorGUILayout.ObjectField
and set your object directly. But before that you have to Undo.RecordObject(yourObject, "Some title");
if you want undo support.
If there's a solution to setting allowSceneObjects
yourself for PropertyField
then it's gonna be a hack, definitely a hack.
Answer by TonyVT · Mar 25, 2016 at 11:22 AM
I know the question is a bit old, but i stumbled upon the same problem and found a workaround. Maybe it is not elegant, but works. I'll write it here, because this question is #1 in Google if you look for this problem.
The idea is to check in the Editor script if the reference provided is from a prefab. If not, the previous reference has to be restored. This is an example code:
[CustomEditor(typeof(ModelAvatarGenerator), false)]
public class CustomModelAvatarEditor : Editor
{
#region Serialized Properties
/// <summary>
/// Serialized property of fbxModel of target
/// </summary>
private SerializedProperty m_fbxModel;
#endregion
public void OnEnable()
{
m_fbxModel = serializedObject.FindProperty("fbxModel");
}
/// <summary>
/// Executed at script displaying
/// </summary>
public override void OnInspectorGUI()
{
serializedObject.Update();
//holds label and tooltip of each control
GUIContent labelTooltip;
//Custom Avatar Model (remember to force the user to insert only prefabs instances)
GUILayout.BeginVertical();
labelTooltip = new GUIContent("Model Avatar", "Model to use as user avatar");
GameObject oldReference = (GameObject)m_fbxModel.objectReferenceValue; //save current avatar reference
EditorGUILayout.PropertyField(m_fbxModel, labelTooltip);
if ((GameObject)m_fbxModel.objectReferenceValue != null) //to allow null (None) to be used as a correct value
{
PrefabType avatarPrefabType = PrefabUtility.GetPrefabType((GameObject)m_fbxModel.objectReferenceValue); //get its prefab type
if(avatarPrefabType != PrefabType.ModelPrefab && avatarPrefabType != PrefabType.Prefab) //if it is not a prefab on disk, restore previous reference
{
m_fbxModel.objectReferenceValue = oldReference;
}
}
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
Hope this helps! Happy coding ;)