0
votes

In the CustomEditor script I color in yellow objects that have attached a specific component in this case Mesh Renderer.

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
//Adapted from Unity3DCollege YouTube Video Tutorial https://www.youtube.com/watch?v=pdDrY8Mc2lU
[InitializeOnLoad]
public class CustomHierarchy : MonoBehaviour
{
    private static Vector2 offset = new Vector2(0, 2);
    public static Color gameObjectFontColor = Color.black;
    public static Color prefabOrgFontColor = Color.black;
    public static Color prefabModFontColor = Color.white;
    public static Color inActiveColor = new Color(0.01f, 0.4f, 0.25f);
    public static Color meshRendererColor = Color.yellow;
    public static List<string> componentsList = new List<string>();

    static CustomHierarchy()
    {
        EditorApplication.hierarchyWindowItemOnGUI += HandleHierarchyWindowItemOnGUI;
    }
    private static void HandleHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
    {
        Color fontColor = gameObjectFontColor;
        Color backgroundColor = new Color(.76f, .76f, .76f);
        FontStyle styleFont = FontStyle.Normal;
        var obj = EditorUtility.InstanceIDToObject(instanceID);
        GameObject gameObj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;

        if (Selection.instanceIDs.Contains(instanceID))
        {
            backgroundColor = new Color(0.24f, 0.48f, 0.90f);
        }
        if (obj != null)
        {
            var prefabType = PrefabUtility.GetPrefabType(obj);
            if (gameObj.activeInHierarchy == false)
            {
                backgroundColor = inActiveColor;
            }

            if (prefabType == PrefabType.PrefabInstance)
            {
                styleFont = FontStyle.Bold;
                PropertyModification[] prefabMods = PrefabUtility.GetPropertyModifications(obj);
                foreach (PropertyModification prefabMod in prefabMods)
                {
                    if (prefabMod.propertyPath.ToString() != "m_Name" && prefabMod.propertyPath.ToString() != "m_LocalPosition.x" && prefabMod.propertyPath.ToString() != "m_LocalPosition.y" && prefabMod.propertyPath.ToString() != "m_LocalPosition.z" && prefabMod.propertyPath.ToString() != "m_LocalRotation.x" && prefabMod.propertyPath.ToString() != "m_LocalRotation.y" && prefabMod.propertyPath.ToString() != "m_LocalRotation.z" && prefabMod.propertyPath.ToString() != "m_LocalRotation.w" && prefabMod.propertyPath.ToString() != "m_RootOrder" && prefabMod.propertyPath.ToString() != "m_IsActive")
                    {
                        if (gameObj.GetComponent<MeshRenderer>() == true)
                            fontColor = meshRendererColor;
                        else
                            fontColor = prefabModFontColor;

                        break;
                    }
                }
                if (fontColor != prefabModFontColor)
                {
                    if (gameObj.GetComponent<MeshRenderer>() == true)
                        fontColor = meshRendererColor;
                    else
                        fontColor = prefabOrgFontColor;
                }
            }
            else
            {
                if (gameObj.GetComponent<MeshRenderer>() == true)
                    fontColor = meshRendererColor;
            }
            Rect offsetRect = new Rect(selectionRect.position + offset, selectionRect.size);
            EditorGUI.DrawRect(selectionRect, backgroundColor);
            EditorGUI.LabelField(offsetRect, obj.name, new GUIStyle()
            {
                normal = new GUIStyleState() { textColor = fontColor },
                fontStyle = styleFont
            }
            );
        }
    }
}

In the EditorWindow script I'm using the SetSearchFilter:

using System;
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.Reflection;

public class HierarchyEditor : EditorWindow
{
    private static SearchableEditorWindow hierarchy { get; set; }
    private string filterText = "";

    [MenuItem("Tools/Hierarchy Editor")]
    public static void ShowWindow()
    {
        GetWindow<HierarchyEditor>("HierarchyEditor");
    }
    private void OnGUI()
    {
        CustomHierarchy.gameObjectFontColor = EditorGUILayout.ColorField("Original Font Color", CustomHierarchy.gameObjectFontColor);
        CustomHierarchy.prefabOrgFontColor = EditorGUILayout.ColorField("Prefab Original Font Color", CustomHierarchy.prefabOrgFontColor);
        CustomHierarchy.prefabModFontColor = EditorGUILayout.ColorField("Prefab Modified Font Color", CustomHierarchy.prefabModFontColor);
        CustomHierarchy.inActiveColor = EditorGUILayout.ColorField("Inactive Color", CustomHierarchy.inActiveColor);
        CustomHierarchy.meshRendererColor = EditorGUILayout.ColorField("Mesh Renderer Color", CustomHierarchy.meshRendererColor);

        filterText = GUI.TextField(new Rect(30,190,120,30),filterText, 25);

        SetSearchFilter(filterText, 1);
    }

