Example #1
0
        private DragHandle BeginDragHandle(ListDrawerConfigInfo info, int j, int i)
        {
            var child      = info.property.Children[j];
            var dragHandle = DragAndDropManager.BeginDragHandle(child, (TElement)child.ValueEntry.WeakSmartValue, info.IsReadOnly ? DragAndDropMethods.Reference : DragAndDropMethods.Move);

            dragHandle.Enabled = info.Draggable;

            if (dragHandle.OnDragStarted)
            {
                ListDrawerStaticInfo.CurrentDraggingPropertyInfo = info.property.Children[j];
                dragHandle.OnDragFinnished = dropEvent =>
                {
                    if (dropEvent == DropEvents.Moved)
                    {
                        // If it's a cross-window drag, the changes will for some reason be lost if we don't do this.
                        if (dragHandle.IsCrossWindowDrag)
                        {
                            GUIHelper.RequestRepaint();
                            EditorApplication.delayCall += () =>
                            {
                                info.ListValueChanger.RemoveListElementAt(j, CHANGE_ID);
                            };
                        }
                        else
                        {
                            info.ListValueChanger.RemoveListElementAt(j, CHANGE_ID);
                        }
                    }

                    ListDrawerStaticInfo.CurrentDraggingPropertyInfo = null;
                };
            }

            return(dragHandle);
        }
Example #2
0
        private static UnityEngine.Object[] HandleUnityObjectsDrop(ListDrawerConfigInfo info)
        {
            if (info.IsReadOnly)
            {
                return(null);
            }

            var eventType = Event.current.type;

            if (eventType == EventType.Layout)
            {
                info.IsAboutToDroppingUnityObjects = false;
            }
            if ((eventType == EventType.DragUpdated || eventType == EventType.DragPerform) && info.DropZone.Rect.Contains(Event.current.mousePosition))
            {
                UnityEngine.Object[] objReferences = null;

                if (DragAndDrop.objectReferences.Any(n => n != null && info.CollectionResolver.ElementType.IsAssignableFrom(n.GetType())))
                {
                    objReferences = DragAndDrop.objectReferences.Where(x => x != null && info.CollectionResolver.ElementType.IsAssignableFrom(x.GetType())).Reverse().ToArray();
                }
                else if (info.CollectionResolver.ElementType.InheritsFrom(typeof(Component)))
                {
                    objReferences = DragAndDrop.objectReferences.OfType <GameObject>().Select(x => x.GetComponent(info.CollectionResolver.ElementType)).Where(x => x != null).Reverse().ToArray();
                }
                else if (info.CollectionResolver.ElementType.InheritsFrom(typeof(Sprite)) && DragAndDrop.objectReferences.Any(n => n is Texture2D && AssetDatabase.Contains(n)))
                {
                    objReferences = DragAndDrop.objectReferences.OfType <Texture2D>().Select(x =>
                    {
                        var path = AssetDatabase.GetAssetPath(x);
                        return(AssetDatabase.LoadAssetAtPath <Sprite>(path));
                    }).Where(x => x != null).Reverse().ToArray();
                }

                bool acceptsDrag = objReferences != null && objReferences.Length > 0;

                if (acceptsDrag)
                {
                    DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                    Event.current.Use();
                    info.IsAboutToDroppingUnityObjects = true;
                    info.IsDroppingUnityObjects        = info.IsAboutToDroppingUnityObjects;
                    if (eventType == EventType.DragPerform)
                    {
                        DragAndDrop.AcceptDrag();
                        return(objReferences);
                    }
                }
            }
            if (eventType == EventType.Repaint)
            {
                info.IsDroppingUnityObjects = info.IsAboutToDroppingUnityObjects;
            }
            return(null);
        }
Example #3
0
        private DropZoneHandle BeginDropZone(ListDrawerConfigInfo info)
        {
            var dropZone = DragAndDropManager.BeginDropZone(UniqueDrawerKey.Create(info.property, this), typeof(TElement), true);

            if (Event.current.type == EventType.Repaint && DragAndDropManager.IsDragInProgress)
            {
                var rect = dropZone.Rect;
                dropZone.Rect = rect;
            }

            dropZone.Enabled = info.IsReadOnly == false;
            info.DropZone    = dropZone;
            return(dropZone);
        }
