Is it possible to rename tabs in editor?

When I work in a project I usually keep multiple tabs of same type opened. I know in general based on position what contains what, but is it possible to rename them? I ask this especially for the Project tab, which I’m using for instance atm 3 (server, common, and clients scripts), + 5 (scriptable objects, prefabs, etc)

For instance when right clicking the “rename” option should appear. I’m aware in this post linked below #4 and #5 replies asked the same thing:

so I’m assuming it’s not possible since I didn’t find anything else, but I wanted to try to give more visibility to this QoL improvement, and ask if is possible maybe with some custom scripting.

Like @sacredgeometry said there’s currently no built-in way to do that. However technically you can already simply change the “titleContent” of an EditorWindow instance from outside and it should change the name and icon in the tab. Though the main issue is how to reference a certain editor window. I’ve looked into extending the tab-context menu, however most dynamic changes you can do to the context menu is up to the class itself, so we can’t simply add a menu item from the outside.

Though I’ve found a mechanism deep burried in internal code that allows Unity to add so called WindowActions to that context menu. Those are stored in an internal static array inside the internal HostView class. In theory one could use a huge chunk of reflection (since almost everything involved is internal / private) and replace that array that is populated based on internal attributes and add some custom WindowActions to it.

However this would be very hacky and I don’t even know how well it would survive an assembly reload and where / when we should inject our own context menu items.

A simple solution may be to just create an editor window that simply lists all EditorWindows and you can rename them there “blindly”.

Here I quickly created such an editor window:

// RenameEditorTab.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class RenameEditorTab : EditorWindow
{
    [MenuItem("Tools/B83/RenameEditorTabs")]
    static void Init()
    {
        GetWindow<RenameEditorTab>();
    }

    [System.Serializable]
    public class Window
    {
        public EditorWindow window;
        public bool changed = false;
        public GUIContent content;
    }

    Vector2 m_ScrollPos;
    List<Window> m_Windows = new List<Window>();
    [System.NonSerialized]
    HashSet<EditorWindow> m_EditorWindows = new HashSet<EditorWindow>();
    bool m_UpdateWindowTitles = false;

    private void OnEnable()
    {
        UpdateWindowList();
        m_UpdateWindowTitles = true;
        // delayed update
        EditorApplication.update += UpdateWindowTitles;
    }
    void UpdateWindowList()
    {
        m_EditorWindows.Clear();
        foreach (var win in m_Windows)
            m_EditorWindows.Add(win.window);
        foreach (var win in Resources.FindObjectsOfTypeAll<EditorWindow>())
        {
            if (!m_EditorWindows.Contains(win))
                m_Windows.Add(new Window { window = win, content = new GUIContent(win.titleContent) });
        }
        UpdateWindowTitles();
    }
    void UpdateWindowTitles()
    {
        EditorApplication.update -= UpdateWindowTitles;
        m_UpdateWindowTitles = false;
        foreach (var win in m_Windows)
        {
            if (win.changed && win.window)
            {
                win.window.titleContent = win.content;
            }
        }
    }
    private void OnGUI()
    {
        if (GUILayout.Button("update window list"))
            UpdateWindowList();
        m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos);
        foreach (var win in m_Windows)
        {
            GUILayout.BeginHorizontal();
            if (win.window)
            {
                win.changed = GUILayout.Toggle(win.changed, "", GUILayout.Width(16));
                EditorGUILayout.ObjectField(win.window, typeof(EditorWindow), false, GUILayout.Width(200));
                using (new EditorGUI.DisabledScope(!win.changed))
                {
                    EditorGUI.BeginChangeCheck();
                    win.content.image = (Texture)EditorGUILayout.ObjectField(win.content.image, typeof(Texture), false, GUILayout.Width(32));
                    win.content.text = GUILayout.TextField(win.content.text);
                    if (EditorGUI.EndChangeCheck())
                    {
                        win.window.titleContent = win.content;
                        win.window.ShowTab();
                        win.window.Repaint();
                        ShowTab();
                    }
                }
            }
            else
            {
                GUILayout.Label("window has been closed");
            }
            if (GUILayout.Button("X", GUILayout.Width(30)))
            {
                m_Windows.Remove(win);
                m_EditorWindows.Remove(win.window);
                GUIUtility.ExitGUI();
            }
            GUILayout.EndHorizontal();
        }
        GUILayout.EndScrollView();
    }
}

Place this script in an editor folder. Open it through the tools menu. Now you can select certain editor windows and change their title text / image. As long as this editor window stays open (can be a hidden tab) those rename actions should survive an assembly reload. That’s because I store the edited content as well as a reference to the editor window inside my own editor window in a list. However restarting Unity would loose those new names. There’s no way to store a reference to an editor window in a file as editor windows are scriptable object instances in memory.

With this little tool you can rename any open editor window and those windows should keep their new title as long as Unity is not closed.

Note that this is also just a hacky solution. Though I tried my best to not be too intrusive so it should not put much burden on the editor.

189341-renamedprojecttab.png

I don’t believe there is but there is a thread to discuss adding the feature here (albeit not primarily about project tabs has digressed into a more general discussion) :

https://forum.unity.com/threads/renaming-locked-inspector-tabs.909965/

OK, maybe I did something terrible here, but I am really tired of that heap of Project tabs.

// Script that changes the locked Project tab title to their current folder name
using System;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

public static class ProjectTabTitler
{
    private static bool isInitialized = false;
    private static Type projectBrowserType;
    private static FieldInfo titleContentField;
    private static MethodInfo getActiveFolderMethod;
    private static PropertyInfo isLockedProperty;

    [InitializeOnLoadMethod, ExecuteInEditMode]
    private static void Initialize()
    {
        if (isInitialized)
            return;

        projectBrowserType = Assembly.GetAssembly(typeof(EditorWindow)).GetTypes().First(x => x.Name == "ProjectBrowser");

        titleContentField = projectBrowserType.GetField("m_TitleContent", BindingFlags.Instance | BindingFlags.NonPublic);
        getActiveFolderMethod = projectBrowserType.GetMethod("GetActiveFolderPath", BindingFlags.NonPublic | BindingFlags.Instance);
        isLockedProperty = projectBrowserType.GetProperty("isLocked", BindingFlags.Instance | BindingFlags.NonPublic);

        EditorApplication.update += UpdateProjectTabTitles;

        isInitialized = true;
    }

    private static void UpdateProjectTabTitles()
    {
        var windows = Resources.FindObjectsOfTypeAll(projectBrowserType);
        string title;
        foreach (var window in windows)
        {
            // Revert to default Project tab
            if (!(bool)isLockedProperty.GetValue(window))
            {
                title = "Project";
            }
            // Set custom title
            else
            {
                // Path relative to Project folder
                title = getActiveFolderMethod.Invoke(window, new object[] { }).ToString();

                // Folder name only
                title = title.Split("/").Last();
            }

            GUIContent titleContent = new GUIContent(titleContentField.GetValue(window) as GUIContent);
            titleContent.text = title;

            titleContentField.SetValue(window, titleContent);
        }
    }
}

+1 waiting for this!