EditorGUI.DelayedTextField not applying when focus lost

Hi all,

I have created a custom visual scripting node. One of the properties I want editable in the inspector is an array whose elements include a string I am exposing via a EditorGUI.DelayedTextField in a custom property drawer. For the most part this works fine and looks like this:

When I type into the text field the text updates as expected and, when I am done, it all works as nicely if I then interact with something else in the inspector, like the “Character” properties in that screenshot, for example. However, if I type something in the DelayedTextField and then without interacting with anything else in the inspector, click on something like another node in the graph or just the background of the graph window, I’ll find that when I re-select the node, the changes I made are gone.

I assume that, when I continue interacting with the inspector, focus is moved away from the text field, causing it to update the stored text, but that when I select something in the graph, the UI is completely destroyed without that process taking placed.

Does anyone know a way around this. I could, of course, just use a TextField instead of a DelayedTextField. That behaves correctly but is unusably slow when I am working on my laptop.

I have another related question which is that, when I am using the DelayedTextField, I don’t know how to calculate it’s height. This is what my code for the property drawer looks like:

class DialogueEntry_Property : PropertyDrawer
{
    private float myLastWidth = 1.0f;
    private readonly int myDialogeWidthCorrection = 20;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        myLastWidth = position.width;
        EditorGUI.BeginProperty(position, label, property);

        position.height = EditorGUIUtility.singleLineHeight;
        SerializedProperty poseProperty = property.FindPropertyRelative("myPoseData");
        EditorGUI.PropertyField(position, poseProperty, new GUIContent("Character"));

        position.y += position.height;
        SerializedProperty locationProperty = property.FindPropertyRelative("myLocation");
        EditorGUI.PropertyField(position, locationProperty, new GUIContent("Location"));

        position.y += position.height;
        SerializedProperty mirroredProperty = property.FindPropertyRelative("myMirrored");
        EditorGUI.PropertyField(position, mirroredProperty, new GUIContent("Mirrored"));

        position.y += position.height;

        SerializedProperty textProperty = property.FindPropertyRelative("myText");
        GUIStyle textStyle = new GUIStyle(GUI.skin.textField);
        textStyle.wordWrap = true;
        string oldValue = textProperty.stringValue;
        position.height = GetTextHeight(oldValue, position.width - myDialogeWidthCorrection);
        textProperty.stringValue = EditorGUI.TextField(position, oldValue, textStyle);
        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return GetPropertyHeight(property, myLastWidth - myDialogeWidthCorrection);
    }

    private static float GetPropertyHeight(SerializedProperty property, float aWidth)
    {
        SerializedProperty textProperty = property.FindPropertyRelative("myText");
        EditorGUI.GetPropertyHeight(textProperty);
        float height = 3.0f * EditorGUIUtility.singleLineHeight + GetTextHeight(textProperty.stringValue, aWidth);
        return height;
    }

    private static float GetTextHeight(string aText, float aWidth)
    {
        GUIStyle textStyle = new GUIStyle();
        textStyle.wordWrap = true;
        GUIContent textContent = new GUIContent(aText);
        return 10 + textStyle.CalcHeight(textContent, aWidth);
    }
}

And in there, for GetPropertyHeight to work correctly I need to know the width of the drawer, as I am using word wrap. I am getting that by caching it during the draw function, which doesn’t seem right but at least works. However to get the height of the TextField I need to know what the latest input string is, which, so long as I am using the DelayedTextField, I don’t have access to, so the height of the property in the inspector always lags behind what it should be.

No real good answer here. Delayed text field is a bit crap for exactly the reasons you’re discovering.

You could implement your own delayed text field by storing the cached string value, and just using a TextField, so updating doesn’t become slow. That’ll take a bit of writing, though!