how do I make a Property Drawer open a popup window and return value into the property?

I have a custom String class called LocalizedString, with a custom property drawer that has a button that opens up a custom editor window.
The editor window finds all strings in a database, shows them in a list, with a button after each.
Clicking that button should send that database entry back into the property window.
I’ve gotten it to work somewhat, but it has some weird behavior.

edit: To try and understand it better, imagine a picker element, like for a material, or GameObject, or similar, but a custom one for strings from a big list. That’s what I’m trying to make.

alt text

The top script is the database, it shows a key (‘test’) and a value (‘this is a test string’).
You can add more, shuffle them around, etc.
The bottom script is a demo script of the localization stuff.
It looks like this:

public class DemoGlitchLocalization : MonoBehaviour
{
    public LocalizedString string1;
    public LocalizedString string2;
    public LocalizedString[] stringArray;
}

You can see that the custom property drawer is shown, with the find button at the end.
The property drawer has the following code in OnGUI:

string pending;

public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
    SerializedProperty text = prop.FindPropertyRelative("text");
    label = EditorGUI.BeginProperty(pos, label, prop);
    ... // [label and text field]
    if (GUI.Button(new Rect(pos.x + pos.width * 0.9f, pos.y, pos.width * 0.1f, pos.height), new GUIContent("find", "Find in GlitchLocalization")))
    {
        GlitchLocalizationWindow.Show(this);           
    }

    if (!string.IsNullOrEmpty(pending))
    {
        text.stringValue = pending;
        pending = null;
    }
    EditorGUI.EndProperty();
}

public void SetValue(string value)
{
    pending = "$" + value;
}

This function is described as:

LocalizedStringDrawer drawer;
public static void Show(LocalizedStringDrawer drawer)
{
    EditorWindow window = EditorWindow.GetWindow(typeof(GlitchLocalizationWindow));
    (window as GlitchLocalizationWindow).drawer = drawer;
}

So I’m passing a reference to the property drawer when the editor window is shown. It looks like this:

alt text

It has the same entry as the GlitchLocalization script. Clicking the checkmark does the following:

void SaveSelection(string selection)
{
    drawer.SetValue(selection);
    Close();
}

So it sends the selection string back to the property drawer that opened the window. Setvalue is defined in the property drawer (see above).

Now the first problem:

It doesn’t automatically refresh the property drawer. I have to click outside of the property, before the Inspector refreshes and sees that the value is changed.
For String1 and String2 in the demo script, the value is put in the right place, the only problem is the refresh.

The second problem

Once I place the values in an Array, the value will always be put in the first item of the array, even when clicking the find button on properties that are further down. If you would click on the find button behind Element1 in the String Array of the demo script, and select a value, it will place it in Element0.

I’m guessing there’s a better way to do all of this, and I’d love to hear it.

Figured it out. You should send a reference to the SerializedProperty along, insead of a reference to the Property Drawer.

updated code snippets:

public static void Show(SerializedProperty prop)
{
    EditorWindow window = EditorWindow.GetWindow(typeof(GlitchLocalizationWindow));
    (window as GlitchLocalizationWindow).property = prop;
}

void SaveSelection(string selection)
{
    property.FindPropertyRelative("text").stringValue = "$" + selection;
    property.serializedObject.ApplyModifiedProperties();
    Close();
}

For the first problem, I solve this by repainting everything:

UnityEditorInternal.InternalEditorUtility.RepaintAllViews();

I wrote myself a singleton that performs a maximum of one repaint per update, since I use this in a lot of places.

For the second problem, I feel like passing around the drawer instance is going to cause problems. I’ve only ever treated the PropertyDrawer class as transient as I have no idea what Unity is doing behind the scenes to create/destroy them.

NGUI does something similar to what you’re attempting. It has SerializedProperty sprite string fields drawn in the inspector, and when you press a button it opens a sprite picker, which in turn updates the field.

It does this by passing the SerializedObject to the editor window, using a callback when the window updates something.

I have some very old code I wrote here that may help you, sorry it’s kinda rough: