Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Reorderable List v2

Discussion in 'Immediate Mode GUI (IMGUI)' started by CDF, Jul 9, 2015.

  1. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Yes, you can use a property defined on the NestedChild and reference that in the attribute:

    Code (CSharp):
    1. [System.Serializable]
    2. public class ExampleChild {
    3.  
    4.     [Reorderable("myElementName")]
    5.     public NestedChildList nested;
    6. }
    7.  
    8. [System.Serializable]
    9. public class NestedChild {
    10.  
    11.     public string myElementName;
    12. }
    13.  
    14. [System.Serializable]
    15. public class NestedChildList : ReorderableArray<NestedChild> {
    16. }
    It will also, by default, use the "name" property of NestedChild, if defined.
     
  2. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @CDF It looks like I may have spoke too soon about getting the nested list working. If I derive from
    ReorderableArray<string> I cannot seem to edit the element's string field. But if I derive another built-in type like ReorderableArray<int> I can. Do you know what causes this behavior?

    Also, is there a way to set the element name in code and not in the inspector?
     
    Last edited: Apr 11, 2017
  3. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Ah looks like this is focus/event ordering issue, not trivial to fix. Working on something now
     
    Ben-BearFish likes this.
  4. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Hey, I've updated the Repository. Focus and Event capture should be fixed now.

    In terms of setting the element name through code, check the NestedExampleEditor script. However, I'm not exactly sure what your use case is here? It's not exactly straightforward to modify the element names of a nested list. It is possible though. Using the ReorderableAttribute is easier and allows you to use a property of the element, which is generally preferable.
     
  5. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @CDF My use case would be to rename Element 0-1 as something else 0-1. and the nested Element 0-1 as something else 0-1.

    So for example, I have a list of Cars, and in each car is a nested list of Car Parts. Element 0-1 would be renamed "Cars" 0-1. Nested Element 0-1 would be renamed "Car Par" 0-1. 2017_04_12_13_13_53_Reorderable_List_v2_Page_2_Unity_Community.png
     
  6. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @CDF Also, in your latest update the string field entry works, but after text is entered into the string field the reorder no longer works for the nested list/array.
     
    Last edited: Apr 12, 2017
  7. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    @Ben-BearFish I've updated the Repo.

    Added a "elementNameOverride" property to ReorderableList and ReorderableAttribute.
    The NameOverrideEditor example shows whats possible. If you really need to change the element names dynamically you can, similar to before, but without requiring callbacks. The easier method is to define the override on the attribute
     
  8. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    I've changed the default functionality to favor keyboard focus for fields rather than the list. There are 3.5 options:

    1: Set "captureFocus" on ReorderableList to true
    2: Use Middle click
    3: De-focus the active field by selecting something other than the list and drag again
    3.5: Convince me that "captureFocus" should default to true ;) It has pros/cons.
    • Pros: Dragging is more intuitive
    • Cons: No Tabbed navigation between fields, no keyboard actions on fields, no right-click option for field
    That being said, I didn't spend a whole lot of time on the capture stuff. So maybe there's a workaround...
     
    Last edited: Apr 12, 2017
  9. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    I think for me, captureFocus = true is perfectly fine. And Middle mouse click. Having the option to change it is great for the users though. I would just recommend that you put that in the documentation somewhere, so the users realize they can change between captureFocus.

    Finally, in your last change it looks like in your last push/change you seemed to have removed the NestedExampleEditor script, but still have the prefab/script for NestedExample.

    Thanks for all the fixes and changes. Your Reorderable List now does exactly what I needed.
     
  10. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Hey Guys, just updated the Repo.

    - Fixed dragging at high speed
    - Removed "captureFocus". Keyboard focus for a field is retained until you start dragging. Best of both worlds ;)
    - Bugfix when deselecting an element during dragging

    Let me know if you find any issues over on the Github page.

    Thanks
     
    Deleted User likes this.
  11. sponger94

    sponger94

    Joined:
    Dec 8, 2016
    Posts:
    3
    Hey CDN - Great Work!

    Just one question, is there a way to make it draw elements which are have their own CustomEditor's? It's drawing the standard editor, but doesn't want to draw my own.
     
  12. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    It supports PropertyDrawers. Are you trying to draw an element using the [CustomEditor] attribute?
     
  13. sponger94

    sponger94

    Joined:
    Dec 8, 2016
    Posts:
    3
    Yes, I'm trying to draw element using CustomEditor attribute.
     
  14. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    By default Unity doesn't draw elements using their CustomEditors when that object is not currently being inspected.
    If you draw the list normally, as default Unity, you'll see the elements show up as Object Fields.

    You can however, add a callback to drawElementCallback and override the drawing of each element to use your custom editor. However, Custom editors are not really designed to be used like this. Things get a little weird if you're editing serialized properties of your element while inside the serialized object of the list. Also, some strange delays in rendering occur too. But if you're really interested in doing this, which I don't recommend then here you go:

    Make sure to grab the latest Repo, just added an "IsDragging" property which this example uses

    Code (CSharp):
    1.  
    2. public class CustomDraw : MonoBehaviour {
    3.  
    4.     public CustomDrawChild[] myList;
    5. }
    6.  
    7. public class CustomDrawChild : MonoBehaviour {
    8.  
    9.     public float myValue = 0;
    10.     public bool myBool = true;
    11.     public string myString = "Hello";
    12. }
    13.  
    14. [CustomEditor(typeof(CustomDrawChild))]
    15. public class CustomDrawChildEditor : Editor {
    16.  
    17.     public override void OnInspectorGUI() {
    18.  
    19.         base.OnInspectorGUI();
    20.     }
    21. }
    22.  
    23. [CustomEditor(typeof(CustomDraw))]
    24. public class CustomDrawEditor : Editor {
    25.  
    26.     private ReorderableList list;
    27.     private Dictionary<Object, Editor> editors;
    28.  
    29.     private void OnEnable() {
    30.  
    31.         list = new ReorderableList(serializedObject.FindProperty("myList"));
    32.         list.drawElementCallback += DrawElement;
    33.         list.getElementHeightCallback += GetElementHeight;
    34.  
    35.         editors = new Dictionary<Object, Editor>();
    36.     }
    37.  
    38.     private float GetElementHeight(SerializedProperty element) {
    39.  
    40.         float height = EditorGUI.GetPropertyHeight(element);
    41.  
    42.         if (!element.objectReferenceValue) {
    43.  
    44.             return height;
    45.         }
    46.  
    47.         //iterate members inside the objectReference element
    48.  
    49.         SerializedProperty copy = element.Copy();      
    50.         SerializedProperty end = copy.GetEndProperty();
    51.  
    52.         while (copy.Next(true) && !SerializedProperty.EqualContents(copy, end)) {
    53.  
    54.             height += EditorGUI.GetPropertyHeight(copy) + 2;
    55.         }
    56.  
    57.         //add some extra height because the default inspector draws the "Script" field. But that's not enemurated above
    58.  
    59.         return height + (EditorGUIUtility.singleLineHeight + 2) * 2;
    60.     }
    61.  
    62.     private void DrawElement(Rect rect, SerializedProperty element, GUIContent label, bool selected, bool focused) {
    63.  
    64.         EditorGUI.PropertyField(rect, element, label, true);
    65.  
    66.         if (!element.objectReferenceValue) {
    67.  
    68.             return;
    69.         }
    70.  
    71.         Editor editor;
    72.         editors.TryGetValue(element.objectReferenceValue, out editor);
    73.  
    74.         CreateCachedEditor(element.objectReferenceValue, typeof(CustomDrawChildEditor), ref editor);  
    75.  
    76.         if (editor != null && !list.IsDragging) {
    77.  
    78.             editors[element.objectReferenceValue] = editor;
    79.  
    80.             rect.y += EditorGUIUtility.singleLineHeight + 2;
    81.  
    82.             GUILayout.BeginArea(rect);
    83.             editor.OnInspectorGUI();
    84.             GUILayout.EndArea();
    85.         }
    86.     }
    87.  
    88.     public override void OnInspectorGUI() {
    89.  
    90.         serializedObject.Update();
    91.  
    92.         list.DoLayoutList();
    93.  
    94.         serializedObject.ApplyModifiedProperties();
    95.     }
    96. }
    97.  
    This was pretty quick and dirty. Maybe there's a better way. Very quirky as is, but it does seem to work.
     
  15. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    First, awesome, thanks for this!

    Second, you can't have UnityEvent items more then 1 level "deep" or they do not draw properly. This isn't a big issue, i can make everything 1 level deep, but would be great if UnityEvent items could be nested arbitrarily deep. I don't even know where to start to help with figuring out what the issue is, other then the HUGE stack trace i get when i have a list with a list of items, which have UnityEvents in them. I used the NestedExample code, and simply added a UnityEvent to the NestedChild class. While the Events have nothing in them, no errors. When you click the '+' to add a field to them, you get the following stack trace. This may be an unsolvable problem, due to how unity renders UnityEvents, i don't know.

    Thanks again for this hugely useful code.

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. UnityEditorInternal.UnityEventDrawer.AddEventListener (UnityEditorInternal.ReorderableList list) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/UnityEventDrawer.cs:359)
    3. UnityEditorInternal.ReorderableList+Defaults.DrawFooter (Rect rect, UnityEditorInternal.ReorderableList list) (at /Users/builduser/buildslave/unity/build/Editor/Mono/GUI/ReorderableList.cs:105)
    4. UnityEditorInternal.ReorderableList.DoListFooter (Rect footerRect) (at /Users/builduser/buildslave/unity/build/Editor/Mono/GUI/ReorderableList.cs:627)
    5. UnityEditorInternal.ReorderableList.DoList (Rect rect) (at /Users/builduser/buildslave/unity/build/Editor/Mono/GUI/ReorderableList.cs:402)
    6. UnityEditorInternal.UnityEventDrawer.OnGUI (Rect position) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/UnityEventDrawer.cs:146)
    7. UnityEditorInternal.UnityEventDrawer.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/UnityEventDrawer.cs:115)
    8. UnityEditor.PropertyDrawer.OnGUISafe (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyDrawer.cs:22)
    9. UnityEditor.PropertyHandler.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs:142)
    10. UnityEditor.PropertyHandler.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs:177)
    11. UnityEditor.EditorGUI.PropertyFieldInternal (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/EditorGUI.cs:5213)
    12. UnityEditor.EditorGUI.PropertyField (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/editor/EditorGUIBindings.gen.cs:1047)
    13. Malee.Editor.ReorderableList.DrawElement (UnityEditor.SerializedProperty element, Rect rect, Boolean selected, Boolean focused) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:706)
    14. Malee.Editor.ReorderableList.DrawElements (Rect rect, UnityEngine.Event evt) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:607)
    15. Malee.Editor.ReorderableList.DoList (Rect rect, UnityEngine.GUIContent label) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:263)
    16. Malee.Editor.ReorderableDrawer.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableDrawer.cs:25)
    17. UnityEditor.PropertyDrawer.OnGUISafe (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyDrawer.cs:22)
    18. UnityEditor.PropertyHandler.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs:142)
    19. UnityEditor.PropertyHandler.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs:177)
    20. UnityEditor.EditorGUI.PropertyFieldInternal (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/EditorGUI.cs:5213)
    21. UnityEditor.EditorGUI.PropertyField (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/editor/EditorGUIBindings.gen.cs:1047)
    22. Malee.Editor.ReorderableList.DrawElement (UnityEditor.SerializedProperty element, Rect rect, Boolean selected, Boolean focused) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:706)
    23. Malee.Editor.ReorderableList.DrawElements (Rect rect, UnityEngine.Event evt) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:607)
    24. Malee.Editor.ReorderableList.DoList (Rect rect, UnityEngine.GUIContent label) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableList.cs:263)
    25. Malee.Editor.ReorderableDrawer.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at Assets/3rdParty/ReorderableList/List/Editor/ReorderableDrawer.cs:25)
    26. UnityEditor.PropertyDrawer.OnGUISafe (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyDrawer.cs:22)
    27. UnityEditor.PropertyHandler.OnGUI (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs:142)
    28. UnityEditor.EditorGUI.PropertyFieldInternal (Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/Editor/Mono/EditorGUI.cs:5213)
    29. UnityEditor.EditorGUI.PropertyField (Rect position, UnityEditor.SerializedProperty property, Boolean includeChildren) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/editor/EditorGUIBindings.gen.cs:1034)
    30. UnityEditor.EditorGUI.PropertyField (Rect position, UnityEditor.SerializedProperty property) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/editor/EditorGUIBindings.gen.cs:1029)
    31. UnityEditor.Editor.OptimizedInspectorGUIImplementation (Rect contentRect) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/editor/EditorBindings.gen.cs:273)
    32. UnityEditor.GenericInspector.OnOptimizedInspectorGUI (Rect contentRect) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/GenericInspector.cs:32)
    33. UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1209)
    34. UnityEditor.InspectorWindow.DrawEditors (UnityEditor.Editor[] editors) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1019)
    35. UnityEditor.InspectorWindow.OnGUI () (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:358)
    36. System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
    37.  
     
  16. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Interesting. I get:

    "Serialization depth limit 7 exceeded at 'UnityEngine.Events::ArgumentCache.m_ObjectArgument'. There may be an object composition cycle in one or more of your serialized classes."

    There is a solution though. The top level list must be defined explicitly as an array or list. Looks like a class acting on behalf of an array causes the serialization depth errors. This of course requires a CustomEditor to convert that list into a Reorderable one :(

    Ignoring the Reorderable attribute and just rendering as default Unity. Here's an example:
    Code (CSharp):
    1. //Error - Serialization depth limit 7
    2. public class NestedExample : MonoBehaviour {
    3.  
    4.     public ShallowChildList list;
    5.  
    6.     [System.Serializable]
    7.     public class ShallowChildList {
    8.  
    9.         public ShallowChild[] children;
    10.     }
    11.  
    12.     [System.Serializable]
    13.     public class ShallowChild {
    14.  
    15.         public DeepChildList list;
    16.     }
    17.  
    18.     [System.Serializable]
    19.     public class DeepChildList {
    20.  
    21.         public DeepChild[] children;
    22.     }
    23.  
    24.     [System.Serializable]
    25.     public class DeepChild {
    26.  
    27.         public float myValue;
    28.         public UnityEvent myEvent;
    29.     }
    30. }
    31.  
    32. //Working
    33. public class NestedExample : MonoBehaviour {
    34.  
    35.     public ShallowChild[] list;
    36.  
    37.     [System.Serializable]
    38.     public class ShallowChild {
    39.  
    40.         public DeepChildList list;
    41.     }
    42.  
    43.     [System.Serializable]
    44.     public class DeepChildList {
    45.  
    46.         public DeepChild[] children;
    47.     }
    48.  
    49.     [System.Serializable]
    50.     public class DeepChild {
    51.  
    52.         public float myValue;
    53.         public UnityEvent myEvent;
    54.     }
    55. }
    If Unity ever decides to implement an "ArrayPropertyDrawer" This whole thing could be avoided. Sadly, I doubt that will ever happen. So In order to make everything Reorderable in the above working example:

    Code (CSharp):
    1. [CustomEditor(typeof(NestedExample))]
    2. public class NestedExampleEditor : Editor {
    3.  
    4.     private ReorderableList list;
    5.  
    6.     private void OnEnable() {
    7.  
    8.         list = new ReorderableList(serializedObject.FindProperty("list"));
    9.     }
    10.  
    11.     public override void OnInspectorGUI() {
    12.  
    13.         serializedObject.Update();
    14.         list.DoLayoutList();
    15.         serializedObject.ApplyModifiedProperties();
    16.     }
    17. }
    18.  
    19. public class NestedExample : MonoBehaviour {
    20.  
    21.     public ShallowChild[] list;
    22.  
    23.     [System.Serializable]
    24.     public class ShallowChild {
    25.  
    26.         [Reorderable]
    27.         public DeepChildList list;
    28.     }
    29.  
    30.     [System.Serializable]
    31.     public class DeepChildList : ReorderableArray<DeepChild> {
    32.     }
    33.  
    34.     [System.Serializable]
    35.     public class DeepChild {
    36.  
    37.         public float myValue;
    38.         public UnityEvent myEvent;
    39.     }
    40. }
    At some point I'll add this to some much needed "Wiki". I'll let Unity know as well, could be a bug.
     
  17. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    I've been trying to add a new item to a ReorderableArray item at run-time, and am getting errors. Is there any magic that one needs to do to add/edit the underlying array? I looked at the code, and it seemed like it should work, but sometimes I make mistakes... ;)
     
  18. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    What errors are you getting?
     
  19. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Hi, I've fixed this. ReorderableArray now wraps a List.
     
    Jos-Yule likes this.
  20. gtzpower

    gtzpower

    Joined:
    Jan 23, 2011
    Posts:
    318
    Hey there. Thanks a lot for this plugin, it is fantastic!

    I am having a problem I was hoping you could help me solve. If I have a nested reorderable list that is displaying an object with a custom property drawer I cannot click on things in the list (directly). For example, in the screen shot below, I have a custom property drawer that lets me have a check box and a game object side by side:


    I cannot click on the check box (or on the little circle to the right of the game object field) directly to interact with them. I have to click 1-3 pixels below the check box, and that will check/uncheck the box. If I click directly on the box, it seems like the row is selected. Do you have any ideas how I can resolve this?

    The property drawer works just fine in a reorderable list that isn't nested inside a reorderable list. This is specifically a problem when it is nested for some reason.
     
  21. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    I'll take a look. Little busy with work, so might be a little while
     
    gtzpower likes this.
  22. gtzpower

    gtzpower

    Joined:
    Jan 23, 2011
    Posts:
    318
    Thanks a lot! No problem on time, we have a workaround that will keep us going for now.
     
    CDF likes this.
  23. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    So I believe this is fixed now. Latest version is on the git repo.

    The problem was related to CustomPropertyDrawers. The issue relates to Mouse capture and drag area. It's not possible to determine whether a property drawer will draw everything on a single line or not, or whether a drop down arrow is present. So the previous version assumed that if the element had children, it would expand. It would then capture mouse focus if the element was identified as expandable if the user pressed on the first row. Clearly this is not the case when using property drawers.

    So I've removed the header capture focus. Downside is that dragging an element must occur from white space or the drag thumb. But it's better than not being able to press other things :)

    Also fixed some render issues with element heights. You should see the ObjectField circle at the correct size now.
     
    gtzpower likes this.
  24. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Does this reorderable list do some kinds of measurements of the content (so it is compatible with GUILayout)?
    Or do you have to provide the height of each item yourself like in the basic reorderable list?
     
  25. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    It works with GUILayout.

    call list.DoLayoutList();

    internally it just calls EditorGUIUtility.GetPropertyHeight
     
  26. gtzpower

    gtzpower

    Joined:
    Jan 23, 2011
    Posts:
    318
    Awesome! It works great now. Thank you for looking into that for me.
     
  27. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    Thanks man for this great asset.
     
  28. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,225
    Is there a way to make this beauty work without requiring use of ReorderableArray type?
    I don't want to change my data type for GUI candy.
     
  29. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Should be possible. Just make sure your Array class has an "array" property.
    Of course you can just create the list directly with a custom editor:

    list = new ReorderableList(serializedObject.FindProperty("myArrayProperty"));

    then call list.DoLayoutList(); inside your OnGUI
     
  30. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,225
    I don't understand, what does the code look like>?
     
  31. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    What's your data type look like?

    Here's what I was thinking:
    Code (CSharp):
    1. public class MyObject : MonoBehaviour {
    2.  
    3.     [Reorderable]
    4.     public MyList list = new MyList();
    5.  
    6.     [System.Serializable]
    7.     public class MyList {
    8.  
    9.         public string[] array = new string[0];
    10.     }
    11. }
    However, if you're trying to do the following:
    Code (CSharp):
    1. public class MyObject : MonoBehaviour {
    2.  
    3.     [Reorderable]
    4.     public string[] list = new string[0];
    5. }
    That won't work as Custom Property drawers for array types only apply at the element level :(
    You need to wrap your array through a class, or, write a custom editor for "MyObject" that creates a
    ReorderableList manually. Like so:

    Code (CSharp):
    1. [CustomEditor(typeof(MyObject))]
    2. public class MyObjectEditor : Editor {
    3.  
    4.     private ReorderableList list;
    5.  
    6.     void OnEnable() {
    7.  
    8.         list = new ReorderableList(serializedObject.FindProperty("list"));
    9.     }
    10.  
    11.     public override void OnInspectorGUI() {
    12.  
    13.         serializedObject.Update();
    14.  
    15.         list.DoLayoutList();
    16.  
    17.         serializedObject.ApplyModifiedProperties();
    18.     }
    19. }
    20.  
    There was a very brief time when CustomPropertyDrawers worked on the entire array. But that didn't last long. The power and convenience was too great!
     
  32. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,225
    did you try [CustomEditor(typeof(UnityEngine.Object))]?
     
  33. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Sorry, I don't understand what you're trying to do?

    Not sure how creating a CustomEditor for every Object would work here.
     
  34. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,225
    it would allow reorderable lists on List<string> for example, no need for List<SomeClass>
     
  35. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    I think you can check this for reference on making a custom editor for (UnityEngine.Object) class.
    He made a custom editor that replaces all arrays with reorderable arrays for every class deriving from UnityEngine.Object.
     
  36. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,225
    That's what I use, but was looking for one that has propert foldouts and drag and drop.
    Do you know hot to turn it into an attribute thing, so instead of transforming all the lists into reorderables, it only does with lists that have the [Reorderable] attribute in front.
     
    Last edited: Jan 7, 2018
  37. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    I'm not sure about the [Reorderable] attribute, but I would say try making your desired classes implement an interface and then use that interface in place of the "UnityEngine.Object" in the custom editor.
     
  38. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    You would need to find the "FieldInfo" object of the array field, find if that field has any custom attributes, determine if any of those are the "Reorderable" attribute and then create a ReorderableList to render that field with.

    Something like this to get the field info: https://answers.unity.com/questions/1347203/a-smarter-way-to-get-the-type-of-serializedpropert.html

    then get the attributes: https://msdn.microsoft.com/en-us/library/kff8s254(v=vs.110).aspx

    I think this is pretty overkill and messy. Reflecting this much (imo) is never a good thing, and can lead to strange behavior if API's change. But by all means, if you want to fork the repo and add this, go for it. Don't think I'm going to add anything like this to the main repo.

    I'll hold out forever on Property Drawers that work with arrays rather than elements.
     
  39. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    Hi guys,

    I'm trying also to create a reorderable list for CustomEditor, I get a strange error:
    saadsa.png
    Any idea? :(
     
  40. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    @D0R1N
    You should Initialize the list with the ReorderableList constructor.
    List = new ReorderableList(serializedObject, serializedObject.FindProperty("List")
    , true, true, true, true);
    something like that.
     
  41. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    Hi @YaserDev ,

    I fixed the problem, I did some n00b mistakes :p thanks anyway ;)

    P.S I have some problems with arranging (layouts) of elements in the reorderable lists, I tried a lot of things, I spent 24 hours to smoothly/dynamically render elements in list without success :(
    screenGUI.png

    I'm trying to display the elements horizontally 50% of Rect for each elements with labels, my current code:

    Code (CSharp):
    1.    
    2. private void DrawElement(Rect rect, int index, bool active, bool focused)
    3.         {
    4.             var element = testList.serializedProperty.GetArrayElementAtIndex(index);
    5.             var _trs = element.FindPropertyRelative("transformEx");
    6.             var _btn = element.FindPropertyRelative("buttonEx");
    7.  
    8.             EditorGUI.PropertyField(new Rect(rect.x, rect.y += 2, 120, EditorGUIUtility.singleLineHeight), _trs, new GUIContent("Transform Ex"));
    9.             EditorGUI.PropertyField(new Rect(rect.x + 130, rect.y += 2, rect.width / 2, EditorGUIUtility.singleLineHeight), _btn, new GUIContent("Button Ex));
    10.        }
    ATTACHED GIF:
    https://gfycat.com/gifs/detail/PaleFluffyAmericancreamdraft

    Any ideas, suggestions please?
    Thanks in advance!
     
    Last edited: Feb 27, 2018
  42. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Try this:
    Code (CSharp):
    1. private void DrawElement(Rect rect, int index, bool active, bool focused)
    2. {
    3.     var element = testList.serializedProperty.GetArrayElementAtIndex(index);
    4.     var _trs = element.FindPropertyRelative("transformEx");
    5.     var _btn = element.FindPropertyRelative("buttonEx");
    6.  
    7.     Rect r1 = rect;
    8.     r1.y += 2;
    9.     r1.width *= 0.5;
    10.     r1.height = EditorGUIUtility.singleLineHeight;
    11.  
    12.     Rect r2 = r1;
    13.     r2.xMin = r1.xMax + 10;
    14.     r2.xMax = rect.xMax;
    15.  
    16.     EditorGUI.PropertyField(r1, _trs, new GUIContent("Transform Ex"));
    17.     EditorGUI.PropertyField(r2, _btn, new GUIContent("Button Ex));
    18. }
     
    RoyalCoder likes this.
  43. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    Hi @CDF ,

    Thanks for the help it's much better now ;), I also use for accurate rendering for the list the following code:

    Code (CSharp):
    1.             GUILayout.BeginVertical();
    2.             {
    3.                 float restoreLabelWidth = EditorGUIUtility.labelWidth;
    4.                 EditorGUIUtility.labelWidth = 45;
    5.  
    6.                 reordListTest.DoLayoutList();
    7.  
    8.                 EditorGUIUtility.labelWidth = restoreLabelWidth;
    9.             }
    10.  
    11.             GUILayout.EndVertical();
    12.  
    *If not, I get really weird spaces between the element label and element property...I don't know why :(. It's my first attempt of scripting Inspectors in Unity.

    P.S: It's possible to insert buttons in elements row?
    Thanks!
     
  44. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    By default Unity calculates the labelWidth dynamically based on the context. So yeah I think what you've done is totally fine. You could also calculate the labelWidth by the label if you wanted:

    GUIContent label = new GUIContent("Transform Ex");
    Vector2 size = EditorStyles.label.CalcSize(label);
    EditorGUIUtility.labelWidth = size.x;

    you can reset the labelWidth to default by just setting: EditorGUIUtility.labelWidth = 0;

    And yes, you can draw buttons/whatever you like in the "DrawElement" function.
    You can also supply a custom height function for every element as well:

    reordListTest.getElementHeightCallback = element => 100; //fixed value of 100px

    Of course you can create a method and do more advanced stuff, like checking for properties/expanded states and return a dynamic height
     
    RoyalCoder likes this.
  45. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    Hi @CDF ,

    With your guidance I managed to understand much better how the reorderable list works, thanks a lot!

    My only problem now is to draw a button inside the element from list, like in this image:
    screenshot.png

    Regards!
     
  46. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    Maybe try something like this:

    Code (CSharp):
    1. private void DrawElement(Rect rect, int index, bool active, bool focused)
    2. {
    3.     var element = testList.serializedProperty.GetArrayElementAtIndex(index);
    4.     var _trs = element.FindPropertyRelative("transformEx");
    5.     var _btn = element.FindPropertyRelative("buttonEx");
    6.  
    7.     var buttonWidth = 100;
    8.  
    9.     Rect r1 = rect;
    10.     r1.y += 2;
    11.     r1.width = (rect.width / 2) - 10 - buttonWidth - 5;
    12.     r1.height = EditorGUIUtility.singleLineHeight;
    13.  
    14.     Rect r2 = r1;
    15.     r2.xMin = r1.xMax + 10;
    16.     r2.xMax = rect.xMax - buttonWidth - 5;
    17.  
    18.     Rect r3 = r1;
    19.     r3.xMin = r2.xMax + 5;
    20.     r3.xMax = rect.xMax;
    21.  
    22.     EditorGUI.PropertyField(r1, _trs, new GUIContent("Transform Ex"));
    23.     EditorGUI.PropertyField(r2, _btn, new GUIContent("Button Ex"));
    24.  
    25.     if (GUI.Button(r3, "My Button")) {
    26.  
    27.         //do some action
    28.     }
    29. }
    Just typing this directly, might not work exactly.
     
  47. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    Thanks @CDF ,

    Now it works :p, I have been so close to solve it by my self, the problem was using GUILayout.Button instead GUI.Button ...Thanks you some much for your help and guidance! ;););)
     
  48. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    I completely forgot about BeginArea. That might ease the pain a little:

    Code (CSharp):
    1. private void DrawElement(Rect rect, int index, bool active, bool focused)
    2. {
    3.     var element = testList.serializedProperty.GetArrayElementAtIndex(index);
    4.     var _trs = element.FindPropertyRelative("transformEx");
    5.     var _btn = element.FindPropertyRelative("buttonEx");
    6.  
    7.     rect.y += 2;
    8.     rect.height = EditorGUIUtility.singleLineHeight;
    9.  
    10.     GUILayout.BeginArea(rect);
    11.     GUILayout.BeginHorizontal();
    12.  
    13.     EditorGUILayout.PropertyField(_trs, new GUIContent("Transform Ex"));
    14.     EditorGUILayout.PropertyField(_btn, new GUIContent("Button Ex"));
    15.  
    16.     if (GUILayout.Button("My Button")) {
    17.         //do some action
    18.     }
    19.  
    20.     GUILayout.EndHorizontal();
    21.     GUILayout.EndArea();
    22. }
     
  49. RoyalCoder

    RoyalCoder

    Joined:
    Oct 4, 2013
    Posts:
    301
    On this way I get the error:

    GUI Error: You are pushing more GUIClips than you are popping. Make sure they are balanced)
    UnityEngine.GUIUtility:processEvent(Int32, IntPtr)

    *Fixed the error!

    => But nothing is drawing inside elements form reorderable list :(
     
  50. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,307
    I can't open Unity at the moment, but I'll take a look later