SHARE
TWEET

Untitled

Alireza-Tarahomi May 25th, 2019 84 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 UnityEngine;
  5.  
  6. namespace Infrastructure.ScriptableObjectMultiSelectDropdown
  7. {
  8.     [Serializable]
  9.     public class ScriptableObjectReference
  10.     {
  11.         public ScriptableObject[] values;
  12.     }
  13. }
  14.  
  15. // ===========
  16.  
  17. using System;
  18. using System.Collections;
  19. using System.Collections.Generic;
  20. using UnityEngine;
  21.  
  22. namespace Infrastructure.ScriptableObjectMultiSelectDropdown
  23. {
  24.     /// <summary>
  25.     /// Indicates how selectable scriptableObjects should be collated in drop-down menu.
  26.     /// </summary>
  27.     public enum ScriptableObjectGrouping
  28.     {
  29.         /// <summary>
  30.         /// No grouping, just show type names in a list; for instance, "MainFolder > NestedFolder > SpecialScriptableObject".
  31.         /// </summary>
  32.         None,
  33.         /// <summary>
  34.         /// Group classes by namespace and show foldout menus for nested namespaces; for
  35.         /// instance, "MainFolder >> NestedFolder >> SpecialScriptableObject".
  36.         /// </summary>
  37.         ByFolder,
  38.         /// <summary>
  39.         /// Group scriptableObjects by folder; for instance, "MainFolder > NestedFolder >> SpecialScriptableObject".
  40.         /// </summary>
  41.         ByFolderFlat
  42.     }
  43.  
  44.     [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
  45.     public class ScriptableObjectMultiSelectDropdownAttribute : PropertyAttribute
  46.     {
  47.         public ScriptableObjectGrouping grouping = ScriptableObjectGrouping.None;
  48.  
  49.         private Type _baseType;
  50.         public Type BaseType
  51.         {
  52.             get { return _baseType; }
  53.             private set { _baseType = value; }
  54.         }
  55.  
  56.         public ScriptableObjectMultiSelectDropdownAttribute(Type baseType)
  57.         {
  58.             _baseType = baseType;
  59.         }
  60.     }
  61. }
  62.  
  63. // =======
  64.  
  65. using System.Collections;
  66. using System.Collections.Generic;
  67. using UnityEngine;
  68. using UnityEditor;
  69. using System.Reflection;
  70. using System;
  71. using System.Linq;
  72.  
  73. namespace Infrastructure.ScriptableObjectMultiSelectDropdown.Editor
  74. {
  75.     [CustomPropertyDrawer(typeof(ScriptableObjectReference))]
  76.     [CustomPropertyDrawer(typeof(ScriptableObjectMultiSelectDropdownAttribute))]
  77.     public class ScriptableObjectMultiSelectionDropdownDrawer : PropertyDrawer
  78.     {
  79.         private static ScriptableObject[] _scriptableObjects;
  80.         private static List<ScriptableObject> _selectedScriptableObjects = new List<ScriptableObject>();
  81.         private static readonly int _controlHint = typeof(ScriptableObjectMultiSelectDropdownAttribute).GetHashCode();
  82.         private static GUIContent _tempContent = new GUIContent();
  83.         private static int _selectionControlID;
  84.         private static readonly GenericMenu.MenuFunction2 _onSelectedScriptableObject = OnSelectedScriptableObject;
  85.  
  86.         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  87.         {
  88.             GetScriptableObjects(attribute as ScriptableObjectMultiSelectDropdownAttribute);
  89.             DrawScriptableObjectSelectionControl(position, label, property.FindPropertyRelative("values"), attribute as ScriptableObjectMultiSelectDropdownAttribute);
  90.         }
  91.  
  92.         public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  93.         {
  94.             return EditorStyles.popup.CalcHeight(GUIContent.none, 0);
  95.         }
  96.  
  97.         private static void GetScriptableObjects(ScriptableObjectMultiSelectDropdownAttribute attribute)
  98.         {
  99.             Type genericClassType = typeof(Resources);
  100.             MethodInfo[] methodsInfo = genericClassType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  101.             MethodInfo methodInfo = methodsInfo.Where(_ => _.IsGenericMethod && _.Name.Equals("LoadAll") && _.GetParameters().FirstOrDefault().ParameterType == typeof(string))
  102.                                     .FirstOrDefault();
  103.             Type[] genericArguments = new Type[] { attribute.BaseType };
  104.             MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
  105.             _scriptableObjects = genericMethodInfo.Invoke(null, new object[] { "" }) as ScriptableObject[];
  106.         }
  107.  
  108.         private static bool ResolveSelectedScriptableObject(ScriptableObject scriptableObject)
  109.         {
  110.             // TODO: You may fix this if
  111.             if (_scriptableObjects != null)
  112.             {
  113.                 return _selectedScriptableObjects.Contains(scriptableObject);
  114.             }
  115.             else
  116.             {
  117.                 return false;
  118.             }
  119.         }
  120.  
  121.         private static ScriptableObject[] DrawScriptableObjectSelectionControl(Rect position, GUIContent label,
  122.             ScriptableObject[] scriptableObjects, SerializedProperty property, ScriptableObjectMultiSelectDropdownAttribute attribute)
  123.         {
  124.             if (label != null && label != GUIContent.none)
  125.                 position = EditorGUI.PrefixLabel(position, label);
  126.  
  127.             int controlID = GUIUtility.GetControlID(_controlHint, FocusType.Keyboard, position);
  128.  
  129.             bool triggerDropDown = false;
  130.  
  131.             switch (Event.current.GetTypeForControl(controlID))
  132.             {
  133.                 case EventType.ExecuteCommand:
  134.                     if (Event.current.commandName == "ScriptableObjectReferenceUpdated")
  135.                     {
  136.                         if (_selectionControlID == controlID)
  137.                         {
  138.                             if (scriptableObjects != _selectedScriptableObjects.ToArray())
  139.                             {
  140.                                 scriptableObjects = _selectedScriptableObjects.ToArray();
  141.                                 GUI.changed = true;
  142.                             }
  143.  
  144.                             _selectionControlID = 0;
  145.                             _selectedScriptableObjects = null;
  146.                         }
  147.                     }
  148.                     break;
  149.  
  150.                 case EventType.MouseDown:
  151.                     if (GUI.enabled && position.Contains(Event.current.mousePosition))
  152.                     {
  153.                         GUIUtility.keyboardControl = controlID;
  154.                         triggerDropDown = true;
  155.                         Event.current.Use();
  156.                     }
  157.                     break;
  158.  
  159.                 case EventType.KeyDown:
  160.                     if (GUI.enabled && GUIUtility.keyboardControl == controlID)
  161.                     {
  162.                         if (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.Space)
  163.                         {
  164.                             triggerDropDown = true;
  165.                             Event.current.Use();
  166.                         }
  167.                     }
  168.                     break;
  169.  
  170.                 case EventType.Repaint:
  171.                     if (scriptableObjects.Length == 0)
  172.                     {
  173.                         _tempContent.text = "Nothing";
  174.                     }
  175.                     else if (scriptableObjects.Length == _scriptableObjects.Length)
  176.                     {
  177.                         _tempContent.text = "Everything";
  178.                     }
  179.                     else if (scriptableObjects.Length >= 2)
  180.                     {
  181.                         _tempContent.text = "Mixed ...";
  182.                     }
  183.                     else
  184.                     {
  185.                         _tempContent.text = scriptableObjects[0].name;
  186.                     }
  187.  
  188.                     EditorStyles.popup.Draw(position, _tempContent, controlID);
  189.                     break;
  190.             }
  191.  
  192.             if (triggerDropDown)
  193.             {
  194.                 _selectionControlID = controlID;
  195.                 _selectedScriptableObjects = scriptableObjects.ToList();
  196.  
  197.                 DisplayDropDown(position, scriptableObjects, attribute.grouping);
  198.             }
  199.  
  200.             return scriptableObjects;
  201.         }
  202.  
  203.         private static ScriptableObject[] Read(SerializedProperty property)
  204.         {
  205.             List<ScriptableObject> selectedScriptableObjects = new List<ScriptableObject>();
  206.             for (int i = 0; i < property.arraySize; i++)
  207.             {
  208.                 selectedScriptableObjects.Add(property.GetArrayElementAtIndex(i).objectReferenceValue as ScriptableObject);
  209.             }
  210.  
  211.             return selectedScriptableObjects.ToArray();
  212.         }
  213.  
  214.         private static void Write(SerializedProperty property, ScriptableObject[] scriptableObjects)
  215.         {
  216.             property.arraySize = 0;
  217.             for (int i = 0; i < scriptableObjects.Length; i++)
  218.             {
  219.                 property.arraySize++;
  220.                 property.GetArrayElementAtIndex(i).objectReferenceValue = scriptableObjects[i];
  221.             }
  222.         }
  223.  
  224.         private static void DrawScriptableObjectSelectionControl(Rect position, GUIContent label,
  225.             SerializedProperty property, ScriptableObjectMultiSelectDropdownAttribute attribute)
  226.         {
  227.             bool restoreShowMixedValue = EditorGUI.showMixedValue;
  228.             EditorGUI.showMixedValue = property.hasMultipleDifferentValues;
  229.  
  230.             ScriptableObject[] output = DrawScriptableObjectSelectionControl(position, label, Read(property), property, attribute);
  231.             if (GUI.changed)
  232.             {
  233.                 Write(property, output);
  234.             }
  235.  
  236.             EditorGUI.showMixedValue = restoreShowMixedValue;
  237.         }
  238.  
  239.         private static void DisplayDropDown(Rect position, ScriptableObject[] selectedScriptableObject, ScriptableObjectGrouping grouping)
  240.         {
  241.             var menu = new GenericMenu();
  242.  
  243.             menu.AddItem(new GUIContent("Nothing"), selectedScriptableObject.Length == 0, _onSelectedScriptableObject, null);
  244.             menu.AddItem(new GUIContent("Everything"), selectedScriptableObject.Length == _scriptableObjects.Length, _onSelectedScriptableObject, _scriptableObjects);
  245.  
  246.             for (int i = 0; i < _scriptableObjects.Length; ++i)
  247.             {
  248.                 var scriptableObject = _scriptableObjects[i];
  249.  
  250.                 string menuLabel = FormatGroupedScriptableObject(scriptableObject, grouping);
  251.                 if (string.IsNullOrEmpty(menuLabel))
  252.                     continue;
  253.  
  254.                 var content = new GUIContent(menuLabel);
  255.                 menu.AddItem(content, ResolveSelectedScriptableObject(scriptableObject), _onSelectedScriptableObject, scriptableObject);
  256.             }
  257.  
  258.             menu.DropDown(position);
  259.         }
  260.  
  261.         private static string FindPath(ScriptableObject scriptableObject)
  262.         {
  263.             string path = AssetDatabase.GetAssetPath(scriptableObject);
  264.             path = path.Replace("Assets/Resources/", "");
  265.             path = path.Replace(".asset", "");
  266.  
  267.             return path;
  268.         }
  269.  
  270.         private static string FormatGroupedScriptableObject(ScriptableObject scriptableObject, ScriptableObjectGrouping grouping)
  271.         {
  272.             string path = FindPath(scriptableObject);
  273.  
  274.             switch (grouping)
  275.             {
  276.                 default:
  277.                 case ScriptableObjectGrouping.None:
  278.                     path = path.Replace("/", " > ");
  279.                     return path;
  280.  
  281.                 case ScriptableObjectGrouping.ByFolder:
  282.                     return path;
  283.  
  284.                 case ScriptableObjectGrouping.ByFolderFlat:
  285.                     int last = path.LastIndexOf('/');
  286.                     string part1 = path.Substring(0, last);
  287.                     string part2 = path.Substring(last);
  288.                     path = part1.Replace("/", " > ") + part2;
  289.                     return path;
  290.             }
  291.         }
  292.  
  293.         private static void OnSelectedScriptableObject(object userData)
  294.         {
  295.             if (userData == null)
  296.             {
  297.                 _selectedScriptableObjects.Clear();
  298.             }
  299.             else if (userData.GetType().IsArray)
  300.             {
  301.                 _selectedScriptableObjects = (userData as ScriptableObject[]).ToList();
  302.             }
  303.             else
  304.             {
  305.                 ScriptableObject scriptableObject = userData as ScriptableObject;
  306.  
  307.                 if (!ResolveSelectedScriptableObject(scriptableObject))
  308.                 {
  309.                     _selectedScriptableObjects.Add(scriptableObject);
  310.                 }
  311.                 else
  312.                 {
  313.                     _selectedScriptableObjects.Remove(scriptableObject);
  314.                 }
  315.             }
  316.  
  317.             var scriptableObjectReferenceUpdatedEvent = EditorGUIUtility.CommandEvent("ScriptableObjectReferenceUpdated");
  318.             EditorWindow.focusedWindow.SendEvent(scriptableObjectReferenceUpdatedEvent);
  319.         }
  320.     }
  321. }
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