Building a Custom Editor Window in Unity

Manindra Krishna Motukuri
XRPractices
Published in
10 min readFeb 27, 2023

Are you tired of navigating through multiple menus and windows in Unity to get to the features you need? Do you wish you had a customised interface tailored to your game’s specific development requirements? If so, building a custom editor window in Unity might just be the solution you’re looking for! This blog, will demonstrate you how to create a custom editor window from scratch, with your unique interface and functionality. We’ll cover everything from setting up the window layout to adding buttons and other UI Elements. By the end of this blog, you’ll have the skills to build a custom editor window that will streamline your game development process and make your life easier. So, let’s get started!

Building a custom editor window in unity doesn’t require any complex plugins or frameworks. Some basic understanding of HTML, CSS and C# will suffice.

This blog will guide you through the process of building a simple editor window in Unity that allows you to create a primitive game object at the origin with a custom name and active status, all from within the window. We’ll explore Unity Editor’s built-in tools and resources that enable you to create a custom window.

Setting up Your Project: Creating the Necessary Files

Creating the necessary files for your custom Unity editor window begins with setting up your project. Start by creating a new Unity project, or opening an existing one.

Once you have your project open, you can create the necessary files for your editor window by following these steps:

  1. In the Unity Editor, navigate to the Project window and right-click to bring up the options menu.
  2. From the Create option, select UI Toolkit, and then navigate to the Unity Editor option in the expanded menu.
Creating necessary files

When you select the Unity Editor option, a popup will appear prompting you to name your C# script, UXML file, and USS file. These files will serve as the foundation for your custom editor window’s code and interface design. Once you’ve named your files, hit the Confirm button in the popup to create them.

Popup for creating UXML, USS and C# Files

After clicking Confirm in the popup, the Unity Editor will create and place the UXML, USS, and C# files in the Editor folder under the Assets folder.

UXML, USS and C# files

This folder is designated for editor-related files and scripts, and can be found in the Project window. By storing your custom editor window’s files in this folder, you’ll ensure that they are only accessible and visible in the Unity Editor, and not in the final build of your game or application.

With the necessary files in place, you’re now ready to start customising your editor window. In the upcoming sections, we’ll explore how to add UI elements, create styles using USS, and write C# code to add functionality to your custom editor window.

Overview of the generated files:

  1. C# script(s): These scripts provide the functionality for the custom window. They define how the UI elements behave and respond to user input.
  2. UXML file: This file contains the XML markup that defines the UI elements that make up the custom window, such as buttons, text fields, and sliders.
  3. USS file: This file defines the visual styles for the UI elements defined in the UXML file. It specifies attributes such as colour, font size, and position.

Let’s examine the C# script that was generated, The script has a class that inherits from Editor Window. This class has a static method as well as a create GUI method.

The static method serves as the endpoint for opening the window, while the menu item attribute specifies the location in the menu bar where the window can be accessed.

Editor Window
Custom Window Location

By modifying the menu item value, we can alter the location in the menu where the custom window option will appear.

Modified Menu Item
New Menu item

When we click on the custom window option, the newly created window should open.

New custom window

Let’s understand what is happening in the static method. The GetWindow<CustomEditor>() method retrieves the current custom editor window. If there isn’t a current window, this method generates a new one.

We can use the window object we get from GetWindow<CustomEditor>() to modify the properties of the window like position, size, title and icon.

An icon can be added along with changing the title by modifying the titleContent of the window object.

[MenuItem("Spawner/Primitive Spawner")]
public static void ShowWindow()
{
var window = GetWindow<CustomEditor>();
var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Editor/Images/gear.png");
window.titleContent = new GUIContent("Primitive Spawner", icon);
}
Editor with new icon and modified title

The C# Script is associated with the editor window, and the linking of UXML, USS to C# script occurs in the CreateGUI method of the script. This method is an event function that is triggered whenever the window is created.

