Skip to content

Commit

Permalink
Added Surrogates
Browse files Browse the repository at this point in the history
commenetd out recursion test. No need for the spammy warnings!
  • Loading branch information
foulston committed Nov 1, 2018
1 parent 96a7198 commit 22d0ab3
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 16 deletions.
45 changes: 45 additions & 0 deletions Example/Editor/SurrogateTestEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Malee.Editor;

[CustomEditor(typeof(SurrogateTest))]
public class SurrogateTestEditor : Editor {

private ReorderableList list;
private SerializedProperty myClassArray;

private void OnEnable() {

//custom list with more complex surrogate functionalty

list = new ReorderableList(serializedObject.FindProperty("objects"));
list.surrogate = new ReorderableList.Surrogate(typeof(GameObject), AppendObject);

//myClassArray uses an auto surrogate property on the "ReorderableAttribute"
//it's limited to only setting a property field to the dragged object reference. Still handy!

myClassArray = serializedObject.FindProperty("myClassArray");
}

public override void OnInspectorGUI() {

GUILayout.Label("Drag a GameObject onto the lists. Even though the list type is not a GameObject!");

serializedObject.Update();

list.DoLayoutList();
EditorGUILayout.PropertyField(myClassArray);

serializedObject.ApplyModifiedProperties();
}

private void AppendObject(SerializedProperty element, Object objectReference, ReorderableList list) {

//we can do more with a custom surrogate delegate :)

element.FindPropertyRelative("gameObject").objectReferenceValue = objectReference;
element.FindPropertyRelative("name").stringValue = objectReference.name;
}
}
11 changes: 11 additions & 0 deletions Example/Editor/SurrogateTestEditor.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Example/RecursionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

public class RecursionTest : MonoBehaviour {

/* Don't do this!
[Reorderable]
public Tables tables = new Tables();
Expand All @@ -20,4 +21,5 @@ public class Table {
[System.Serializable]
public class Tables : ReorderableArray<Table> {
}
*/
}
24 changes: 24 additions & 0 deletions Example/SurrogateTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Malee;

public class SurrogateTest : MonoBehaviour {

[SerializeField]
private MyClass[] objects;

[SerializeField, Reorderable(surrogateType = typeof(GameObject), surrogateProperty = "gameObject")]
private MyClassArray myClassArray;

[System.Serializable]
public class MyClass {

public string name;
public GameObject gameObject;
}

[System.Serializable]
public class MyClassArray : ReorderableArray<MyClass> {
}
}
11 changes: 11 additions & 0 deletions Example/SurrogateTest.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Example/SurrogateTest.prefab
Binary file not shown.
8 changes: 8 additions & 0 deletions Example/SurrogateTest.prefab.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion List/Attributes/ReorderableAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using UnityEngine;
using System;

