Search Unity

Select X Window

Discussion in 'Immediate Mode GUI (IMGUI)' started by TommySKD, May 8, 2017.

  1. TommySKD

    TommySKD

    Joined:
    Jul 23, 2014
    Posts:
    25
    Hello,

    Unity has this very useful "Select GameObject" window popping up when you want to assign prefab fields which lists all your prefabs and even gives you a quick search box.
    Is it possible to still have this "Select X" window where X would be prefabs that have script X on them?

    Here for example I want to do this with prefabs that have a Particle script on them but as you can see it lists nothing. Would it be possible to have a working "Select Particle" window with a custom editor or some other way?

    2017-05-08_23h46_21.png 2017-05-08_23h52_19.png 2017-05-08_23h53_17.png
     
  2. PsyKaw

    PsyKaw

    Joined:
    Aug 16, 2012
    Posts:
    102
  3. TommySKD

    TommySKD

    Joined:
    Jul 23, 2014
    Posts:
    25
    I tried it but it does the same thing, a "Select Particle" window with 0 result. I mean it makes sense since a GameObject with a Particle component is still just a GameObject, but yeah that's too bad for this kind of listing purpose
     
  4. PsyKaw

    PsyKaw

    Joined:
    Aug 16, 2012
    Posts:
    102
    Oh wait it doesn't work for components... :(

    You can do it with a little trick. You have to make an AssetPostProcessor to set a label "Particle" to your prefabs (try to make it by your own, if u can't I will help). And use this code like that:

    Code (csharp):
    1.  
    2. public static T ObjectFieldFiltered<T> (GUIContent _label, UnityEngine.Object _obj, bool _allowSceneObjects, string _searchFilter, params GUILayoutOption[] _options) where T : UnityEngine.Object
    3. {
    4.     Type objType = typeof(T);
    5.  
    6.     float height = 16f;
    7.     Rect position = EditorGUILayout.GetControlRect(true, height, _options);
    8.  
    9.     // Get control ID according label (so label is unique identifier for filtered objectfields
    10.     int controlId = GUIUtility.GetControlID(("ObjectField"+_label).GetHashCode(), FocusType.Keyboard);
    11.  
    12.     EditorGUIUtility.SetIconSize(new Vector2(12f, 12f));
    13.     GUIContent content = EditorGUIUtility.ObjectContent(_obj, objType);
    14.     position = EditorGUI.PrefixLabel(position, controlId, _label);
    15.  
    16.     if (Event.current.IsRepaint())
    17.     {
    18.         EditorStyles.objectField.Draw(position, content, controlId, false);
    19.     }
    20.  
    21.     if (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform)
    22.     {
    23.         if (position.Contains(Event.current.mousePosition) && GUI.enabled)
    24.         {
    25.             UnityEngine.Object[] objectReferences = DragAndDrop.objectReferences;
    26.             if (objectReferences.Length != 0)
    27.             {
    28.                 UnityEngine.Object target = objectReferences[0];
    29.                 if (target != null)
    30.                 {
    31.                     DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
    32.                     if (Event.current.type == EventType.DragPerform)
    33.                     {
    34.                         _obj = target;
    35.                         GUI.changed = true;
    36.                         DragAndDrop.AcceptDrag();
    37.                         DragAndDrop.activeControlID = 0;
    38.                     }
    39.                     else
    40.                         DragAndDrop.activeControlID = controlId;
    41.                     Event.current.Use();
    42.                 }
    43.  
    44.             }
    45.         }
    46.     }
    47.  
    48.     if (Event.current.type != EventType.ExecuteCommand)
    49.     {
    50.         if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && position.Contains(Event.current.mousePosition))
    51.         {
    52.             Rect rect = new Rect(position.xMax - 15f, position.y, 15f, position.height);
    53.             EditorGUIUtility.editingTextField = false;
    54.             if (rect.Contains(Event.current.mousePosition))
    55.             {
    56.                 if (GUI.enabled)
    57.                 {
    58.                     GUIUtility.keyboardControl = controlId;
    59.                     EditorGUIUtility.ShowObjectPicker<T>(_obj, _allowSceneObjects, _searchFilter, controlId);
    60.  
    61.                     Event.current.Use();
    62.                     GUIUtility.ExitGUI();
    63.                 }
    64.             }
    65.             else
    66.             {
    67.                 UnityEngine.Object @object = _obj;
    68.                 Component component = @object as Component;
    69.                 if ((bool) ((UnityEngine.Object) component))
    70.                     @object = (UnityEngine.Object) component.gameObject;
    71.                 if (EditorGUI.showMixedValue)
    72.                     @object = (UnityEngine.Object) null;
    73.                 if (Event.current.clickCount == 1)
    74.                 {
    75.                     GUIUtility.keyboardControl = controlId;
    76.                     EditorGUIUtility.PingObject(@object);
    77.                     Event.current.Use();
    78.                 }
    79.                 else if (Event.current.clickCount == 2)
    80.                 {
    81.                     if ((bool) @object)
    82.                     {
    83.                         AssetDatabase.OpenAsset(@object);
    84.                         GUIUtility.ExitGUI();
    85.                     }
    86.                     Event.current.Use();
    87.                 }
    88.             }
    89.         }
    90.     }
    91.     if (Event.current.commandName == "ObjectSelectorUpdated" && EditorGUIUtility.GetObjectPickerControlID() == controlId && GUIUtility.keyboardControl == controlId)
    92.     {
    93.         GUI.changed = true;
    94.         //Event.current.Use();
    95.         return EditorGUIUtility.GetObjectPickerObject() as T;
    96.     }
    97.  
    98.     return _obj as T;
    99. }
    100.  
    Use this one in your custom inspector:
    Code (csharp):
    1. particle = EditorGUILayoutTools.ObjectFieldFiltered<GameObject>(new GUIContent("Particle"), particle, false, "l:Particle ");
     
    Last edited: May 11, 2017
    TommySKD likes this.
  5. TommySKD

    TommySKD

    Joined:
    Jul 23, 2014
    Posts:
    25
    I didn't know about AssetPostProcessor it is great I was actually looking for something like this for some other automatic spritesheet processing thing too.
    This editor script automatically assigns the "Particle" label to prefabs with a Particle component on them:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. class AutoLabel : AssetPostprocessor
    5. {
    6.     private static string[] particleLabels = { "Particle" };
    7.  
    8.     static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    9.     {
    10.         foreach (string str in importedAssets)
    11.             if (str.EndsWith(".prefab"))
    12.             {
    13.                 GameObject prefab = (GameObject) AssetDatabase.LoadAssetAtPath(str, typeof(Object));
    14.                 if (prefab.GetComponent<Particle>())
    15.                     AssetDatabase.SetLabels(prefab, particleLabels);
    16.             }
    17.     }
    18. }
    So now they can easily be listed with "l: Particle" in the object picker search box, which is already very nice.
    Now the problem is that the object picker has that search box empty by default.
    Your script solves that by allowing you to have any default string for the search box. I tried it and it works perfectly inside a custom editor window, but it would be nice to have the field in its usual spot in the normal inspector.

    I tried doing a custom property drawer but it seems that EditorGUILayout or EditorGUIUtility (which has ShowObjectPicker) functions just don't work at all with a custom property drawer? It spams a bunch of Mismatched LayerGroup errors even when I try to brutally only use ShowObjectPicker. They only seem to work in custom editors.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. [CustomPropertyDrawer(typeof(Particle))]
    5. public class ParticleDrawer : PropertyDrawer
    6. {
    7.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    8.     {
    9.         // Default behavior
    10.         EditorGUI.ObjectField(position, property);
    11.  
    12.         // This doesn't work but I wish it did
    13.         Object source = property.objectReferenceValue;
    14.         source = EditorGUILayoutTools.ObjectFieldFiltered<GameObject>(new GUIContent("Particle"), source, false, "l:Particle ");
    15.         property.objectReferenceValue = source;
    16.     }
    17. }
    18.  
    So if this could work somehow that'd be perfect. That auto labelling thing is still great because I can actually toy with the search favorites in the project view now and just have a "All Particles" favorite that searches "l: Particle" or just manually type/paste that in the object picker. And auto labelling more types is very easy.
    Thanks for helping so far!
     
    Last edited: May 12, 2017