SHARE
TWEET

Untitled

Alireza-Tarahomi May 19th, 2019 114 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEditor;
  5. using UnityEngine;
  6.  
  7. namespace Infrastructure.ScriptableObjectDropdown
  8. {
  9.     /// <summary>
  10.     /// Indicates how selectable scriptableObjects should be collated in drop-down menu.
  11.     /// </summary>
  12.     public enum ScriptableObjectGrouping
  13.     {
  14.         /// <summary>
  15.         /// No grouping, just show type names in a list; for instance, "MainFolder > NestedFolder > SpecialScriptableObject".
  16.         /// </summary>
  17.         None,
  18.         /// <summary>
  19.         /// Group classes by namespace and show foldout menus for nested namespaces; for
  20.         /// instance, "MainFolder >> NestedFolder >> SpecialScriptableObject".
  21.         /// </summary>
  22.         ByFolder,
  23.         /// <summary>
  24.         /// Group scriptableObjects by folder; for instance, "MainFolder > NestedFolder >> SpecialScriptableObject".
  25.         /// </summary>
  26.         ByFolderFlat
  27.     }
  28.  
  29.     [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
  30.     public class ScriptableObjectDropdownAttribute : PropertyAttribute
  31.     {
  32.         public ScriptableObjectGrouping grouping = ScriptableObjectGrouping.None;
  33.  
  34.         public ScriptableObjectDropdownAttribute() { }
  35.     }
  36. }
  37.  
  38. // ======================
  39.  
  40. using System.Collections;
  41. using System.Collections.Generic;
  42. using UnityEngine;
  43. using UnityEditor;
  44. using System.Reflection;
  45. using System;
  46. using System.Linq;
  47.  
  48. namespace Infrastructure.ScriptableObjectDropdown.Editor
  49. {
  50.     [CustomPropertyDrawer(typeof(ScriptableObjectDropdownAttribute))]
  51.     public class ScriptableObjectDropdownDrawer : PropertyDrawer
  52.     {
  53.         private static ScriptableObject[] _scriptableObjects;
  54.         private static ScriptableObject _selectedScriptableObject;
  55.         private static readonly int _controlHint = typeof(ScriptableObjectDropdownAttribute).GetHashCode();
  56.         private static GUIContent _guiContent = new GUIContent();
  57.         private static int _selectionControlID;
  58.         private static readonly GenericMenu.MenuFunction2 _onSelectedScriptableObject = OnSelectedScriptableObject;
  59.  
  60.         public static Type GetPropertyType(SerializedProperty property)
  61.         {
  62.             Type parentType = property.serializedObject.targetObject.GetType();
  63.             FieldInfo fieldInfo = parentType.GetField(property.propertyPath);
  64.             return fieldInfo.FieldType;
  65.         }
  66.  
  67.         private static ScriptableObject[] GetScriptableObjects(SerializedProperty property)
  68.         {
  69.             Type genericClassType = typeof(Resources);
  70.             MethodInfo[] methodsInfo = genericClassType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  71.             MethodInfo methodInfo = methodsInfo.Where(_ => _.IsGenericMethod && _.Name.Equals("LoadAll") && _.GetParameters().FirstOrDefault().ParameterType == typeof(string))
  72.                                     .FirstOrDefault();
  73.             Type[] genericArguments = new Type[] { GetPropertyType(property) };
  74.             MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
  75.             _scriptableObjects = genericMethodInfo.Invoke(null, new object[] { "" }) as ScriptableObject[];
  76.  
  77.             return _scriptableObjects;
  78.         }
  79.  
  80.         private static UnityEngine.Object DrawScriptableObjectSelectionControl(Rect position, GUIContent label,
  81.             ScriptableObject scriptableObject, SerializedProperty property, ScriptableObjectDropdownAttribute attribute)
  82.         {
  83.             if (label != null && label != GUIContent.none)
  84.                 position = EditorGUI.PrefixLabel(position, label);
  85.  
  86.             int controlID = GUIUtility.GetControlID(_controlHint, FocusType.Keyboard, position);
  87.  
  88.             bool triggerDropDown = false;
  89.  
  90.             switch (Event.current.GetTypeForControl(controlID))
  91.             {
  92.                 case EventType.ExecuteCommand:
  93.                     if (Event.current.commandName == "ScriptableObjectReferenceUpdated")
  94.                     {
  95.                         if (_selectionControlID == controlID)
  96.                         {
  97.                             if (scriptableObject != _selectedScriptableObject)
  98.                             {
  99.                                 scriptableObject = _selectedScriptableObject;
  100.                                 GUI.changed = true;
  101.                             }
  102.  
  103.                             _selectionControlID = 0;
  104.                             _selectedScriptableObject = null;
  105.                         }
  106.                     }
  107.                     break;
  108.  
  109.                 case EventType.MouseDown:
  110.                     if (GUI.enabled && position.Contains(Event.current.mousePosition))
  111.                     {
  112.                         GUIUtility.keyboardControl = controlID;
  113.                         triggerDropDown = true;
  114.                         Event.current.Use();
  115.                     }
  116.                     break;
  117.  
  118.                 case EventType.KeyDown:
  119.                     if (GUI.enabled && GUIUtility.keyboardControl == controlID)
  120.                     {
  121.                         if (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.Space)
  122.                         {
  123.                             triggerDropDown = true;
  124.                             Event.current.Use();
  125.                         }
  126.                     }
  127.                     break;
  128.  
  129.                 case EventType.Repaint:
  130.                     if (scriptableObject == null)
  131.                     {
  132.                         _guiContent.text = "Nothing";
  133.                     }
  134.                     else
  135.                     {
  136.                         _guiContent.text = scriptableObject.name;
  137.                     }
  138.  
  139.                     EditorStyles.popup.Draw(position, _guiContent, controlID);
  140.                     break;
  141.             }
  142.  
  143.             if (triggerDropDown)
  144.             {
  145.                 _selectionControlID = controlID;
  146.                 _selectedScriptableObject = scriptableObject;
  147.  
  148.                 DisplayDropDown(position, scriptableObject, attribute.grouping);
  149.             }
  150.  
  151.             return scriptableObject;
  152.         }
  153.  
  154.         private static void DrawScriptableObjectSelectionControl(Rect position, GUIContent label,
  155.             SerializedProperty property, ScriptableObjectDropdownAttribute attribute)
  156.         {
  157.             bool restoreShowMixedValue = EditorGUI.showMixedValue;
  158.             EditorGUI.showMixedValue = property.hasMultipleDifferentValues;
  159.  
  160.             property.objectReferenceValue = DrawScriptableObjectSelectionControl(position, label,
  161.                 property.objectReferenceValue as ScriptableObject, property, attribute);
  162.  
  163.             EditorGUI.showMixedValue = restoreShowMixedValue;
  164.         }
  165.  
  166.         private static void DisplayDropDown(Rect position, ScriptableObject selectedScriptableObject, ScriptableObjectGrouping grouping)
  167.         {
  168.             var menu = new GenericMenu();
  169.  
  170.             menu.AddItem(new GUIContent("Nothing"), selectedScriptableObject == null, _onSelectedScriptableObject, null);
  171.             menu.AddSeparator("");
  172.  
  173.             for (int i = 0; i < _scriptableObjects.Length; ++i)
  174.             {
  175.                 var scriptableObject = _scriptableObjects[i];
  176.  
  177.                 string menuLabel = FormatGroupedScriptableObject(scriptableObject, grouping);
  178.                 if (string.IsNullOrEmpty(menuLabel))
  179.                     continue;
  180.  
  181.                 var content = new GUIContent(menuLabel);
  182.                 menu.AddItem(content, scriptableObject == selectedScriptableObject, _onSelectedScriptableObject, scriptableObject);
  183.             }
  184.  
  185.             menu.DropDown(position);
  186.         }
  187.  
  188.         private static string FindPath(ScriptableObject scriptableObject)
  189.         {
  190.             string path = AssetDatabase.GetAssetPath(scriptableObject);
  191.             path = path.Replace("Assets/Resources/", "");
  192.             path = path.Replace(".asset", "");
  193.  
  194.             return path;
  195.         }
  196.  
  197.         private static string FormatGroupedScriptableObject(ScriptableObject scriptableObject, ScriptableObjectGrouping grouping)
  198.         {
  199.             string path = FindPath(scriptableObject);
  200.  
  201.             switch (grouping)
  202.             {
  203.                 default:
  204.                 case ScriptableObjectGrouping.None:
  205.                     path = path.Replace("/", " > ");
  206.                     return path;
  207.  
  208.                 case ScriptableObjectGrouping.ByFolder:
  209.                     return path;
  210.  
  211.                 case ScriptableObjectGrouping.ByFolderFlat:
  212.                     int last = path.LastIndexOf('/');
  213.                     string part1 = path.Substring(0, last);
  214.                     string part2 = path.Substring(last);
  215.                     path = part1.Replace("/", " > ") + part2;
  216.                     return path;
  217.             }
  218.         }
  219.  
  220.         private static void OnSelectedScriptableObject(object userData)
  221.         {
  222.             _selectedScriptableObject = userData as ScriptableObject;
  223.             var scriptableObjectReferenceUpdatedEvent = EditorGUIUtility.CommandEvent("ScriptableObjectReferenceUpdated");
  224.             EditorWindow.focusedWindow.SendEvent(scriptableObjectReferenceUpdatedEvent);
  225.         }
  226.  
  227.         public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  228.         {
  229.             return EditorStyles.popup.CalcHeight(GUIContent.none, 0);
  230.         }
  231.  
  232.         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  233.         {
  234.             GetScriptableObjects(property);
  235.             DrawScriptableObjectSelectionControl(position, label, property, attribute as ScriptableObjectDropdownAttribute);
  236.         }
  237.     }
  238. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top