Hi,
I am trying to have a list of objects A in component B. In object type A, a public variable is set with a custom property attribute, which provides a drop-down-list in inspector for that field.
The problem is, that the selection in one entry object in the list seems to change all other fields of that type in all the objects in the list as well, and this is of course not what I want.
The attribute and drawer code I downloaded somewhere from a link provided by Unity. Here is my test code:
PopupTest.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class ListEntry
{
[Popup ("value1", "value2", "value3")]
public string value;
}
public class PopupTest : MonoBehaviour {
public List<ListEntry> entries;
}
PopupAttribute.cs
using UnityEngine;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
/// <summary>
/// Prepares variables to be used by PopupDrawer.
/// </summary>
public class PopupAttribute : PropertyAttribute
{
public string[] list;
public object variableType;
#region PopupAttribute()
/// <summary>
/// Makes necessary operations to prepare the variables for later use by PopupDrawer.
/// </summary>
/// <param name="list">Parameters array to be analized and assigned.</param>
public PopupAttribute(params object[] list)
{
if (IsVariablesTypeConsistent(list) && AssignVariableType(list[0]))
{
this.list = new string[list.Length];
for (int i = 0; i < list.Length; i++)
{
this.list[i] = list[i].ToString();
}
}
else
{
return;
}
}
#endregion
#region Helper Methods.
#region AssignVariableType()
/// <summary>
/// Checks if variable type is valid, and assignes the variable type to the proper variable.
/// </summary>
/// <param name="variable">Object to get type from.</param>
/// <returns>Returns true if variable type is valid, and false if it isn't.</returns>
private bool AssignVariableType(object variable)
{
if (variable.GetType() == typeof(int))
{
variableType = typeof(int[]);
return true;
}
else if (variable.GetType() == typeof(float))
{
variableType = typeof(float[]);
return true;
}
else if (variable.GetType() == typeof(double))
{
Debug.LogWarning("Popup Drawer doesn't properly support double type, for float variables please use 'f' at the end of each value.");
variableType = typeof(float[]);
return true;
}
else if (variable.GetType() == typeof(string))
{
variableType = typeof(string[]);
return true;
}
else
{
Debug.LogError("Popup Property Drawer doesn't support " + variable.GetType() + " this type of variable");
return false;
}
}
#endregion
#region IsVariablesTypeConsistent()
/// <summary>
/// Checks to see if there is only one variable type in the given value.
/// </summary>
/// <param name="list">Array of variables to be checked.</param>
/// <returns>True if there is only one type, false if there is 2 or more.</returns>
private bool IsVariablesTypeConsistent(object[] list)
{
for (int i = 0; i < list.Length; i++)
{
if (i == 0)
{
variableType = list[i].GetType();
}
else if (variableType != list[i].GetType())
{
Debug.LogError("Popup Property Drawer can only contain one type per variable");
return false;
}
}
return true;
}
#endregion
#endregion
}
PopupDrawer.cs
using UnityEditor;
using UnityEngine;
using System;
/// <summary>
/// Creates a popup list with the provided values.
/// </summary>
[CustomPropertyDrawer(typeof(PopupAttribute))]
public class PopupDrawer : PropertyDrawer
{
PopupAttribute popupAttribute { get { return ((PopupAttribute)attribute); } }
int index;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Checks to see what is the type of the provided values and acts accordingly.
if (popupAttribute.variableType == typeof(int[]))
{
EditorGUI.BeginChangeCheck();
index = EditorGUI.Popup(position, label.text, property.intValue, popupAttribute.list);
if (EditorGUI.EndChangeCheck())
{
property.intValue = index;
}
}
else if (popupAttribute.variableType == typeof(float[]))
{
EditorGUI.BeginChangeCheck();
// Checks all items in the provided list, to see if any of them is a match with the property value, if so assigns that value to the index.
for (int i = 0; i < popupAttribute.list.Length; i++)
{
if (property.floatValue == Convert.ToSingle(popupAttribute.list[i]))
{
index = i;
}
}
index = EditorGUI.Popup(position, label.text, index, popupAttribute.list);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = Convert.ToSingle(popupAttribute.list[index]);
}
}
else if (popupAttribute.variableType == typeof(string[]))
{
EditorGUI.BeginChangeCheck();
// Checks all items in the provided list, to see if any of them is a match with the property value, if so assigns that value to the index.
for (int i = 0; i < popupAttribute.list.Length; i++)
{
if (property.stringValue == popupAttribute.list[i])
{
index = i;
}
}
index = EditorGUI.Popup(position, label.text, index, popupAttribute.list);
if (EditorGUI.EndChangeCheck())
{
property.stringValue = popupAttribute.list[index];
}
}
else
{
EditorGUI.LabelField(position, "ERROR READ CONSOLE FOR MORE INFO");
}
}
}
I am not well acquainted with editor customization. Help appreciated!
Cheers,
A888