Example #4
0
        private DropZoneHandle BeginDropZone(ListDrawerConfigInfo info)
        {
            var dropZone = DragAndDropManager.BeginDropZone(info.property.Tree.GetHashCode() + "-" + info.property.Path, typeof(TElement), true);

            if (Event.current.type == EventType.Repaint && DragAndDropManager.IsDragInProgress)
            {
                var rect = dropZone.Rect;
                dropZone.Rect = rect;
            }

            dropZone.Enabled = info.IsReadOnly == false;
            info.DropZone    = dropZone;
            return(dropZone);
        }
Example #5
0
        private void EndDragHandle(ListDrawerConfigInfo info, int i)
        {
            var handle = DragAndDropManager.EndDragHandle();

            if (handle.IsDragging)
            {
                info.property.Tree.DelayAction(() =>
                {
                    if (DragAndDropManager.CurrentDraggingHandle != null)
                    {
                        ListDrawerStaticInfo.DelayedGUIDrawer.Draw(Event.current.mousePosition - DragAndDropManager.CurrentDraggingHandle.MouseDownPostionOffset);
                    }
                });
            }
        }
Example #6
0
        private void EndDropZone(ListDrawerConfigInfo info)
        {
            if (info.DropZone.IsReadyToClaim)
            {
                ListDrawerStaticInfo.CurrentDraggingPropertyInfo = null;
                object droppedObject = info.DropZone.ClaimObject();

                object[] values = new object[info.ListValueChanger.ValueCount];

                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = droppedObject;
                }

                if (info.DropZone.IsCrossWindowDrag)
                {
                    // If it's a cross-window drag, the changes will for some reason be lost if we don't do this.
                    GUIHelper.RequestRepaint();
                    EditorApplication.delayCall += () =>
                    {
                        info.ListValueChanger.InsertListElementAt(Mathf.Clamp(info.InsertAt, 0, info.property.Children.Count), values, CHANGE_ID);
                    };
                }
                else
                {
                    info.ListValueChanger.InsertListElementAt(Mathf.Clamp(info.InsertAt, 0, info.property.Children.Count), values, CHANGE_ID);
                }
            }
            else
            {
                UnityEngine.Object[] droppedObjects = HandleUnityObjectsDrop(info);
                if (droppedObjects != null)
                {
                    foreach (var obj in droppedObjects)
                    {
                        object[] values = new object[info.ListValueChanger.ValueCount];

                        for (int i = 0; i < values.Length; i++)
                        {
                            values[i] = obj;
                        }

                        info.ListValueChanger.InsertListElementAt(Mathf.Clamp(info.InsertAt, 0, info.property.Children.Count), values, CHANGE_ID);
                    }
                }
            }
            DragAndDropManager.EndDropZone();
        }
Example #7
0
        private DragHandle BeginDragHandle(ListDrawerConfigInfo info, int j, int i)
        {
            var child      = info.property.Children[j];
            var dragHandle = DragAndDropManager.BeginDragHandle(child, (TElement)child.ValueEntry.WeakSmartValue, info.IsReadOnly ? DragAndDropMethods.Reference : DragAndDropMethods.Move);

            dragHandle.Enabled = info.Draggable;

            if (dragHandle.OnDragStarted)
            {
                ListDrawerStaticInfo.CurrentDroppingPropertyInfo = null;
                ListDrawerStaticInfo.CurrentDraggingPropertyInfo = info.property.Children[j];
                dragHandle.OnDragFinnished = dropEvent =>
                {
                    if (dropEvent == DropEvents.Moved)
                    {
                        if (dragHandle.IsCrossWindowDrag || (ListDrawerStaticInfo.CurrentDroppingPropertyInfo != null && ListDrawerStaticInfo.CurrentDroppingPropertyInfo.Tree != info.property.Tree))
                        {
                            // Make sure drop happens a bit later, as deseiralization and other things sometimes
                            // overrides the cahnge.
                            GUIHelper.RequestRepaint();
                            UnityEditorEventUtility.DelayAction(() =>
                            {
                                GUIHelper.RequestRepaint();
                                UnityEditorEventUtility.DelayAction(() =>
                                {
                                    GUIHelper.RequestRepaint();
                                    UnityEditorEventUtility.DelayAction(() =>
                                    {
                                        info.ListValueChanger.RemoveListElementAt(j, CHANGE_ID);
                                    });
                                });
                            });
                        }
                        else
                        {
                            info.ListValueChanger.RemoveListElementAt(j, CHANGE_ID);
                        }
                    }

                    ListDrawerStaticInfo.CurrentDraggingPropertyInfo = null;
                };
            }

            return(dragHandle);
        }