public void CreateGUI()
{
// Each editor window contains a root VisualElement object
VisualElement root = rootVisualElement;

// VisualElements objects can contain other VisualElement following a tree hierarchy.
VisualElement label = new Label("Hello World! From C#");
label.name = "text";
label.AddToClassList("cSharpText");
root.Add(label);

// Import UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/CustomEditor.uxml");
VisualElement labelFromUXML = visualTree.Instantiate();
root.Add(labelFromUXML);

// A stylesheet can be added to a VisualElement.
// The style will be applied to the VisualElement and all of its children.
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/CustomEditor.uss");
root.styleSheets.Add(styleSheet);
}

The rootVisualElement can be compared to the Body element in HTML. There are two ways to add content to a window:

  • Adding elements directly to the UXML
  • Injecting elements using C#.

The provided script exemplifies the process of linking UXML and USS files and injecting elements through C#.

The Unity Scripting Documentation includes all the remaining event functions for the EditorWindow.

For building the spawner let’s remove all the elements on the custom Editor Window.

<?xml version="1.0" encoding="utf-8"?>
<engine:UXML
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:engine="UnityEngine.UIElements"
xmlns:editor="UnityEditor.UIElements"
xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
>
</engine:UXML>
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;


public class CustomEditor : EditorWindow
{
[MenuItem("Spawner/Primitive Spawner")]
public static void ShowWindow()
{
var window = GetWindow<CustomEditor>();
var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Editor/Images/gear.png");
window.titleContent = new GUIContent("Primitive Spawner", icon);
}

public void CreateGUI()
{
// Each editor window contains a root VisualElement object
var root = rootVisualElement;

// Import UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/CustomEditor.uxml");
var labelFromUXML = visualTree.Instantiate();
root.Add(labelFromUXML);

// A stylesheet can be added to a VisualElement.
// The style will be applied to the VisualElement and all of its children.
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/CustomEditor.uss");
root.styleSheets.Add(styleSheet);
}
}

The above files should spawn an empty EditorWindow with a customised title and icon with UXML and USS files linked.

Adding elements to the Custom Editor Window via UXML

To ensure that any changes made to the UXML file are automatically reflected in the custom editor window, it is recommended to enable the UI Toolkit Live Reload option before making any modifications. To do this, right-click on the title of the custom Editor Window and select the UI Toolkit Live Reload option.

UI Toolkit Live Reload Settings

For this particular scenario, let’s include a dropdown menu that allows the selection of a primitive game object to be spawned, an input field that reads the desired name for the spawned object, a toggle to determine whether to spawn an inactive or active object and a button to spawn the object at its origin.

To incorporate these elements into UXML, the utilisation of a Unity utility named UI Builder is necessary. To access the UI Builder, you can expand the top menu’s Window option, then navigate to the UI Toolkit option and select UI Builder.

Open UI Builder

After launching the UI Builder, select the File option, then choose Open and locate the UXML file that was previously created under the editor folder.

Opening the UXML

The UI Builder interface is comprised of three main sections. On the left-hand side, you’ll find StyleSheets, Hierarchy, and Library. In the middle, there is a Viewport that displays the preview of the editor window. On the right-hand side, the Inspector displays the USS styles.

Hierarchy is the tree representation of elements inside UXML, Library has the UI elements which can be used to create the window and Inspector shows the USS styles of the selected element.

Drag and drop the IMGUI Container from Library to the Hierarchy window. Drag and drop the Dropdown, Text Field, Toggle and Button from Library to Hierarchy such that they become children of the IMGUI Container.

Select any element in Hierarchy, and the Inspector panel will display all the properties and styles associated with it.

For IMGUI Container, In the Inspector panel add “container” in the Name field in Inspector.

For Dropdown, In the Inspector panel add “primitiveSelector” in the Name, Add “Primitive Type” in the Label, Change the Index to “0”, and Add “Cube,Sphere,Capsule,Cylinder,Plane,Quad” in the Choices field in the Inspector.

For Textfield, In the Inspector panel add “gameObjectName” in the Name, Add “Name” in the Label, Delete the value in the Value field, and Delete the value in the Text field in the Inspector.

For Toggle, In the Inspector panel add “IsActive” in the Name, Add “Is Active” in the Label, and Check the Value field in the Inspector.

