├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Editor.meta ├── Editor ├── Malee.ReorderableList.Editor.asmdef ├── Malee.ReorderableList.Editor.asmdef.meta ├── ReorderableDrawer.cs ├── ReorderableDrawer.cs.meta ├── ReorderableList.cs └── ReorderableList.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── Attributes.meta ├── Attributes │ ├── ReorderableAttribute.cs │ └── ReorderableAttribute.cs.meta ├── Malee.ReorderableList.asmdef ├── Malee.ReorderableList.asmdef.meta ├── ReorderableArray.cs └── ReorderableArray.cs.meta ├── Samples~ ├── Examples.meta └── Examples │ ├── Editor.meta │ ├── Editor │ ├── ExampleEditor.cs │ ├── ExampleEditor.cs.meta │ ├── GameObjectEditor.cs │ ├── GameObjectEditor.cs.meta │ ├── NameOverrideEditor.cs │ ├── NameOverrideEditor.cs.meta │ ├── NestedChildDrawer.cs │ ├── NestedChildDrawer.cs.meta │ ├── SurrogateTestEditor.cs │ └── SurrogateTestEditor.cs.meta │ ├── Prefabs.meta │ ├── Prefabs │ ├── Example.prefab │ ├── Example.prefab.meta │ ├── GameObjects.prefab │ ├── GameObjects.prefab.meta │ ├── NameOverride 1.prefab │ ├── NameOverride 1.prefab.meta │ ├── NameOverride.prefab │ ├── NameOverride.prefab.meta │ ├── NestedExample 1.prefab │ ├── NestedExample 1.prefab.meta │ ├── NestedExample.prefab │ ├── NestedExample.prefab.meta │ ├── Recursion.prefab │ ├── Recursion.prefab.meta │ ├── ScriptableObject Example 1.asset │ ├── ScriptableObject Example 1.asset.meta │ ├── ScriptableObject Example 2.asset │ ├── ScriptableObject Example 2.asset.meta │ ├── SurrogateTest.prefab │ └── SurrogateTest.prefab.meta │ ├── ReorderablePrefabs.unity │ ├── ReorderablePrefabs.unity.meta │ ├── Runtime.meta │ └── Runtime │ ├── Example.cs │ ├── Example.cs.meta │ ├── GameObjectExample.cs │ ├── GameObjectExample.cs.meta │ ├── NameOverride.cs │ ├── NameOverride.cs.meta │ ├── NestedExample.cs │ ├── NestedExample.cs.meta │ ├── RecursionTest.cs │ ├── RecursionTest.cs.meta │ ├── ScriptableObjectExample.cs │ ├── ScriptableObjectExample.cs.meta │ ├── SurrogateTest.cs │ └── SurrogateTest.cs.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /[Pp]rojectSettings/ 7 | /Assets/AssetStoreTools* 8 | /.vs/ 9 | 10 | # Autogenerated VS/MD solution and project files 11 | ExportedObj/ 12 | *.csproj 13 | *.unityproj 14 | *.sln 15 | *.suo 16 | *.tmp 17 | *.user 18 | *.userprefs 19 | *.pidb 20 | *.booproj 21 | *.svd 22 | 23 | 24 | # Unity3D generated meta files 25 | *.pidb.meta 26 | 27 | # Unity3D Generated File On Crash Reports 28 | sysinfo.txt 29 | 30 | # Builds 31 | *.apk 32 | *.unitypackage 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this package will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.0.1] - 2020-05-26 8 | 9 | ### Changed 10 | - Changed namespace from Malee and Malee.Editor to Malee.List. 11 | 12 | ## [1.0.0] - 2020-05-12 13 | 14 | ### Added 15 | - Support for managed reference property type in "IsTypeExpandable" 16 | 17 | ### Changed 18 | - Improved layout and styling for 2019.3. 19 | 20 | ### Fixed 21 | - Fixed accessing EditorStyles before GUI Skin was loaded. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f3e38c242b123142a294dc60e775707 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6bc2dc710f98310489d6b4d40d9a1a7d 3 | folderAsset: yes 4 | timeCreated: 1436466600 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Editor/Malee.ReorderableList.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Malee.ReorderableList.Editor", 3 | "references": [ 4 | "GUID:d178ac4b10764814c8ae876ce6354d19" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Editor/Malee.ReorderableList.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 466d4cb32fd66ef4f99747d4eb7191d9 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/ReorderableDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace Malee.List { 6 | 7 | [CustomPropertyDrawer(typeof(ReorderableAttribute))] 8 | public class ReorderableDrawer : PropertyDrawer { 9 | 10 | public const string ARRAY_PROPERTY_NAME = "array"; 11 | 12 | private static Dictionary lists = new Dictionary(); 13 | 14 | public override bool CanCacheInspectorGUI(SerializedProperty property) { 15 | 16 | return false; 17 | } 18 | 19 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { 20 | 21 | ReorderableList list = GetList(property, attribute as ReorderableAttribute, ARRAY_PROPERTY_NAME); 22 | 23 | return list != null ? list.GetHeight() : EditorGUIUtility.singleLineHeight; 24 | } 25 | 26 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { 27 | 28 | ReorderableList list = GetList(property, attribute as ReorderableAttribute, ARRAY_PROPERTY_NAME); 29 | 30 | if (list != null) { 31 | 32 | list.DoList(EditorGUI.IndentedRect(position), label); 33 | } 34 | else { 35 | 36 | GUI.Label(position, "Array must extend from ReorderableArray", EditorStyles.label); 37 | } 38 | } 39 | 40 | public static int GetListId(SerializedProperty property) { 41 | 42 | if (property != null) { 43 | 44 | int h1 = property.serializedObject.targetObject.GetHashCode(); 45 | int h2 = property.propertyPath.GetHashCode(); 46 | 47 | return (((h1 << 5) + h1) ^ h2); 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | public static ReorderableList GetList(SerializedProperty property, string arrayPropertyName) { 54 | 55 | return GetList(property, null, GetListId(property), arrayPropertyName); 56 | } 57 | 58 | public static ReorderableList GetList(SerializedProperty property, ReorderableAttribute attrib, string arrayPropertyName) { 59 | 60 | return GetList(property, attrib, GetListId(property), arrayPropertyName); 61 | } 62 | 63 | public static ReorderableList GetList(SerializedProperty property, int id, string arrayPropertyName) { 64 | 65 | return GetList(property, null, id, arrayPropertyName); 66 | } 67 | 68 | public static ReorderableList GetList(SerializedProperty property, ReorderableAttribute attrib, int id, string arrayPropertyName) { 69 | 70 | if (property == null) { 71 | 72 | return null; 73 | } 74 | 75 | ReorderableList list = null; 76 | SerializedProperty array = property.FindPropertyRelative(arrayPropertyName); 77 | 78 | if (array != null && array.isArray) { 79 | 80 | if (!lists.TryGetValue(id, out list)) { 81 | 82 | if (attrib != null) { 83 | 84 | Texture icon = !string.IsNullOrEmpty(attrib.elementIconPath) ? AssetDatabase.GetCachedIcon(attrib.elementIconPath) : null; 85 | 86 | ReorderableList.ElementDisplayType displayType = attrib.singleLine ? ReorderableList.ElementDisplayType.SingleLine : ReorderableList.ElementDisplayType.Auto; 87 | 88 | list = new ReorderableList(array, attrib.add, attrib.remove, attrib.draggable, displayType, attrib.elementNameProperty, attrib.elementNameOverride, icon); 89 | list.paginate = attrib.paginate; 90 | list.pageSize = attrib.pageSize; 91 | list.sortable = attrib.sortable; 92 | list.elementLabels = attrib.labels; 93 | 94 | //handle surrogate if any 95 | 96 | if (attrib.surrogateType != null) { 97 | 98 | SurrogateCallback callback = new SurrogateCallback(attrib.surrogateProperty); 99 | 100 | list.surrogate = new ReorderableList.Surrogate(attrib.surrogateType, callback.SetReference); 101 | } 102 | } 103 | else { 104 | 105 | list = new ReorderableList(array, true, true, true); 106 | } 107 | 108 | lists.Add(id, list); 109 | } 110 | else { 111 | 112 | list.List = array; 113 | } 114 | } 115 | 116 | return list; 117 | } 118 | 119 | private struct SurrogateCallback { 120 | 121 | private string property; 122 | 123 | internal SurrogateCallback(string property) { 124 | 125 | this.property = property; 126 | } 127 | 128 | internal void SetReference(SerializedProperty element, Object objectReference, ReorderableList list) { 129 | 130 | SerializedProperty prop = !string.IsNullOrEmpty(property) ? element.FindPropertyRelative(property) : null; 131 | 132 | if (prop != null && prop.propertyType == SerializedPropertyType.ObjectReference) { 133 | 134 | prop.objectReferenceValue = objectReference; 135 | } 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Editor/ReorderableDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b5cb2f0917b1f34f8aceb725a71bfe7 3 | timeCreated: 1491846866 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Editor/ReorderableList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Malee.List { 9 | 10 | public class ReorderableList { 11 | 12 | #if UNITY_2019_3_OR_NEWER 13 | private const float ELEMENT_EDGE_TOP = 1; 14 | private const float ELEMENT_EDGE_BOT = 2; 15 | #else 16 | private const float ELEMENT_EDGE_TOP = 1; 17 | private const float ELEMENT_EDGE_BOT = 3; 18 | #endif 19 | private const float ELEMENT_HEIGHT_OFFSET = ELEMENT_EDGE_TOP + ELEMENT_EDGE_BOT; 20 | 21 | private static int selectionHash = "ReorderableListSelection".GetHashCode(); 22 | private static int dragAndDropHash = "ReorderableListDragAndDrop".GetHashCode(); 23 | 24 | private const string EMPTY_LABEL = "List is Empty"; 25 | private const string ARRAY_ERROR = "{0} is not an Array!"; 26 | 27 | public enum ElementDisplayType { 28 | Auto, 29 | Expandable, 30 | SingleLine 31 | } 32 | 33 | public delegate void DrawHeaderDelegate(Rect rect, GUIContent label); 34 | public delegate void DrawFooterDelegate(Rect rect); 35 | public delegate void DrawElementDelegate(Rect rect, SerializedProperty element, GUIContent label, bool selected, bool focused); 36 | public delegate void ActionDelegate(ReorderableList list); 37 | public delegate bool ActionBoolDelegate(ReorderableList list); 38 | public delegate void AddDropdownDelegate(Rect buttonRect, ReorderableList list); 39 | public delegate Object DragDropReferenceDelegate(Object[] references, ReorderableList list); 40 | public delegate void DragDropAppendDelegate(Object reference, ReorderableList list); 41 | public delegate float GetElementHeightDelegate(SerializedProperty element); 42 | public delegate float GetElementsHeightDelegate(ReorderableList list); 43 | public delegate string GetElementNameDelegate(SerializedProperty element); 44 | public delegate GUIContent GetElementLabelDelegate(SerializedProperty element); 45 | public delegate void SurrogateCallback(SerializedProperty element, Object objectReference, ReorderableList list); 46 | 47 | public event DrawHeaderDelegate drawHeaderCallback; 48 | public event DrawFooterDelegate drawFooterCallback; 49 | public event DrawElementDelegate drawElementCallback; 50 | public event DrawElementDelegate drawElementBackgroundCallback; 51 | public event GetElementHeightDelegate getElementHeightCallback; 52 | public event GetElementsHeightDelegate getElementsHeightCallback; 53 | public event GetElementNameDelegate getElementNameCallback; 54 | public event GetElementLabelDelegate getElementLabelCallback; 55 | public event DragDropReferenceDelegate onValidateDragAndDropCallback; 56 | public event DragDropAppendDelegate onAppendDragDropCallback; 57 | public event ActionDelegate onReorderCallback; 58 | public event ActionDelegate onSelectCallback; 59 | public event ActionDelegate onAddCallback; 60 | public event AddDropdownDelegate onAddDropdownCallback; 61 | public event ActionDelegate onRemoveCallback; 62 | public event ActionDelegate onMouseUpCallback; 63 | public event ActionBoolDelegate onCanRemoveCallback; 64 | public event ActionDelegate onChangedCallback; 65 | 66 | public bool canAdd; 67 | public bool canRemove; 68 | public bool draggable; 69 | public bool sortable; 70 | public bool expandable; 71 | public bool multipleSelection; 72 | public GUIContent label; 73 | public float headerHeight; 74 | public float footerHeight; 75 | public float paginationHeight; 76 | public float slideEasing; 77 | public float verticalSpacing; 78 | public bool showDefaultBackground; 79 | public ElementDisplayType elementDisplayType; 80 | public string elementNameProperty; 81 | public string elementNameOverride; 82 | public bool elementLabels; 83 | public Texture elementIcon; 84 | public Surrogate surrogate; 85 | 86 | public bool paginate { 87 | 88 | get { return pagination.enabled; } 89 | set { pagination.enabled = value; } 90 | } 91 | 92 | public int pageSize { 93 | 94 | get { return pagination.fixedPageSize; } 95 | set { pagination.fixedPageSize = value; } 96 | } 97 | 98 | internal readonly int id; 99 | 100 | private SerializedProperty list; 101 | private int controlID = -1; 102 | private Rect[] elementRects; 103 | private GUIContent elementLabel; 104 | private GUIContent pageInfoContent; 105 | private GUIContent pageSizeContent; 106 | private ListSelection selection; 107 | private SlideGroup slideGroup; 108 | private int pressIndex; 109 | 110 | private bool doPagination { 111 | 112 | get { return pagination.enabled && !list.serializedObject.isEditingMultipleObjects; } 113 | } 114 | 115 | private float elementSpacing { 116 | 117 | get { return Mathf.Max(0, verticalSpacing - 2); } 118 | } 119 | 120 | private bool dragging; 121 | private float pressPosition; 122 | private float dragPosition; 123 | private int dragDirection; 124 | private DragList dragList; 125 | private ListSelection beforeDragSelection; 126 | private Pagination pagination; 127 | 128 | private int dragDropControlID = -1; 129 | 130 | public ReorderableList(SerializedProperty list) 131 | : this(list, true, true, true) { 132 | } 133 | 134 | public ReorderableList(SerializedProperty list, bool canAdd, bool canRemove, bool draggable) 135 | : this(list, canAdd, canRemove, draggable, ElementDisplayType.Auto, null, null, null) { 136 | } 137 | 138 | public ReorderableList(SerializedProperty list, bool canAdd, bool canRemove, bool draggable, ElementDisplayType elementDisplayType, string elementNameProperty, Texture elementIcon) 139 | : this(list, canAdd, canRemove, draggable, elementDisplayType, elementNameProperty, null, elementIcon) { 140 | } 141 | 142 | public ReorderableList(SerializedProperty list, bool canAdd, bool canRemove, bool draggable, ElementDisplayType elementDisplayType, string elementNameProperty, string elementNameOverride, Texture elementIcon) { 143 | 144 | if (list == null) { 145 | 146 | throw new MissingListExeption(); 147 | } 148 | else if (!list.isArray) { 149 | 150 | //check if user passed in a ReorderableArray, if so, that becomes the list object 151 | 152 | SerializedProperty array = list.FindPropertyRelative("array"); 153 | 154 | if (array == null || !array.isArray) { 155 | 156 | throw new InvalidListException(); 157 | } 158 | 159 | this.list = array; 160 | } 161 | else { 162 | 163 | this.list = list; 164 | } 165 | 166 | this.canAdd = canAdd; 167 | this.canRemove = canRemove; 168 | this.draggable = draggable; 169 | this.elementDisplayType = elementDisplayType; 170 | this.elementNameProperty = elementNameProperty; 171 | this.elementNameOverride = elementNameOverride; 172 | this.elementIcon = elementIcon; 173 | 174 | id = GetHashCode(); 175 | list.isExpanded = true; 176 | label = new GUIContent(list.displayName); 177 | pageInfoContent = new GUIContent(); 178 | pageSizeContent = new GUIContent(); 179 | 180 | #if UNITY_5_6_OR_NEWER 181 | verticalSpacing = EditorGUIUtility.standardVerticalSpacing; 182 | #else 183 | verticalSpacing = 2f; 184 | #endif 185 | slideEasing = 0.15f; 186 | expandable = true; 187 | elementLabels = true; 188 | showDefaultBackground = true; 189 | multipleSelection = true; 190 | pagination = new Pagination(); 191 | elementLabel = new GUIContent(); 192 | 193 | dragList = new DragList(0); 194 | selection = new ListSelection(); 195 | slideGroup = new SlideGroup(); 196 | elementRects = new Rect[0]; 197 | 198 | //We can't access Style information yet as GUISkin hasn't loaded, so hard code the values 199 | 200 | #if UNITY_2019_3_OR_NEWER 201 | headerHeight = 20f; 202 | footerHeight = 20f; 203 | paginationHeight = 18f; 204 | #else 205 | headerHeight = 20f; 206 | footerHeight = 13f; 207 | paginationHeight = 20f; 208 | #endif 209 | } 210 | 211 | // 212 | // -- PROPERTIES -- 213 | // 214 | 215 | public SerializedProperty List { 216 | 217 | get { return list; } 218 | internal set { list = value; } 219 | } 220 | 221 | public bool HasList { 222 | 223 | get { return list != null && list.isArray; } 224 | } 225 | 226 | public int Length { 227 | 228 | get { 229 | 230 | if (!HasList) { 231 | 232 | return 0; 233 | } 234 | else if (!list.hasMultipleDifferentValues) { 235 | 236 | return list.arraySize; 237 | } 238 | 239 | //When multiple objects are selected, because of a Unity bug, list.arraySize is never guranteed to actually be the smallest 240 | //array size. So we have to find it. Not that great since we're creating SerializedObjects here. There has to be a better way! 241 | 242 | int smallerArraySize = list.arraySize; 243 | 244 | foreach (Object targetObject in list.serializedObject.targetObjects) { 245 | 246 | SerializedObject serializedObject = new SerializedObject(targetObject); 247 | SerializedProperty property = serializedObject.FindProperty(list.propertyPath); 248 | 249 | smallerArraySize = Mathf.Min(property.arraySize, smallerArraySize); 250 | } 251 | 252 | return smallerArraySize; 253 | } 254 | } 255 | 256 | public int VisibleLength { 257 | 258 | get { return pagination.GetVisibleLength(Length); } 259 | } 260 | 261 | public int[] Selected { 262 | 263 | get { return selection.ToArray(); } 264 | set { selection = new ListSelection(value); } 265 | } 266 | 267 | public int Index { 268 | 269 | get { return selection.First; } 270 | set { selection.Select(value); } 271 | } 272 | 273 | public bool IsDragging { 274 | 275 | get { return dragging; } 276 | } 277 | 278 | // 279 | // -- PUBLIC -- 280 | // 281 | 282 | public float GetHeight() { 283 | 284 | if (HasList) { 285 | 286 | float topHeight = doPagination ? headerHeight + paginationHeight : headerHeight; 287 | 288 | return list.isExpanded ? topHeight + GetElementsHeight() + footerHeight : headerHeight; 289 | } 290 | else { 291 | 292 | return EditorGUIUtility.singleLineHeight; 293 | } 294 | } 295 | 296 | public float GetElementHeight(int index) { 297 | 298 | return index >= 0 && index < Length ? GetElementHeight(list.GetArrayElementAtIndex(index)) : 0; 299 | } 300 | 301 | public void DoLayoutList() { 302 | 303 | Rect position = EditorGUILayout.GetControlRect(false, GetHeight(), EditorStyles.largeLabel); 304 | 305 | DoList(EditorGUI.IndentedRect(position), label); 306 | } 307 | 308 | public void DoList(Rect rect, GUIContent label) { 309 | 310 | int indent = EditorGUI.indentLevel; 311 | EditorGUI.indentLevel = 0; 312 | 313 | Rect headerRect = rect; 314 | headerRect.height = headerHeight; 315 | 316 | if (!HasList) { 317 | 318 | DrawEmpty(headerRect, string.Format(ARRAY_ERROR, label.text), GUIStyle.none, EditorStyles.helpBox); 319 | } 320 | else { 321 | 322 | controlID = GUIUtility.GetControlID(selectionHash, FocusType.Keyboard, rect); 323 | dragDropControlID = GUIUtility.GetControlID(dragAndDropHash, FocusType.Passive, rect); 324 | 325 | DrawHeader(headerRect, label); 326 | 327 | if (list.isExpanded) { 328 | 329 | if (doPagination) { 330 | 331 | Rect paginateHeaderRect = headerRect; 332 | paginateHeaderRect.y += headerRect.height; 333 | paginateHeaderRect.height = paginationHeight; 334 | 335 | DrawPaginationHeader(paginateHeaderRect); 336 | 337 | #if UNITY_2019_3_OR_NEWER 338 | headerRect.yMax = paginateHeaderRect.yMax; 339 | #else 340 | headerRect.yMax = paginateHeaderRect.yMax - 1; 341 | #endif 342 | } 343 | 344 | Rect elementBackgroundRect = rect; 345 | elementBackgroundRect.yMin = headerRect.yMax; 346 | elementBackgroundRect.yMax = rect.yMax - footerHeight; 347 | 348 | Event evt = Event.current; 349 | 350 | if (selection.Length > 1) { 351 | 352 | if (evt.type == EventType.ContextClick && CanSelect(evt.mousePosition)) { 353 | 354 | HandleMultipleContextClick(evt); 355 | } 356 | } 357 | 358 | if (Length > 0) { 359 | 360 | //update element rects if not dragging. Dragging caches draw rects so no need to update 361 | 362 | if (!dragging) { 363 | 364 | UpdateElementRects(elementBackgroundRect, evt); 365 | } 366 | 367 | if (elementRects.Length > 0) { 368 | 369 | int start, end; 370 | 371 | pagination.GetVisibleRange(elementRects.Length, out start, out end); 372 | 373 | Rect selectableRect = elementBackgroundRect; 374 | selectableRect.yMin = elementRects[start].yMin; 375 | selectableRect.yMax = elementRects[end - 1].yMax; 376 | 377 | HandlePreSelection(selectableRect, evt); 378 | DrawElements(elementBackgroundRect, evt); 379 | HandlePostSelection(selectableRect, evt); 380 | } 381 | } 382 | else { 383 | 384 | DrawEmpty(elementBackgroundRect, EMPTY_LABEL, Style.boxBackground, Style.verticalLabel); 385 | } 386 | 387 | Rect footerRect = rect; 388 | footerRect.yMin = elementBackgroundRect.yMax; 389 | footerRect.xMin = rect.xMax - 58; 390 | footerRect.height = footerHeight; 391 | 392 | DrawFooter(footerRect); 393 | } 394 | } 395 | 396 | EditorGUI.indentLevel = indent; 397 | } 398 | 399 | public SerializedProperty AddItem(T item) where T : Object { 400 | 401 | SerializedProperty property = AddItem(); 402 | 403 | if (property != null) { 404 | 405 | property.objectReferenceValue = item; 406 | } 407 | 408 | return property; 409 | } 410 | 411 | public SerializedProperty AddItem() { 412 | 413 | if (HasList) { 414 | 415 | list.arraySize++; 416 | selection.Select(list.arraySize - 1); 417 | 418 | SetPageByIndex(list.arraySize - 1); 419 | DispatchChange(); 420 | 421 | return list.GetArrayElementAtIndex(selection.Last); 422 | } 423 | else { 424 | 425 | throw new InvalidListException(); 426 | } 427 | } 428 | 429 | public void Remove(int[] selection) { 430 | 431 | System.Array.Sort(selection); 432 | 433 | int i = selection.Length; 434 | 435 | while (--i > -1) { 436 | 437 | RemoveItem(selection[i]); 438 | } 439 | } 440 | 441 | public void RemoveItem(int index) { 442 | 443 | if (index >= 0 && index < Length) { 444 | 445 | SerializedProperty property = list.GetArrayElementAtIndex(index); 446 | 447 | if (property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue) { 448 | 449 | property.objectReferenceValue = null; 450 | } 451 | 452 | list.DeleteArrayElementAtIndex(index); 453 | selection.Remove(index); 454 | 455 | if (Length > 0) { 456 | 457 | selection.Select(Mathf.Max(0, index - 1)); 458 | } 459 | 460 | DispatchChange(); 461 | } 462 | } 463 | 464 | public SerializedProperty GetItem(int index) { 465 | 466 | if (index >= 0 && index < Length) { 467 | 468 | return list.GetArrayElementAtIndex(index); 469 | } 470 | else { 471 | 472 | return null; 473 | } 474 | } 475 | 476 | public int IndexOf(SerializedProperty element) { 477 | 478 | if (element != null) { 479 | 480 | int i = Length; 481 | 482 | while (--i > -1) { 483 | 484 | if (SerializedProperty.EqualContents(element, list.GetArrayElementAtIndex(i))) { 485 | 486 | return i; 487 | } 488 | } 489 | } 490 | 491 | return -1; 492 | } 493 | 494 | public void GrabKeyboardFocus() { 495 | 496 | GUIUtility.keyboardControl = id; 497 | } 498 | 499 | public bool HasKeyboardControl() { 500 | 501 | return GUIUtility.keyboardControl == id; 502 | } 503 | 504 | public void ReleaseKeyboardFocus() { 505 | 506 | if (GUIUtility.keyboardControl == id) { 507 | 508 | GUIUtility.keyboardControl = 0; 509 | } 510 | } 511 | 512 | public void SetPage(int page) { 513 | 514 | if (doPagination) { 515 | 516 | pagination.page = page; 517 | } 518 | } 519 | 520 | public void SetPageByIndex(int index) { 521 | 522 | if (doPagination) { 523 | 524 | pagination.page = pagination.GetPageForIndex(index); 525 | } 526 | } 527 | 528 | public int GetPage(int index) { 529 | 530 | return doPagination ? pagination.page : 0; 531 | } 532 | 533 | public int GetPageByIndex(int index) { 534 | 535 | return doPagination ? pagination.GetPageForIndex(index) : 0; 536 | } 537 | 538 | // 539 | // -- PRIVATE -- 540 | // 541 | 542 | private float GetElementsHeight() { 543 | 544 | if (getElementsHeightCallback != null) { 545 | 546 | return getElementsHeightCallback(this); 547 | } 548 | 549 | int i, len = Length; 550 | 551 | if (len == 0) { 552 | 553 | return 28; 554 | } 555 | 556 | float totalHeight = 0; 557 | float spacing = elementSpacing; 558 | 559 | int start, end; 560 | 561 | pagination.GetVisibleRange(len, out start, out end); 562 | 563 | for (i = start; i < end; i++) { 564 | 565 | totalHeight += GetElementHeight(list.GetArrayElementAtIndex(i)) + spacing; 566 | } 567 | 568 | return totalHeight + 7 - spacing; 569 | } 570 | 571 | private float GetElementHeight(SerializedProperty element) { 572 | 573 | if (getElementHeightCallback != null) { 574 | 575 | return getElementHeightCallback(element) + ELEMENT_HEIGHT_OFFSET; 576 | } 577 | else { 578 | 579 | return EditorGUI.GetPropertyHeight(element, GetElementLabel(element, elementLabels), IsElementExpandable(element)) + ELEMENT_HEIGHT_OFFSET; 580 | } 581 | } 582 | 583 | private Rect GetElementDrawRect(int index, Rect desiredRect) { 584 | 585 | if (slideEasing <= 0) { 586 | 587 | return desiredRect; 588 | } 589 | else { 590 | 591 | //lerp the drag easing toward slide easing, this creates a stronger easing at the start then slower at the end 592 | //when dealing with large lists, we can 593 | 594 | return dragging ? slideGroup.GetRect(dragList[index].startIndex, desiredRect, slideEasing) : slideGroup.SetRect(index, desiredRect); 595 | } 596 | } 597 | 598 | /* 599 | private Rect GetElementHeaderRect(SerializedProperty element, Rect elementRect) { 600 | 601 | Rect rect = elementRect; 602 | rect.height = EditorGUIUtility.singleLineHeight + verticalSpacing; 603 | 604 | return rect; 605 | } 606 | */ 607 | 608 | private Rect GetElementRenderRect(SerializedProperty element, Rect elementRect) { 609 | 610 | float offset = draggable ? 20 : 5; 611 | 612 | Rect rect = elementRect; 613 | rect.xMin += IsElementExpandable(element) ? offset + 10 : offset; 614 | rect.xMax -= 5; 615 | rect.yMin += ELEMENT_EDGE_TOP; 616 | rect.yMax -= ELEMENT_EDGE_BOT; 617 | 618 | return rect; 619 | } 620 | 621 | private void DrawHeader(Rect rect, GUIContent label) { 622 | 623 | if (showDefaultBackground && Event.current.type == EventType.Repaint) { 624 | 625 | Style.headerBackground.Draw(rect, false, false, false, false); 626 | } 627 | 628 | HandleDragAndDrop(rect, Event.current); 629 | 630 | bool multiline = elementDisplayType != ElementDisplayType.SingleLine; 631 | 632 | Rect titleRect = rect; 633 | titleRect.xMin += 6f; 634 | titleRect.xMax -= multiline ? 95f : 55f; 635 | 636 | label = EditorGUI.BeginProperty(titleRect, label, list); 637 | 638 | if (drawHeaderCallback != null) { 639 | 640 | drawHeaderCallback(titleRect, label); 641 | } 642 | else if (expandable) { 643 | 644 | titleRect.xMin += 10; 645 | 646 | EditorGUI.BeginChangeCheck(); 647 | 648 | bool isExpanded = EditorGUI.Foldout(titleRect, list.isExpanded, label, true); 649 | 650 | if (EditorGUI.EndChangeCheck()) { 651 | 652 | list.isExpanded = isExpanded; 653 | } 654 | } 655 | else { 656 | 657 | GUI.Label(titleRect, label, EditorStyles.label); 658 | } 659 | 660 | EditorGUI.EndProperty(); 661 | 662 | if (multiline) { 663 | 664 | Rect bRect1 = rect; 665 | bRect1.xMin = rect.xMax - 25; 666 | bRect1.xMax = rect.xMax - 5; 667 | 668 | if (GUI.Button(bRect1, Style.expandButton, Style.preButtonStretch)) { 669 | 670 | ExpandElements(true); 671 | } 672 | 673 | Rect bRect2 = rect; 674 | bRect2.xMin = bRect1.xMin - 20; 675 | bRect2.xMax = bRect1.xMin; 676 | 677 | if (GUI.Button(bRect2, Style.collapseButton, Style.preButtonStretch)) { 678 | 679 | ExpandElements(false); 680 | } 681 | 682 | rect.xMax = bRect2.xMin + 5; 683 | } 684 | 685 | //draw sorting options 686 | 687 | if (sortable) { 688 | 689 | Rect sortRect1 = rect; 690 | sortRect1.xMin = rect.xMax - 25; 691 | sortRect1.xMax = rect.xMax; 692 | 693 | Rect sortRect2 = rect; 694 | sortRect2.xMin = sortRect1.xMin - 20; 695 | sortRect2.xMax = sortRect1.xMin; 696 | 697 | if (EditorGUI.DropdownButton(sortRect1, Style.sortAscending, FocusType.Passive, Style.preButtonStretch)) { 698 | 699 | SortElements(sortRect1, false); 700 | } 701 | 702 | if (EditorGUI.DropdownButton(sortRect2, Style.sortDescending, FocusType.Passive, Style.preButtonStretch)) { 703 | 704 | SortElements(sortRect2, true); 705 | } 706 | } 707 | } 708 | 709 | private void ExpandElements(bool expand) { 710 | 711 | if (!list.isExpanded && expand) { 712 | 713 | list.isExpanded = true; 714 | } 715 | 716 | int i, len = Length; 717 | 718 | for (i = 0; i < len; i++) { 719 | 720 | list.GetArrayElementAtIndex(i).isExpanded = expand; 721 | } 722 | } 723 | 724 | private void SortElements(Rect rect, bool descending) { 725 | 726 | int total = Length; 727 | 728 | //no point in sorting a list with 1 element! 729 | 730 | if (total <= 1) { 731 | 732 | return; 733 | } 734 | 735 | //the first property tells us what type of items are in the list 736 | //if generic, then we give the user a list of properties to sort on 737 | 738 | SerializedProperty prop = list.GetArrayElementAtIndex(0); 739 | 740 | if (prop.propertyType == SerializedPropertyType.Generic) { 741 | 742 | GenericMenu menu = new GenericMenu(); 743 | 744 | SerializedProperty property = prop.Copy(); 745 | SerializedProperty end = property.GetEndProperty(); 746 | 747 | bool enterChildren = true; 748 | 749 | while (property.NextVisible(enterChildren) && !SerializedProperty.EqualContents(property, end)) { 750 | 751 | menu.AddItem(new GUIContent(property.name), false, userData => { 752 | 753 | //sort based on the property selected then apply the changes 754 | 755 | ListSort.SortOnProperty(list, total, descending, (string)userData); 756 | 757 | ApplyReorder(); 758 | 759 | HandleUtility.Repaint(); 760 | 761 | }, property.name); 762 | 763 | enterChildren = false; 764 | } 765 | 766 | menu.DropDown(rect); 767 | } 768 | else { 769 | 770 | //list is not generic, so we just sort directly on the type then apply the changes 771 | 772 | ListSort.SortOnType(list, total, descending, prop.propertyType); 773 | 774 | ApplyReorder(); 775 | } 776 | } 777 | 778 | private void DrawEmpty(Rect rect, string label, GUIStyle backgroundStyle, GUIStyle labelStyle) { 779 | 780 | if (showDefaultBackground && Event.current.type == EventType.Repaint) { 781 | 782 | backgroundStyle.Draw(rect, false, false, false, false); 783 | } 784 | 785 | EditorGUI.LabelField(rect, label, labelStyle); 786 | } 787 | 788 | private void UpdateElementRects(Rect rect, Event evt) { 789 | 790 | //resize array if elements changed 791 | 792 | int i, len = Length; 793 | 794 | if (len != elementRects.Length) { 795 | 796 | System.Array.Resize(ref elementRects, len); 797 | } 798 | 799 | if (evt.type == EventType.Repaint) { 800 | 801 | //start rect 802 | 803 | Rect elementRect = rect; 804 | elementRect.yMin = elementRect.yMax = rect.yMin + 2; 805 | 806 | float spacing = elementSpacing; 807 | 808 | int start, end; 809 | 810 | pagination.GetVisibleRange(len, out start, out end); 811 | 812 | for (i = start; i < end; i++) { 813 | 814 | SerializedProperty element = list.GetArrayElementAtIndex(i); 815 | 816 | //update the elementRects value for this object. Grab the last elementRect for startPosition 817 | 818 | elementRect.y = elementRect.yMax; 819 | elementRect.height = GetElementHeight(element); 820 | elementRects[i] = elementRect; 821 | 822 | elementRect.yMax += spacing; 823 | } 824 | } 825 | } 826 | 827 | private void DrawElements(Rect rect, Event evt) { 828 | 829 | //draw list background 830 | 831 | if (showDefaultBackground && evt.type == EventType.Repaint) { 832 | 833 | Style.boxBackground.Draw(rect, false, false, false, false); 834 | } 835 | 836 | //if not dragging, draw elements as usual 837 | 838 | if (!dragging) { 839 | 840 | int start, end; 841 | 842 | pagination.GetVisibleRange(Length, out start, out end); 843 | 844 | for (int i = start; i < end; i++) { 845 | 846 | bool selected = selection.Contains(i); 847 | 848 | DrawElement(list.GetArrayElementAtIndex(i), GetElementDrawRect(i, elementRects[i]), selected, selected && GUIUtility.keyboardControl == controlID); 849 | } 850 | } 851 | else if (evt.type == EventType.Repaint) { 852 | 853 | //draw dragging elements only when repainting 854 | 855 | int i, s, len = dragList.Length; 856 | int sLen = selection.Length; 857 | 858 | //first, find the rects of the selected elements, we need to use them for overlap queries 859 | 860 | for (i = 0; i < sLen; i++) { 861 | 862 | DragElement element = dragList[i]; 863 | 864 | //update the element desiredRect if selected. Selected elements appear first in the dragList, so other elements later in iteration will have rects to compare 865 | 866 | element.desiredRect.y = dragPosition - element.dragOffset; 867 | dragList[i] = element; 868 | } 869 | 870 | //draw elements, start from the bottom of the list as first elements are the ones selected, so should be drawn last 871 | 872 | i = len; 873 | 874 | while (--i > -1) { 875 | 876 | DragElement element = dragList[i]; 877 | 878 | //draw dragging elements last as the loop is backwards 879 | 880 | if (element.selected) { 881 | 882 | DrawElement(element.property, element.desiredRect, true, true); 883 | continue; 884 | } 885 | 886 | //loop over selection and see what overlaps 887 | //if dragging down we start from the bottom of the selection 888 | //otherwise we start from the top. This helps to cover multiple selected objects 889 | 890 | Rect elementRect = element.rect; 891 | int elementIndex = element.startIndex; 892 | 893 | int start = dragDirection > 0 ? sLen - 1 : 0; 894 | int end = dragDirection > 0 ? -1 : sLen; 895 | 896 | for (s = start; s != end; s -= dragDirection) { 897 | 898 | DragElement selected = dragList[s]; 899 | 900 | if (selected.Overlaps(elementRect, elementIndex, dragDirection)) { 901 | 902 | elementRect.y -= selected.rect.height * dragDirection; 903 | elementIndex += dragDirection; 904 | } 905 | } 906 | 907 | //draw the element with the new rect 908 | 909 | DrawElement(element.property, GetElementDrawRect(i, elementRect), false, false); 910 | 911 | //reassign the element back into the dragList 912 | 913 | element.desiredRect = elementRect; 914 | dragList[i] = element; 915 | } 916 | } 917 | } 918 | 919 | private void DrawElement(SerializedProperty element, Rect rect, bool selected, bool focused) { 920 | 921 | Rect backgroundRect = rect; 922 | 923 | #if UNITY_2019_3_OR_NEWER 924 | backgroundRect.xMin++; 925 | backgroundRect.xMax--; 926 | #endif 927 | Event evt = Event.current; 928 | 929 | if (drawElementBackgroundCallback != null) { 930 | 931 | drawElementBackgroundCallback(backgroundRect, element, null, selected, focused); 932 | } 933 | else if (evt.type == EventType.Repaint) { 934 | 935 | Style.elementBackground.Draw(backgroundRect, false, selected, selected, focused); 936 | } 937 | 938 | if (evt.type == EventType.Repaint && draggable) { 939 | 940 | Style.draggingHandle.Draw(new Rect(rect.x + 5, rect.y + 6, 10, rect.height - (rect.height - 6)), false, false, false, false); 941 | } 942 | 943 | GUIContent label = GetElementLabel(element, elementLabels); 944 | 945 | Rect renderRect = GetElementRenderRect(element, rect); 946 | 947 | if (drawElementCallback != null) { 948 | 949 | drawElementCallback(renderRect, element, label, selected, focused); 950 | } 951 | else { 952 | 953 | EditorGUI.PropertyField(renderRect, element, label, true); 954 | } 955 | 956 | //handle context click 957 | 958 | int controlId = GUIUtility.GetControlID(label, FocusType.Passive, rect); 959 | 960 | switch (evt.GetTypeForControl(controlId)) { 961 | 962 | case EventType.ContextClick: 963 | 964 | if (rect.Contains(evt.mousePosition)) { 965 | 966 | HandleSingleContextClick(evt, element); 967 | } 968 | 969 | break; 970 | } 971 | } 972 | 973 | private GUIContent GetElementLabel(SerializedProperty element, bool allowElementLabel) { 974 | 975 | if (!allowElementLabel) { 976 | 977 | return GUIContent.none; 978 | } 979 | else if (getElementLabelCallback != null) { 980 | 981 | return getElementLabelCallback(element); 982 | } 983 | 984 | string name; 985 | 986 | if (getElementNameCallback != null) { 987 | 988 | name = getElementNameCallback(element); 989 | } 990 | else { 991 | 992 | name = GetElementName(element, elementNameProperty, elementNameOverride); 993 | } 994 | 995 | elementLabel.text = !string.IsNullOrEmpty(name) ? name : element.displayName; 996 | elementLabel.tooltip = element.tooltip; 997 | elementLabel.image = elementIcon; 998 | 999 | return elementLabel; 1000 | } 1001 | 1002 | private static string GetElementName(SerializedProperty element, string nameProperty, string nameOverride) { 1003 | 1004 | if (!string.IsNullOrEmpty(nameOverride)) { 1005 | 1006 | string path = element.propertyPath; 1007 | 1008 | const string arrayEndDelimeter = "]"; 1009 | const char arrayStartDelimeter = '['; 1010 | 1011 | if (path.EndsWith(arrayEndDelimeter)) { 1012 | 1013 | int startIndex = path.LastIndexOf(arrayStartDelimeter) + 1; 1014 | 1015 | return string.Format("{0} {1}", nameOverride, path.Substring(startIndex, path.Length - startIndex - 1)); 1016 | } 1017 | 1018 | return nameOverride; 1019 | } 1020 | else if (string.IsNullOrEmpty(nameProperty)) { 1021 | 1022 | return null; 1023 | } 1024 | else if (element.propertyType == SerializedPropertyType.ObjectReference && nameProperty == "name") { 1025 | 1026 | return element.objectReferenceValue ? element.objectReferenceValue.name : null; 1027 | } 1028 | 1029 | SerializedProperty prop = element.FindPropertyRelative(nameProperty); 1030 | 1031 | if (prop != null) { 1032 | 1033 | switch (prop.propertyType) { 1034 | 1035 | case SerializedPropertyType.ObjectReference: 1036 | 1037 | return prop.objectReferenceValue ? prop.objectReferenceValue.name : null; 1038 | 1039 | case SerializedPropertyType.Enum: 1040 | 1041 | return prop.enumDisplayNames[prop.enumValueIndex]; 1042 | 1043 | case SerializedPropertyType.Integer: 1044 | case SerializedPropertyType.Character: 1045 | 1046 | return prop.intValue.ToString(); 1047 | 1048 | case SerializedPropertyType.LayerMask: 1049 | 1050 | return GetLayerMaskName(prop.intValue); 1051 | 1052 | case SerializedPropertyType.String: 1053 | 1054 | return prop.stringValue; 1055 | 1056 | case SerializedPropertyType.Float: 1057 | 1058 | return prop.floatValue.ToString(); 1059 | } 1060 | 1061 | return prop.displayName; 1062 | } 1063 | 1064 | return null; 1065 | } 1066 | 1067 | private static string GetLayerMaskName(int mask) { 1068 | 1069 | if (mask == 0) { 1070 | 1071 | return "Nothing"; 1072 | } 1073 | else if (mask < 0) { 1074 | 1075 | return "Everything"; 1076 | } 1077 | 1078 | string name = string.Empty; 1079 | int n = 0; 1080 | 1081 | for (int i = 0; i < 32; i++) { 1082 | 1083 | if (((1 << i) & mask) != 0) { 1084 | 1085 | if (n == 4) { 1086 | 1087 | return "Mixed ..."; 1088 | } 1089 | 1090 | name += (n > 0 ? ", " : string.Empty) + LayerMask.LayerToName(i); 1091 | n++; 1092 | } 1093 | } 1094 | 1095 | return name; 1096 | } 1097 | 1098 | private void DrawFooter(Rect rect) { 1099 | 1100 | if (drawFooterCallback != null) { 1101 | 1102 | drawFooterCallback(rect); 1103 | return; 1104 | } 1105 | 1106 | if (Event.current.type == EventType.Repaint) { 1107 | 1108 | Style.footerBackground.Draw(rect, false, false, false, false); 1109 | } 1110 | 1111 | Rect addRect = new Rect(rect.xMin + 4f, rect.y, 25f, Style.preButton.fixedHeight); 1112 | Rect subRect = new Rect(rect.xMax - 29f, rect.y, 25f, Style.preButton.fixedHeight); 1113 | 1114 | EditorGUI.BeginDisabledGroup(!canAdd); 1115 | 1116 | if (GUI.Button(addRect, onAddDropdownCallback != null ? Style.iconToolbarPlusMore : Style.iconToolbarPlus, Style.preButton)) { 1117 | 1118 | if (onAddDropdownCallback != null) { 1119 | 1120 | onAddDropdownCallback(addRect, this); 1121 | } 1122 | else if (onAddCallback != null) { 1123 | 1124 | onAddCallback(this); 1125 | } 1126 | else { 1127 | 1128 | AddItem(); 1129 | } 1130 | } 1131 | 1132 | EditorGUI.EndDisabledGroup(); 1133 | 1134 | EditorGUI.BeginDisabledGroup(!CanSelect(selection) || !canRemove || (onCanRemoveCallback != null && !onCanRemoveCallback(this))); 1135 | 1136 | if (GUI.Button(subRect, Style.iconToolbarMinus, Style.preButton)) { 1137 | 1138 | if (onRemoveCallback != null) { 1139 | 1140 | onRemoveCallback(this); 1141 | } 1142 | else { 1143 | 1144 | Remove(selection.ToArray()); 1145 | } 1146 | } 1147 | 1148 | EditorGUI.EndDisabledGroup(); 1149 | } 1150 | 1151 | private void DrawPaginationHeader(Rect rect) { 1152 | 1153 | int total = Length; 1154 | int pages = pagination.GetPageCount(total); 1155 | int page = Mathf.Clamp(pagination.page, 0, pages - 1); 1156 | 1157 | //some actions may have reduced the page count, so we need to check the current page against the clamped one 1158 | //if different, we need to change and repaint 1159 | 1160 | if (page != pagination.page) { 1161 | 1162 | pagination.page = page; 1163 | 1164 | HandleUtility.Repaint(); 1165 | } 1166 | 1167 | Rect prevRect = new Rect(rect.xMin + 4f, rect.y, 17f, rect.height - 1); 1168 | Rect popupRect = new Rect(prevRect.xMax, rect.y, 14f, rect.height - 1); 1169 | Rect nextRect = new Rect(popupRect.xMax, rect.y, 17f, rect.height - 1); 1170 | 1171 | if (Event.current.type == EventType.Repaint) { 1172 | 1173 | Style.paginationHeader.Draw(rect, false, true, true, false); 1174 | } 1175 | 1176 | pageInfoContent.text = string.Format(Style.PAGE_INFO_FORMAT, pagination.page + 1, pages); 1177 | 1178 | Rect pageInfoRect = rect; 1179 | pageInfoRect.xMin = rect.xMax - Style.paginationText.CalcSize(pageInfoContent).x - 7; 1180 | 1181 | //draw page info 1182 | 1183 | GUI.Label(pageInfoRect, pageInfoContent, Style.paginationText); 1184 | 1185 | //draw page buttons and page popup 1186 | 1187 | if (GUI.Button(prevRect, Style.iconPagePrev, Style.preButtonStretch)) { 1188 | 1189 | pagination.page = Mathf.Max(0, pagination.page - 1); 1190 | } 1191 | 1192 | if (EditorGUI.DropdownButton(popupRect, Style.iconPagePopup, FocusType.Passive, Style.preButtonStretch)) { 1193 | 1194 | GenericMenu menu = new GenericMenu(); 1195 | 1196 | for (int i = 0; i < pages; i++) { 1197 | 1198 | int pageIndex = i; 1199 | 1200 | menu.AddItem(new GUIContent(string.Format("Page {0}", i + 1)), i == pagination.page, OnPageDropDownSelect, pageIndex); 1201 | } 1202 | 1203 | menu.DropDown(popupRect); 1204 | } 1205 | 1206 | if (GUI.Button(nextRect, Style.iconPageNext, Style.preButtonStretch)) { 1207 | 1208 | pagination.page = Mathf.Min(pages - 1, pagination.page + 1); 1209 | } 1210 | 1211 | //if we're allowed to control the page size manually, show an editor 1212 | 1213 | bool useFixedPageSize = pagination.fixedPageSize > 0; 1214 | int currentPageSize = useFixedPageSize ? pagination.fixedPageSize : pagination.customPageSize; 1215 | 1216 | EditorGUI.BeginDisabledGroup(useFixedPageSize); 1217 | 1218 | pageSizeContent.text = currentPageSize.ToString(); 1219 | 1220 | GUIStyle style = Style.pageSizeTextField; 1221 | Texture icon = Style.listIcon.image; 1222 | 1223 | float labelWidth = icon.width + 2; 1224 | float width = style.CalcSize(pageSizeContent).x + 50; 1225 | 1226 | Rect pageSizeRect = rect; 1227 | pageSizeRect.x = rect.center.x - (width - labelWidth) / 2; 1228 | pageSizeRect.width = width; 1229 | 1230 | EditorGUI.BeginChangeCheck(); 1231 | 1232 | EditorGUIUtility.labelWidth = labelWidth; 1233 | EditorGUIUtility.SetIconSize(new Vector2(icon.width, icon.height)); 1234 | 1235 | int newPageSize = EditorGUI.DelayedIntField(pageSizeRect, Style.listIcon, currentPageSize, style); 1236 | 1237 | EditorGUIUtility.labelWidth = 0; 1238 | EditorGUIUtility.SetIconSize(Vector2.zero); 1239 | 1240 | if (EditorGUI.EndChangeCheck()) { 1241 | 1242 | pagination.customPageSize = Mathf.Clamp(newPageSize, 0, total); 1243 | pagination.page = Mathf.Min(pagination.GetPageCount(total) - 1, pagination.page); 1244 | } 1245 | 1246 | EditorGUI.EndDisabledGroup(); 1247 | } 1248 | 1249 | private void OnPageDropDownSelect(object userData) { 1250 | 1251 | pagination.page = (int)userData; 1252 | } 1253 | 1254 | private void DispatchChange() { 1255 | 1256 | if (onChangedCallback != null) { 1257 | 1258 | onChangedCallback(this); 1259 | } 1260 | } 1261 | 1262 | private void HandleSingleContextClick(Event evt, SerializedProperty element) { 1263 | 1264 | selection.Select(IndexOf(element)); 1265 | 1266 | GenericMenu menu = new GenericMenu(); 1267 | 1268 | if (element.isInstantiatedPrefab) { 1269 | 1270 | menu.AddItem(new GUIContent($"Revert { GetElementLabel(element, true).text } to Prefab"), false, selection.RevertValues, list); 1271 | menu.AddSeparator(string.Empty); 1272 | } 1273 | 1274 | HandleSharedContextClick(evt, menu, "Duplicate Array Element", "Delete Array Element", "Move Array Element"); 1275 | } 1276 | 1277 | private void HandleMultipleContextClick(Event evt) { 1278 | 1279 | GenericMenu menu = new GenericMenu(); 1280 | 1281 | if (selection.CanRevert(list)) { 1282 | 1283 | menu.AddItem(new GUIContent("Revert Values to Prefab"), false, selection.RevertValues, list); 1284 | menu.AddSeparator(string.Empty); 1285 | } 1286 | 1287 | HandleSharedContextClick(evt, menu, "Duplicate Array Elements", "Delete Array Elements", "Move Array Elements"); 1288 | } 1289 | 1290 | private void HandleSharedContextClick(Event evt, GenericMenu menu, string duplicateLabel, string deleteLabel, string moveLabel) { 1291 | 1292 | menu.AddItem(new GUIContent(duplicateLabel), false, HandleDuplicate, list); 1293 | menu.AddItem(new GUIContent(deleteLabel), false, HandleDelete, list); 1294 | 1295 | if (doPagination) { 1296 | 1297 | int pages = pagination.GetPageCount(Length); 1298 | 1299 | if (pages > 1) { 1300 | 1301 | for (int i = 0; i < pages; i++) { 1302 | 1303 | string label = string.Format("{0}/Page {1}", moveLabel, i + 1); 1304 | 1305 | menu.AddItem(new GUIContent(label), i == pagination.page, HandleMoveElement, i); 1306 | } 1307 | } 1308 | } 1309 | 1310 | menu.ShowAsContext(); 1311 | 1312 | evt.Use(); 1313 | } 1314 | 1315 | private void HandleMoveElement(object userData) { 1316 | 1317 | int toPage = (int)userData; 1318 | int fromPage = pagination.page; 1319 | int size = pagination.pageSize; 1320 | int offset = (toPage * size) - (fromPage * size); 1321 | int direction = offset > 0 ? 1 : -1; 1322 | int total = Length; 1323 | 1324 | //We need to find the actually positions things will move to and not clamp the index 1325 | //because sometimes something wants to move to a negative index, or beyond the length 1326 | //we need to find this overlow and adjust the move offsets based on that 1327 | 1328 | int overflow = 0; 1329 | 1330 | for (int i = 0; i < selection.Length; i++) { 1331 | 1332 | int desiredIndex = selection[i] + offset; 1333 | 1334 | overflow = direction < 0 ? Mathf.Min(overflow, desiredIndex) : Mathf.Max(overflow, desiredIndex - total); 1335 | } 1336 | 1337 | offset -= overflow; 1338 | 1339 | //copy the current list to prepare for moving 1340 | 1341 | UpdateDragList(0, 0, total); 1342 | 1343 | //create a list that will act as our new order 1344 | 1345 | List orderedList = new List(dragList.Elements.Where(t => !selection.Contains(t.startIndex))); 1346 | 1347 | //go through the selection and insert them into the new order based on the page offset 1348 | 1349 | selection.Sort(); 1350 | 1351 | for (int i = 0; i < selection.Length; i++) { 1352 | 1353 | int selIndex = selection[i]; 1354 | int oldIndex = dragList.GetIndexFromSelection(selIndex); 1355 | int newIndex = Mathf.Clamp(selIndex + offset, 0, orderedList.Count); 1356 | 1357 | orderedList.Insert(newIndex, dragList[oldIndex]); 1358 | } 1359 | 1360 | //finally, perform the re-order 1361 | 1362 | dragList.Elements = orderedList.ToArray(); 1363 | 1364 | ReorderDraggedElements(direction, 0, null); 1365 | 1366 | //assume we still want to view these items 1367 | 1368 | pagination.page = toPage; 1369 | 1370 | HandleUtility.Repaint(); 1371 | } 1372 | 1373 | private void HandleDelete(object userData) { 1374 | 1375 | selection.Delete(userData as SerializedProperty); 1376 | 1377 | DispatchChange(); 1378 | } 1379 | 1380 | private void HandleDuplicate(object userData) { 1381 | 1382 | selection.Duplicate(userData as SerializedProperty); 1383 | 1384 | DispatchChange(); 1385 | } 1386 | 1387 | private void HandleDragAndDrop(Rect rect, Event evt) { 1388 | 1389 | switch (evt.GetTypeForControl(dragDropControlID)) { 1390 | 1391 | case EventType.DragUpdated: 1392 | case EventType.DragPerform: 1393 | 1394 | if (GUI.enabled && rect.Contains(evt.mousePosition)) { 1395 | 1396 | Object[] objectReferences = DragAndDrop.objectReferences; 1397 | Object[] references = new Object[1]; 1398 | 1399 | bool acceptDrag = false; 1400 | 1401 | foreach (Object object1 in objectReferences) { 1402 | 1403 | references[0] = object1; 1404 | Object object2 = ValidateObjectDragAndDrop(references); 1405 | 1406 | if (object2 != null) { 1407 | 1408 | DragAndDrop.visualMode = DragAndDropVisualMode.Copy; 1409 | 1410 | if (evt.type == EventType.DragPerform) { 1411 | 1412 | AppendDragAndDropValue(object2); 1413 | 1414 | acceptDrag = true; 1415 | DragAndDrop.activeControlID = 0; 1416 | } 1417 | else { 1418 | 1419 | DragAndDrop.activeControlID = dragDropControlID; 1420 | } 1421 | } 1422 | } 1423 | 1424 | if (acceptDrag) { 1425 | 1426 | GUI.changed = true; 1427 | DragAndDrop.AcceptDrag(); 1428 | } 1429 | } 1430 | 1431 | break; 1432 | 1433 | case EventType.DragExited: 1434 | 1435 | if (GUI.enabled) { 1436 | 1437 | HandleUtility.Repaint(); 1438 | } 1439 | 1440 | break; 1441 | } 1442 | } 1443 | 1444 | private Object ValidateObjectDragAndDrop(Object[] references) { 1445 | 1446 | if (onValidateDragAndDropCallback != null) { 1447 | 1448 | return onValidateDragAndDropCallback(references, this); 1449 | } 1450 | else if (surrogate.HasType) { 1451 | 1452 | //if we have a surrogate type, then validate using the surrogate type rather than the list 1453 | 1454 | return Internals.ValidateObjectDragAndDrop(references, null, surrogate.type, surrogate.exactType); 1455 | } 1456 | 1457 | return Internals.ValidateObjectDragAndDrop(references, list, null, false); 1458 | } 1459 | 1460 | private void AppendDragAndDropValue(Object obj) { 1461 | 1462 | if (onAppendDragDropCallback != null) { 1463 | 1464 | onAppendDragDropCallback(obj, this); 1465 | } 1466 | else { 1467 | 1468 | //check if we have a surrogate type. If so use that for appending 1469 | 1470 | if (surrogate.HasType) { 1471 | 1472 | surrogate.Invoke(AddItem(), obj, this); 1473 | } 1474 | else { 1475 | 1476 | Internals.AppendDragAndDropValue(obj, list); 1477 | } 1478 | } 1479 | 1480 | DispatchChange(); 1481 | } 1482 | 1483 | private void HandlePreSelection(Rect rect, Event evt) { 1484 | 1485 | if (evt.type == EventType.MouseDrag && draggable && GUIUtility.hotControl == controlID) { 1486 | 1487 | if (selection.Length > 0 && UpdateDragPosition(evt.mousePosition, rect, dragList)) { 1488 | 1489 | GUIUtility.keyboardControl = controlID; 1490 | dragging = true; 1491 | } 1492 | 1493 | evt.Use(); 1494 | } 1495 | } 1496 | 1497 | private void HandlePostSelection(Rect rect, Event evt) { 1498 | 1499 | switch (evt.GetTypeForControl(controlID)) { 1500 | 1501 | case EventType.MouseDown: 1502 | 1503 | if (rect.Contains(evt.mousePosition) && IsSelectionButton(evt)) { 1504 | 1505 | int index = GetSelectionIndex(evt.mousePosition); 1506 | 1507 | if (CanSelect(index)) { 1508 | 1509 | DoSelection(index, GUIUtility.keyboardControl == 0 || GUIUtility.keyboardControl == controlID || evt.button == 2, evt); 1510 | } 1511 | else { 1512 | 1513 | selection.Clear(); 1514 | } 1515 | 1516 | HandleUtility.Repaint(); 1517 | } 1518 | 1519 | break; 1520 | 1521 | case EventType.MouseUp: 1522 | 1523 | if (!draggable) { 1524 | 1525 | //select the single object if no selection modifier is being performed 1526 | 1527 | selection.SelectWhenNoAction(pressIndex, evt); 1528 | 1529 | if (onMouseUpCallback != null && IsPositionWithinElement(evt.mousePosition, selection.Last)) { 1530 | 1531 | onMouseUpCallback(this); 1532 | } 1533 | } 1534 | else if (GUIUtility.hotControl == controlID) { 1535 | 1536 | evt.Use(); 1537 | 1538 | if (dragging) { 1539 | 1540 | dragging = false; 1541 | 1542 | //move elements in list 1543 | 1544 | ReorderDraggedElements(dragDirection, dragList.StartIndex, () => dragList.SortByPosition()); 1545 | } 1546 | else { 1547 | 1548 | //if we didn't drag, then select the original pressed object 1549 | 1550 | selection.SelectWhenNoAction(pressIndex, evt); 1551 | 1552 | if (onMouseUpCallback != null) { 1553 | 1554 | onMouseUpCallback(this); 1555 | } 1556 | } 1557 | 1558 | GUIUtility.hotControl = 0; 1559 | } 1560 | 1561 | HandleUtility.Repaint(); 1562 | 1563 | break; 1564 | 1565 | case EventType.KeyDown: 1566 | 1567 | if (GUIUtility.keyboardControl == controlID) { 1568 | 1569 | if (evt.keyCode == KeyCode.DownArrow && !dragging) { 1570 | 1571 | selection.Select(Mathf.Min(selection.Last + 1, Length - 1)); 1572 | evt.Use(); 1573 | } 1574 | else if (evt.keyCode == KeyCode.UpArrow && !dragging) { 1575 | 1576 | selection.Select(Mathf.Max(selection.Last - 1, 0)); 1577 | evt.Use(); 1578 | } 1579 | else if (evt.keyCode == KeyCode.Escape && GUIUtility.hotControl == controlID) { 1580 | 1581 | GUIUtility.hotControl = 0; 1582 | 1583 | if (dragging) { 1584 | 1585 | dragging = false; 1586 | selection = beforeDragSelection; 1587 | } 1588 | 1589 | evt.Use(); 1590 | } 1591 | } 1592 | 1593 | break; 1594 | } 1595 | } 1596 | 1597 | private bool IsSelectionButton(Event evt) { 1598 | 1599 | return evt.button == 0 || evt.button == 2; 1600 | } 1601 | 1602 | private void DoSelection(int index, bool setKeyboardControl, Event evt) { 1603 | 1604 | //append selections based on action, this may be a additive (ctrl) or range (shift) selection 1605 | 1606 | if (multipleSelection) { 1607 | 1608 | selection.AppendWithAction(pressIndex = index, evt); 1609 | } 1610 | else { 1611 | 1612 | selection.Select(pressIndex = index); 1613 | } 1614 | 1615 | if (onSelectCallback != null) { 1616 | 1617 | onSelectCallback(this); 1618 | } 1619 | 1620 | if (draggable) { 1621 | 1622 | dragging = false; 1623 | dragPosition = pressPosition = evt.mousePosition.y; 1624 | 1625 | int start, end; 1626 | 1627 | pagination.GetVisibleRange(Length, out start, out end); 1628 | 1629 | UpdateDragList(dragPosition, start, end); 1630 | 1631 | selection.Trim(start, end); 1632 | 1633 | beforeDragSelection = selection.Clone(); 1634 | 1635 | GUIUtility.hotControl = controlID; 1636 | } 1637 | 1638 | if (setKeyboardControl) { 1639 | 1640 | GUIUtility.keyboardControl = controlID; 1641 | } 1642 | 1643 | evt.Use(); 1644 | } 1645 | 1646 | private void UpdateDragList(float dragPosition, int start, int end) { 1647 | 1648 | dragList.Resize(start, end - start); 1649 | 1650 | for (int i = start; i < end; i++) { 1651 | 1652 | SerializedProperty property = list.GetArrayElementAtIndex(i); 1653 | Rect elementRect = elementRects[i]; 1654 | 1655 | DragElement dragElement = new DragElement() { 1656 | property = property, 1657 | dragOffset = dragPosition - elementRect.y, 1658 | rect = elementRect, 1659 | desiredRect = elementRect, 1660 | selected = selection.Contains(i), 1661 | startIndex = i 1662 | }; 1663 | 1664 | dragList[i - start] = dragElement; 1665 | } 1666 | 1667 | //finally, sort the dragList by selection, selected objects appear first in the list 1668 | //selection order is preserved as well 1669 | 1670 | dragList.SortByIndex(); 1671 | } 1672 | 1673 | private bool UpdateDragPosition(Vector2 position, Rect bounds, DragList dragList) { 1674 | 1675 | //find new drag position 1676 | 1677 | int startIndex = 0; 1678 | int endIndex = selection.Length - 1; 1679 | 1680 | float minOffset = dragList[startIndex].dragOffset; 1681 | float maxOffset = dragList[endIndex].rect.height - dragList[endIndex].dragOffset; 1682 | 1683 | dragPosition = Mathf.Clamp(position.y, bounds.yMin + minOffset, bounds.yMax - maxOffset); 1684 | 1685 | if (Mathf.Abs(dragPosition - pressPosition) > 1) { 1686 | 1687 | dragDirection = (int)Mathf.Sign(dragPosition - pressPosition); 1688 | return true; 1689 | } 1690 | 1691 | return false; 1692 | } 1693 | 1694 | private void ReorderDraggedElements(int direction, int offset, System.Action sortList) { 1695 | 1696 | //save the current expanded states on all elements. I don't see any other way to do this 1697 | //MoveArrayElement does not move the foldout states, so... fun. 1698 | 1699 | dragList.RecordState(); 1700 | 1701 | if (sortList != null) { 1702 | 1703 | sortList(); 1704 | } 1705 | 1706 | selection.Sort((a, b) => { 1707 | 1708 | int d1 = dragList.GetIndexFromSelection(a); 1709 | int d2 = dragList.GetIndexFromSelection(b); 1710 | 1711 | return direction > 0 ? d1.CompareTo(d2) : d2.CompareTo(d1); 1712 | }); 1713 | 1714 | //swap the selected elements in the List 1715 | 1716 | int s = selection.Length; 1717 | 1718 | while (--s > -1) { 1719 | 1720 | int newIndex = dragList.GetIndexFromSelection(selection[s]); 1721 | int listIndex = newIndex + offset; 1722 | 1723 | selection[s] = listIndex; 1724 | 1725 | list.MoveArrayElement(dragList[newIndex].startIndex, listIndex); 1726 | } 1727 | 1728 | //restore expanded states on items 1729 | 1730 | dragList.RestoreState(list); 1731 | 1732 | //apply and update 1733 | 1734 | ApplyReorder(); 1735 | } 1736 | 1737 | private void ApplyReorder() { 1738 | 1739 | list.serializedObject.ApplyModifiedProperties(); 1740 | list.serializedObject.Update(); 1741 | 1742 | if (onReorderCallback != null) { 1743 | 1744 | onReorderCallback(this); 1745 | } 1746 | 1747 | DispatchChange(); 1748 | } 1749 | 1750 | private int GetSelectionIndex(Vector2 position) { 1751 | 1752 | int start, end; 1753 | 1754 | pagination.GetVisibleRange(elementRects.Length, out start, out end); 1755 | 1756 | for (int i = start; i < end; i++) { 1757 | 1758 | Rect rect = elementRects[i]; 1759 | 1760 | if (rect.Contains(position) || (i == 0 && position.y <= rect.yMin) || (i == end - 1 && position.y >= rect.yMax)) { 1761 | 1762 | return i; 1763 | } 1764 | } 1765 | 1766 | return -1; 1767 | } 1768 | 1769 | private bool CanSelect(ListSelection selection) { 1770 | 1771 | return selection.Length > 0 ? selection.All(s => CanSelect(s)) : false; 1772 | } 1773 | 1774 | private bool CanSelect(int index) { 1775 | 1776 | return index >= 0 && index < Length; 1777 | } 1778 | 1779 | private bool CanSelect(Vector2 position) { 1780 | 1781 | return selection.Length > 0 ? selection.Any(s => IsPositionWithinElement(position, s)) : false; 1782 | } 1783 | 1784 | private bool IsPositionWithinElement(Vector2 position, int index) { 1785 | 1786 | return CanSelect(index) ? elementRects[index].Contains(position) : false; 1787 | } 1788 | 1789 | private bool IsElementExpandable(SerializedProperty element) { 1790 | 1791 | switch (elementDisplayType) { 1792 | 1793 | case ElementDisplayType.Auto: 1794 | 1795 | return element.hasVisibleChildren && IsTypeExpandable(element.propertyType); 1796 | 1797 | case ElementDisplayType.Expandable: return true; 1798 | case ElementDisplayType.SingleLine: return false; 1799 | } 1800 | 1801 | return false; 1802 | } 1803 | 1804 | private bool IsTypeExpandable(SerializedPropertyType type) { 1805 | 1806 | switch (type) { 1807 | 1808 | case SerializedPropertyType.Generic: 1809 | case SerializedPropertyType.Vector4: 1810 | case SerializedPropertyType.Quaternion: 1811 | case SerializedPropertyType.ArraySize: 1812 | #if UNITY_2019_3_OR_NEWER 1813 | case SerializedPropertyType.ManagedReference: 1814 | #endif 1815 | return true; 1816 | 1817 | default: 1818 | 1819 | return false; 1820 | } 1821 | } 1822 | 1823 | // 1824 | // -- LIST STYLE -- 1825 | // 1826 | 1827 | static class Style { 1828 | 1829 | internal const string PAGE_INFO_FORMAT = "{0} / {1}"; 1830 | 1831 | internal static GUIContent iconToolbarPlus; 1832 | internal static GUIContent iconToolbarPlusMore; 1833 | internal static GUIContent iconToolbarMinus; 1834 | internal static GUIContent iconPagePrev; 1835 | internal static GUIContent iconPageNext; 1836 | internal static GUIContent iconPagePopup; 1837 | 1838 | internal static GUIStyle paginationText; 1839 | internal static GUIStyle pageSizeTextField; 1840 | internal static GUIStyle draggingHandle; 1841 | internal static GUIStyle headerBackground; 1842 | internal static GUIStyle footerBackground; 1843 | internal static GUIStyle paginationHeader; 1844 | internal static GUIStyle boxBackground; 1845 | internal static GUIStyle preButton; 1846 | internal static GUIStyle preButtonStretch; 1847 | internal static GUIStyle elementBackground; 1848 | internal static GUIStyle verticalLabel; 1849 | internal static GUIContent expandButton; 1850 | internal static GUIContent collapseButton; 1851 | internal static GUIContent sortAscending; 1852 | internal static GUIContent sortDescending; 1853 | 1854 | internal static GUIContent listIcon; 1855 | 1856 | static Style() { 1857 | 1858 | iconToolbarPlus = EditorGUIUtility.IconContent("Toolbar Plus", "Add to list"); 1859 | iconToolbarPlusMore = EditorGUIUtility.IconContent("Toolbar Plus More", "Choose to add to list"); 1860 | iconToolbarMinus = EditorGUIUtility.IconContent("Toolbar Minus", "Remove selection from list"); 1861 | iconPagePrev = EditorGUIUtility.IconContent("Animation.PrevKey", "Previous page"); 1862 | iconPageNext = EditorGUIUtility.IconContent("Animation.NextKey", "Next page"); 1863 | 1864 | #if UNITY_2018_3_OR_NEWER 1865 | iconPagePopup = EditorGUIUtility.IconContent("PopupCurveEditorDropDown", "Select page"); 1866 | #else 1867 | iconPagePopup = EditorGUIUtility.IconContent("MiniPopupNoBg", "Select page"); 1868 | #endif 1869 | paginationText = new GUIStyle(); 1870 | paginationText.margin = new RectOffset(2, 2, 0, 0); 1871 | paginationText.fontSize = EditorStyles.miniTextField.fontSize; 1872 | paginationText.font = EditorStyles.miniFont; 1873 | paginationText.normal.textColor = EditorStyles.miniTextField.normal.textColor; 1874 | paginationText.alignment = TextAnchor.MiddleLeft; 1875 | paginationText.clipping = TextClipping.Clip; 1876 | 1877 | #if UNITY_2019_3_OR_NEWER 1878 | pageSizeTextField = new GUIStyle("RL Background"); 1879 | #else 1880 | pageSizeTextField = new GUIStyle("RL Footer"); 1881 | pageSizeTextField.overflow = new RectOffset(0, 0, -2, -3); 1882 | pageSizeTextField.contentOffset = new Vector2(0, -1); 1883 | #endif 1884 | pageSizeTextField.alignment = TextAnchor.MiddleLeft; 1885 | pageSizeTextField.clipping = TextClipping.Clip; 1886 | pageSizeTextField.fixedHeight = 0; 1887 | pageSizeTextField.padding = new RectOffset(3, 0, 0, 0); 1888 | pageSizeTextField.font = EditorStyles.miniFont; 1889 | pageSizeTextField.fontSize = EditorStyles.miniTextField.fontSize; 1890 | pageSizeTextField.fontStyle = FontStyle.Normal; 1891 | pageSizeTextField.wordWrap = false; 1892 | 1893 | draggingHandle = new GUIStyle("RL DragHandle"); 1894 | headerBackground = new GUIStyle("RL Header"); 1895 | footerBackground = new GUIStyle("RL Footer"); 1896 | 1897 | #if UNITY_2019_3_OR_NEWER 1898 | paginationHeader = new GUIStyle("TimeRulerBackground"); 1899 | paginationHeader.fixedHeight = 0; 1900 | #else 1901 | paginationHeader = new GUIStyle("RL Element"); 1902 | paginationHeader.border = new RectOffset(2, 3, 2, 3); 1903 | #endif 1904 | elementBackground = new GUIStyle("RL Element"); 1905 | elementBackground.border = new RectOffset(2, 3, 2, 3); 1906 | verticalLabel = new GUIStyle(EditorStyles.label); 1907 | verticalLabel.alignment = TextAnchor.UpperLeft; 1908 | verticalLabel.contentOffset = new Vector2(10, 3); 1909 | boxBackground = new GUIStyle("RL Background"); 1910 | boxBackground.border = new RectOffset(6, 3, 3, 6); 1911 | 1912 | #if UNITY_2019_3_OR_NEWER 1913 | preButton = new GUIStyle("RL FooterButton"); 1914 | #else 1915 | preButton = new GUIStyle("RL FooterButton"); 1916 | preButton.contentOffset = new Vector2(0, -4); 1917 | #endif 1918 | preButtonStretch = new GUIStyle("RL FooterButton"); 1919 | preButtonStretch.fixedHeight = 0; 1920 | preButtonStretch.stretchHeight = true; 1921 | 1922 | expandButton = EditorGUIUtility.IconContent("winbtn_win_max"); 1923 | expandButton.tooltip = "Expand All Elements"; 1924 | 1925 | collapseButton = EditorGUIUtility.IconContent("winbtn_win_min"); 1926 | collapseButton.tooltip = "Collapse All Elements"; 1927 | 1928 | sortAscending = EditorGUIUtility.IconContent("align_vertically_bottom"); 1929 | sortAscending.tooltip = "Sort Ascending"; 1930 | 1931 | sortDescending = EditorGUIUtility.IconContent("align_vertically_top"); 1932 | sortDescending.tooltip = "Sort Descending"; 1933 | 1934 | listIcon = EditorGUIUtility.IconContent("align_horizontally_right"); 1935 | } 1936 | } 1937 | 1938 | // 1939 | // -- DRAG LIST -- 1940 | // 1941 | 1942 | struct DragList { 1943 | 1944 | private int startIndex; 1945 | private DragElement[] elements; 1946 | private int length; 1947 | 1948 | internal DragList(int length) { 1949 | 1950 | this.length = length; 1951 | 1952 | startIndex = 0; 1953 | elements = new DragElement[length]; 1954 | } 1955 | 1956 | internal int StartIndex { 1957 | 1958 | get { return startIndex; } 1959 | } 1960 | 1961 | internal int Length { 1962 | 1963 | get { return length; } 1964 | } 1965 | 1966 | internal DragElement[] Elements { 1967 | 1968 | get { return elements; } 1969 | set { elements = value; } 1970 | } 1971 | 1972 | internal DragElement this[int index] { 1973 | 1974 | get { return elements[index]; } 1975 | set { elements[index] = value; } 1976 | } 1977 | 1978 | internal void Resize(int start, int length) { 1979 | 1980 | startIndex = start; 1981 | 1982 | this.length = length; 1983 | 1984 | if (elements.Length != length) { 1985 | 1986 | System.Array.Resize(ref elements, length); 1987 | } 1988 | } 1989 | 1990 | internal void SortByIndex() { 1991 | 1992 | System.Array.Sort(elements, (a, b) => { 1993 | 1994 | if (b.selected) { 1995 | 1996 | return a.selected ? a.startIndex.CompareTo(b.startIndex) : 1; 1997 | } 1998 | else if (a.selected) { 1999 | 2000 | return b.selected ? b.startIndex.CompareTo(a.startIndex) : -1; 2001 | } 2002 | 2003 | return a.startIndex.CompareTo(b.startIndex); 2004 | }); 2005 | } 2006 | 2007 | internal void RecordState() { 2008 | 2009 | for (int i = 0; i < length; i++) { 2010 | 2011 | elements[i].RecordState(); 2012 | } 2013 | } 2014 | 2015 | internal void RestoreState(SerializedProperty list) { 2016 | 2017 | for (int i = 0; i < length; i++) { 2018 | 2019 | elements[i].RestoreState(list.GetArrayElementAtIndex(i + startIndex)); 2020 | } 2021 | } 2022 | 2023 | internal void SortByPosition() { 2024 | 2025 | System.Array.Sort(elements, (a, b) => a.desiredRect.center.y.CompareTo(b.desiredRect.center.y)); 2026 | } 2027 | 2028 | internal int GetIndexFromSelection(int index) { 2029 | 2030 | return System.Array.FindIndex(elements, t => t.startIndex == index); 2031 | } 2032 | } 2033 | 2034 | // 2035 | // -- DRAG ELEMENT -- 2036 | // 2037 | 2038 | struct DragElement { 2039 | 2040 | internal SerializedProperty property; 2041 | internal int startIndex; 2042 | internal float dragOffset; 2043 | internal bool selected; 2044 | internal Rect rect; 2045 | internal Rect desiredRect; 2046 | 2047 | private bool isExpanded; 2048 | private Dictionary states; 2049 | 2050 | internal bool Overlaps(Rect value, int index, int direction) { 2051 | 2052 | if (direction < 0 && index < startIndex) { 2053 | 2054 | return desiredRect.yMin < value.center.y; 2055 | } 2056 | else if (direction > 0 && index > startIndex) { 2057 | 2058 | return desiredRect.yMax > value.center.y; 2059 | } 2060 | 2061 | return false; 2062 | } 2063 | 2064 | internal void RecordState() { 2065 | 2066 | states = new Dictionary(); 2067 | isExpanded = property.isExpanded; 2068 | 2069 | Iterate(this, property, (DragElement e, SerializedProperty p, int index) => { 2070 | 2071 | e.states[index] = p.isExpanded; 2072 | }); 2073 | } 2074 | 2075 | internal void RestoreState(SerializedProperty property) { 2076 | 2077 | property.isExpanded = isExpanded; 2078 | 2079 | Iterate(this, property, (DragElement e, SerializedProperty p, int index) => { 2080 | 2081 | p.isExpanded = e.states[index]; 2082 | }); 2083 | } 2084 | 2085 | private static void Iterate(DragElement element, SerializedProperty property, System.Action action) { 2086 | 2087 | SerializedProperty copy = property.Copy(); 2088 | SerializedProperty end = copy.GetEndProperty(); 2089 | 2090 | int index = 0; 2091 | 2092 | while (copy.NextVisible(true) && !SerializedProperty.EqualContents(copy, end)) { 2093 | 2094 | if (copy.hasVisibleChildren) { 2095 | 2096 | action(element, copy, index); 2097 | index++; 2098 | } 2099 | } 2100 | } 2101 | } 2102 | 2103 | // 2104 | // -- SLIDE GROUP -- 2105 | // 2106 | 2107 | class SlideGroup { 2108 | 2109 | private Dictionary animIDs; 2110 | 2111 | public SlideGroup() { 2112 | 2113 | animIDs = new Dictionary(); 2114 | } 2115 | 2116 | public Rect GetRect(int id, Rect r, float easing) { 2117 | 2118 | if (Event.current.type != EventType.Repaint) { 2119 | 2120 | return r; 2121 | } 2122 | 2123 | if (!animIDs.ContainsKey(id)) { 2124 | 2125 | animIDs.Add(id, r); 2126 | return r; 2127 | } 2128 | else { 2129 | 2130 | Rect rect = animIDs[id]; 2131 | 2132 | if (rect.y != r.y) { 2133 | 2134 | float delta = r.y - rect.y; 2135 | float absDelta = Mathf.Abs(delta); 2136 | 2137 | //if the distance between current rect and target is too large, then move the element towards the target rect so it reaches the destination faster 2138 | 2139 | if (absDelta > (rect.height * 2)) { 2140 | 2141 | r.y = delta > 0 ? r.y - rect.height : r.y + rect.height; 2142 | } 2143 | else if (absDelta > 0.5) { 2144 | 2145 | r.y = Mathf.Lerp(rect.y, r.y, easing); 2146 | } 2147 | 2148 | animIDs[id] = r; 2149 | HandleUtility.Repaint(); 2150 | } 2151 | 2152 | return r; 2153 | } 2154 | } 2155 | 2156 | public Rect SetRect(int id, Rect rect) { 2157 | 2158 | if (animIDs.ContainsKey(id)) { 2159 | 2160 | animIDs[id] = rect; 2161 | } 2162 | else { 2163 | 2164 | animIDs.Add(id, rect); 2165 | } 2166 | 2167 | return rect; 2168 | } 2169 | } 2170 | 2171 | // 2172 | // -- PAGINATION -- 2173 | // 2174 | 2175 | struct Pagination { 2176 | 2177 | internal bool enabled; 2178 | internal int fixedPageSize; 2179 | internal int customPageSize; 2180 | internal int page; 2181 | 2182 | internal bool usePagination { 2183 | 2184 | get { return enabled && pageSize > 0; } 2185 | } 2186 | 2187 | internal int pageSize { 2188 | 2189 | get { return fixedPageSize > 0 ? fixedPageSize : customPageSize; } 2190 | } 2191 | 2192 | internal int GetVisibleLength(int total) { 2193 | 2194 | int start, end; 2195 | 2196 | if (GetVisibleRange(total, out start, out end)) { 2197 | 2198 | return end - start; 2199 | } 2200 | 2201 | return total; 2202 | } 2203 | 2204 | internal int GetPageForIndex(int index) { 2205 | 2206 | return usePagination ? Mathf.FloorToInt(index / (float)pageSize) : 0; 2207 | } 2208 | 2209 | internal int GetPageCount(int total) { 2210 | 2211 | return usePagination ? Mathf.CeilToInt(total / (float)pageSize) : 1; 2212 | } 2213 | 2214 | internal bool GetVisibleRange(int total, out int start, out int end) { 2215 | 2216 | if (usePagination) { 2217 | 2218 | int size = pageSize; 2219 | 2220 | start = Mathf.Clamp(page * size, 0, total - 1); 2221 | end = Mathf.Min(start + size, total); 2222 | return true; 2223 | } 2224 | 2225 | start = 0; 2226 | end = total; 2227 | return false; 2228 | } 2229 | } 2230 | 2231 | // 2232 | // -- SELECTION -- 2233 | // 2234 | 2235 | class ListSelection : IEnumerable { 2236 | 2237 | private List indexes; 2238 | 2239 | internal int? firstSelected; 2240 | 2241 | public ListSelection() { 2242 | 2243 | indexes = new List(); 2244 | } 2245 | 2246 | public ListSelection(int[] indexes) { 2247 | 2248 | this.indexes = new List(indexes); 2249 | } 2250 | 2251 | public int First { 2252 | 2253 | get { return indexes.Count > 0 ? indexes[0] : -1; } 2254 | } 2255 | 2256 | public int Last { 2257 | 2258 | get { return indexes.Count > 0 ? indexes[indexes.Count - 1] : -1; } 2259 | } 2260 | 2261 | public int Length { 2262 | 2263 | get { return indexes.Count; } 2264 | } 2265 | 2266 | public int this[int index] { 2267 | 2268 | get { return indexes[index]; } 2269 | set { 2270 | 2271 | int oldIndex = indexes[index]; 2272 | 2273 | indexes[index] = value; 2274 | 2275 | if (oldIndex == firstSelected) { 2276 | 2277 | firstSelected = value; 2278 | } 2279 | } 2280 | } 2281 | 2282 | public bool Contains(int index) { 2283 | 2284 | return indexes.Contains(index); 2285 | } 2286 | 2287 | public void Clear() { 2288 | 2289 | indexes.Clear(); 2290 | firstSelected = null; 2291 | } 2292 | 2293 | public void SelectWhenNoAction(int index, Event evt) { 2294 | 2295 | if (!EditorGUI.actionKey && !evt.shift) { 2296 | 2297 | Select(index); 2298 | } 2299 | } 2300 | 2301 | public void Select(int index) { 2302 | 2303 | indexes.Clear(); 2304 | indexes.Add(index); 2305 | 2306 | firstSelected = index; 2307 | } 2308 | 2309 | public void Remove(int index) { 2310 | 2311 | if (indexes.Contains(index)) { 2312 | 2313 | indexes.Remove(index); 2314 | } 2315 | } 2316 | 2317 | public void AppendWithAction(int index, Event evt) { 2318 | 2319 | if (EditorGUI.actionKey) { 2320 | 2321 | if (Contains(index)) { 2322 | 2323 | Remove(index); 2324 | } 2325 | else { 2326 | 2327 | Append(index); 2328 | firstSelected = index; 2329 | } 2330 | } 2331 | else if (evt.shift && indexes.Count > 0 && firstSelected.HasValue) { 2332 | 2333 | indexes.Clear(); 2334 | 2335 | AppendRange(firstSelected.Value, index); 2336 | } 2337 | else if (!Contains(index)) { 2338 | 2339 | Select(index); 2340 | } 2341 | } 2342 | 2343 | public void Sort() { 2344 | 2345 | if (indexes.Count > 0) { 2346 | 2347 | indexes.Sort(); 2348 | } 2349 | } 2350 | 2351 | public void Sort(System.Comparison comparison) { 2352 | 2353 | if (indexes.Count > 0) { 2354 | 2355 | indexes.Sort(comparison); 2356 | } 2357 | } 2358 | 2359 | public int[] ToArray() { 2360 | 2361 | return indexes.ToArray(); 2362 | } 2363 | 2364 | public ListSelection Clone() { 2365 | 2366 | ListSelection clone = new ListSelection(ToArray()); 2367 | clone.firstSelected = firstSelected; 2368 | 2369 | return clone; 2370 | } 2371 | 2372 | internal void Trim(int min, int max) { 2373 | 2374 | int i = indexes.Count; 2375 | 2376 | while (--i > -1) { 2377 | 2378 | int index = indexes[i]; 2379 | 2380 | if (index < min || index >= max) { 2381 | 2382 | if (index == firstSelected && i > 0) { 2383 | 2384 | firstSelected = indexes[i - 1]; 2385 | } 2386 | 2387 | indexes.RemoveAt(i); 2388 | } 2389 | } 2390 | } 2391 | 2392 | internal bool CanRevert(SerializedProperty list) { 2393 | 2394 | if (list.serializedObject.targetObjects.Length == 1) { 2395 | 2396 | for (int i = 0; i < Length; i++) { 2397 | 2398 | if (list.GetArrayElementAtIndex(this[i]).isInstantiatedPrefab) { 2399 | 2400 | return true; 2401 | } 2402 | } 2403 | } 2404 | 2405 | return false; 2406 | } 2407 | 2408 | internal void RevertValues(object userData) { 2409 | 2410 | SerializedProperty list = userData as SerializedProperty; 2411 | 2412 | for (int i = 0; i < Length; i++) { 2413 | 2414 | SerializedProperty property = list.GetArrayElementAtIndex(this[i]); 2415 | 2416 | if (property.isInstantiatedPrefab) { 2417 | 2418 | property.prefabOverride = false; 2419 | } 2420 | } 2421 | 2422 | list.serializedObject.ApplyModifiedProperties(); 2423 | list.serializedObject.Update(); 2424 | 2425 | HandleUtility.Repaint(); 2426 | } 2427 | 2428 | internal void Duplicate(SerializedProperty list) { 2429 | 2430 | int offset = 0; 2431 | 2432 | for (int i = 0; i < Length; i++) { 2433 | 2434 | this[i] += offset; 2435 | 2436 | list.GetArrayElementAtIndex(this[i]).DuplicateCommand(); 2437 | list.serializedObject.ApplyModifiedProperties(); 2438 | list.serializedObject.Update(); 2439 | 2440 | offset++; 2441 | } 2442 | 2443 | HandleUtility.Repaint(); 2444 | } 2445 | 2446 | internal void Delete(SerializedProperty list) { 2447 | 2448 | Sort(); 2449 | 2450 | int i = Length; 2451 | 2452 | while (--i > -1) { 2453 | 2454 | list.GetArrayElementAtIndex(this[i]).DeleteCommand(); 2455 | } 2456 | 2457 | Clear(); 2458 | 2459 | list.serializedObject.ApplyModifiedProperties(); 2460 | list.serializedObject.Update(); 2461 | 2462 | HandleUtility.Repaint(); 2463 | } 2464 | 2465 | private void Append(int index) { 2466 | 2467 | if (index >= 0 && !indexes.Contains(index)) { 2468 | 2469 | indexes.Add(index); 2470 | } 2471 | } 2472 | 2473 | private void AppendRange(int from, int to) { 2474 | 2475 | int dir = (int)Mathf.Sign(to - from); 2476 | 2477 | if (dir != 0) { 2478 | 2479 | for (int i = from; i != to; i += dir) { 2480 | 2481 | Append(i); 2482 | } 2483 | } 2484 | 2485 | Append(to); 2486 | } 2487 | 2488 | public IEnumerator GetEnumerator() { 2489 | 2490 | return ((IEnumerable)indexes).GetEnumerator(); 2491 | } 2492 | 2493 | IEnumerator IEnumerable.GetEnumerator() { 2494 | 2495 | return ((IEnumerable)indexes).GetEnumerator(); 2496 | } 2497 | } 2498 | 2499 | // 2500 | // -- SORTING -- 2501 | // 2502 | 2503 | static class ListSort { 2504 | 2505 | private delegate int SortComparision(SerializedProperty p1, SerializedProperty p2); 2506 | 2507 | internal static void SortOnProperty(SerializedProperty list, int length, bool descending, string propertyName) { 2508 | 2509 | BubbleSort(list, length, (p1, p2) => { 2510 | 2511 | SerializedProperty a = p1.FindPropertyRelative(propertyName); 2512 | SerializedProperty b = p2.FindPropertyRelative(propertyName); 2513 | 2514 | if (a != null && b != null && a.propertyType == b.propertyType) { 2515 | 2516 | int comparison = Compare(a, b, descending, a.propertyType); 2517 | 2518 | return descending ? -comparison : comparison; 2519 | } 2520 | 2521 | return 0; 2522 | }); 2523 | } 2524 | 2525 | internal static void SortOnType(SerializedProperty list, int length, bool descending, SerializedPropertyType type) { 2526 | 2527 | BubbleSort(list, length, (p1, p2) => { 2528 | 2529 | int comparision = Compare(p1, p2, descending, type); 2530 | 2531 | return descending ? -comparision : comparision; 2532 | }); 2533 | } 2534 | 2535 | // 2536 | // -- PRIVATE -- 2537 | // 2538 | 2539 | private static void BubbleSort(SerializedProperty list, int length, SortComparision comparision) { 2540 | 2541 | for (int i = 0; i < length; i++) { 2542 | 2543 | SerializedProperty p1 = list.GetArrayElementAtIndex(i); 2544 | 2545 | for (int j = i + 1; j < length; j++) { 2546 | 2547 | SerializedProperty p2 = list.GetArrayElementAtIndex(j); 2548 | 2549 | if (comparision(p1, p2) > 0) { 2550 | 2551 | list.MoveArrayElement(j, i); 2552 | } 2553 | } 2554 | } 2555 | } 2556 | 2557 | private static int Compare(SerializedProperty p1, SerializedProperty p2, bool descending, SerializedPropertyType type) { 2558 | 2559 | if (p1 == null || p2 == null) { 2560 | 2561 | return 0; 2562 | } 2563 | 2564 | switch (type) { 2565 | 2566 | case SerializedPropertyType.Boolean: 2567 | 2568 | return p1.boolValue.CompareTo(p2.boolValue); 2569 | 2570 | case SerializedPropertyType.Character: 2571 | case SerializedPropertyType.Enum: 2572 | case SerializedPropertyType.Integer: 2573 | case SerializedPropertyType.LayerMask: 2574 | 2575 | return p1.longValue.CompareTo(p2.longValue); 2576 | 2577 | case SerializedPropertyType.Color: 2578 | 2579 | return p1.colorValue.grayscale.CompareTo(p2.colorValue.grayscale); 2580 | 2581 | case SerializedPropertyType.ExposedReference: 2582 | 2583 | return CompareObjects(p1.exposedReferenceValue, p2.exposedReferenceValue, descending); 2584 | 2585 | case SerializedPropertyType.Float: 2586 | 2587 | return p1.doubleValue.CompareTo(p2.doubleValue); 2588 | 2589 | case SerializedPropertyType.ObjectReference: 2590 | 2591 | return CompareObjects(p1.objectReferenceValue, p2.objectReferenceValue, descending); 2592 | 2593 | case SerializedPropertyType.String: 2594 | 2595 | return p1.stringValue.CompareTo(p2.stringValue); 2596 | 2597 | default: 2598 | 2599 | return 0; 2600 | } 2601 | } 2602 | 2603 | private static int CompareObjects(Object obj1, Object obj2, bool descending) { 2604 | 2605 | if (obj1 && obj2) { 2606 | 2607 | return obj1.name.CompareTo(obj2.name); 2608 | } 2609 | else if (obj1) { 2610 | 2611 | return descending ? 1 : -1; 2612 | } 2613 | 2614 | return descending ? -1 : 1; 2615 | } 2616 | } 2617 | 2618 | // 2619 | // -- SURROGATE -- 2620 | // 2621 | 2622 | public struct Surrogate { 2623 | 2624 | public System.Type type; 2625 | public bool exactType; 2626 | public SurrogateCallback callback; 2627 | 2628 | internal bool enabled; 2629 | 2630 | public bool HasType { 2631 | 2632 | get { return enabled && type != null; } 2633 | } 2634 | 2635 | public Surrogate(System.Type type) 2636 | : this(type, null) { 2637 | } 2638 | 2639 | public Surrogate(System.Type type, SurrogateCallback callback) { 2640 | 2641 | this.type = type; 2642 | this.callback = callback; 2643 | 2644 | enabled = true; 2645 | exactType = false; 2646 | } 2647 | 2648 | public void Invoke(SerializedProperty element, Object objectReference, ReorderableList list) { 2649 | 2650 | if (element != null && callback != null) { 2651 | 2652 | callback.Invoke(element, objectReference, list); 2653 | } 2654 | } 2655 | } 2656 | 2657 | // 2658 | // -- EXCEPTIONS -- 2659 | // 2660 | 2661 | class InvalidListException : System.InvalidOperationException { 2662 | 2663 | public InvalidListException() : base("ReorderableList serializedProperty must be an array") { 2664 | } 2665 | } 2666 | 2667 | class MissingListExeption : System.ArgumentNullException { 2668 | 2669 | public MissingListExeption() : base("ReorderableList serializedProperty is null") { 2670 | } 2671 | } 2672 | 2673 | // 2674 | // -- INTERNAL -- 2675 | // 2676 | 2677 | static class Internals { 2678 | 2679 | private static MethodInfo dragDropValidation; 2680 | private static object[] dragDropValidationParams; 2681 | private static MethodInfo appendDragDrop; 2682 | private static object[] appendDragDropParams; 2683 | 2684 | static Internals() { 2685 | 2686 | dragDropValidation = System.Type.GetType("UnityEditor.EditorGUI, UnityEditor").GetMethod("ValidateObjectFieldAssignment", BindingFlags.NonPublic | BindingFlags.Static); 2687 | appendDragDrop = typeof(SerializedProperty).GetMethod("AppendFoldoutPPtrValue", BindingFlags.NonPublic | BindingFlags.Instance); 2688 | } 2689 | 2690 | internal static Object ValidateObjectDragAndDrop(Object[] references, SerializedProperty property, System.Type type, bool exactType) { 2691 | 2692 | #if UNITY_2017_1_OR_NEWER 2693 | dragDropValidationParams = GetParams(ref dragDropValidationParams, 4); 2694 | dragDropValidationParams[0] = references; 2695 | dragDropValidationParams[1] = type; 2696 | dragDropValidationParams[2] = property; 2697 | dragDropValidationParams[3] = exactType ? 1 : 0; 2698 | #else 2699 | dragDropValidationParams = GetParams(ref dragDropValidationParams, 3); 2700 | dragDropValidationParams[0] = references; 2701 | dragDropValidationParams[1] = type; 2702 | dragDropValidationParams[2] = property; 2703 | #endif 2704 | return dragDropValidation.Invoke(null, dragDropValidationParams) as Object; 2705 | } 2706 | 2707 | internal static void AppendDragAndDropValue(Object obj, SerializedProperty list) { 2708 | 2709 | appendDragDropParams = GetParams(ref appendDragDropParams, 1); 2710 | appendDragDropParams[0] = obj; 2711 | appendDragDrop.Invoke(list, appendDragDropParams); 2712 | } 2713 | 2714 | private static object[] GetParams(ref object[] parameters, int count) { 2715 | 2716 | if (parameters == null) { 2717 | 2718 | parameters = new object[count]; 2719 | } 2720 | 2721 | return parameters; 2722 | } 2723 | } 2724 | } 2725 | } 2726 | 2727 | -------------------------------------------------------------------------------- /Editor/ReorderableList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7524a33cc4881484f94d10e60833382b 3 | timeCreated: 1434688391 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Chris Foulston 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab74623b8b4c7774cb7ce95730a03f28 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reorderable List 2 | 3 | An attempt to mimic the ReorderableList within Unity while adding some extended functionality. 4 | 5 | ![screenshot](https://user-images.githubusercontent.com/6723783/45054643-70b46200-b042-11e8-874c-0d93a46e05a5.jpg) 6 | 7 | ## Installation 8 | 9 | This extension can be installed using Unity package manager. 10 | `https://github.com/cfoulston/Unity-Reorderable-List.git` 11 | 12 | * Package manager UI 13 | 14 | ![screenshot](https://user-images.githubusercontent.com/6723783/72479980-c9554c80-37aa-11ea-8fd8-978d3fa860bd.png) 15 | 16 | * Manifest 17 | 18 | { 19 | "dependencies": { 20 | "com.malee.reorderablelist": "https://github.com/cfoulston/Unity-Reorderable-List.git" 21 | } 22 | } 23 | 24 | * A standalone version is available under the [standalone](https://github.com/cfoulston/Unity-Reorderable-List/tree/standalone) branch, although this version is no longer maintained. 25 | 26 | ## Features 27 | 28 | * Drag and Drop references (like array inspector) 29 | * Expandable items and list itself 30 | * Multiple selection (ctrl/command, shift select) 31 | * Draggable selection 32 | * Context menu items (revert values, duplicate values, delete values) 33 | * Custom attribute which allows automatic list generation for properties* 34 | * Event delegates and custom styling 35 | * Pagination 36 | * Sorting (sort based on field, ascending and descending) 37 | * Surrogates (Enable adding elements of a different type) 38 | 39 | ## Usage 40 | 41 | There are two ways to use the ReorderableList 42 | 1. Create a custom Editor for your class and create a ReorderableList pointing to your serializedProperty 43 | 2. Create custom list class which extends from ReorderableArray, assign [Reorderable] attribute above property (not class). 44 | 45 | ## Pagination 46 | 47 | Pagination can be enabled in two ways: 48 | 49 | 1. With the [Reorderable] attribute: 50 | * `[Reorderable(paginate = true, pageSize = 0)]` 51 | 2. Properties of the ReorderableList: 52 | * `list.paginate` 53 | * `list.pageSize` 54 | 55 | `pageSize` defines the desired elements per page. Setting `pageSize = 0` will enable the custom page size GUI 56 | 57 | When enabled, the ReorderableList GUI will display a small section below the header to facilitate navigating the pages 58 | 59 | ![pagination](https://user-images.githubusercontent.com/6723783/45054642-701bcb80-b042-11e8-84e4-0886d23c83c9.jpg) 60 | 61 | #### NOTE 62 | *Elements can be moved between pages by right-clicking and selecting "Move Array Element"* 63 | 64 | ## Surrogates 65 | 66 | Surrogates can be created to facilitate adding Objects to a ReorderableList that don't match the ReorderableList type. 67 | This can be achieved in two ways: 68 | 69 | 1. With the [Reorderable] attribute: 70 | * `[Reorderable(surrogateType = typeof(ObjectType), surrogateProperty = "objectProperty")]` 71 | 2. Property of the ReorderableList: 72 | * `list.surrogate = new ReorderableList.Surrogate(typeof(ObjectType), Callback);` 73 | 74 | Check the `SurrogateTest` and `SurrogateTestEditor` examples for more information -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7be19ada3cefe554cb3808a48c7e0b20 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e6e6e0703755a04c86e731850bdf18c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Attributes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b01a1a9e8f5c586419eba255ce2c3ec6 3 | folderAsset: yes 4 | timeCreated: 1436466573 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Runtime/Attributes/ReorderableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Malee.List { 5 | 6 | public class ReorderableAttribute : PropertyAttribute { 7 | 8 | public bool add; 9 | public bool remove; 10 | public bool draggable; 11 | public bool singleLine; 12 | public bool paginate; 13 | public bool sortable; 14 | public bool labels; 15 | public int pageSize; 16 | public string elementNameProperty; 17 | public string elementNameOverride; 18 | public string elementIconPath; 19 | public Type surrogateType; 20 | public string surrogateProperty; 21 | 22 | public ReorderableAttribute() 23 | : this(null) { 24 | } 25 | 26 | public ReorderableAttribute(string elementNameProperty) 27 | : this(true, true, true, elementNameProperty, null, null) { 28 | } 29 | 30 | public ReorderableAttribute(string elementNameProperty, string elementIconPath) 31 | : this(true, true, true, elementNameProperty, null, elementIconPath) { 32 | } 33 | 34 | public ReorderableAttribute(string elementNameProperty, string elementNameOverride, string elementIconPath) 35 | : this(true, true, true, elementNameProperty, elementNameOverride, elementIconPath) { 36 | } 37 | 38 | public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementIconPath = null) 39 | : this(add, remove, draggable, elementNameProperty, null, elementIconPath) { 40 | } 41 | 42 | public ReorderableAttribute(bool add, bool remove, bool draggable, string elementNameProperty = null, string elementNameOverride = null, string elementIconPath = null) { 43 | 44 | this.add = add; 45 | this.remove = remove; 46 | this.draggable = draggable; 47 | this.elementNameProperty = elementNameProperty; 48 | this.elementNameOverride = elementNameOverride; 49 | this.elementIconPath = elementIconPath; 50 | 51 | sortable = true; 52 | labels = true; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Runtime/Attributes/ReorderableAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af18777bcf6ae2c47a02c3ff8adabb0e 3 | timeCreated: 1434664597 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Runtime/Malee.ReorderableList.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Malee.ReorderableList" 3 | } 4 | -------------------------------------------------------------------------------- /Runtime/Malee.ReorderableList.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d178ac4b10764814c8ae876ce6354d19 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/ReorderableArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace Malee.List { 7 | 8 | [Serializable] 9 | public abstract class ReorderableArray : ICloneable, IList, ICollection, IEnumerable { 10 | 11 | [SerializeField] 12 | private List array = new List(); 13 | 14 | public ReorderableArray() 15 | : this(0) { 16 | } 17 | 18 | public ReorderableArray(int length) { 19 | 20 | array = new List(length); 21 | } 22 | 23 | public T this[int index] { 24 | 25 | get { return array[index]; } 26 | set { array[index] = value; } 27 | } 28 | 29 | public int Length { 30 | 31 | get { return array.Count; } 32 | } 33 | 34 | public bool IsReadOnly { 35 | 36 | get { return false; } 37 | } 38 | 39 | public int Count { 40 | 41 | get { return array.Count; } 42 | } 43 | 44 | public object Clone() { 45 | 46 | return new List(array); 47 | } 48 | 49 | public void CopyFrom(IEnumerable value) { 50 | 51 | array.Clear(); 52 | array.AddRange(value); 53 | } 54 | 55 | public bool Contains(T value) { 56 | 57 | return array.Contains(value); 58 | } 59 | 60 | public int IndexOf(T value) { 61 | 62 | return array.IndexOf(value); 63 | } 64 | 65 | public void Insert(int index, T item) { 66 | 67 | array.Insert(index, item); 68 | } 69 | 70 | public void RemoveAt(int index) { 71 | 72 | array.RemoveAt(index); 73 | } 74 | 75 | public void Add(T item) { 76 | 77 | array.Add(item); 78 | } 79 | 80 | public void Clear() { 81 | 82 | array.Clear(); 83 | } 84 | 85 | public void CopyTo(T[] array, int arrayIndex) { 86 | 87 | this.array.CopyTo(array, arrayIndex); 88 | } 89 | 90 | public bool Remove(T item) { 91 | 92 | return array.Remove(item); 93 | } 94 | 95 | public T[] ToArray() { 96 | 97 | return array.ToArray(); 98 | } 99 | 100 | public IEnumerator GetEnumerator() { 101 | 102 | return array.GetEnumerator(); 103 | } 104 | 105 | IEnumerator IEnumerable.GetEnumerator() { 106 | 107 | return array.GetEnumerator(); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Runtime/ReorderableArray.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5132fa5788b8a7347b370fa5d071c913 3 | timeCreated: 1436466574 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 11380b259ee07a640863f318c89e9b3e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff234ccf4da01a34ba1901fd7cbee30a 3 | folderAsset: yes 4 | timeCreated: 1436467406 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/ExampleEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | using Malee.List; 5 | using System; 6 | 7 | [CanEditMultipleObjects] 8 | [CustomEditor(typeof(Example))] 9 | public class ExampleEditor : Editor { 10 | 11 | private ReorderableList list1; 12 | private SerializedProperty list2; 13 | private ReorderableList list3; 14 | 15 | void OnEnable() { 16 | 17 | list1 = new ReorderableList(serializedObject.FindProperty("list1")); 18 | list1.elementNameProperty = "myEnum"; 19 | 20 | list2 = serializedObject.FindProperty("list2"); 21 | 22 | list3 = new ReorderableList(serializedObject.FindProperty("list3")); 23 | list3.getElementNameCallback += GetList3ElementName; 24 | } 25 | 26 | private string GetList3ElementName(SerializedProperty element) { 27 | 28 | return element.propertyPath; 29 | } 30 | 31 | public override void OnInspectorGUI() { 32 | 33 | serializedObject.Update(); 34 | 35 | //draw the list using GUILayout, you can of course specify your own position and label 36 | list1.DoLayoutList(); 37 | 38 | //Caching the property is recommended 39 | EditorGUILayout.PropertyField(list2); 40 | 41 | //draw the final list, the element name is supplied through the callback defined above "GetList3ElementName" 42 | list3.DoLayoutList(); 43 | 44 | //Draw without caching property 45 | EditorGUILayout.PropertyField(serializedObject.FindProperty("list4")); 46 | EditorGUILayout.PropertyField(serializedObject.FindProperty("list5")); 47 | 48 | serializedObject.ApplyModifiedProperties(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/ExampleEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 55bad6365695dff4eb2c827c6f4edb31 3 | timeCreated: 1436467419 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/GameObjectEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | [CustomEditor(typeof(GameObjectExample))] 7 | public class GameObjectEditor : Editor { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/GameObjectEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d5be105bd272c44ba196f249ec007a6 3 | timeCreated: 1492484892 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/NameOverrideEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using Malee.List; 3 | using System; 4 | 5 | [CanEditMultipleObjects] 6 | [CustomEditor(typeof(NameOverride))] 7 | public class NameOverrideEditor : Editor { 8 | 9 | private SerializedProperty autoList; 10 | private SerializedProperty dynamicList; 11 | private SerializedProperty nameOverride; 12 | private SerializedProperty nestedNameOverride; 13 | 14 | private void OnEnable() { 15 | 16 | //get references to the properties. Could also create the ReorderableList directly here which would avoid the lookup in ReorderableDrawer.GetList 17 | //but just wanted to highlight the usage of the [Reorderable] attribute 18 | 19 | autoList = serializedObject.FindProperty("autoNameList"); 20 | dynamicList = serializedObject.FindProperty("dynamicNameList"); 21 | nameOverride = serializedObject.FindProperty("nameOverride"); 22 | nestedNameOverride = serializedObject.FindProperty("nestedNameOverride"); 23 | } 24 | 25 | public override void OnInspectorGUI() { 26 | 27 | serializedObject.Update(); 28 | 29 | EditorGUILayout.PropertyField(nameOverride); 30 | EditorGUILayout.PropertyField(nestedNameOverride); 31 | 32 | EditorGUILayout.PropertyField(autoList); 33 | EditorGUILayout.PropertyField(dynamicList); 34 | 35 | //dynamically change the names of the elements 36 | 37 | UpdateElementNames(dynamicList, nameOverride); 38 | UpdateNestedElementNames(dynamicList.FindPropertyRelative("array"), nestedNameOverride); 39 | 40 | serializedObject.ApplyModifiedProperties(); 41 | } 42 | 43 | private void UpdateNestedElementNames(SerializedProperty array, SerializedProperty nameOverride) { 44 | 45 | for (int i = 0; i < array.arraySize; i++) { 46 | 47 | UpdateElementNames(array.GetArrayElementAtIndex(i).FindPropertyRelative("nested"), nameOverride); 48 | } 49 | } 50 | 51 | private void UpdateElementNames(SerializedProperty listProperty, SerializedProperty nameOverride) { 52 | 53 | ReorderableList list = ReorderableDrawer.GetList(listProperty, ReorderableDrawer.ARRAY_PROPERTY_NAME); 54 | 55 | if (list != null) { 56 | 57 | list.elementNameOverride = nameOverride.stringValue; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/NameOverrideEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8747cca643cdcf48b78b4edb811c302 3 | timeCreated: 1492033589 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/NestedChildDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | [CustomPropertyDrawer(typeof(NestedExample.NestedChildCustomDrawer))] 7 | public class NestedChildDrawer : PropertyDrawer { 8 | 9 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { 10 | 11 | Rect r1 = position; 12 | r1.width = 20; 13 | 14 | Rect r2 = position; 15 | r2.xMin = r1.xMax + 10; 16 | 17 | EditorGUI.BeginProperty(position, label, property); 18 | 19 | EditorGUI.PropertyField(r1, property.FindPropertyRelative("myBool"), GUIContent.none); 20 | EditorGUI.PropertyField(r2, property.FindPropertyRelative("myGameObject"), GUIContent.none); 21 | 22 | EditorGUI.EndProperty(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/NestedChildDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23274f94d2eb0024c9a5495720cb3c4e 3 | timeCreated: 1511997911 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/SurrogateTestEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using Malee.List; 6 | 7 | [CustomEditor(typeof(SurrogateTest))] 8 | public class SurrogateTestEditor : Editor { 9 | 10 | private ReorderableList list; 11 | private SerializedProperty myClassArray; 12 | 13 | private void OnEnable() { 14 | 15 | //custom list with more complex surrogate functionalty 16 | 17 | list = new ReorderableList(serializedObject.FindProperty("objects")); 18 | list.surrogate = new ReorderableList.Surrogate(typeof(GameObject), AppendObject); 19 | 20 | //myClassArray uses an auto surrogate property on the "ReorderableAttribute" 21 | //it's limited to only setting a property field to the dragged object reference. Still handy! 22 | 23 | myClassArray = serializedObject.FindProperty("myClassArray"); 24 | } 25 | 26 | public override void OnInspectorGUI() { 27 | 28 | GUILayout.Label("Drag a GameObject onto the lists. Even though the list type is not a GameObject!"); 29 | 30 | serializedObject.Update(); 31 | 32 | list.DoLayoutList(); 33 | EditorGUILayout.PropertyField(myClassArray); 34 | 35 | serializedObject.ApplyModifiedProperties(); 36 | } 37 | 38 | private void AppendObject(SerializedProperty element, Object objectReference, ReorderableList list) { 39 | 40 | //we can do more with a custom surrogate delegate :) 41 | 42 | element.FindPropertyRelative("gameObject").objectReferenceValue = objectReference; 43 | element.FindPropertyRelative("name").stringValue = objectReference.name; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Samples~/Examples/Editor/SurrogateTestEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5877d6ab8ea9b064b89e8f643fb899d3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d62a9c65be9a78740a08dd089a1030e1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/Example.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &153236 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 405140} 12 | - component: {fileID: 11448876} 13 | m_Layer: 0 14 | m_Name: Example 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &405140 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 153236} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &11448876 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 153236} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: af3458bf8c0bae74da4a0547963310ff, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | list1: 47 | - name: 48 | value: 1.11 49 | myEnum: 0 50 | layerMask: 51 | serializedVersion: 2 52 | m_Bits: 0 53 | longValue: 1 54 | charValue: 52 55 | byteValue: 0 56 | - name: 57 | value: 1.27 58 | myEnum: 0 59 | layerMask: 60 | serializedVersion: 2 61 | m_Bits: 4294967295 62 | longValue: 0 63 | charValue: 52 64 | byteValue: 0 65 | - name: 66 | value: 8.06 67 | myEnum: 0 68 | layerMask: 69 | serializedVersion: 2 70 | m_Bits: 16 71 | longValue: 3 72 | charValue: 57 73 | byteValue: 0 74 | - name: 75 | value: 1.47 76 | myEnum: 0 77 | layerMask: 78 | serializedVersion: 2 79 | m_Bits: 4 80 | longValue: 2 81 | charValue: 48 82 | byteValue: 255 83 | list2: 84 | array: 85 | - name: Second 86 | value: -0.04 87 | myEnum: 0 88 | layerMask: 89 | serializedVersion: 2 90 | m_Bits: 0 91 | longValue: 0 92 | charValue: 0 93 | byteValue: 0 94 | - name: Third 95 | value: -0.3 96 | myEnum: 0 97 | layerMask: 98 | serializedVersion: 2 99 | m_Bits: 0 100 | longValue: 0 101 | charValue: 0 102 | byteValue: 0 103 | - name: First 104 | value: -1.31 105 | myEnum: 0 106 | layerMask: 107 | serializedVersion: 2 108 | m_Bits: 0 109 | longValue: 0 110 | charValue: 0 111 | byteValue: 0 112 | - name: Forth 113 | value: 0 114 | myEnum: 0 115 | layerMask: 116 | serializedVersion: 2 117 | m_Bits: 0 118 | longValue: 0 119 | charValue: 0 120 | byteValue: 0 121 | - name: Fifth 122 | value: 0 123 | myEnum: 0 124 | layerMask: 125 | serializedVersion: 2 126 | m_Bits: 0 127 | longValue: 0 128 | charValue: 0 129 | byteValue: 0 130 | list3: 131 | array: 132 | - name: 133 | value: 0 134 | myEnum: 0 135 | layerMask: 136 | serializedVersion: 2 137 | m_Bits: 0 138 | longValue: 0 139 | charValue: 0 140 | byteValue: 0 141 | - name: 142 | value: 0 143 | myEnum: 0 144 | layerMask: 145 | serializedVersion: 2 146 | m_Bits: 0 147 | longValue: 0 148 | charValue: 0 149 | byteValue: 0 150 | - name: 151 | value: 0 152 | myEnum: 2 153 | layerMask: 154 | serializedVersion: 2 155 | m_Bits: 0 156 | longValue: 0 157 | charValue: 0 158 | byteValue: 0 159 | list4: 160 | array: 161 | - 162 | - df 163 | list5: 164 | array: 165 | - {x: 0, y: 0, z: 0, w: 0} 166 | - {x: 0, y: 0, z: 0, w: 0} 167 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/Example.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4963c3cb67bce2a459043899068fe87c 3 | timeCreated: 1436470369 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/GameObjects.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1400574306493906 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4688285583432476} 12 | - component: {fileID: 114408100911702980} 13 | m_Layer: 0 14 | m_Name: GameObjects 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &4688285583432476 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 1400574306493906} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114408100911702980 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 1400574306493906} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: d0103a5e439fa9643adb92b1913cd5aa, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | list: 47 | array: 48 | - {fileID: 153236, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 49 | - {fileID: 1400574306493906} 50 | - {fileID: 1939093664255724, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 51 | - {fileID: 0} 52 | - {fileID: 0} 53 | - {fileID: 0} 54 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/GameObjects.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 16d46c3976545084696abd91dcefb546 3 | timeCreated: 1492483683 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NameOverride 1.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1939093664255724 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4084475993505058} 12 | - component: {fileID: 114708834545353134} 13 | m_Layer: 0 14 | m_Name: NameOverride 1 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &4084475993505058 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 1939093664255724} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114708834545353134 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 1939093664255724} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: c7d571dc48f14af469b71bb423061dfc, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | nameOverride: My Car 47 | nestedNameOverride: Some Car Part 48 | autoNameList: 49 | array: 50 | - nested: 51 | array: 52 | - 53 | - 54 | - nested: 55 | array: 56 | - 57 | - 58 | - 59 | - 60 | - nested: 61 | array: 62 | - Yes 63 | - 2 64 | - 3 65 | - 4 66 | - nested: 67 | array: 68 | - Yes 69 | - 2 70 | - 3 71 | - 4 72 | dynamicNameList: 73 | array: 74 | - nested: 75 | array: 76 | - 77 | - 78 | - nested: 79 | array: 80 | - 81 | - 82 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NameOverride 1.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f20c0e7ca77a0d64b9b3c56602651962 3 | timeCreated: 1492034369 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NameOverride.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1939093664255724 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4084475993505058} 12 | - component: {fileID: 114708834545353134} 13 | m_Layer: 0 14 | m_Name: NameOverride 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &4084475993505058 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 1939093664255724} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114708834545353134 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 1939093664255724} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: c7d571dc48f14af469b71bb423061dfc, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | nameOverride: My Car 47 | nestedNameOverride: Some Car Part 48 | autoNameList: 49 | array: 50 | - nested: 51 | array: 52 | - 53 | - 54 | - nested: 55 | array: 56 | - 57 | - 58 | - 59 | - 60 | - nested: 61 | array: 62 | - Yes 63 | - 2 64 | - 3 65 | - 4 66 | - nested: 67 | array: 68 | - Yes 69 | - 2 70 | - 3 71 | - 4 72 | dynamicNameList: 73 | array: 74 | - nested: 75 | array: 76 | - 77 | - 78 | - nested: 79 | array: 80 | - 81 | - 82 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NameOverride.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd140f6c302d9fa4f8f821dc5c29f532 3 | timeCreated: 1492034369 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NestedExample 1.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &153236 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 405140} 12 | - component: {fileID: 114422533319628934} 13 | m_Layer: 0 14 | m_Name: NestedExample 1 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &405140 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 153236} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114422533319628934 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 153236} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: 2df27572c047a7a4fa8620ed7036383e, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | list: 47 | array: 48 | - nested: 49 | array: 50 | - myBool: 0 51 | myGameObject: {fileID: 0} 52 | - myBool: 0 53 | myGameObject: {fileID: 0} 54 | - myBool: 0 55 | myGameObject: {fileID: 0} 56 | - nested: 57 | array: 58 | - myBool: 0 59 | myGameObject: {fileID: 0} 60 | - myBool: 0 61 | myGameObject: {fileID: 0} 62 | - nested: 63 | array: 64 | - myBool: 0 65 | myGameObject: {fileID: 0} 66 | - myBool: 0 67 | myGameObject: {fileID: 0} 68 | - nested: 69 | array: 70 | - myBool: 0 71 | myGameObject: {fileID: 0} 72 | - myBool: 0 73 | myGameObject: {fileID: 0} 74 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NestedExample 1.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a38ddb64c54b7248a439e3b4731c30e 3 | timeCreated: 1436470369 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NestedExample.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &153236 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 405140} 12 | - component: {fileID: 114422533319628934} 13 | m_Layer: 0 14 | m_Name: NestedExample 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &405140 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 153236} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114422533319628934 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 153236} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: 2df27572c047a7a4fa8620ed7036383e, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | list: 47 | array: 48 | - nested: 49 | array: 50 | - myBool: 0 51 | myGameObject: {fileID: 0} 52 | - myBool: 0 53 | myGameObject: {fileID: 0} 54 | - nested: 55 | array: 56 | - myBool: 0 57 | myGameObject: {fileID: 0} 58 | - myBool: 0 59 | myGameObject: {fileID: 0} 60 | - myBool: 0 61 | myGameObject: {fileID: 0} 62 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/NestedExample.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e88bceeae38d8d34da23ff0aa6945f8f 3 | timeCreated: 1436470369 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/Recursion.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1164693187312736 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4340923265471038} 12 | - component: {fileID: 114115380435015346} 13 | m_Layer: 0 14 | m_Name: Recursion 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &4340923265471038 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 1164693187312736} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114115380435015346 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 1164693187312736} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: 0f2d4341b782e3f4d8c1be535119a983, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/Recursion.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d024d69a4ddb914c9cc19a0a210dc8a 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 100100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/ScriptableObject Example 1.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 1d42752ae62b22b47aef2032ceee5689, type: 3} 13 | m_Name: ScriptableObject Example 1 14 | m_EditorClassIdentifier: 15 | list: 16 | array: 17 | - myBool: 1 18 | myValue: 1 19 | myString: 20 | - myBool: 0 21 | myValue: 2 22 | myString: 23 | - myBool: 0 24 | myValue: 3 25 | myString: 26 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/ScriptableObject Example 1.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b5da86673e71c024a80e42862cf9a3b9 3 | timeCreated: 1525975230 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 11400000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/ScriptableObject Example 2.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 1d42752ae62b22b47aef2032ceee5689, type: 3} 13 | m_Name: ScriptableObject Example 2 14 | m_EditorClassIdentifier: 15 | list: 16 | array: 17 | - myBool: 1 18 | myValue: 1 19 | myString: I'm first 20 | - myBool: 1 21 | myValue: 2 22 | myString: I'm second 23 | - myBool: 1 24 | myValue: 2 25 | myString: I'm second 26 | - myBool: 1 27 | myValue: 2 28 | myString: I'm second 29 | - myBool: 1 30 | myValue: 2 31 | myString: I'm second 32 | - myBool: 1 33 | myValue: 2 34 | myString: I'm second 35 | - myBool: 1 36 | myValue: 2 37 | myString: I'm second 38 | - myBool: 1 39 | myValue: 2 40 | myString: I'm second 41 | - myBool: 1 42 | myValue: 2 43 | myString: I'm second 44 | - myBool: 1 45 | myValue: 2 46 | myString: I'm second 47 | - myBool: 1 48 | myValue: 2 49 | myString: I'm second 50 | - myBool: 1 51 | myValue: 2 52 | myString: I'm second 53 | - myBool: 1 54 | myValue: 2 55 | myString: I'm second 56 | - myBool: 1 57 | myValue: 2 58 | myString: I'm second 59 | - myBool: 1 60 | myValue: 2 61 | myString: I'm second 62 | - myBool: 1 63 | myValue: 2 64 | myString: I'm second 65 | - myBool: 1 66 | myValue: 2 67 | myString: I'm second 68 | - myBool: 1 69 | myValue: 2 70 | myString: I'm second 71 | - myBool: 1 72 | myValue: 2 73 | myString: I'm second 74 | - myBool: 1 75 | myValue: 2 76 | myString: I'm second 77 | - myBool: 1 78 | myValue: 2 79 | myString: I'm second 80 | - myBool: 1 81 | myValue: 2 82 | myString: I'm second 83 | - myBool: 1 84 | myValue: 2 85 | myString: I'm second 86 | - myBool: 1 87 | myValue: 2 88 | myString: I'm second 89 | - myBool: 1 90 | myValue: 2 91 | myString: I'm second 92 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/ScriptableObject Example 2.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3de0dc138251b7d4bbb29ca8d4b10ada 3 | timeCreated: 1525975230 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 11400000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/SurrogateTest.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1404859341055318 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 4521775596195526} 12 | - component: {fileID: 114831566704652670} 13 | m_Layer: 0 14 | m_Name: SurrogateTest 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &4521775596195526 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 1404859341055318} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &114831566704652670 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 1404859341055318} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 11500000, guid: b36c6dccb89b95a4788ef8e868164c01, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | objects: 47 | - name: Example 48 | gameObject: {fileID: 153236, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 49 | myClassArray: 50 | array: 51 | - name: 52 | gameObject: {fileID: 153236, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 53 | - name: 54 | gameObject: {fileID: 153236, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 55 | -------------------------------------------------------------------------------- /Samples~/Examples/Prefabs/SurrogateTest.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b7204639ebbd91b47a2e8740100ad0a4 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 100100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/ReorderablePrefabs.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 3 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &4 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 0 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 0 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 1024 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 1 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 500 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 2 83 | m_PVRDenoiserTypeDirect: 0 84 | m_PVRDenoiserTypeIndirect: 0 85 | m_PVRDenoiserTypeAO: 0 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 0 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_UseShadowmask: 0 102 | --- !u!196 &5 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | debug: 122 | m_Flags: 0 123 | m_NavMeshData: {fileID: 0} 124 | --- !u!1 &146106284 125 | GameObject: 126 | m_ObjectHideFlags: 0 127 | m_CorrespondingSourceObject: {fileID: 0} 128 | m_PrefabInstance: {fileID: 0} 129 | m_PrefabAsset: {fileID: 0} 130 | serializedVersion: 6 131 | m_Component: 132 | - component: {fileID: 146106289} 133 | - component: {fileID: 146106288} 134 | - component: {fileID: 146106286} 135 | - component: {fileID: 146106285} 136 | m_Layer: 0 137 | m_Name: Main Camera 138 | m_TagString: MainCamera 139 | m_Icon: {fileID: 0} 140 | m_NavMeshLayer: 0 141 | m_StaticEditorFlags: 0 142 | m_IsActive: 1 143 | --- !u!81 &146106285 144 | AudioListener: 145 | m_ObjectHideFlags: 0 146 | m_CorrespondingSourceObject: {fileID: 0} 147 | m_PrefabInstance: {fileID: 0} 148 | m_PrefabAsset: {fileID: 0} 149 | m_GameObject: {fileID: 146106284} 150 | m_Enabled: 1 151 | --- !u!124 &146106286 152 | Behaviour: 153 | m_ObjectHideFlags: 0 154 | m_CorrespondingSourceObject: {fileID: 0} 155 | m_PrefabInstance: {fileID: 0} 156 | m_PrefabAsset: {fileID: 0} 157 | m_GameObject: {fileID: 146106284} 158 | m_Enabled: 1 159 | --- !u!20 &146106288 160 | Camera: 161 | m_ObjectHideFlags: 0 162 | m_CorrespondingSourceObject: {fileID: 0} 163 | m_PrefabInstance: {fileID: 0} 164 | m_PrefabAsset: {fileID: 0} 165 | m_GameObject: {fileID: 146106284} 166 | m_Enabled: 1 167 | serializedVersion: 2 168 | m_ClearFlags: 1 169 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} 170 | m_projectionMatrixMode: 1 171 | m_GateFitMode: 2 172 | m_FOVAxisMode: 0 173 | m_SensorSize: {x: 36, y: 24} 174 | m_LensShift: {x: 0, y: 0} 175 | m_FocalLength: 50 176 | m_NormalizedViewPortRect: 177 | serializedVersion: 2 178 | x: 0 179 | y: 0 180 | width: 1 181 | height: 1 182 | near clip plane: 0.3 183 | far clip plane: 1000 184 | field of view: 60 185 | orthographic: 1 186 | orthographic size: 5 187 | m_Depth: -1 188 | m_CullingMask: 189 | serializedVersion: 2 190 | m_Bits: 4294967295 191 | m_RenderingPath: -1 192 | m_TargetTexture: {fileID: 0} 193 | m_TargetDisplay: 0 194 | m_TargetEye: 3 195 | m_HDR: 0 196 | m_AllowMSAA: 1 197 | m_AllowDynamicResolution: 0 198 | m_ForceIntoRT: 0 199 | m_OcclusionCulling: 1 200 | m_StereoConvergence: 10 201 | m_StereoSeparation: 0.022 202 | --- !u!4 &146106289 203 | Transform: 204 | m_ObjectHideFlags: 0 205 | m_CorrespondingSourceObject: {fileID: 0} 206 | m_PrefabInstance: {fileID: 0} 207 | m_PrefabAsset: {fileID: 0} 208 | m_GameObject: {fileID: 146106284} 209 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 210 | m_LocalPosition: {x: 0, y: 0, z: -10} 211 | m_LocalScale: {x: 1, y: 1, z: 1} 212 | m_Children: [] 213 | m_Father: {fileID: 0} 214 | m_RootOrder: 0 215 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 216 | --- !u!1001 &1386932973 217 | PrefabInstance: 218 | m_ObjectHideFlags: 0 219 | serializedVersion: 2 220 | m_Modification: 221 | m_TransformParent: {fileID: 0} 222 | m_Modifications: 223 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 224 | propertyPath: m_LocalPosition.x 225 | value: 0 226 | objectReference: {fileID: 0} 227 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 228 | propertyPath: m_LocalPosition.y 229 | value: 0 230 | objectReference: {fileID: 0} 231 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 232 | propertyPath: m_LocalPosition.z 233 | value: 0 234 | objectReference: {fileID: 0} 235 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 236 | propertyPath: m_LocalRotation.x 237 | value: 0 238 | objectReference: {fileID: 0} 239 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 240 | propertyPath: m_LocalRotation.y 241 | value: 0 242 | objectReference: {fileID: 0} 243 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 244 | propertyPath: m_LocalRotation.z 245 | value: 0 246 | objectReference: {fileID: 0} 247 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 248 | propertyPath: m_LocalRotation.w 249 | value: 1 250 | objectReference: {fileID: 0} 251 | - target: {fileID: 405140, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 252 | propertyPath: m_RootOrder 253 | value: 2 254 | objectReference: {fileID: 0} 255 | m_RemovedComponents: [] 256 | m_SourcePrefab: {fileID: 100100000, guid: e88bceeae38d8d34da23ff0aa6945f8f, type: 3} 257 | --- !u!1001 &1403507907 258 | PrefabInstance: 259 | m_ObjectHideFlags: 0 260 | serializedVersion: 2 261 | m_Modification: 262 | m_TransformParent: {fileID: 0} 263 | m_Modifications: 264 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 265 | propertyPath: m_LocalPosition.x 266 | value: 0 267 | objectReference: {fileID: 0} 268 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 269 | propertyPath: m_LocalPosition.y 270 | value: 0 271 | objectReference: {fileID: 0} 272 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 273 | propertyPath: m_LocalPosition.z 274 | value: 0 275 | objectReference: {fileID: 0} 276 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 277 | propertyPath: m_LocalRotation.x 278 | value: 0 279 | objectReference: {fileID: 0} 280 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 281 | propertyPath: m_LocalRotation.y 282 | value: 0 283 | objectReference: {fileID: 0} 284 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 285 | propertyPath: m_LocalRotation.z 286 | value: 0 287 | objectReference: {fileID: 0} 288 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 289 | propertyPath: m_LocalRotation.w 290 | value: 1 291 | objectReference: {fileID: 0} 292 | - target: {fileID: 4084475993505058, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 293 | propertyPath: m_RootOrder 294 | value: 3 295 | objectReference: {fileID: 0} 296 | m_RemovedComponents: [] 297 | m_SourcePrefab: {fileID: 100100000, guid: bd140f6c302d9fa4f8f821dc5c29f532, type: 3} 298 | --- !u!1001 &1478244043 299 | PrefabInstance: 300 | m_ObjectHideFlags: 0 301 | serializedVersion: 2 302 | m_Modification: 303 | m_TransformParent: {fileID: 0} 304 | m_Modifications: 305 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 306 | propertyPath: m_LocalPosition.x 307 | value: 0 308 | objectReference: {fileID: 0} 309 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 310 | propertyPath: m_LocalPosition.y 311 | value: 0 312 | objectReference: {fileID: 0} 313 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 314 | propertyPath: m_LocalPosition.z 315 | value: 0 316 | objectReference: {fileID: 0} 317 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 318 | propertyPath: m_LocalRotation.x 319 | value: 0 320 | objectReference: {fileID: 0} 321 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 322 | propertyPath: m_LocalRotation.y 323 | value: 0 324 | objectReference: {fileID: 0} 325 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 326 | propertyPath: m_LocalRotation.z 327 | value: 0 328 | objectReference: {fileID: 0} 329 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 330 | propertyPath: m_LocalRotation.w 331 | value: 1 332 | objectReference: {fileID: 0} 333 | - target: {fileID: 405140, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 334 | propertyPath: m_RootOrder 335 | value: 1 336 | objectReference: {fileID: 0} 337 | - target: {fileID: 11448876, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 338 | propertyPath: list2._hashCode 339 | value: 2124080960 340 | objectReference: {fileID: 0} 341 | - target: {fileID: 11448876, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 342 | propertyPath: list2.array.Array.data[0].name 343 | value: Third 344 | objectReference: {fileID: 0} 345 | m_RemovedComponents: [] 346 | m_SourcePrefab: {fileID: 100100000, guid: 4963c3cb67bce2a459043899068fe87c, type: 3} 347 | -------------------------------------------------------------------------------- /Samples~/Examples/ReorderablePrefabs.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9113b3724fdc84042bd956d6a368b549 3 | timeCreated: 1436470366 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 49157f2b53e9fec48bc5be840c19d3f7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/Example.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Malee.List; 5 | 6 | public class Example : MonoBehaviour { 7 | 8 | public List list1; 9 | 10 | [Reorderable] 11 | public ExampleChildList list2; 12 | 13 | [Reorderable] 14 | public ExampleChildList list3; 15 | 16 | [Reorderable] 17 | public StringList list4; 18 | 19 | [Reorderable] 20 | public VectorList list5; 21 | 22 | [System.Serializable] 23 | public class ExampleChild { 24 | 25 | public string name; 26 | public float value; 27 | public ExampleEnum myEnum; 28 | public LayerMask layerMask; 29 | public long longValue; 30 | public char charValue; 31 | public byte byteValue; 32 | 33 | public enum ExampleEnum { 34 | EnumValue1, 35 | EnumValue2, 36 | EnumValue3 37 | } 38 | } 39 | 40 | [System.Serializable] 41 | public class ExampleChildList : ReorderableArray { 42 | } 43 | 44 | [System.Serializable] 45 | public class StringList : ReorderableArray { 46 | } 47 | 48 | [System.Serializable] 49 | public class VectorList : ReorderableArray { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/Example.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af3458bf8c0bae74da4a0547963310ff 3 | timeCreated: 1436467410 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/GameObjectExample.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | public class GameObjectExample : MonoBehaviour { 7 | 8 | //There's a bug with Unity and rendering when an Object has no CustomEditor defined. As in this example 9 | //The list will reorder correctly, but depth sorting and animation will not update :( 10 | [Reorderable(paginate = true, pageSize = 2)] 11 | public GameObjectList list; 12 | 13 | [System.Serializable] 14 | public class GameObjectList : ReorderableArray { 15 | } 16 | 17 | private void Update() { 18 | 19 | if (Input.GetKeyDown(KeyCode.Space)) { 20 | 21 | list.Add(gameObject); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/GameObjectExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0103a5e439fa9643adb92b1913cd5aa 3 | timeCreated: 1492477782 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/NameOverride.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | public class NameOverride : MonoBehaviour { 7 | 8 | public string nameOverride = "Car"; 9 | public string nestedNameOverride = "Car Part"; 10 | 11 | [Reorderable(null, "Car", null)] 12 | public ExampleChildList autoNameList; 13 | 14 | [Reorderable] 15 | public DynamicExampleChildList dynamicNameList; 16 | 17 | [System.Serializable] 18 | public class ExampleChild { 19 | 20 | [Reorderable(null, "Car Part", null)] 21 | public StringList nested; 22 | } 23 | 24 | [System.Serializable] 25 | public class DynamicExampleChild { 26 | 27 | [Reorderable] 28 | public StringList nested; 29 | } 30 | 31 | [System.Serializable] 32 | public class ExampleChildList : ReorderableArray { 33 | } 34 | 35 | [System.Serializable] 36 | public class DynamicExampleChildList : ReorderableArray { 37 | } 38 | 39 | [System.Serializable] 40 | public class StringList : ReorderableArray { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/NameOverride.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7d571dc48f14af469b71bb423061dfc 3 | timeCreated: 1492033597 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/NestedExample.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | public class NestedExample : MonoBehaviour { 7 | 8 | [Reorderable] 9 | public ExampleChildList list; 10 | 11 | [System.Serializable] 12 | public class ExampleChild { 13 | 14 | [Reorderable(singleLine = true)] 15 | public NestedChildList nested; 16 | } 17 | 18 | [System.Serializable] 19 | public class NestedChild { 20 | 21 | public float myValue; 22 | } 23 | 24 | [System.Serializable] 25 | public class NestedChildCustomDrawer { 26 | 27 | public bool myBool; 28 | public GameObject myGameObject; 29 | } 30 | 31 | [System.Serializable] 32 | public class ExampleChildList : ReorderableArray { 33 | } 34 | 35 | [System.Serializable] 36 | public class NestedChildList : ReorderableArray { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/NestedExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2df27572c047a7a4fa8620ed7036383e 3 | timeCreated: 1491846458 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/RecursionTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | public class RecursionTest : MonoBehaviour { 7 | 8 | /* Don't do this! 9 | [Reorderable] 10 | public Tables tables = new Tables(); 11 | 12 | [System.Serializable] 13 | public class Table { 14 | 15 | public string name; 16 | 17 | [Reorderable] 18 | public Tables table; 19 | } 20 | 21 | [System.Serializable] 22 | public class Tables : ReorderableArray { 23 | } 24 | */ 25 | } 26 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/RecursionTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0f2d4341b782e3f4d8c1be535119a983 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/ScriptableObjectExample.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | [CreateAssetMenu(fileName = "New ScriptableObject Example", menuName = "ScriptableObject Example")] 7 | public class ScriptableObjectExample : ScriptableObject { 8 | 9 | [SerializeField, Reorderable(paginate = true, pageSize = 0, elementNameProperty = "myString")] 10 | private MyList list; 11 | 12 | [System.Serializable] 13 | private struct MyObject { 14 | 15 | public bool myBool; 16 | public float myValue; 17 | public string myString; 18 | 19 | public MyObject(bool myBool, float myValue, string myString) { 20 | 21 | this.myBool = myBool; 22 | this.myValue = myValue; 23 | this.myString = myString; 24 | } 25 | } 26 | 27 | [System.Serializable] 28 | private class MyList : ReorderableArray { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/ScriptableObjectExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d42752ae62b22b47aef2032ceee5689 3 | timeCreated: 1525975128 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/SurrogateTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Malee.List; 5 | 6 | public class SurrogateTest : MonoBehaviour { 7 | 8 | [SerializeField] 9 | private MyClass[] objects; 10 | 11 | [SerializeField, Reorderable(surrogateType = typeof(GameObject), surrogateProperty = "gameObject")] 12 | private MyClassArray myClassArray; 13 | 14 | [System.Serializable] 15 | public class MyClass { 16 | 17 | public string name; 18 | public GameObject gameObject; 19 | } 20 | 21 | [System.Serializable] 22 | public class MyClassArray : ReorderableArray { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples~/Examples/Runtime/SurrogateTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b36c6dccb89b95a4788ef8e868164c01 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.malee.reorderablelist", 3 | "author": "Chris Foulston", 4 | "displayName": "Reorderable List", 5 | "version": "1.0.1", 6 | "unity": "2018.1", 7 | "keywords": [ 8 | "unity", 9 | "editor", 10 | "list" 11 | ], 12 | "description": "Editor extension for managing the ordering of List and Array contents", 13 | "samples": [ 14 | { 15 | "displayName": "Examples", 16 | "description": "A set of examples highlighting various features of the ReorderableList package", 17 | "path": "Samples~/Examples" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e6198cea7116cf4ea17cbc611b20280 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------