Reorderable List v2

Hey CDF thank you so much for the update it’s awesome!!

to get back on the GetItem function. Is there a way to access the variables from the list in another non-editor script? Because I can get it to work, but only in editor scripts where I can put ‘using Malee.Editor’.

Unfortunately, without reflection I don’t think that’s possible. Due to the way Unity compiles assemblies.

What variables do you want to change from a non editor script?

you could write an editor for a class that looks for changes and updates the ReorderableList variables on behalf.
something like:

public class MyClass : MonoBehaviour {

    [SerializeField]
    private GameObject[] testList;

    [SerializeField]
    private ListData listData = new ListData();

    void Update() {

        if (Time.time > 3) {

            listData.draggable = true;
        }
    }

    [System.Serializable]
    internal class ListData {
     
        internal bool draggable = false;
    }
}


[CustomEditor(typeof(MyClass))]
public class MyEditor : Editor {

    private ReorderableList list;
    private serializedProperty listData;

    void OnEnable() {

        list = new ReorderableList(serializedObject.FindProperty("testList"));
        listData = serializedObject.FindProperty("listData");
    }

    public override OnInspectorGUI() {

        serializedObject.Update();

        list.draggable = listData.FindPropertyRelative("draggable").boolValue;
        list.DoLayoutList();

        serializedObject.ApplyModifiedProperties();
    }
}

Untested code, but hopefully you get the idea

I’ll take a look at your code. In more detail, I want to access the variables in my list from another (non editor script) and use those values. I don’t want to modify the values, but just read-only. So for example in a script attached to a gameobject, there is a variable that has the value of whatever is inputted in the list from the editor script before running the game.

You can just access the array as usual on your non editor script.

I got it to work! I owe you so much :slight_smile: more questions (im’ sorry) might be coming but for now I’m good. Awesome package!

Nice project! Just thought I’d let you know there is a very similar project by someone else here: Bitbucket which also works well and maybe you’ll find it interesting to see how someone else solves the same problem.

hey CDF, me again. Is there a way to change the default values of variables in the list. So that when the user attaches the script to an object, and adds a list element, some variables already have default values. (without using a prefab), thanks! And also I noticed, when I enter values in a list element, and then I add a new element, it copies the variable values of the previous list, is there a way to modify this?

That’s just how Unity’s serialization system works. Unless your objects derive from MonoBehaviour or ScriptableObject those items will initialize to their base default values: float = 0, bool = false etc.
When duplicating an element, Unity will copy the serialized properties into the new object automatically.

You can see this happening on a regular array. Right click the element in the Editor and Duplicate it, notice the values are copied.

You can listen to the “onAddCallback” on the List to override the “add” button functionality.

In order to initialize a complete list on Startup you would do something similar. Make a private “initialized” bool on your class. Check the value on the CustomEditor “OnInspectorGUI” method, if false, make it true. Use list.AddItem() as above and initialize the default values. Something like:

class MyClass {

    [SerializeField]
    private bool initialized;

    public MyItem[] items;

    [System.Serializable]
    public class MyItem {

        public bool myBool;
        public float myFloat;
    }
}

class MyClassEditor : Editor {

    void OnEnable() {

        list = new ReorderableList(serializedObject.FindProperty("items"));
        list.onAddCallback += AddItemToList;
    }

    public override OnInspectorGUI() {

        serializedObject.Update();

        if (!serializedObject.FindProperty("initialized").boolValue) {

            serializedObject.FindProperty("initialized").boolValue = true;

            InitializeItems();
        }

        serializedObject.ApplyModifiedProperties();
    }

    void AddItemToList(ReorderableList list) {

        InitializeItem(list.AddItem());
    }

    private void InitializeItems() {

        for (int i = 0; i < 10; i++) {

            InitializeItem(list.AddItem());
        }
    }

    private void InitializeItem(SerializedProperty item) {

        item.FindPropertyRelative("myBool").boolValue = true;
        item.FindPropertyRelative("myFloat").floatValue = 1;
    }
}