For the Button, In the Inspector panel add “create” in the Name, and Add “Create” in the text field in the Inspector.

Click the file and save. The below documentation explains all the UI Elements and their properties.

Styling elements of the Custom Editor Window via USS

Custom elements within Unity Editor Windows share similarities with HTML elements, while USS syntax follows a similar structure to CSS. In UXML, the element Name is equivalent to the ID in HTML and styling can be achieved using either the Name, Class, or Element Type. In the present case, we will apply a 5px padding to the container and a 0px margin to the dropdown, as well as a 0px margin and 10px margin-top to the other elements.

#container {
width: 100%;
height: 100%;
padding: 5px;
}

#primitiveSelector {
margin: 0px;
}

#gameObjectName, #IsActive, #create {
margin: 0px;
margin-top: 10px;
}

Below documentation from Unity explains all the USS properties and the differences between CSS and USS.

Open the custom editor window and it should look like the below.

Adding functionality to the Editor with the C# Script

After adding all the necessary fields to the Custom Editor, the only remaining task is to obtain user input and generate the gameobject at the origin. In order to read the user input from the fields, it is necessary to query the fields from the rootVisualElement within the CreateGUI method.

using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;


public class CustomEditor : EditorWindow
{
private DropdownField _primitiveType;
private TextField _textField;
private Toggle _isActiveToggle;
private Button _createButton;

[MenuItem("Spawner/Primitive Spawner")]
public static void ShowWindow()
{
var window = GetWindow<CustomEditor>();
var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Editor/Images/gear.png");
window.titleContent = new GUIContent("Primitive Spawner", icon);
}

public void CreateGUI()
{
// Each editor window contains a root VisualElement object
var root = rootVisualElement;

// Import UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/CustomEditor.uxml");
var labelFromUXML = visualTree.Instantiate();
root.Add(labelFromUXML);

// A stylesheet can be added to a VisualElement.
// The style will be applied to the VisualElement and all of its children.
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/CustomEditor.uss");
root.styleSheets.Add(styleSheet);

// Getting the UI element by name needs type cast
_primitiveType = (DropdownField) rootVisualElement.Query("primitiveSelector").First();

// Getting the UI element by type needs to be filtered inorder to get what we want
_textField = rootVisualElement.Query<TextField>().First();

// Getting the UI element by type and name
_isActiveToggle = rootVisualElement.Query<Toggle>("IsActive");
_createButton = rootVisualElement.Query<Button>("create");
_createButton.clicked += CreatePrimitive;
}

private void CreatePrimitive()
{
var primitiveType = Enum.Parse<PrimitiveType>(_primitiveType.choices[_primitiveType.index], true);
var created = GameObject.CreatePrimitive(primitiveType);
created.transform.position = Vector3.zero;
created.name = _textField.text == "" ? primitiveType.ToString() : _textField.text;
created.SetActive(_isActiveToggle.value);
}
}

The above script has CreateGUI which shows the ways to get the UXML element in C# and CreatePrimitive method shows how to get user input from different fields.

Once the script is modified, We should be able to create all types of primitives from this custom Unity Editor Window.

Debugging UXML and USS

Similar to UI Builder, Unity also provides a built-in tool called UI Toolkit Debugger. To open the UI Toolkit Debugger, you can right-click on the title of the Custom Editor Window and select the corresponding option.

The UI Toolkit Debugger facilitates the debugging of UXML and USS.

UI Toolkit Debugger

The left side of the UI Toolkit Debugger displays all the elements in the Editor Window and the right side shows the layout and styling of the selected visual element.

In conclusion, building a custom editor window in Unity is a great way to streamline your workflow and improve your productivity. With the detailed steps and tips provided in this blog post, you should now have a good understanding of how to create a basic custom editor window and add various controls and functionalities to it. Remember that custom editor windows are incredibly versatile and can be tailored to suit your specific project requirements. With practice and experimentation, you can develop your skills and create even more complex and powerful custom editor windows. By taking advantage, you can unlock a whole new level of efficiency and creativity in your game development process. So, start exploring and building your custom editor windows today!

--

--