How can I do a copy/paste on SerializedProperty?

I have a custom serializable class as a field of my component and I created a property drawer for it like:

[Serializable]
public class MyInnerClass
{
    public int value;
}
[Serializable]
public class MyClass
{
    public int value;
    public MyInnerClass innerValue;
}
public class MyComponent : MonoBehaviour
{
    [SerializedField]
    public MyClass data;
}

[CustomPropertyDrawer(typeof(MyClass))]
public class MyClassDrawer : PropertyDrawer
{
}

And when I add more than one MyComponent into the scene I want add a context menu to the MyClassDrawer which could do a copy/paste function so I can copy the values on one MyClass to another.

And here are my questions:

  1. In the MyClassDrawer I can only handle the SerializedProperty but the SerializedProperty doesn’t provide an interface to CopyFrom others.
  2. MyClass is not inherited from UnityEngine.Object thus the EditorUtility.CopySerialized can’t work here.
  3. I’m looking for a generic solution to copy to/from between SerializedProperty without get into the details of each class to copy the fields one by one.
3 Likes

Hello! Are you found answer to your question?

I would also like to know how to do this…

It seems when implementing the custom PropertyDrawer by overriding OnGUI() using EditorGUI.BeginProperty / EditorGUI.EndProperty() you get prefab override logic and the right click copy context menu for free.
(I found out just by using the example code from the PropertyDrawer documentation page).

This is the code I tested this with:
Code

using System;
using UnityEditor;
using UnityEngine;

public class MyComponent : MonoBehaviour {
    [SerializeField]
    public MyClass data;
}
[Serializable]
public class MyInnerClass {
    public int value;
}
[Serializable]
public class MyClass {
    public int value;
    public MyInnerClass innerValue;
}

[CustomPropertyDrawer(typeof(MyClass))]
public class MyClassDrawer : PropertyDrawer {

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        // Using BeginProperty / EndProperty on the parent property means that
        // prefab override logic works on the entire property.
        EditorGUI.BeginProperty(position, label, property);

        // Draw label
        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

        // Calculate rects
        var value = new Rect(position.x, position.y, 30, position.height);
        var innerValue = new Rect(position.x + 35, position.y, 50, position.height);

        // Draw fields - passs GUIContent.none to each so they are drawn without labels
        EditorGUI.PropertyField(value, property.FindPropertyRelative("value"), GUIContent.none);
        EditorGUI.PropertyField(innerValue, property.FindPropertyRelative("innerValue.value"), GUIContent.none);


        EditorGUI.EndProperty();
    }
}

And this is the result:
8026259--1034087--Recording 2022-04-06 at 21.37.11.gif Unity - Scripting API: EditorGUI.BeginProperty

3 Likes

Lovely! Thanks so much

How can we do something similar for UI elements?

PropertyElement should support this by default

Yeah, but I want to create custom property drawers, so, right now they don’t support it, if add a custom label they don’t work as they did when using IMGUI.

UIElements are great when dealing with “meta” stuff, but if you’re doing a single element that can be used in both IMGUI and UIElement contexts, it’s still better to use IMGUI