How to create a window in Unity from a script and attach it to an existing tab?

Viewed 954

i'm trying to make a custom editor script for Unity, but i'm stuck in what I thought would be an easy step. When using UnityEditor.GetWindow(), the window doesn't open in the main tab but as a separate Window. The scene view is not attached to the main Unity window.

I've tried a few workarounds but none seem to work:

  • First I tried to use the desiredDockNextTo parameter from the API, but I keep getting an error i'm not able to fix.

      Type inspWndType = typeof(Editor).Assembly.GetType("UnityEditor.SceneView");
    
     EditorWindow[] allWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
     Type[] insWindTypeList = new Type[allWindows.Length];
     for(int i = 0; i < allWindows.Length; i++)
     {
         insWindTypeList[i] = allWindows[i].GetType();
     }
     var window = EditorWindow.GetWindow<typeof(inspWndType)>(insWindTypeList);
    

I keep getting an error in <typeof(inspWndType)> saying that it's a variable instead of a type (I also tried with inspWndType.gettype or casting it, nothing worked).

TLDR: I want to be able to create a window using EditorWindow.GetWindow() and dock it from a script.

Thank you to anyone that could help me with this.

1 Answers

First of all typeof expects a compile time constant type not a dynamic variable.

So if something it should be e.g.

var inspWndType = typeof(UnityEditor.SceneView);

However, the second issue: You can't have this as generic type parameter.

What you want to do is assuming your editorwindow looks like e.g.

public class YOURWINDOW : EditorWindow
{
    ...
}

then it should rather be

var inspWndType = typeof(UnityEditor.SceneView);
var window = EditorWindow.GetWindow<YOURWINDOW>(inspWndType);

There is no reflection needed here as you don't want o deal with any runtime types and UnityEditor.SceneView is public anyway.


Example:

using System;
using UnityEditor;

public class ExampleWindow : EditorWindow
{
    [MenuItem("Examples/ExampleWindow")]
    private static void Init()
    {
        var inspWndType = typeof(SceneView);
        var window = GetWindow<ExampleWindow>(inspWndType);
    }

    private void OnGUI()
    {
        EditorGUILayout.LabelField("Tadaaaa!", EditorStyles.boldLabel);
    }
}

enter image description here


Now if you actually want to have it docked no matter what tab is opened you could use reflection to find just each and every inheritor of EditorWindow and do

using Linq;

...

var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))).ToArray();
// This kind of equals doing something like
//var typesList = new List<Type>();
//var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//foreach(var assembly in assemblies)
//{
//    var allTypes = assembly.GetTypes();
//    foreach(var type in allTypes)
//    {
//        if(type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow)))
//        {
//            typesList.Add(type);
//        }
//    }
//}
//var types = typesList.ToArray();

var window = GetWindow<YOURWINDOW>(types);

Note though that due to order the ConsoleWindow is kinda the first entry almost so if there is a console tab opened it would always first attach to that one ^^

You can still add your preferred ones though like e.g.

var types = new List<Type>()
{ 
    // first add your preferences
    typeof(SceneView), 
    typeof(Editor).Assembly.GetType("UnityEditor.GameView"),
    typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow"),
    typeof(Editor).Assembly.GetType("UnityEditor.ConsoleWindow"), 
    typeof(Editor).Assembly.GetType("UnityEditor.ProjectBrowser"), 
    typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow")
};

// and then add all others as fallback (who cares about duplicates at this point ? ;) )
types.AddRange(AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))));
var window = GetWindow<YOURWINDOW>(types.ToArray());
 

since it literally goes through this array from start to end and uses the first matching opened window type.

Related