- Home /
Fold/unfold gameobject from code
Is there some way to do something like
Selection.unfold = true;
Or something like that? I basically want to, in code, unfold my currently selected gameobject (it would have children of course).
Cheers!
Not sure there's a straight-forward public editor functionality for that - but a simple way would be to select any of the children objects (that way we collapse to their level) - and then re-select the main parent object (in case you want that) - This would help you collapse (unfold), not sure about folding though...
This works for unfolding/collapsing:
public static void Collapse(GameObject go)
{
SelectObject(go.transform.GetChild(0).gameObject);
EditorApplication.delayCall += () => SelectObject(go); // If you don't put the delay, it would be too fast for the editor - he would select the child and immediately select the parent go so there won't be enough time to unfold - this line is optional all together...
}
public static void SelectObject(Object obj)
{
Selection.activeObject = obj;
}
If you're stubborn, there's a way that must
work: (if you're on a Windows box) get a reference to the ProjectWindow
, find the exact position of the folding symbol, position the mouse at it (WinAPI) and send a $$anonymous$$ouseDown
event :D
Answer by vexe · Mar 06, 2014 at 09:33 AM
Here you go :)
public static void Collapse(GameObject go, bool collapse)
{
// bail out immediately if the go doesn't have children
if (go.transform.childCount == 0) return;
// get a reference to the hierarchy window
var hierarchy = GetFocusedWindow("Hierarchy");
// select our go
SelectObject(go);
// create a new key event (RightArrow for collapsing, LeftArrow for folding)
var key = new Event { keyCode = collapse ? KeyCode.RightArrow : KeyCode.LeftArrow, type = EventType.keyDown };
// finally, send the window the event
hierarchy.SendEvent(key);
}
public static void SelectObject(Object obj)
{
Selection.activeObject = obj;
}
public static EditorWindow GetFocusedWindow(string window)
{
FocusOnWindow(window);
return EditorWindow.focusedWindow;
}
public static void FocusOnWindow(string window)
{
EditorApplication.ExecuteMenuItem("Window/" + window);
}
You might ask, why focus on the hierarchy window, and then select the go? Well, giving focus to the hierarchy window is the only way I found to get a reference to it, If there was an easier way, I would go for it.
Ok... YOU are INCREDIBLE :)
Thank you so much for so quickly sharing your findings!
I gave the collapse parameter a default of true just to make the call that much easier :)
public static void Collapse(GameObject go, bool collapse = true)
{
// ...
}
Cheers!!!!
Also, this allows for expanding/collapsing (recursively) while preserving the active selection.
public static void SetExpandedRecursive(GameObject go, bool expand)
{
var type = typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
var methodInfo = type.Get$$anonymous$$ethod("SetExpandedRecursive");
EditorApplication.Execute$$anonymous$$enuItem("Window/Hierarchy");
var window = EditorWindow.focusedWindow;
methodInfo.Invoke(window, new object[] { go.GetInstanceID(), expand });
}
Great use of internal hidden code with reflection!, it would be great if Unity guys add this kind of stuff in the editor (not the hidden code but the feature I mean). Do you know a way to do something similar but with the Inspector window? Some times I want to collapse all components in order to edit only one and it kinda sucks to have to collapse them one by one.
For the new version, change this in the answer of Jlpeebles: EditorApplication.Execute$$anonymous$$enuItem("Window/General/Hierarchy");
How do you Collapse only the parent with your code @jlpeebles ?
^ This should be an answer of its own! Beautiful hack!
Answer by bjarkeck · Jan 06, 2018 at 10:58 AM
You can also find a child of the object you want to expand, and ping it using
EditorGUIUtility.PingObject(go)
This will expand everything for you.
Works in 2020.1.9f1. Flashes the GameObject in the Hierarchy as though it were clicked. Does not inspect the GameObject itself but does unfold all parents... very useful if you have a bunch of settings on a GameObject with a deep parent structure - you don't have to manually unfold them all to get to the settings, just click the GameObject which flashes.
Answer by sandolkakos · Nov 22, 2020 at 09:32 AM
For those who are still trying to find a good solution, based on a lot of research, I've created a utility with these methods:
- IsExpanded(GameObject go)
- GetExpandedGameObjects()
- SetExpanded(GameObject go, bool expand)
- SetExpandedRecursive(GameObject go, bool expand)
You can find my script here, I hope you guys make good use of it: - https://github.com/sandolkakos/unity-utilities/blob/main/Scripts/Editor/SceneHierarchyUtility.cs
Answer by astracat111 · Feb 20, 2020 at 10:20 AM
You now have to use EditorCoroutines.
Here is the result of what you can do with this: https://twitter.com/i/status/1230264906085105664
Firstly, install:
Window > Package Manager Download
Editor, Coroutines Package
Here is what worked for me. You call it like this:
EditorWindowControl.EditorCoroutineUtility.StartCoroutineOwnerless(CollapseObjectInHierarchy(myObjectNameInScene, false);
Then here are the two scripts needed:
using UnityEditor;
using UntiyEngine;
using Unity.EditorCoroutines.Editor;
public class EditorWindowControl {
private static IEnumerator CollapseObjectInHierarchyWindow(string gameObjectName, bool collapse)
{
GameObject obj = GameObject.Find(gameObjectName);
if (obj != null)
{
yield return EditorCoroutineUtility.StartCoroutineOwnerless(CollapseInHierarchyWindow(obj, collapse));
}
else
{
EditorUtility.DisplayDialog("Error", "No '" + gameObjectName + "' GameObject in Scene!", "OK");
}
yield return true;
}
private static IEnumerator CollapseInHierarchyWindow(GameObject go, bool collapse)
{
FocusUnityEditorWindow(SelectWindowType.Hierarchy);
yield return new EditorWaitForSeconds(0.05f);
Selection.activeGameObject = null;
while (Selection.activeGameObject != null)
yield return false;
Selection.activeGameObject = go;
while (Selection.activeGameObject != go)
yield return false;
if (collapse == false)
{
SimulatePCControl.RightArrow();
}
else
{
SimulatePCControl.LeftArrow();
}
yield return true;
}
private enum SelectWindowType { Inspector, ProjectBrowser, Game, Console, Hierarchy, Scene };
private static IEnumerator FocusUnityEditorWindow(SelectWindowType swt)
{
System.Type unityEditorWindowType = null;
EditorWindow editorWindow = null;
switch (swt)
{
case SelectWindowType.Inspector:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.InspectorWindow");
break;
case SelectWindowType.ProjectBrowser:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.ProjectBrowser");
break;
case SelectWindowType.Game:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
break;
case SelectWindowType.Console:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.ConsoleView");
break;
case SelectWindowType.Hierarchy:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
break;
case SelectWindowType.Scene:
unityEditorWindowType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.SceneView");
break;
}
editorWindow = EditorWindow.GetWindow(unityEditorWindowType);
while (editorWindow == null)
{
yield return false;
}
yield return true;
}
}
Also make a file for this class:
public class SimulatePCControl
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
//Mouse actions
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void keybd_event(uint bVk, uint bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Vector2 GetMousePosition()
{
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Vector2(w32Mouse.X, w32Mouse.Y);
}
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
private const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
private const int MOUSEEVENTF_MIDDLEUP = 0x40;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public enum ClickType { Left, Middle, Right }
public static void Click(ClickType clickType, int _X, int _Y)
{
//Call the imported function with the cursor's current position
uint X = (uint)_X;
uint Y = (uint)_Y;
switch (clickType)
{
case ClickType.Left:
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
break;
case ClickType.Middle:
mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, X, Y, 0, 0);
break;
case ClickType.Right:
mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, X, Y, 0, 0);
break;
}
}
public static IEnumerator DoubleClick(ClickType clickType)
{
switch (clickType)
{
case ClickType.Left:
Click(ClickType.Left, (int)GetMousePosition().x, (int)GetMousePosition().y);
yield return new EditorWaitForSeconds(0.1f);
Click(ClickType.Left, (int)GetMousePosition().x, (int)GetMousePosition().y);
break;
case ClickType.Middle:
Click(ClickType.Middle, (int)GetMousePosition().x, (int)GetMousePosition().y);
yield return new EditorWaitForSeconds(0.1f);
Click(ClickType.Middle, (int)GetMousePosition().x, (int)GetMousePosition().y);
break;
case ClickType.Right:
Click(ClickType.Right, (int)GetMousePosition().x, (int)GetMousePosition().y);
yield return new EditorWaitForSeconds(0.1f);
Click(ClickType.Right, (int)GetMousePosition().x, (int)GetMousePosition().y);
break;
}
}
private const int VK_LEFT = 0x25;
private const int VK_RIGHT = 0x27;
private const int VK_UP = 0x26;
private const int VK_DOWN = 0x28;
public static void Key(string keyName)
{
uint keyCode = 0x00;
switch (keyName.ToLower())
{
case "a":
keyCode = 0x41;
break;
case "b":
keyCode = 0x42;
break;
case "c":
keyCode = 0x43;
break;
case "d":
keyCode = 0x44;
break;
case "e":
keyCode = 0x45;
break;
case "f":
keyCode = 0x46;
break;
case "g":
keyCode = 0x47;
break;
case "h":
keyCode = 0x48;
break;
case "i":
keyCode = 0x49;
break;
case "j":
keyCode = 0x4A;
break;
case "k":
keyCode = 0x4B;
break;
case "l":
keyCode = 0x4C;
break;
case "m":
keyCode = 0x4D;
break;
case "n":
keyCode = 0x4E;
break;
case "o":
keyCode = 0x4F;
break;
case "p":
keyCode = 0x50;
break;
case "q":
keyCode = 0x51;
break;
case "r":
keyCode = 0x52;
break;
case "s":
keyCode = 0x53;
break;
case "t":
keyCode = 0x54;
break;
case "u":
keyCode = 0x55;
break;
case "v":
keyCode = 0x56;
break;
case "w":
keyCode = 0x57;
break;
case "x":
keyCode = 0x58;
break;
case "y":
keyCode = 0x59;
break;
case "z":
keyCode = 0x5A;
break;
default:
Debug.Log("INVALID KEYNAME: " + keyName);
return;
}
keybd_event(keyCode, 0, 0, 0);
keybd_event(keyCode, 0, 0x0002, 0);
}
public const int VK_CONTROL = 0x11; //Control key code
public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag
public const int VK_CONTROLKEY = 0x11; //Control key code
public const int Z = 0x5A;
public static void Shortcuts_Undo()
{
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
keybd_event(Z, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0x9e, 0, 0);
keybd_event(Z, 0x9e, 0, 0);
keybd_event(Z, 0x9e, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0x9e, KEYEVENTF_KEYUP, 0);
}
public static void LeftArrow()
{
keybd_event(VK_LEFT, 0, 0, 0);
keybd_event(VK_LEFT, 0, 0x0002, 0);
}
public static void RightArrow()
{
keybd_event(VK_RIGHT, 0, 0, 0);
keybd_event(VK_RIGHT, 0, 0x0002, 0);
}
public static void UpArrow()
{
keybd_event(VK_UP, 0, 0, 0);
keybd_event(VK_UP, 0, 0x0002, 0);
}
public static void DownArrow()
{
keybd_event(VK_DOWN, 0, 0, 0);
keybd_event(VK_DOWN, 0, 0x0002, 0);
}
}
Your answer
Follow this Question
Related Questions
selecting and organising objects in editor 0 Answers
Can you mirror a bunch of gameobjects ? 2 Answers
Unity lag on selection 0 Answers