Skip to content

Instantly share code, notes, and snippets.

@ProGM
Created October 19, 2016 10:39
Show Gist options
  • Star 54 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save ProGM/9cb9ae1f7c8c2a4bd3873e4df14a6687 to your computer and use it in GitHub Desktop.
Save ProGM/9cb9ae1f7c8c2a4bd3873e4df14a6687 to your computer and use it in GitHub Desktop.
A PropertyDrawer to show a popup field with a generic list of string for your Unity3d attribute
public class MyBehavior : MonoBehaviour {
// This will store the string value
[StringInList("Cat", "Dog")] public string Animal;
// This will store the index of the array value
[StringInList("John", "Jack", "Jim")] public int PersonID;
// Showing a list of loaded scenes
[StringInList(typeof(PropertyDrawersHelper), "AllSceneNames")] public string SceneName;
}
using UnityEditor;
using UnityEngine;
public static class PropertyDrawersHelper {
#if UNITY_EDITOR
public static string[] AllSceneNames()
{
var temp = new List<string>();
foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
{
if (S.enabled)
{
string name = S.path.Substring(S.path.LastIndexOf('/')+1);
name = name.Substring(0,name.Length-6);
temp.Add(name);
}
}
return temp.ToArray();
}
#endif
}
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class StringInList : PropertyAttribute {
public delegate string[] GetStringList();
public StringInList(params string [] list) {
List = list;
}
public StringInList(Type type, string methodName) {
var method = type.GetMethod (methodName);
if (method != null) {
List = method.Invoke (null, null) as string[];
} else {
Debug.LogError ("NO SUCH METHOD " + methodName + " FOR " + type);
}
}
public string[] List {
get;
private set;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(StringInList))]
public class StringInListDrawer : PropertyDrawer {
// Draw the property inside the given rect
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
var stringInList = attribute as StringInList;
var list = stringInList.List;
if (property.propertyType == SerializedPropertyType.String) {
int index = Mathf.Max (0, Array.IndexOf (list, property.stringValue));
index = EditorGUI.Popup (position, property.displayName, index, list);
property.stringValue = list [index];
} else if (property.propertyType == SerializedPropertyType.Integer) {
property.intValue = EditorGUI.Popup (position, property.displayName, property.intValue, list);
} else {
base.OnGUI (position, property, label);
}
}
}
#endif
@Feddas
Copy link

Feddas commented Apr 18, 2018

This is awesome. Thanks for posting this and the run down on coderwall.

I did have a little trouble getting it to work. After reading a forum post I realized the StringInListDrawer class needed to be in a separate file so that the PropertyDrawer is in an Editor folder and the PropertyAttribute (& Helper) is not.

@EduardoSimon
Copy link

I've have implemented this kind of behaviour by myself, but when I rename the scene asset in the editor window, my serialized property gets lost. I have tried to set up a callback to find if the project's changed, but I cant find a proper way to get the asset that has been changed and check if its one of the loaded scenes. Any help with it?

@seyoung-hyun
Copy link

Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.

@ProGM
Copy link
Author

ProGM commented Aug 17, 2021

Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.

Sure! Assume the license is MIT :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment