How to nicely select item in the Unity’s two-column Project Browser

Hey, I’ll try to be short.
I’m working on the Maintainer‘s Issues Finder improvements and one of such improvement was to select (show) the scene file at the Project Browser along with target GameObject in the Hierarchy when user press “Show” next to the found issue.

At the first iteration, I did the selection using Selection.objects and it worked great with One-column view mode of the Project Browser.
But things get weird when I switched to the two-column mode: target scene file still get selected, but it didn’t show up until I manually navigated to the folder with that file.

And surprisingly, I faced two common issues here:
1. Unity has no API to let you know in which mode the Project Browser is.
2. Unity has no API to select specific folder in the first column of the Project Browser.

But thankfully, we have ILSpy and reflection! 😉
So, using ILSpy I managed to find all what I need;
UnityEditor.ProjectBrowser class
– static s_LastInteractedProjectBrowser field to access last used ProjectBrowser window (we can have lot of ProjectBrowsers in Unity layout).
– private field m_ViewMode of the ViewMode enum type which has two values – OneColumn (0) and TwoColumns(1)
– private ShowFolderContents() method which expands first column of the TreeView to the specified folder and selects it

And here is a resulting code which selects both object in scene hierarchy and scene file in Project Browser in any column mode (one or two columns):

public void SelectObjectAndScene(GameObject targetGameObjectInScene, string scenePath)
{
	List<Object> selection = new List<Object>();

	Object sceneFile = AssetDatabase.LoadAssetAtPath(scenePath, typeof(Object));
	selection.Add(sceneFile);

	Type projectBrowserType = Type.GetType("UnityEditor.ProjectBrowser,UnityEditor");
	if (projectBrowserType != null)
	{
		FieldInfo lastProjectBrowser = projectBrowserType.GetField("s_LastInteractedProjectBrowser", BindingFlags.Static | BindingFlags.Public);
		if (lastProjectBrowser != null)
		{
			object lastProjectBrowserInstance = lastProjectBrowser.GetValue(null);
			FieldInfo projectBrowserViewMode = projectBrowserType.GetField("m_ViewMode", BindingFlags.Instance | BindingFlags.NonPublic);
			if (projectBrowserViewMode != null)
			{
				// 0 - one column, 1 - two column
				int viewMode = (int)projectBrowserViewMode.GetValue(lastProjectBrowserInstance);
				if (viewMode == 1)
				{
					
					MethodInfo showFolderContents = projectBrowserType.GetMethod("ShowFolderContents", BindingFlags.NonPublic | BindingFlags.Instance);
					if (showFolderContents != null)
					{
						Object sceneFolder = AssetDatabase.LoadAssetAtPath(Path.GetDirectoryName(scenePath), typeof(Object));
						showFolderContents.Invoke(lastProjectBrowserInstance, new object[] { sceneFolder.GetInstanceID(),  true});
					}
					else
					{
						Debug.LogError("Can't find ShowFolderContents method!");
					}
				}
			}
			else
			{
				Debug.LogError("Can't find m_ViewMode field!");
			}
		}
		else
		{
			Debug.LogError("Can't find s_LastInteractedProjectBrowser field!");
		}
	}
	else
	{
		Debug.LogError("Can't find UnityEditor.ProjectBrowser type!");
	}

	selection.Add(targetGameObjectInScene);
	Selection.objects = selection.ToArray();
}

This code might be not elegant and clean since it’s a quick try to leave snippet in the blog. Feel free to correct my where I’m wrong.

P.S.: if you wish only show some file in the Project Browser without selection, just use EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(scenePath, typeof(Object))); It will work fine with one-column layout and will work with two-column layout if you don’t select anything else.

Found a typo? Please, highlight it and press Shift + Enter or click here to inform me!

Share Button

Comments

How to nicely select item in the Unity’s two-column Project Browser — 1 Comment