    public const int FILTERMODE_ALL = 0;
    public const int FILTERMODE_NAME = 1;
    public const int FILTERMODE_TYPE = 2;

    public static void SetSearchFilter(string filter, int filterMode)
    {
        SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll(typeof(SearchableEditorWindow));

        foreach (SearchableEditorWindow window in windows)
        {
            if (window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow")
            {
                hierarchy = window;
                break;
            }
        }

        if (hierarchy == null)
            return;

        MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
        object[] parameters = new object[] { filter, filterMode, false };

        setSearchType.Invoke(hierarchy, parameters); 
    }
}

Here I'm typing in the filterText TextField and it's filtering by name in this case.

But I want to filter by name but also to filter only objects that attached to them a Mesh Renderer component. Not the FILTERMODE_TYPE but objects that have attached with Mesh Renderer component. So the filter mode should be Name(1) but also to filter at the same time objects with mesh renderer.

I tried to add to the OnGUI two lines: The two lines are:

System.Type type = SceneModeUtility.SearchBar(typeof(BoxCollider), typeof(MeshRenderer));
SceneModeUtility.SearchForType(type);

But then in the EditorWindow I see 3 icons All BoxCollider MeshRenderer. If I click on BoxCollider it's filtering all objects with boxcollider but then when I'm typing a name in the hierarchy search bar it will filter all objects with the name and box collider but then when I click on the editorwindow again it's changing it to the All icon. Same for the meshrenderer.

And I can't select both boxcollider and meshrenderer I can select only one of them.

Screenshot of the EditorWindow:

EditorWindow

private void OnGUI()
    {
        CustomHierarchy.gameObjectFontColor = EditorGUILayout.ColorField("Original Font Color", CustomHierarchy.gameObjectFontColor);
        CustomHierarchy.prefabOrgFontColor = EditorGUILayout.ColorField("Prefab Original Font Color", CustomHierarchy.prefabOrgFontColor);
        CustomHierarchy.prefabModFontColor = EditorGUILayout.ColorField("Prefab Modified Font Color", CustomHierarchy.prefabModFontColor);
        CustomHierarchy.inActiveColor = EditorGUILayout.ColorField("Inactive Color", CustomHierarchy.inActiveColor);
        CustomHierarchy.meshRendererColor = EditorGUILayout.ColorField("Mesh Renderer Color", CustomHierarchy.meshRendererColor);

        multipleComponents = GUI.Toggle(new Rect(30, 160, 120, 30), multipleComponents, "Multiple components");
        if(multipleComponents == true)
        {
            GUI.enabled = true;
        }
        else
        {
            GUI.enabled = false;
        }
        multipleComponentsString = GUI.TextField(new Rect(30, 180, 120, 30), multipleComponentsString, 25);

        GUI.enabled = true;
        filterText = GUI.TextField(new Rect(30, 230, 120, 30), filterText, 25);

        System.Type type = SceneModeUtility.SearchBar(typeof(BoxCollider), typeof(MeshRenderer));
        SceneModeUtility.SearchForType(type);
    }
1
It probably works the same way the project's search window and Hierarchy filter does. Use "t:" with the component name, a space, then the name filter string. So "t:MeshCollider Ham" will match any object with MeshCollider components that has "Ham" somewhere in the name.Foggzie
@Foggzie Great thanks. So I was working for nothing but at least I learned something.Dubi Duboni
@Foggzie What the searcher can't find for example is objects with mesh renderer and also box collider. for example I have 40 objects with mesh renderer some have box collider. Is there a way to filter only the objects with the mesh renderer and also with box collider ? (Multiple components filtering)Dubi Duboni
I'm not sure if you can do multiple but you can use base classes so instead of MeshCollider and BoxCollider you can just do Collider.Foggzie

1 Answers

0
votes

I noticed you're using reflection to do this. You don't have to. There is an undocumented API called SceneModeUtility that can be used to search Objects in the Editor. See the non-official API for this here. It can be easily translated into English with a Chrome browser.

If you just want to search and filter an Object with a component (MeshRenderer) in the SearchField in the Editor:

SceneModeUtility.SearchForType(typeof(MeshRenderer));

To filter the search with multiple components on a GameObject and return the result:

System.Type type = SceneModeUtility.SearchBar(typeof(MeshRenderer), typeof(Rigidbody));

You can pass as many components as you wish to the SearchBar function.