Programmatically change editor layout

I’m working on a project with several custom editor windows and I have several different layouts depending on the stage I’m working on. I’d like to implement a simple button or menu item that programmatically changes to one of the others layouts and starts some operations.
My problem is that I have no idea how to load a layout programmatically and I didn’t find anything close in the documentation. I’m wondering if it is even possible …
any help? :slight_smile:

2019 Update - Tested with Unity 2018.2.0f2


If you’re just looking to save and load layouts programmatically and you’re using a new version of the Unity Editor, this code should help you out.


Usage:
LayoutUtility.SaveLayout(path);
LayoutUtility.LoadLayout(path);

Place in: Assets/Scripts/Editor/LayoutUtility.cs

using UnityEngine;
using UnityEditor;
using System.IO;
using System.Reflection;
using Type = System.Type;

public static class LayoutUtility {

    private enum MethodType {Save, Load};

    static MethodInfo GetMethod (MethodType method_type) {

        Type layout = Type.GetType("UnityEditor.WindowLayout,UnityEditor");

        MethodInfo save = null;
        MethodInfo load = null;

        if (layout != null) {
            load = layout.GetMethod("LoadWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] {typeof(string), typeof(bool)}, null);
            save = layout.GetMethod("SaveWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] {typeof(string)}, null);
        }

        if (method_type == MethodType.Save) {
            return save;
        }
        else {
            return load;
        }

    }

    public static void SaveLayout(string path) {
        path = Path.Combine(Directory.GetCurrentDirectory(), path);
        GetMethod(MethodType.Save).Invoke(null, new object[] {path});
    }

    public static void LoadLayout(string path) {
        path = Path.Combine(Directory.GetCurrentDirectory(), path);
        GetMethod(MethodType.Load).Invoke(null, new object[] { path, false });
    }

}

Unity does not expose a function to adjust the layout of the Unity editor manually. However there is a hack which someone kindly told me about on the IRC channel. I would give them credit but I honestly cannot remember who told me :S

WARNING - You cannot load Unity 3.x layouts in Unity 4.x because it will crash. In fact, you cannot even place a Unity 3.x layout asset in a Unity 4.x project because it will crash.

Example of Usage:

Ensure that the folder Assets/Editor/Layouts/ exists before using the following hack:

using UnityEngine;
using UnityEditor;

public static class LayoutHackExample {

    [MenuItem("Layout Hack/Save Layout")]
    static void SaveLayoutHack() {
        // Saving the current layout to an asset
        LayoutUtility.SaveLayoutToAsset("Assets/Editor/Layouts/Your Layout.wlt");
    }

    [MenuItem("Layout Hack/Load Layout")]
    static void LoadLayoutHack() {
        // Loading layout from an asset
        LayoutUtility.LoadLayoutFromAsset("Assets/Editor/Layouts/Your Layout.wlt");
    }

}

Installing a Layout:

If you want to install a layout into the drop-down list then you can programatically copy the layout. Here is how to determine the path for your layout:

string targetPath = Path.Combine(LayoutUtility.LayoutsPath, "Layout Name.wlt");

Utility Class Source:

using UnityEngine;
using UnityEditor;

using System.IO;
using System.Reflection;

using Type = System.Type;

public static class LayoutUtility {

	private static MethodInfo _miLoadWindowLayout;
	private static MethodInfo _miSaveWindowLayout;
	private static MethodInfo _miReloadWindowLayoutMenu;

	private static bool _available;
	private static string _layoutsPath;

	static LayoutUtility() {
		Type tyWindowLayout = Type.GetType("UnityEditor.WindowLayout,UnityEditor");
		Type tyEditorUtility = Type.GetType("UnityEditor.EditorUtility,UnityEditor");
		Type tyInternalEditorUtility = Type.GetType("UnityEditorInternal.InternalEditorUtility,UnityEditor");

		if (tyWindowLayout != null && tyEditorUtility != null && tyInternalEditorUtility != null) {
			MethodInfo miGetLayoutsPath = tyWindowLayout.GetMethod("GetLayoutsPath", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
			_miLoadWindowLayout = tyWindowLayout.GetMethod("LoadWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null);
			_miSaveWindowLayout = tyWindowLayout.GetMethod("SaveWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null);
			_miReloadWindowLayoutMenu = tyInternalEditorUtility.GetMethod("ReloadWindowLayoutMenu", BindingFlags.Public | BindingFlags.Static);

			if (miGetLayoutsPath == null || _miLoadWindowLayout == null || _miSaveWindowLayout == null || _miReloadWindowLayoutMenu == null)
				return;

			_layoutsPath = (string)miGetLayoutsPath.Invoke(null, null);
			if (string.IsNullOrEmpty(_layoutsPath))
				return;

			_available = true;
		}
	}

	// Gets a value indicating whether all required Unity API
	// functionality is available for usage.
	public static bool IsAvailable {
		get { return _available; }
	}

	// Gets absolute path of layouts directory.
	// Returns `null` when not available.
	public static string LayoutsPath {
		get { return _layoutsPath; }
	}

	// Save current window layout to asset file.
	// `assetPath` must be relative to project directory.
	public static void SaveLayoutToAsset(string assetPath) {
		SaveLayout(Path.Combine(Directory.GetCurrentDirectory(), assetPath));
	}

	// Load window layout from asset file.
	// `assetPath` must be relative to project directory.
	public static void LoadLayoutFromAsset(string assetPath) {
		if (_miLoadWindowLayout != null) {
			string path = Path.Combine(Directory.GetCurrentDirectory(), assetPath);
			_miLoadWindowLayout.Invoke(null, new object[] { path });
		}
	}

	// Save current window layout to file.
	// `path` must be absolute.
	public static void SaveLayout(string path) {
		if (_miSaveWindowLayout != null)
			_miSaveWindowLayout.Invoke(null, new object[] { path });
	}

}

Hi pascal, try wi a repaint().
it’s just a guess though, I’m not sure it will work and I can’t test it :slight_smile:
bye!