Example #8
0
        /// <summary>
        /// Initializes the drawer.
        /// </summary>
        protected override void Initialize()
        {
            var  resolver   = this.Property.ChildResolver as ICollectionResolver;
            bool isReadOnly = resolver.IsReadOnly;

            var customListDrawerOptions = this.Property.GetAttribute <ListDrawerSettingsAttribute>() ?? new ListDrawerSettingsAttribute();

            isReadOnly = this.ValueEntry.IsEditable == false || isReadOnly || customListDrawerOptions.IsReadOnlyHasValue && customListDrawerOptions.IsReadOnly;

            info = new ListDrawerConfigInfo()
            {
                StartIndex = 0,
                Toggled    = this.ValueEntry.Context.GetPersistent <bool>(this, "ListDrawerToggled", customListDrawerOptions.ExpandedHasValue ? customListDrawerOptions.Expanded : GeneralDrawerConfig.Instance.OpenListsByDefault),
                RemoveAt   = -1,

                // Now set further down, so it can be kept updated every frame
                //Label = new GUIContent(label == null || string.IsNullOrEmpty(label.text) ? this.Property.ValueEntry.TypeOfValue.GetNiceName() : label.text, label == null ? string.Empty : label.tooltip),
                ShowAllWhilePaging      = false,
                EndIndex                = 0,
                CustomListDrawerOptions = customListDrawerOptions,
                IsReadOnly              = isReadOnly,
                Draggable               = !isReadOnly && (!customListDrawerOptions.IsReadOnlyHasValue),
                HideAddButton           = isReadOnly || customListDrawerOptions.HideAddButton,
                HideRemoveButton        = isReadOnly || customListDrawerOptions.HideRemoveButton,
            };

            info.ListConfig = GeneralDrawerConfig.Instance;
            info.Property   = this.Property;

            if (customListDrawerOptions.DraggableHasValue && !customListDrawerOptions.DraggableItems)
            {
                info.Draggable = false;
            }

            if (!(this.Property.ChildResolver is IOrderedCollectionResolver))
            {
                info.Draggable = false;
            }

            if (info.CustomListDrawerOptions.OnBeginListElementGUI != null)
            {
                string     error;
                MemberInfo memberInfo = this.Property.ParentType
                                        .FindMember()
                                        .IsMethod()
                                        .IsNamed(info.CustomListDrawerOptions.OnBeginListElementGUI)
                                        .HasParameters <int>()
                                        .ReturnsVoid()
                                        .GetMember <MethodInfo>(out error);

                if (memberInfo == null || error != null)
                {
                    // TOOD: Do something about this "There should really be an error message here." thing.
                    // For this to trigger both the member and the error message should be null. Can that happen?
                    this.errorMessage = error ?? "There should really be an error message here.";
                }
                else
                {
                    info.OnBeginListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo);
                }
            }

            if (info.CustomListDrawerOptions.OnEndListElementGUI != null)
            {
                string     error;
                MemberInfo memberInfo = this.Property.ParentType
                                        .FindMember()
                                        .IsMethod()
                                        .IsNamed(info.CustomListDrawerOptions.OnEndListElementGUI)
                                        .HasParameters <int>()
                                        .ReturnsVoid()
                                        .GetMember <MethodInfo>(out error);

                if (memberInfo == null || error != null)
                {
                    // TOOD: Do something about this "There should really be an error message here." thing.
                    // For this to trigger both the member and the error message should be null. Can that happen?
                    this.errorMessage = error ?? "There should really be an error message here.";
                }
                else
                {
                    info.OnEndListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo);
                }
            }

            if (info.CustomListDrawerOptions.OnTitleBarGUI != null)
            {
                string     error;
                MemberInfo memberInfo = this.Property.ParentType
                                        .FindMember()
                                        .IsMethod()
                                        .IsNamed(info.CustomListDrawerOptions.OnTitleBarGUI)
                                        .HasNoParameters()
                                        .ReturnsVoid()
                                        .GetMember <MethodInfo>(out error);

                if (memberInfo == null || error != null)
                {
                    // TOOD: Do something about this "There should really be an error message here." thing.
                    // For this to trigger both the member and the error message should be null. Can that happen?
                    this.errorMessage = error ?? "There should really be an error message here.";
                }
                else
                {
                    info.OnTitleBarGUI = EmitUtilities.CreateWeakInstanceMethodCaller(memberInfo as MethodInfo);
                }
            }

            if (info.CustomListDrawerOptions.ListElementLabelName != null)
            {
                string     error;
                MemberInfo memberInfo = resolver.ElementType
                                        .FindMember()
                                        .HasNoParameters()
                                        .IsNamed(info.CustomListDrawerOptions.ListElementLabelName)
                                        .HasReturnType <object>(true)
                                        .GetMember(out error);

                if (memberInfo == null || error != null)
                {
                    // TOOD: Do something about this "There should really be an error message here." thing.
                    // For this to trigger both the member and the error message should be null. Can that happen?
                    this.errorMessage = error ?? "There should really be an error message here.";
                }
                else
                {
                    string methodSuffix = memberInfo as MethodInfo == null ? "" : "()";
                    info.GetListElementLabelText = DeepReflection.CreateWeakInstanceValueGetter(resolver.ElementType, typeof(object), info.CustomListDrawerOptions.ListElementLabelName + methodSuffix);
                }
            }

            // Resolve custom add method member reference.
            if (info.CustomListDrawerOptions.CustomAddFunction != null)
            {
                string     error;
                MemberInfo memberInfo = this.Property.ParentType
                                        .FindMember()
                                        .HasNoParameters()
                                        .IsNamed(info.CustomListDrawerOptions.CustomAddFunction)
                                        .IsInstance()
                                        .HasReturnType(resolver.ElementType)
                                        .GetMember(out error);

                if (memberInfo == null || error != null)
                {
                    string error2;

                    memberInfo = this.Property.ParentType
                                 .FindMember()
                                 .IsMethod()
                                 .HasNoParameters()
                                 .IsNamed(info.CustomListDrawerOptions.CustomAddFunction)
                                 .IsInstance()
                                 .ReturnsVoid()
                                 .GetMember(out error2);

                    if (memberInfo == null || error2 != null)
                    {
                        this.errorMessage = error + " - or - " + error2;
                    }
                    else
                    {
                        info.GetCustomAddFunctionVoid = EmitUtilities.CreateWeakInstanceMethodCaller(memberInfo as MethodInfo);
                    }
                }
                else
                {
                    string methodSuffix = memberInfo as MethodInfo == null ? "" : "()";
                    info.GetCustomAddFunction = DeepReflection.CreateWeakInstanceValueGetter(
                        this.Property.ParentType,
                        resolver.ElementType,
                        info.CustomListDrawerOptions.CustomAddFunction + methodSuffix
                        );
                }
            }

            // Resolve custom remove index method member reference.
            if (info.CustomListDrawerOptions.CustomRemoveIndexFunction != null)
            {
                if (this.Property.ChildResolver is IOrderedCollectionResolver == false)
                {
                    this.errorMessage = "ListDrawerSettings.CustomRemoveIndexFunction is invalid on unordered collections. Use ListDrawerSetings.CustomRemoveElementFunction instead.";
                }
                else
                {
                    MethodInfo method = this.Property.ParentType
                                        .FindMember()
                                        .IsNamed(info.CustomListDrawerOptions.CustomRemoveIndexFunction)
                                        .IsMethod()
                                        .IsInstance()
                                        .HasParameters <int>()
                                        .ReturnsVoid()
                                        .GetMember <MethodInfo>(out this.errorMessage);

                    if (method != null)
                    {
                        info.CustomRemoveIndexFunction = EmitUtilities.CreateWeakInstanceMethodCaller <int>(method);
                    }
                }
            }
            // Resolve custom remove element method member reference.
            else if (info.CustomListDrawerOptions.CustomRemoveElementFunction != null)
            {
                var element = (this.Property.ChildResolver as ICollectionResolver).ElementType;

                MethodInfo method = this.Property.ParentType
                                    .FindMember()
                                    .IsNamed(info.CustomListDrawerOptions.CustomRemoveElementFunction)
                                    .IsMethod()
                                    .IsInstance()
                                    .HasParameters(element)
                                    .ReturnsVoid()
                                    .GetMember <MethodInfo>(out this.errorMessage);

                if (method != null)
                {
                    // TOOD: Emit dis.
                    info.CustomRemoveElementFunction = (o, e) => method.Invoke(o, new object[] { e });
                }
            }
        }
