protected virtual float DrawTitle(Rect position, SerializedProperty property, SerializedProperty collection)
        {
            Rect startPosition = position;
            var  fieldValue    = SerializationReflection.GetPathReference(collection);

            Type[]        generics      = fieldValue.GetType().GenericTypeArguments;
            StringBuilder typeArguments = new StringBuilder();

            for (var i = 0; i < generics.Length; i++)
            {
                typeArguments.Append(ObjectNames.NicifyVariableName(generics[i].Name));
                if (i < generics.Length - 1)
                {
                    typeArguments.Append(", ");
                }
            }

            string     nicePropertyType = ObjectNames.NicifyVariableName(property.type);
            GUIContent label            = new GUIContent($"{nicePropertyType} ({typeArguments.ToString()})");

            position.height = EditorStyles.label.CalcHeight(label, position.width) + 5;

            EditorGUI.LabelField(position, label, headerStyle);

            position.y += position.height;

            return(position.y - startPosition.y);
        }
        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;
        }