I don’t have a callback for Duplicate yet though. I’m pretty busy now, if you need it, check "
HandleContextClick" and “HandleMultipleContextClick” functions. You should be able to hook up a callback in there with the right data

Also worth mentioning is you could skip the initialization through the list by directly modifying the array. You’ll still need an “initialized” bool. This way, you won’t generate an Undo/Redo on the items.

Thanks! I have one last (I hope) question though. I want to draw some variables outside of list in the inspector window. This is the code for List.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Malee;

public class List : MonoBehaviour
{
    public float x;
    public List<RotationTimelineData> RotationTimeline; //Define a list.

And this is the code in ListEditor.cs

public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        serializedObject.Update();
        RotationTimeline.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
    }

This draws the variable I want and the list, but also the list in the form of an array:

Any fixes you could think of?

UPDATE:

Is this a correct way to achieve what I want?

using UnityEngine;
using UnityEditor;
using System.Collections;
using Malee.Editor;

[CanEditMultipleObjects]
[CustomEditor(typeof(List))]
public class ListEditor : Editor
{
    private ReorderableList RotationTimeline;
   
     public float damage;
    void OnEnable()
    {
        RotationTimeline = new ReorderableList(serializedObject.FindProperty("RotationTimeline"));
        RotationTimeline.elementNameProperty = "RotationType";
    }

    public override void OnInspectorGUI()
    {
        damage = EditorGUILayout.FloatField("Damage", damage);

        serializedObject.Update();
        RotationTimeline.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
    }
}

I’d use the seralized property instead

public override void OnInspectorGUI()
    {
        //damage = EditorGUILayout.FloatField("Damage", damage);
        serializedObject.Update();

       EditorGUILayout.PropertyField(serializedObject.FindProperty("damage"));

        RotationTimeline.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
    }

Works nicely! This way I can more easily access the damage variable in my List.cs (non-editor) script. Have a great day!

Hey CDF, how would I code it so that the variables in a list element are shown or not based on a toggle in that same list element.

So for regular variables outside of the list I would do (in OnInspectorGUI)

if(DoorPro.VisualizeHinge == true)
        {
            EditorGUILayout.PropertyField(serializedObject.FindProperty("HingeType"));
            EditorGUILayout.PropertyField(serializedObject.FindProperty("HingeColor"));
        }

so the variables HingeType and HingeColor would only show when VisualizeHinge is toggle to true. But can I achieve the same inside a list element?

Use the “drawElementCallback” to draw the property and its children. You may want to use the “getElementHeightCallback” to return a different height for each element if you’re changing how properties are shown.

Could you give an example? I’m having trouble implementing this…

Something like this perhaps:

void OnEnable() {

    list = new ReorderableList(serializedObject.FindProperty("MyList"));
    list.drawElementCallback += DrawElement;
    list.getElementHeightCallback += GetElementHeight;
}

void DrawElement(Rect rect, SerializedProperty element, GUIContent label, bool selected, bool focused) {

    if (DoorPro.VisualizeHinge == false) {

        switch (element.name) {

            case "HingeType":
            case "HingeColor":

                //don't draw this element if VisualizeHinge is false and the element is either "HingeType" or "HingeColor"
                return;
        }
    }

    //default element drawing
    EditorGUI.PropertyField(rect, element, label, true);
}

float GetElementHeight(SerializedProperty element) {

    if (DoorPro.VisualizeHinge == false) {

        switch (element.name) {

            case "HingeType":
            case "HingeColor":

                //element won't contribute to the height of the list when VisualizeHinge is false and the element is either "HingeType" or "HingeColor"
                return 0;
        }
    }

    //default element height
    return EditorGUI.GetPropertyHeight(element, null, true);
}

I may add a “getListHeightCallback” with which you can process the entire lists height instead of per element

Alright, this way I can change whether or not variables are present outside of the list, based on variables inside the list, but then how would it work to make variables inside of the list ‘appear’ and ‘dissapear’ ? So I have variables inside the ListData class that shows up in the list, but then I would like to remove it based on an enum variable in that ListData class.

You’ll want to look at PropertyDrawers for that.

Awesome CDF! you da man