Editor Window - How to center a window.

Like the title said, how does one center a popup window for a instance in the Editor?

Using Screen.Width does not work, unless the window is in full screen, and in the primary monitor.

5 Answers

5

So i guess your actual question is how you can find out the position and size of Unity’s main window? Here you go:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;

public static class Extensions
{
    public static System.Type[] GetAllDerivedTypes(this System.AppDomain aAppDomain, System.Type aType)
    {
        var result = new List<System.Type>();
        var assemblies = aAppDomain.GetAssemblies();
        foreach (var assembly in assemblies)
        {
            var types = assembly.GetTypes();
            foreach (var type in types)
            {
                if (type.IsSubclassOf(aType))
                    result.Add(type);
            }
        }
        return result.ToArray();
    }

    public static Rect GetEditorMainWindowPos()
    {
        var containerWinType = System.AppDomain.CurrentDomain.GetAllDerivedTypes(typeof(ScriptableObject)).Where(t => t.Name == "ContainerWindow").FirstOrDefault();
        if (containerWinType == null)
            throw new System.MissingMemberException("Can't find internal type ContainerWindow. Maybe something has changed inside Unity");
        var showModeField = containerWinType.GetField("m_ShowMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var positionProperty = containerWinType.GetProperty("position", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
        if (showModeField == null || positionProperty == null)
            throw new System.MissingFieldException("Can't find internal fields 'm_ShowMode' or 'position'. Maybe something has changed inside Unity");
        var windows = Resources.FindObjectsOfTypeAll(containerWinType);
        foreach (var win in windows)
        {
            var showmode = (int)showModeField.GetValue(win);
            if (showmode == 4) // main window
            {
                var pos = (Rect)positionProperty.GetValue(win, null);
                return pos;
            }
        }
        throw new System.NotSupportedException("Can't find internal main window. Maybe something has changed inside Unity");
    }

    public static void CenterOnMainWin(this UnityEditor.EditorWindow aWin)
    {
        var main = GetEditorMainWindowPos();
        var pos = aWin.position;
        float w = (main.width - pos.width)*0.5f;
        float h = (main.height - pos.height)*0.5f;
        pos.x = main.x + w;
        pos.y = main.y + h;
        aWin.position = pos;
    }
}

Just use Extensions.GetEditorMainWindowPos() to get back the rect of the main window in screen coordinates.

I’ve also written a simple extension method for the EditorWindow class called “CenterOnMainWin”. So inside yout editor window you can simply call CenterOnMainWin() and the window should positioning itself in the center of the main window.

Exactly what I needed, and now I feel dumb for not thinking in Reflecting to get the window position.!! _ Edit : Quick Question though, how did you find name ContainerWindow? Or how did you know that it was the correct one?

Thanks for the code. Pretty much to do to just get the correct center of the screen. This solution was the only one working for me. So I've used this code to create a 200x200 sized window in the screen center: popup window = ScriptableObject.CreateInstance(); window.position = new Rect(0, 0, 200, 200); Extensions.CenterOnMainWin(window);

There is a new method added to Unity 2020: EditorGUIUtility.GetMainWindowPosition().

It acts the same way as GetEditorMainWindowPos() but it’s obviously faster, so you should use only the CenterOnMainWin method from the Bunny83’s answer with the following modification:

public static void CenterOnMainWin(this EditorWindow window)
{
    Rect main = EditorGUIUtility.GetMainWindowPosition();
    Rect pos = window.position;
    float centerWidth = (main.width - pos.width) * 0.5f;
    float centerHeight = (main.height - pos.height) * 0.5f;
    pos.x = main.x + centerWidth;
    pos.y = main.y + centerHeight;
    window.position = pos;
}

Thanks, this is exactly what I was looking for.

Actually the correct answer would rather be:

var window = GetWindow<MyWindow>("Centered Window");
var position = window.position;
position.center = new Rect(0f, 0f, Screen.currentResolution.width, Screen.currentResolution.height).center;
window.position = position;
window.Show();

using Screen.currentResolution.width and Screen.currentResolution.height.

I would be careful with absolute terms like "correct". The question wasn't about centering the window in the main-screen but centered inside the UnityMain window. For example if you have Unity on your second monitor your code would still open the window centered on the main monitor. EditorWindows are sub-windows of the Unity editor and logically belong to Unity itself and do not act like seperate programs. Your code works for centering an editor window on the main monitor but that's not necessarily what you want.

If without 2020, doing this will be much faster

private static Type GetType (this AppDomain aAppDomain, Type aType, string name)
        {
            var        assemblies   = aAppDomain.GetAssemblies ();
            return assemblies.SelectMany (assembly => assembly.GetTypes ()).FirstOrDefault (type => type.IsSubclassOf (aType) && type.Name == name);
        }

var containerWinType =
                AppDomain.CurrentDomain.GetType (typeof (ScriptableObject), "ContainerWindow");

I was having a similar issue and to get Unity’s window center I’m now using:

var windowCenter = EditorGUIUtility.GetMainWindowPosition().center;

I haven’t tested this across multiple setups, but is also working on a recent MacBook which was an issue before.