Search Unity

Expand/Collapse all components in a Gameobject. (Refresh issue)

Discussion in 'Editor & General Support' started by Adrien-Gannerie, Feb 16, 2018.

  1. Adrien-Gannerie

    Adrien-Gannerie

    Joined:
    Feb 18, 2015
    Posts:
    12
    Hi,

    I'm trying to create a tools which expand/collapse all components on a gameobject with a button in the context menu.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEditorInternal;
    4.  
    5. public static class ComponentTools
    6. {
    7.     [MenuItem("CONTEXT/Component/Collapse All")]
    8.     public static void CollapseAll(MenuCommand command)
    9.     {
    10.         GameObject gameObject = (command.context as Component).gameObject;
    11.         Component[] components = gameObject.GetComponents<Component>();
    12.         foreach (Component component in components)
    13.         {    
    14.             InternalEditorUtility.SetIsInspectorExpanded(component, false);
    15.         }
    16.         // Refresh inspector.
    17.     }
    18.  
    19.     [MenuItem("CONTEXT/Component/Expand All")]
    20.     public static void ExpandAll(MenuCommand command)
    21.     {
    22.         GameObject gameObject = (command.context as Component).gameObject;
    23.         Component[] components = gameObject.GetComponents<Component>();
    24.         foreach (Component component in components)
    25.         {
    26.             InternalEditorUtility.SetIsInspectorExpanded(component, true);
    27.         }
    28.         // Resfresh inspector.
    29.     }
    30. }
    That code works but i need to reselect the gameobject to refresh the inspector window.

    What is the right method to refresh/repaint/redraw the inspector window without reselecting the gameobject ?


    Thanks for your help.

    Best regards.

    Adrien Gannerie
     
    Last edited: Feb 16, 2018
  2. Adrien-Gannerie

    Adrien-Gannerie

    Joined:
    Feb 18, 2015
    Posts:
    12
  3. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,297
  4. Adrien-Gannerie

    Adrien-Gannerie

    Joined:
    Feb 18, 2015
    Posts:
    12
    Thank you very much for your help and sorry to bother you by private message.

    If I understood correctly your answer I must find the editor of each component and force a repaint?

    Best regards.
     
  5. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,297
    Yes give that a try and see how it goes.
     
  6. Adrien-Gannerie

    Adrien-Gannerie

    Joined:
    Feb 18, 2015
    Posts:
    12
    Thanks for your help. I tried this but this change nothing.

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using UnityEditorInternal;
    5.  
    6. public static class ComponentTools
    7. {
    8.     [MenuItem("CONTEXT/Component/Collapse All")]
    9.     public static void CollapseAll(MenuCommand command)
    10.     {
    11.         GameObject gameObject = (command.context as Component).gameObject;
    12.         Component[] components = gameObject.GetComponents<Component>();
    13.         foreach (Component component in components)
    14.         {      
    15.             InternalEditorUtility.SetIsInspectorExpanded(component, false);
    16.             Editor editor = null;
    17.             Editor.CreateCachedEditor(component, null, ref editor);
    18.             editor.Repaint();
    19.         }
    20.     }
    21.  
    22.     [MenuItem("CONTEXT/Component/Expand All")]
    23.     public static void ExpandAll(MenuCommand command)
    24.     {
    25.         GameObject gameObject = (command.context as Component).gameObject;
    26.         Component[] components = gameObject.GetComponents<Component>();
    27.         foreach (Component component in components)
    28.         {
    29.             InternalEditorUtility.SetIsInspectorExpanded(component, true);
    30.             Editor editor = null;
    31.             Editor.CreateCachedEditor(component, null, ref editor);
    32.             editor.Repaint();
    33.         }
    34.     }
    35. }
    36.  
    Have you a other idea ?

    Best regards.
     
  7. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    You could try InternalEditorUtility.RepaintAllViews(). It's undocumented, but will repaint everything. Unfortunately, there's no public API to repaint specifically inspector windows.
     
    nirvanajie likes this.
  8. FireMutant

    FireMutant

    Joined:
    Sep 2, 2013
    Posts:
    49
    I don't know if this has any bad side effects, but I found a solution to make the editor refresh from an example that uses a shortcut-key to lock/unlock the inspector. I modified the code below with what is working for me. There is a slight delay (1-2 seconds) before the refresh, but it does refresh and show all the components expanded/collapsed, and now that I've used it for a couple of days, this should absolutely be a standard feature in the inspector AND hierarchy! ;-)


    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using UnityEditorInternal;
    5.  
    6. public static class ComponentTools
    7. {
    8.     [MenuItem("CONTEXT/Component/Collapse All")]
    9.     public static void CollapseAll(MenuCommand command)
    10.     {
    11.         GameObject gameObject = (command.context as Component).gameObject;
    12.         Component[] components = gameObject.GetComponents<Component>();
    13.         foreach (Component component in components)
    14.         {    
    15.             InternalEditorUtility.SetIsInspectorExpanded(component, false);
    16.         }
    17.         ActiveEditorTracker.sharedTracker.ForceRebuild();
    18.     }
    19.  
    20.     [MenuItem("CONTEXT/Component/Expand All")]
    21.     public static void ExpandAll(MenuCommand command)
    22.     {
    23.         GameObject gameObject = (command.context as Component).gameObject;
    24.         Component[] components = gameObject.GetComponents<Component>();
    25.         foreach (Component component in components)
    26.         {
    27.             InternalEditorUtility.SetIsInspectorExpanded(component, true);
    28.         }
    29.         ActiveEditorTracker.sharedTracker.ForceRebuild();
    30.     }
    31. }
    32.  
     
  9. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,824
    Hey this script is super handy!
    I noticed though it doesn't collapse material components, do know why that would be? I'm thinking it might be because they aren't really regular components as such and just displayed to simplify things for the user.
    Might be a little tricky but does anyone know how to add them?
     
  10. villevli

    villevli

    Joined:
    Jan 19, 2016
    Posts:
    89
    This also collapses materials.
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEditorInternal;
    4.  
    5. public static class ComponentTools
    6. {
    7.     [MenuItem("CONTEXT/Component/Collapse All")]
    8.     private static void CollapseAll(MenuCommand command)
    9.     {
    10.         SetAllInspectorsExpanded((command.context as Component).gameObject, false);
    11.     }
    12.  
    13.     [MenuItem("CONTEXT/Component/Expand All")]
    14.     private static void ExpandAll(MenuCommand command)
    15.     {
    16.         SetAllInspectorsExpanded((command.context as Component).gameObject, true);
    17.     }
    18.  
    19.     public static void SetAllInspectorsExpanded(GameObject go, bool expanded)
    20.     {
    21.         Component[] components = go.GetComponents<Component>();
    22.         foreach (Component component in components)
    23.         {
    24.             if (component is Renderer)
    25.             {
    26.                 var mats = ((Renderer)component).sharedMaterials;
    27.                 for (int i = 0; i < mats.Length; ++i)
    28.                 {
    29.                     InternalEditorUtility.SetIsInspectorExpanded(mats[i], expanded);
    30.                 }
    31.             }
    32.             InternalEditorUtility.SetIsInspectorExpanded(component, expanded);
    33.         }
    34.         ActiveEditorTracker.sharedTracker.ForceRebuild();
    35.     }
    36. }
    37.  
     
  11. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,824
  12. IsntCo

    IsntCo

    Joined:
    Apr 12, 2014
    Posts:
    146
    Nice script! I was looking for something like this.
    It seems like it doesn't refresh though?
    So after you Collapse All, you have to reselect the object to see the changes?
     
  13. FireMutant

    FireMutant

    Joined:
    Sep 2, 2013
    Posts:
    49
    Appminis,

    It should refresh automatically (Unity 2017.4.10f1), however, if you have more than 1 inspector window open, it may be expanding/collapsing the other inspector window(s). I don't know why it does not do all of the open inspector windows, or the selected inspector window, but it does not. I have not been able to find a work-around or how to determine which inspector window is considered the "Active" one to the sharedTracker.
     
  14. giantkilleroverunity3d

    giantkilleroverunity3d

    Joined:
    Feb 28, 2014
    Posts:
    383
    I put this ComponentTools.cs in my 2018.3.8f1 editor folder and it does not appear in menu after Unity restart. I had to put it under and exitsting Tools menu itme then it showed up. But then I received:
    NullReferenceException: Object reference not set to an instance of an object
    ComponentTools.CollapseAll (UnityEditor.MenuCommand command) (at Assets/Editor/ComponentTools.cs:10)

    with a heirarchy item selected.
     
    Last edited: Jun 12, 2019
  15. andersemil

    andersemil

    Joined:
    Feb 2, 2015
    Posts:
    112
    Is there any way to scroll inspector to a newly expanded component via script? Unfortunately, setting Selection.activeObject to the expanded component does not scroll the inspector view to it.
     
  16. nih_

    nih_

    Joined:
    Aug 7, 2017
    Posts:
    8
    For anyone else finding this thread in 2020 (Using Unity 2019.4+):

    The little menu beside the lock in the inspector now has this functionality built in


    There is also the activeEditorTracker.SetVisible API available to do this without repaiting the GUI as done in the examples above

    Full code for collapsing / expanding fast below (might need some null-checks, just tested it quickly:
    Code (CSharp):
    1.  
    2.     public static class ComponentTools
    3.     {
    4.         [MenuItem("CONTEXT/Component/Collapse All")]
    5.         private static void CollapseAll()
    6.         {
    7.             SetAllInspectorsExpanded(false);
    8.         }
    9.  
    10.         [MenuItem("CONTEXT/Component/Expand All")]
    11.         private static void ExpandAll(MenuCommand command)
    12.         {
    13.             SetAllInspectorsExpanded(true);
    14.         }
    15.  
    16.         private static void SetAllInspectorsExpanded(bool expanded)
    17.         {
    18.             var activeEditorTracker = ActiveEditorTracker.sharedTracker;
    19.  
    20.             for (var i = 0; i < activeEditorTracker.activeEditors.Length; i++)
    21.             {
    22.                 activeEditorTracker.SetVisible(i, expanded ? 1 : 0);
    23.             }
    24.         }
     
  17. pgrenon

    pgrenon

    Joined:
    Oct 26, 2016
    Posts:
    3
    `ActiveEditorTracker.sharedTracker` is not suitable: it only works if you work with a single Inspector window

    I tried using `myEditor.Repaint()` and `InternalEditorUtility.RepaintAllViews()` but it doesn't do anything. I still have to deselect and reselect the game object.