namespace Malee {

Expand All @@ -14,6 +15,8 @@ public class ReorderableAttribute : PropertyAttribute {
public string elementNameProperty;
public string elementNameOverride;
public string elementIconPath;
public Type surrogateType;
public string surrogateProperty;

public ReorderableAttribute()
: this(null) {
Expand All @@ -31,7 +34,7 @@ public ReorderableAttribute(string elementNameProperty, string elementNameOverri
: this(true, true, true, elementNameProperty, elementNameOverride, elementIconPath) {
}

public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementIconPath = null)
public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementIconPath = null)
: this(add, remove, draggable, elementNameProperty, null, elementIconPath) {
}

Expand Down
29 changes: 29 additions & 0 deletions List/Editor/ReorderableDrawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ public static ReorderableList GetList(SerializedProperty property, ReorderableAt
list.paginate = attrib.paginate;
list.pageSize = attrib.pageSize;
list.sortable = attrib.sortable;

//handle surrogate if any

if (attrib.surrogateType != null) {

SurrogateCallback callback = new SurrogateCallback(attrib.surrogateProperty);

list.surrogate = new ReorderableList.Surrogate(attrib.surrogateType, callback.SetReference);
}
}
else {

Expand All @@ -105,5 +114,25 @@ public static ReorderableList GetList(SerializedProperty property, ReorderableAt

return list;
}

private struct SurrogateCallback {

private string property;

internal SurrogateCallback(string property) {

this.property = property;
}

internal void SetReference(SerializedProperty element, Object objectReference, ReorderableList list) {

SerializedProperty prop = !string.IsNullOrEmpty(property) ? element.FindPropertyRelative(property) : null;

if (prop != null && prop.propertyType == SerializedPropertyType.ObjectReference) {

prop.objectReferenceValue = objectReference;
}
}
}
}
}
84 changes: 70 additions & 14 deletions List/Editor/ReorderableList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public enum ElementDisplayType {
public delegate float GetElementsHeightDelegate(ReorderableList list);
public delegate string GetElementNameDelegate(SerializedProperty element);
public delegate GUIContent GetElementLabelDelegate(SerializedProperty element);
public delegate void SurrogateCallback(SerializedProperty element, Object objectReference, ReorderableList list);

public event DrawHeaderDelegate drawHeaderCallback;
public event DrawFooterDelegate drawFooterCallback;
Expand Down Expand Up @@ -74,6 +75,7 @@ public enum ElementDisplayType {
public string elementNameOverride;
public bool elementLabels;
public Texture elementIcon;
public Surrogate surrogate;

public bool paginate {

Expand Down Expand Up @@ -1385,14 +1387,7 @@ private void HandleDragAndDrop(Rect rect, Event evt) {

if (evt.type == EventType.DragPerform) {

if (onAppendDragDropCallback != null) {

onAppendDragDropCallback(object2, this);
}
else {

AppendDragAndDropValue(object2);
}
AppendDragAndDropValue(object2);

acceptDrag = true;
DragAndDrop.activeControlID = 0;
Expand Down Expand Up @@ -1430,13 +1425,35 @@ private Object ValidateObjectDragAndDrop(Object[] references) {

return onValidateDragAndDropCallback(references, this);
}
else if (surrogate.HasType) {

//if we have a surrogate type, then validate using the surrogate type rather than the list

return Internals.ValidateObjectDragAndDrop(references, null, surrogate.type, surrogate.exactType);
}

return Internals.ValidateObjectDragAndDrop(references, list);
return Internals.ValidateObjectDragAndDrop(references, list, null, false);
}

private void AppendDragAndDropValue(Object obj) {

Internals.AppendDragAndDropValue(obj, list);
if (onAppendDragDropCallback != null) {

onAppendDragDropCallback(obj, this);
}
else {

//check if we have a surrogate type. If so use that for appending

if (surrogate.HasType) {

surrogate.Invoke(AddItem(), obj, this);
}
else {

Internals.AppendDragAndDropValue(obj, list);
}
}

DispatchChange();
}
Expand Down Expand Up @@ -2592,6 +2609,45 @@ private static int CompareObjects(Object obj1, Object obj2, bool descending) {
}
}

//
// -- SURROGATE --
//

public struct Surrogate {

public System.Type type;
public bool exactType;
public SurrogateCallback callback;

internal bool enabled;

public bool HasType {

get { return enabled && type != null; }
}

public Surrogate(System.Type type)
: this(type, null) {
}

public Surrogate(System.Type type, SurrogateCallback callback) {

this.type = type;
this.callback = callback;

enabled = true;
exactType = false;
}

public void Invoke(SerializedProperty element, Object objectReference, ReorderableList list) {

if (element != null && callback != null) {

callback.Invoke(element, objectReference, list);
}
}
}

//
// -- EXCEPTIONS --
//
Expand Down Expand Up @@ -2625,18 +2681,18 @@ static Internals() {
appendDragDrop = typeof(SerializedProperty).GetMethod("AppendFoldoutPPtrValue", BindingFlags.NonPublic | BindingFlags.Instance);
}

internal static Object ValidateObjectDragAndDrop(Object[] references, SerializedProperty property) {
internal static Object ValidateObjectDragAndDrop(Object[] references, SerializedProperty property, System.Type type, bool exactType) {

#if UNITY_2017_1_OR_NEWER
dragDropValidationParams = GetParams(ref dragDropValidationParams, 4);
dragDropValidationParams[0] = references;
dragDropValidationParams[1] = null;
dragDropValidationParams[1] = type;
dragDropValidationParams[2] = property;
dragDropValidationParams[3] = 0;
dragDropValidationParams[3] = exactType ? 1 : 0;
#else
dragDropValidationParams = GetParams(ref dragDropValidationParams, 3);
dragDropValidationParams[0] = references;
dragDropValidationParams[1] = null;
dragDropValidationParams[1] = type;
dragDropValidationParams[2] = property;
#endif
return dragDropValidation.Invoke(null, dragDropValidationParams) as Object;
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ An attempt to mimic the ReorderableList within Unity while adding some extended
* Event delegates and custom styling
* Pagination
* Sorting (sort based on field, ascending and descending)
* Surrogates (Enable adding elements of a different type)

## Usage

Expand All @@ -39,4 +40,17 @@ When enabled, the ReorderableList GUI will display a small section below the hea
![pagination](https://user-images.githubusercontent.com/6723783/45054642-701bcb80-b042-11e8-84e4-0886d23c83c9.jpg)

#### NOTE
*Elements can be moved between pages by right-clicking and selecting "Move Array Element"*
*Elements can be moved between pages by right-clicking and selecting "Move Array Element"*

## Surrogates

Surrogates can be created to facilitate adding Objects to a ReorderableList that don't match the ReorderableList type.
This can be achieved in two ways:

1. With the [Reorderable] attribute:
* `[Reorderable(surrogateType = typeof(ObjectType), surrogateProperty = "objectProperty")]`

2. Property of the ReorderableList:
* `list.surrogate = new ReorderableList.Surrogate(typeof(ObjectType), Callback);`

Check the `SurrogateTest` and `SurrogateTestEditor` examples for more information

0 comments on commit 22d0ab3

Please sign in to comment.