Example #9
0
        private Rect DrawItem(ListDrawerConfigInfo info, InspectorProperty itemProperty, DragHandle dragHandle, int index = -1)
        {
            var listItemInfo = itemProperty.Context.Get <ListItemInfo>(this, "listItemInfo");

            Rect rect;

            rect = SirenixEditorGUI.BeginListItem(false, info.ListItemStyle, listItemOptions);
            {
                if (Event.current.type == EventType.Repaint && !info.IsReadOnly)
                {
                    listItemInfo.Value.Width          = rect.width;
                    dragHandle.DragHandleRect         = new Rect(rect.x + 4, rect.y, 20, rect.height);
                    listItemInfo.Value.DragHandleRect = new Rect(rect.x + 4, rect.y + 2 + ((int)rect.height - 23) / 2, 20, 20);
                    listItemInfo.Value.AddBtnRect     = new Rect(listItemInfo.Value.DragHandleRect.x + rect.width - 22, listItemInfo.Value.DragHandleRect.y + 1, 14, 14);
                    itemProperty.Context.GetGlobal <Rect?>("overrideRect").Value = rect;
                    if (info.Draggable)
                    {
                        //GL.sRGBWrite = QualitySettings.activeColorSpace == ColorSpace.Linear;
                        GUI.Label(listItemInfo.Value.DragHandleRect, EditorIcons.List.Inactive, GUIStyle.none);
                        //GL.sRGBWrite = false;
                    }
                }

                GUIHelper.PushHierarchyMode(false);
                GUIContent label = null;

                if (info.CustomListDrawerOptions.ShowIndexLabelsHasValue)
                {
                    if (info.CustomListDrawerOptions.ShowIndexLabels)
                    {
                        label = new GUIContent(index.ToString());
                    }
                }
                else if (info.listConfig.ShowIndexLabels)
                {
                    label = new GUIContent(index.ToString());
                }

                if (info.GetListElementLabelText != null)
                {
                    var value = itemProperty.ValueEntry.WeakSmartValue;

                    if (object.ReferenceEquals(value, null))
                    {
                        if (label == null)
                        {
                            label = new GUIContent("Null");
                        }
                        else
                        {
                            label.text += " : Null";
                        }
                    }
                    else
                    {
                        label = label ?? new GUIContent("");
                        if (label.text != "")
                        {
                            label.text += " : ";
                        }

                        object text = info.GetListElementLabelText(value);
                        label.text += (text == null ? "" : text.ToString());
                    }
                }

                if (info.OnBeginListElementGUI != null)
                {
                    info.OnBeginListElementGUI(info.property.ParentValues[0], index);
                }
                InspectorUtilities.DrawProperty(itemProperty, label);

                if (info.OnEndListElementGUI != null)
                {
                    info.OnEndListElementGUI(info.property.ParentValues[0], index);
                }

                GUIHelper.PopHierarchyMode();

                if (info.IsReadOnly == false)
                {
                    if (SirenixEditorGUI.IconButton(listItemInfo.Value.AddBtnRect, EditorIcons.X))
                    {
                        if (index >= 0)
                        {
                            info.RemoveAt = index;
                        }
                    }
                }
            }
            SirenixEditorGUI.EndListItem();

            return(rect);
        }
