As you may have seen, you can do a lot of things in a custom inspector (if you don't know what a custom inspector is, check the example here : http://www.riptutorial.com/unity3d/topic/2506/extending-the-editor. But at one point you may want to implement a configuration panel, or a customized asset palette. In those cases you are going to use an EditorWindow. Unity UI itself is composed of Editor Windows ; you can open them (usually through the top bar), tab them, etc.
Creating an custom editor window is fairly simple. All you need to do is extend the EditorWindow class and use the Init() and OnGUI() methods. Here is a simple example :
using UnityEngine;
using UnityEditor;
public class CustomWindow : EditorWindow
{
// Add menu named "Custom Window" to the Window menu
[MenuItem("Window/Custom Window")]
static void Init()
{
// Get existing open window or if none, make a new one:
CustomWindow window = (CustomWindow) EditorWindow.GetWindow(typeof(CustomWindow));
window.Show();
}
void OnGUI()
{
GUILayout.Label("This is a custom Editor Window", EditorStyles.boldLabel);
}
}
The 3 important points are :
The final result will look like this :
Of course you will probably want to manage or modify some assets using this EditorWindow. Here is an example using the Selection class (to get the active Selection) and modifying the selected asset properties via SerializedObject and SerializedProperty.
using System.Linq;
using UnityEngine;
using UnityEditor;
public class CustomWindow : EditorWindow
{
private AnimationClip _animationClip;
private SerializedObject _serializedClip;
private SerializedProperty _events;
private string _text = "Hello World";
// Add menu named "Custom Window" to the Window menu
[MenuItem("Window/Custom Window")]
static void Init()
{
// Get existing open window or if none, make a new one:
CustomWindow window = (CustomWindow) EditorWindow.GetWindow(typeof(CustomWindow));
window.Show();
}
void OnGUI()
{
GUILayout.Label("This is a custom Editor Window", EditorStyles.boldLabel);
// You can use EditorGUI, EditorGUILayout and GUILayout classes to display anything you want
// A TextField example
_text = EditorGUILayout.TextField("Text Field", _text);
// Note that you can modify an asset or a gameobject using an EditorWindow. Here is a quick example with an AnimationClip asset
// The _animationClip, _serializedClip and _events are set in OnSelectionChange()
if (_animationClip == null || _serializedClip == null || _events == null) return;
// We can modify our serializedClip like we would do in a Custom Inspector. For example we can grab its events and display their information
GUILayout.Label(_animationClip.name, EditorStyles.boldLabel);
for (var i = 0; i < _events.arraySize; i++)
{
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField(
"Event : " + _events.GetArrayElementAtIndex(i).FindPropertyRelative("functionName").stringValue,
EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("time"), true,
GUILayout.ExpandWidth(true));
EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("functionName"),
true, GUILayout.ExpandWidth(true));
EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("floatParameter"),
true, GUILayout.ExpandWidth(true));
EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("intParameter"),
true, GUILayout.ExpandWidth(true));
EditorGUILayout.PropertyField(
_events.GetArrayElementAtIndex(i).FindPropertyRelative("objectReferenceParameter"), true,
GUILayout.ExpandWidth(true));
EditorGUILayout.Separator();
EditorGUILayout.EndVertical();
}
// Of course we need to Apply the modified properties. We don't our changes won't be saved
_serializedClip.ApplyModifiedProperties();
}
/// This Message is triggered when the user selection in the editor changes. That's when we should tell our Window to Repaint() if the user selected another AnimationClip
private void OnSelectionChange()
{
_animationClip =
Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets).FirstOrDefault() as AnimationClip;
if (_animationClip == null) return;
_serializedClip = new SerializedObject(_animationClip);
_events = _serializedClip.FindProperty("m_Events");
Repaint();
}
}
You can do some really advanced things in the editor, and the EditorWindow class is perfect for displaying large amount of information. Most advanced assets on the Unity Asset Store (such as NodeCanvas or PlayMaker) use EditorWindow for displaying for custom views.
One interesting thing to do with an EditorWindow is to display information directly in your SceneView. This way you can create a fully customized map/world editor, for example, using your custom EditorWindow as an asset palette and listening to clicks in the SceneView to instantiate new objects. Here is an example :
using UnityEngine;
using System;
using UnityEditor;
public class CustomWindow : EditorWindow {
private enum Mode {
View = 0,
Paint = 1,
Erase = 2
}
private Mode CurrentMode = Mode.View;
[MenuItem ("Window/Custom Window")]
static void Init () {
// Get existing open window or if none, make a new one:
CustomWindow window = (CustomWindow)EditorWindow.GetWindow (typeof (CustomWindow));
window.Show();
}
void OnGUI () {
GUILayout.Label ("This is a custom Editor Window", EditorStyles.boldLabel);
}
void OnEnable() {
SceneView.onSceneGUIDelegate = SceneViewGUI;
if (SceneView.lastActiveSceneView) SceneView.lastActiveSceneView.Repaint();
}
void SceneViewGUI(SceneView sceneView) {
Handles.BeginGUI();
// We define the toolbars' rects here
var ToolBarRect = new Rect((SceneView.lastActiveSceneView.camera.pixelRect.width / 6), 10, (SceneView.lastActiveSceneView.camera.pixelRect.width * 4 / 6) , SceneView.lastActiveSceneView.camera.pixelRect.height / 5);
GUILayout.BeginArea(ToolBarRect);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
CurrentMode = (Mode) GUILayout.Toolbar(
(int) CurrentMode,
Enum.GetNames(typeof(Mode)),
GUILayout.Height(ToolBarRect.height));
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndArea();
Handles.EndGUI();
}
}
This will display the a toolbar directly in your SceneView
Here is a quick glimpse of how far you can go :