Unity Editor Extension Toolkit: Mastering EditorGUIUtility for Custom Tools

EditorGUIUtility is a foundational utility class in Unity’s editor scripting API, desinged to augment and streamline common editor UI tasks. Unlike EditorGUI, which handles immediate-mode control rendering, EditorGUIUtility provides stateless helper functions—ranging from asset loading and coordinate trensformations to object selection workflows and visual feedback mechanisms.

Loading Editor Assets Safely

To load editor-specific assets (e.g., icons, textures, or fonts) at runtime, Unity requires them to reside in the Assets/Editor Default Resources/ folder—a reserved directory that must be named exactly with a space (not EditorDefaultResources). Two primary loading methods exist:

  • EditorGUIUtility.Load<T>(string path): Returns null if the asset is missing or invalid. Safe for optional resources.
  • EditorGUIUtility.LoadRequired<T>(string path): Throws an exception on failure—ideal for critical UI assets where absence indicates misconfiguration.

Both require the full relative path *including file extension*, e.g., "Icons/SettingsIcon.png".

Example: Asset Loading Panel

public class AssetLoaderWindow : EditorWindow
{
    [MenuItem("Tools/Asset Loader")]
    public static void ShowWindow() => GetWindow<AssetLoaderWindow>("Asset Loader").Show();

    private Texture2D _icon;
    private Texture2D _fallback;

    void OnGUI()
    {
        if (GUILayout.Button("Load Icon (Safe)"))
            _icon = EditorGUIUtility.Load<Texture2D>("Icons/ToolIcon.png");

        if (GUILayout.Button("Load Icon (Required)"))
            _fallback = EditorGUIUtility.LoadRequired<Texture2D>("Icons/Fallback.png");

        if (_icon != null)
            GUI.DrawTexture(new Rect(10, 50, 64, 64), _icon);
        
        if (_fallback != null)
            GUI.DrawTexture(new Rect(90, 50, 64, 64), _fallback);
    }
}

Object Selection and Visual Feedback

For interactive resource discovery, EditorGUIUtility.ShowObjectPicker<T> launches Unity’s built-in object browser with filtering support:

  • defaultObject: Pre-selects an asset in the picker.
  • allowSceneObjects: Enables searching scene hierarchy (e.g., for GameObject).
  • filter: Text-based name filter (e.g., "normal" matches rock_normal.png).
  • controlID: Legacy parameter—always pass 0.

Selection results are retrieved via EditorGUIUtility.GetObjectPickerObject(). Because the picker operates asynchronously, your window must listen for two command events:

  • "ObjectSelectorUpdated": Fired when user selects a new item.
  • "ObjectSelectorClosed": Fired when the picker closes (regardless of selection).

Additionally, EditorGUIUtility.PingObject() highlights the selected asset in the Project or Hierarchy view—providing instant visual context.

Example: Picker Integration

public class PickerDemoWindow : EditorWindow
{
    [MenuItem("Tools/Picker Demo")]
    public static void ShowWindow() => GetWindow<PickerDemoWindow>("Picker Demo").Show();

    private Texture2D _selectedTexture;

    void OnGUI()
    {
        if (GUILayout.Button("Open Texture Picker"))
            EditorGUIUtility.ShowObjectPicker<Texture2D>(null, false, "ui", 0);

        // Handle picker events
        if (Event.current.commandName == "ObjectSelectorUpdated" ||
            Event.current.commandName == "ObjectSelectorClosed")
        {
            var picked = EditorGUIUtility.GetObjectPickerObject();
            if (picked is Texture2D tex)
                _selectedTexture = tex;
        }

        if (GUILayout.Button("Ping Selected Texture") && _selectedTexture != null)
            EditorGUIUtility.PingObject(_selectedTexture);
    }
}

Inter-Window Communication and Coordinate Conversion

Unity supports lightweight event-driven communication between editor windows using command events:

  • Create an event with EditorGUIUtility.CommandEvent("MyCommand").
  • Send it via window.SendEvent(event)—the target window will auto-focus if minimized.
  • Recieve it by checking Event.current.type == EventType.ExecuteCommand and matching commandName.

For precise UI positioning, convert between coordinate spaces:

  • EditorGUIUtility.GUIToScreenPoint(Vector2): Transforms from local window space to screen pixels.
  • EditorGUIUtility.ScreenToGUIPoint(Vector2): Converts screen coordinates back to local GUI space (useful for overlays or tooltips).

Note: These conversions respect GUI.BeginGroup() offsets and layout scaling.

Custom Cursor Behavior

Enhance UX by changing the cursor over interactive regions using EditorGUIUtility.AddCursorRect():

if (GUILayout.Button("Hover Me"))
{
    // Apply custom cursor only while mouse is over this button
    EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link);
}

Supported cursors include MouseCursor.ResizeVertical, MouseCursor.Pan, MouseCursor.Zoom, and MouseCursor.CustomCursor for user-defined textures.

Visual Swatches for Editors

Render compact previews alongside property fields:

  • EditorGUIUtility.DrawColorSwatch(Rect, Color): Draws a filled rectangle with border highlighting for color fields.
  • EditorGUIUtility.DrawCurveSwatch(Rect, AnimationCurve, SerializedProperty, Color, Color): Renders a miniature curve preview with optional background and stroke colors—commonly used with EditorGUILayout.CurveField.

Example: Swatch Rendering

public class SwatchDemoWindow : EditorWindow
{
    [MenuItem("Tools/Swatch Demo")]
    public static void ShowWindow() => GetWindow<SwatchDemoWindow>("Swatch Demo").Show();

    private Color _swatchColor = Color.cyan;
    private AnimationCurve _swatchCurve = AnimationCurve.Linear(0, 0, 1, 1);

    void OnGUI()
    {
        _swatchColor = EditorGUILayout.ColorField("Swatch Color", _swatchColor);
        EditorGUIUtility.DrawColorSwatch(new Rect(120, 30, 24, 24), _swatchColor);

        _swatchCurve = EditorGUILayout.CurveField("Swatch Curve", _swatchCurve);
        EditorGUIUtility.DrawCurveSwatch(
            new Rect(10, 70, 100, 60), 
            _swatchCurve, 
            null, 
            Color.green, 
            new Color(0.2f, 0.2f, 0.2f)
        );
    }
}

Tags: unity-editor editor-scripting csharp unity-ui custom-inspector

Posted on Tue, 02 Jun 2026 18:27:12 +0000 by gardnc