Example #10
0
        private void DrawItems(ListDrawerConfigInfo info)
        {
            int  from   = 0;
            int  to     = info.Count;
            bool paging = info.CustomListDrawerOptions.PagingHasValue ? info.CustomListDrawerOptions.ShowPaging : true;

            if (paging && info.ShowAllWhilePageing == false)
            {
                from = Mathf.Clamp(info.StartIndex, 0, info.Count);
                to   = Mathf.Clamp(info.EndIndex, 0, info.Count);
            }

            var   drawEmptySpace = info.DropZone.IsBeingHovered || info.IsDroppingUnityObjects;
            float height         = drawEmptySpace ? info.IsDroppingUnityObjects ? 16 : (DragAndDropManager.CurrentDraggingHandle.Rect.height - 3) : 0;
            var   rect           = SirenixEditorGUI.BeginVerticalList();

            {
                for (int i = 0, j = from, k = from; j < to; i++, j++)
                {
                    var dragHandle = this.BeginDragHandle(info, j, i);
                    {
                        if (drawEmptySpace)
                        {
                            var topHalf = dragHandle.Rect;
                            topHalf.height /= 2;
                            if (topHalf.Contains(info.LayoutMousePosition) || topHalf.y > info.LayoutMousePosition.y && i == 0)
                            {
                                GUILayout.Space(height);
                                drawEmptySpace = false;
                                info.InsertAt  = k;
                            }
                        }

                        if (dragHandle.IsDragging == false)
                        {
                            k++;
                            this.DrawItem(info, info.property.Children[j], dragHandle, j);
                        }
                        else
                        {
                            GUILayout.Space(3);
                            ListDrawerStaticInfo.DelayedGUIDrawer.Begin(dragHandle.Rect.width, dragHandle.Rect.height, dragHandle.CurrentMethod != DragAndDropMethods.Move);
                            DragAndDropManager.AllowDrop = false;
                            this.DrawItem(info, info.property.Children[j], dragHandle, j);
                            DragAndDropManager.AllowDrop = true;
                            ListDrawerStaticInfo.DelayedGUIDrawer.End();
                            if (dragHandle.CurrentMethod != DragAndDropMethods.Move)
                            {
                                GUILayout.Space(3);
                            }
                        }

                        if (drawEmptySpace)
                        {
                            var bottomHalf = dragHandle.Rect;
                            bottomHalf.height /= 2;
                            bottomHalf.y      += bottomHalf.height;

                            if (bottomHalf.Contains(info.LayoutMousePosition) || bottomHalf.yMax < info.LayoutMousePosition.y && j + 1 == to)
                            {
                                GUILayout.Space(height);
                                drawEmptySpace = false;
                                info.InsertAt  = Mathf.Min(k, to);
                            }
                        }
                    }
                    this.EndDragHandle(info, i);
                }

                if (drawEmptySpace)
                {
                    GUILayout.Space(height);
                    info.InsertAt = Event.current.mousePosition.y > rect.center.y ? to : from;
                }

                if (to == info.property.Children.Count && info.property.ValueEntry.ValueState == PropertyValueState.CollectionLengthConflict)
                {
                    SirenixEditorGUI.BeginListItem(false);
                    GUILayout.Label(GUIHelper.TempContent("------"), EditorStyles.centeredGreyMiniLabel);
                    SirenixEditorGUI.EndListItem();
                }
            }
            SirenixEditorGUI.EndVerticalList();

            if (Event.current.type == EventType.Repaint)
            {
                info.LayoutMousePosition = Event.current.mousePosition;
            }
        }
