Editor update whilst displaying dialogue?

Hi all,

I’ve got an Editor tool I’ve written in C# which iterates through objects in the project and performs actions on them.

As it goes through the objects, some of them may need to be deleted and the script checks an EditorUtility.DisplayDialogue for a yes/no response to the question of deleting that object.

All fine so far. However, what I’m trying to do is get Unity to highlight the asset in question so that when the user is faced with the ‘delete yes/no?’ dialogue, they can see exactly which asset is being queried for deletion in the project window, rather than by just its name in the dialogue.

I’m using the following code to highlight the asset so far:

Selection.activeObject = AssetDatabase.LoadAssetAtPath (mat.path, typeof(UnityEngine.Object)) as UnityEngine.Object;

It seems to be highlighting the assets as intended, BUT the Unity project window only highlights the last asset when the script finishes, like it doesn’t have time to update or the EditorUtility.DisplayDialogue is preventing the project window from updating with the highlighted asset until the very end…

It seems I can’t use coroutines as I’m working in the Editor rather than a running project, so does anyone have any ideas or suggestions on how I can get the current asset to be highlighted in the project window whilst a dialogue queries an action on it?

Thanks in advance for your help!

After a lot of editing in this answer :stuck_out_tongue:

The problem is that using EditorUtility.DisplayDialog basically freezes up unity. This means that during the display of a dialog Unity won’t repaint any of it’s Windows, and you can’t tell unity to do so either (Because, well, your code won’t run untill after the user picks an option)

This means that in order to make sure that the project window highlights the object currently used by our dialog, we want to allow it to update in between the dialogs.

In this piece of code I delay the dialog by one (or more) frame(s). Basically what it does, whenever you call the DisplayDialog method, instead of immediatly displaying it, it waits a given amount of frames.(using EditorApplication.update). It also queue’s up every call to this method to make sure that in between each dialog we get the wanted delay for unity to update it’s window’s.

The code for the dialog:

public class DelayedDialog
    {
        public delegate void DialogCallback(Object obj);

        private static DelayedDialog currentDialog = null;

        private int delay;
        private Object obj;
        private string title;
        private string message;
        private string ok;
        private string cancel;
        private DialogCallback callback;

        private DelayedDialog nextDialog;

        private DelayedDialog(Object obj, string title, string message, string ok, string cancel, DialogCallback callback, int delay)
        {
            this.obj = obj;
            this.title = title;
            this.message = message;
            this.ok = ok;
            this.cancel = cancel;
            this.callback = callback;
            this.delay = delay;

            DelayedDialog current = currentDialog;
            while (current != null && current.nextDialog != null)
                current = current.nextDialog;

            if (current != null)
            {
                current.nextDialog = this;
            }
            else
            {
                currentDialog = this;
                StartDialogDisplay();
            }
        }

        public static void DisplayDialog(Object obj,string title,string message,  string ok, string cancel, DialogCallback callback, int delay = 1)
        {
            new DelayedDialog(obj, title, message, ok, cancel, callback, delay);
        }

        private void StartDialogDisplay()
        {
            EditorGUIUtility.PingObject(obj);
            EditorApplication.update += EditorUpdate;
        }

        private void EditorUpdate()
        {
            delay--;
            if (delay >= 0)
                return;

            if (EditorUtility.DisplayDialog(title, message, ok, cancel))
            {
                if (callback != null)
                    callback(obj);
            }

            //EditorApplication.RepaintProjectWindow();
            EditorApplication.update -= EditorUpdate;

            currentDialog = nextDialog;
            if (currentDialog != null)
                currentDialog.StartDialogDisplay();
        }
    }

Calling it would be something like this:

void OnGUI()
    {
        if (condition)
        {
            // obs is a array of Object's ;)
            for (int i = 0; i < obs.Length; i++)
            {
                DelayedDialog.DisplayDialog(obs*, "Title", "Message", "Ok", "Cancel", Callback);*

}
}
}

private void Callback(Object obj)
{
Debug.Log(“clicked ok”, obj);
}