public Rect Render(Rect position, SerializedProperty property, GUIContent label)
        {
            if (property.serializedObject.targetObject == null)
            {
                return(position);
            }

            if (playModeState == PlayModeStateChange.ExitingEditMode || playModeState == PlayModeStateChange.ExitingPlayMode)
            {
                return(position);
            }

            DrawerState state = GetDrawerState(property);

            SerializedProperty collection = property.FindPropertyRelative("values");

            if (collection == null)
            {
                Debug.Log(property.name);
            }
            if (!ReorderableCollection.ListStates.ContainsKey(GetFullPath(collection)))
            {
                var newList = new ReorderableCollection(property, collection);
                newList.DrawHeaderAreaHandlers.Add(DrawTitle);

                newList.DrawElement     += DrawElement;
                newList.DrawAddElement   = DrawAddElement;
                newList.GetElementHeight = GetElementHeight;
                newList.Reorder         += OnReorder;
            }

            state.Property = property;
            state.Height   = 0;

            Rect startPosition = position;

            DisplayState listState   = ReorderableCollection.ListStates[GetFullPath(collection)];
            Color        cachedColor = UnityEngine.GUI.color;
            var          settings    = PackageSettings.Settings.GetListSettings(collection);

            if (settings != null && settings.Color != Color.white)
            {
                UnityEngine.GUI.color = settings.Color;
            }

            if (collection != null)
            {
                position = DrawCollection(position, property, collection, label);
            }
            state.Height          = position.y - startPosition.y;
            UnityEngine.GUI.color = cachedColor;

            return(position);
        }
        public static DrawerState GetDrawerState(SerializedProperty property)
        {
            string      propertyPath = GetFullPath(property);
            DrawerState state;

            if (!DrawerStates.ContainsKey(propertyPath))
            {
                state = new DrawerState(property);
                DrawerStates.Add(GetFullPath(property), state);
                state.Property = property;
                state.Height   = 0;
            }
            else
            {
                state = DrawerStates[propertyPath];
            }

            return(state);
        }
        public ReorderableCollection(SerializedProperty property, SerializedProperty collection)
        {
            bool   allowDrag     = true;
            object pathReference = SerializationReflection.GetPathReference(property);

            if (pathReference != null)
            {
                Type sortedType = SerializationReflection.GetPathReference(property).GetType();

                while (sortedType != null)
                {
                    if (sortedType.GetInterface("SortedCollection`1") != null)
                    {
                        allowDrag = false;
                        break;
                    }
                    sortedType = sortedType.BaseType;
                }
            }

            string collectionPath = CollectionDisplay.GetFullPath(collection);

            DisplayState listState;

            if (ListStates.ContainsKey(collectionPath))
            {
                ListStates.Remove(collectionPath);
            }

            listState = new DisplayState();
            ListStates.Add(collectionPath, listState);
            listState.Collection = collection;
            listState.List       = this;

            DrawerState drawerState = CollectionDisplay.GetDrawerState(property);
            var         newList     = new ReorderableList(collection.serializedObject, collection)
            {
                draggable = allowDrag,
            };

            newList.showDefaultBackground = false;

            newList.onReorderCallbackWithDetails = (ReorderableList list, int oldIndex, int newIndex) =>
            {
                Reorder?.Invoke(drawerState.Property, listState.Collection, oldIndex, newIndex);
            };

            newList.drawHeaderCallback = (Rect position) =>
            {
                SerializedProperty hasLostValue = drawerState.Property.FindPropertyRelative("hasLostValue");
                if (hasLostValue != null && hasLostValue.boolValue == true)
                {
                    EditorUtility.DisplayDialog("Collection Error", "You've attempted to change an element in a way that prevents it from being added to the collection. The element will be moved to the Add Element area of the list so you can change the element and add it back in.", "Okay");
                    ListStates[CollectionDisplay.GetFullPath(listState.Collection)].AddingElement = true;
                    hasLostValue.boolValue = false;
                }

                Rect startPosition = position;

                DrawHeaderBackground(position, drawerState.Property, listState.Collection);
                DrawSettingsButton(position, drawerState.Property, listState.Collection);
                position.y += DrawSettings(position, drawerState.Property, listState.Collection);

                for (var i = 0; i < DrawHeaderAreaHandlers.Count; i++)
                {
                    position.y += DrawHeaderAreaHandlers[i].Invoke(position, drawerState.Property, listState.Collection);
                }

                listState.LastHeaderHeight = position.y - startPosition.y;
                newList.headerHeight       = listState.LastHeaderHeight;
            };

            newList.drawElementCallback += (Rect position, int index, bool isActive, bool isFocused) =>
            {
                position.y += 2;

                var pageRange = GetPageDisplayRange(listState.Collection);
                if (index >= pageRange.x && index < pageRange.y)
                {
                    EditorGUI.BeginDisabledGroup(listState.AddingElement);
                    DrawElement?.Invoke(position, index, drawerState.Property, listState.Collection);
                    EditorGUI.EndDisabledGroup();
                }
            };

            newList.drawElementBackgroundCallback = (Rect position, int index, bool isActive, bool isFocused) =>
            {
                if (Mathf.Approximately(position.height, 0))
                {
                    return;
                }

                Rect backgroundPos = position;
                backgroundPos.yMin       -= 2;
                backgroundPos.yMax       += 2;
                boxBackground.fixedHeight = backgroundPos.height;
                boxBackground.fixedWidth  = backgroundPos.width;
                Color guiColor = UnityEngine.GUI.color;

                if (isActive)
                {
                    UnityEngine.GUI.color = UnityEngine.GUI.skin.settings.selectionColor;
                }

                if (index % 2 == 0)
                {
                    UnityEngine.GUI.color = Color.Lerp(UnityEngine.GUI.color, Color.black, .1f);
                }

                if (Event.current.type == EventType.Repaint)
                {
                    boxBackground.Draw(position, false, isActive, true, false);
                }

                UnityEngine.GUI.color = guiColor;

                position.xMin += 2;
                position.xMax -= 3;
            };

            newList.elementHeightCallback += (int index) =>
            {
                int pageSize       = GetItemsPerPage(listState.Collection);
                int pageStartIndex = (listState.CurrentPageSet * listState.PageSetSize * pageSize) + (listState.CurrentPage * pageSize);
                int pageEndIndex   = pageStartIndex + pageSize;

                if (index >= pageStartIndex && index < pageEndIndex && (GetElementHeight != null))
                {
                    return(GetElementHeight(index, drawerState.Property, listState.Collection) + 2);
                }

                return(0);
            };

            newList.drawFooterCallback = (Rect position) =>
            {
                DrawFooterBackground(position, drawerState.Property, listState.Collection);
                DrawAddRemoveButtons(position, drawerState.Property, listState.Collection);

                Rect startPosition = position;
                for (var i = 0; i < DrawFooterAreaHandlers.Count; i++)
                {
                    position.y += DrawFooterAreaHandlers[i].Invoke(position, drawerState.Property, listState.Collection);
                }

                position.y += DrawPageSelection(position, drawerState.Property, listState.Collection);
                if (listState.List.DrawCustomAdd)
                {
                    position.y += DrawAddArea(position, property, collection);
                }

                listState.LastFooterHeight  = position.y - startPosition.y;
                listState.LastFooterHeight += 4;
                List.footerHeight           = listState.LastFooterHeight;
            };

            newList.onRemoveCallback += (ReorderableList targetList) =>
            {
                if (targetList.index > -1)
                {
                    int pageSize       = GetItemsPerPage(listState.Collection);
                    int pageStartIndex = GetPageDisplayRange(listState.Collection).x;
                    listState.Collection.DeleteArrayElementAtIndex(pageStartIndex + targetList.index);
                }
            };

            newList.onAddCallback += (ReorderableList targetList) =>
            {
                if (DrawCustomAdd)
                {
                    ListStates[collectionPath].AddingElement = !ListStates[collectionPath].AddingElement;
                    if (ListStates[collectionPath].AddingElement)
                    {
                        SerializationReflection.CallPrivateMethod(property, "ClearTemp");
                    }
                }
                else
                {
                    listState.Collection.InsertArrayElementAtIndex(listState.Collection.arraySize);
                }
            };

            List = newList;
        }