Example #11
0
        private void DrawToolbar(ListDrawerConfigInfo info)
        {
            SirenixEditorGUI.BeginHorizontalToolbar();
            {
                // Label
                if (DragAndDropManager.IsDragInProgress && info.DropZone.IsAccepted == false)
                {
                    GUIHelper.PushGUIEnabled(false);
                }

                if (info.property.ValueEntry.ListLengthChangedFromPrefab)
                {
                    GUIHelper.PushIsBoldLabel(true);
                }

                if (info.listConfig.HideFoldoutWhileEmpty && info.IsEmpty || info.CustomListDrawerOptions.Expanded)
                {
                    GUILayout.Label(info.label, GUILayoutOptions.ExpandWidth(false));
                }
                else
                {
                    info.Toggled.Value = SirenixEditorGUI.Foldout(info.Toggled.Value, info.label ?? GUIContent.none);
                }

                if (info.property.ValueEntry.ListLengthChangedFromPrefab)
                {
                    GUIHelper.PopIsBoldLabel();
                }

                if (info.CustomListDrawerOptions.Expanded)
                {
                    info.Toggled.Value = true;
                }

                if (DragAndDropManager.IsDragInProgress && info.DropZone.IsAccepted == false)
                {
                    GUIHelper.PopGUIEnabled();
                }

                GUILayout.FlexibleSpace();

                // Item Count
                if (info.CustomListDrawerOptions.ShowItemCountHasValue ? info.CustomListDrawerOptions.ShowItemCount : info.listConfig.ShowItemCount)
                {
                    if (info.property.ValueEntry.ValueState == PropertyValueState.CollectionLengthConflict)
                    {
                        int maxLength = 0;
                        for (int i = 0; i < info.property.ValueEntry.ValueCount; i++)
                        {
                            maxLength = Math.Max(maxLength, (info.property.ValueEntry.WeakValues[i] as IList <TElement>).Count);
                        }
                        GUILayout.Label(info.Count + " / " + maxLength + " items", EditorStyles.centeredGreyMiniLabel);
                    }
                    else
                    {
                        GUILayout.Label(info.IsEmpty ? "Empty" : info.Count + " items", EditorStyles.centeredGreyMiniLabel);
                    }
                }

                bool paging     = info.CustomListDrawerOptions.PagingHasValue ? info.CustomListDrawerOptions.ShowPaging : true;
                bool hidePaging =
                    info.listConfig.HidePagingWhileCollapsed && info.Toggled.Value == false ||
                    info.listConfig.HidePagingWhileOnlyOnePage && info.Count <= info.NumberOfItemsPerPage;

                int numberOfItemsPrPage = Math.Max(1, info.NumberOfItemsPerPage);
                int numberOfPages       = Mathf.CeilToInt(info.Count / (float)numberOfItemsPrPage);
                int pageIndex           = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;

                // Paging
                if (paging)
                {
                    bool disablePaging = paging && !hidePaging && (DragAndDropManager.IsDragInProgress || info.ShowAllWhilePageing || info.Toggled.Value == false);
                    if (disablePaging)
                    {
                        GUIHelper.PushGUIEnabled(false);
                    }

                    if (!hidePaging)
                    {
                        if (pageIndex == 0)
                        {
                            GUIHelper.PushGUIEnabled(false);
                        }

                        if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleLeft, true))
                        {
                            if (Event.current.button == 0)
                            {
                                info.StartIndex -= numberOfItemsPrPage;
                            }
                            else
                            {
                                info.StartIndex = 0;
                            }
                        }
                        if (pageIndex == 0)
                        {
                            GUIHelper.PopGUIEnabled();
                        }

                        var userPageIndex = EditorGUILayout.IntField((numberOfPages == 0 ? 0 : (pageIndex + 1)), GUILayoutOptions.Width(10 + numberOfPages.ToString(CultureInfo.InvariantCulture).Length * 10)) - 1;
                        if (pageIndex != userPageIndex)
                        {
                            info.StartIndex = userPageIndex * numberOfItemsPrPage;
                        }

                        GUILayout.Label("/ " + numberOfPages);

                        if (pageIndex == numberOfPages - 1)
                        {
                            GUIHelper.PushGUIEnabled(false);
                        }

                        if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleRight, true))
                        {
                            if (Event.current.button == 0)
                            {
                                info.StartIndex += numberOfItemsPrPage;
                            }
                            else
                            {
                                info.StartIndex = numberOfItemsPrPage * numberOfPages;
                            }
                        }
                        if (pageIndex == numberOfPages - 1)
                        {
                            GUIHelper.PopGUIEnabled();
                        }
                    }

                    pageIndex = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;

                    var newStartIndex = Mathf.Clamp(pageIndex * numberOfItemsPrPage, 0, Mathf.Max(0, info.Count - 1));
                    if (newStartIndex != info.StartIndex)
                    {
                        info.StartIndex = newStartIndex;
                        var newPageIndex = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;
                        if (pageIndex != newPageIndex)
                        {
                            pageIndex       = newPageIndex;
                            info.StartIndex = Mathf.Clamp(pageIndex * numberOfItemsPrPage, 0, Mathf.Max(0, info.Count - 1));
                        }
                    }

                    info.EndIndex = Mathf.Min(info.StartIndex + numberOfItemsPrPage, info.Count);

                    if (disablePaging)
                    {
                        GUIHelper.PopGUIEnabled();
                    }
                }
                else
                {
                    info.StartIndex = 0;
                    info.EndIndex   = info.Count;
                }

                if (paging && hidePaging == false && info.listConfig.ShowExpandButton)
                {
                    if (SirenixEditorGUI.ToolbarButton(info.ShowAllWhilePageing ? EditorIcons.TriangleUp : EditorIcons.TriangleDown, true))
                    {
                        info.ShowAllWhilePageing = !info.ShowAllWhilePageing;
                    }
                }

                // Add Button
                if (info.IsReadOnly == false && !info.CustomListDrawerOptions.HideAddButton)
                {
                    info.ObjectPicker = ObjectPicker <TElement> .GetObjectPicker(info);

                    if (SirenixEditorGUI.ToolbarButton(EditorIcons.Plus))
                    {
                        if (info.CustomListDrawerOptions.AlwaysAddDefaultValue)
                        {
                            var objs = new object[info.ListValueChanger.ValueCount];

                            if (info.property.ValueEntry.SerializationBackend == SerializationBackend.Unity)
                            {
                                for (int i = 0; i < objs.Length; i++)
                                {
                                    objs[i] = UnitySerializationUtility.CreateDefaultUnityInitializedObject(typeof(TElement));
                                }
                            }
                            else
                            {
                                for (int i = 0; i < objs.Length; i++)
                                {
                                    objs[i] = default(TElement);
                                }
                            }

                            info.ListValueChanger.AddListElement(objs, "Add default value");
                        }
                        else if (typeof(TElement).InheritsFrom <UnityEngine.Object>() && Event.current.modifiers == EventModifiers.Control)
                        {
                            info.ListValueChanger.AddListElement(new object[info.ListValueChanger.ValueCount], "Add Unity Null Value");
                        }
                        else
                        {
                            info.ObjectPicker.ShowObjectPicker(
                                info.property.Info.GetAttribute <AssetsOnlyAttribute>() == null,
                                GUIHelper.GetCurrentLayoutRect(),
                                info.property.ValueEntry.SerializationBackend == SerializationBackend.Unity);
                        }
                    }

                    info.JumpToNextPageOnAdd = paging && (info.Count % numberOfItemsPrPage == 0) && (pageIndex + 1 == numberOfPages);
                }

                if (info.OnTitleBarGUI != null)
                {
                    info.OnTitleBarGUI(info.property.ParentValues[0]);
                }
            }
            SirenixEditorGUI.EndHorizontalToolbar();
        }