Inheritance: IReorderableListAdaptor
        public override float GetElementHeight(GUIContent label, TCollection collection, fiGraphMetadata metadata)
        {
            EnsureNotNull(ref collection);

            var   pageMetadata = GetPageMetadata(metadata);
            float height       = 0;

            var adaptor = GetAdaptor(collection, metadata);

            if (ShouldDisplayPageControls(collection))
            {
                VerifyPageIndices(pageMetadata, collection);

                adaptor = new PageAdaptor(adaptor, pageMetadata.PageStartIndex, pageMetadata.PageEndIndex);
                height += PagedRegionButtonHeight + PagedRegionVerticalMargin * 2;
            }

            height += DoGetElementHeight(label, collection, metadata, adaptor);

            return(height);
        }
        public override TCollection Edit(Rect region, GUIContent label, TCollection collection, fiGraphMetadata metadata)
        {
            Rect initialRegion = region;

            EnsureNotNull(ref collection);

            var pageMetadata = GetPageMetadata(metadata);

            var unpagedAdaptor = GetAdaptor(collection, metadata);
            var adaptor        = unpagedAdaptor;

            // draw the title
            if (ShouldDisplayTitleRegion(label))
            {
                Rect titleRect = new Rect(region);
                titleRect.height = EditorGUIUtility.singleLineHeight;

                region.y      += titleRect.height;
                region.height -= titleRect.height;

                GUI.Label(titleRect, label);
            }

            if (ShouldDisplayPageControls(collection))
            {
                VerifyPageIndices(pageMetadata, collection);

                Rect pagedRect = region;

                pagedRect.y     += PagedRegionVerticalMargin;
                pagedRect.height = PagedRegionButtonHeight;

                region.y      += PagedRegionButtonHeight + PagedRegionVerticalMargin * 2;
                region.height -= PagedRegionButtonHeight + PagedRegionVerticalMargin * 2;

                const float margin_Empty_StartLabel      = 10;
                const float width_StartLabel             = 100;
                const float margin_StartLabel_StartIndex = 2;
                const float width_StartIndex             = 45;
                const float margin_StartIndex_ThruLabel  = 2;
                const float width_ThruLabel           = 20;
                const float margin_ThruLabel_EndIndex = 2;
                const float width_EndIndex            = 45;
                const float margin_EndIndex_OfCount   = 2;
                const float width_OfCountLabel        = 500;

                // -----

                const float width_DecButton            = 40;
                const float margin_DecButton_IncButton = 1;
                const float width_IncButton            = 40;
                const float margin_IncButton_Empty     = 50;

                const float regionIndexSelectorWidth =
                    margin_Empty_StartLabel +
                    width_StartLabel + margin_StartLabel_StartIndex +
                    width_StartIndex + margin_StartIndex_ThruLabel +
                    width_ThruLabel + margin_ThruLabel_EndIndex +
                    width_EndIndex + margin_EndIndex_OfCount +
                    width_OfCountLabel;

                const float regionIncDecWidth =
                    width_DecButton + margin_DecButton_IncButton + width_IncButton + margin_IncButton_Empty;


                Rect rect_RegionIndexSelector, rect_RegionIncDec, rectDummy;
                fiRectUtility.SplitHorizontalFlexibleMiddle(pagedRect, regionIndexSelectorWidth, regionIncDecWidth,
                                                            out rect_RegionIndexSelector, out rectDummy, out rect_RegionIncDec);


                fiRectUtility.CenterRect(rect_RegionIndexSelector, EditorGUIUtility.singleLineHeight,
                                         out rect_RegionIndexSelector);

                Rect rect_StartLabel, rect_StartIndex, rect_ThruLabel, rect_EndIndex, rect_OfCountLabel;

                {
                    float startX = rect_RegionIndexSelector.x + margin_Empty_StartLabel;

                    rect_StartLabel       = rect_RegionIndexSelector;
                    rect_StartLabel.x     = startX;
                    rect_StartLabel.width = width_StartLabel;
                    startX += width_StartLabel + margin_StartLabel_StartIndex;

                    rect_StartIndex       = rect_RegionIndexSelector;
                    rect_StartIndex.x     = startX;
                    rect_StartIndex.width = width_StartIndex;
                    startX += width_StartIndex + margin_StartIndex_ThruLabel;

                    rect_ThruLabel       = rect_RegionIndexSelector;
                    rect_ThruLabel.x     = startX;
                    rect_ThruLabel.width = width_ThruLabel;
                    startX += width_ThruLabel + margin_ThruLabel_EndIndex;

                    rect_EndIndex       = rect_RegionIndexSelector;
                    rect_EndIndex.x     = startX;
                    rect_EndIndex.width = width_EndIndex;
                    startX += width_EndIndex + margin_EndIndex_OfCount;

                    rect_OfCountLabel       = rect_RegionIndexSelector;
                    rect_OfCountLabel.x     = startX;
                    rect_OfCountLabel.width = width_OfCountLabel;
                }


                Rect rect_IncButton, rect_DecButton;
                {
                    float startX = rect_RegionIncDec.x;

                    rect_DecButton       = rect_RegionIncDec;
                    rect_DecButton.x     = startX;
                    rect_DecButton.width = width_DecButton;
                    startX += width_IncButton + margin_DecButton_IncButton;

                    rect_IncButton       = rect_RegionIncDec;
                    rect_IncButton.x     = startX;
                    rect_IncButton.width = width_IncButton;
                }

                if (unpagedAdaptor.Count > 0)
                {
                    GUI.Label(rect_StartLabel, "Showing indices ");

                    EditorGUI.BeginChangeCheck();
                    int newStartIndex = EditorGUI.IntField(rect_StartIndex, pageMetadata.PageStartIndex);
                    if (EditorGUI.EndChangeCheck())
                    {
                        EnsureWithinLimits(ref newStartIndex, 0, collection.Count);
                        if (newStartIndex > pageMetadata.PageEndIndex)
                        {
                            ShiftPageForward(pageMetadata, newStartIndex - pageMetadata.PageStartIndex, collection.Count);
                        }
                        else
                        {
                            pageMetadata.PageStartIndex = newStartIndex;
                        }
                    }

                    GUI.Label(rect_ThruLabel, " - ");

                    EditorGUI.BeginChangeCheck();
                    int newEndIndex = EditorGUI.IntField(rect_EndIndex, pageMetadata.PageEndIndex);
                    if (EditorGUI.EndChangeCheck())
                    {
                        // we could do the auto shifting going backwards, but it is
                        // easy to accidentaly trigger when typing, say, 150, as Unity
                        // will give us an assigned value of 1 which causes a shift
                        // to 1 length making it annoying, so we disable it

                        /*
                         * EnsureWithinLimits(ref newEndIndex, 0, collection.Count);
                         * if (newEndIndex <= _pageStartIndex) {
                         *  ShiftPageBackward(_pageEndIndex - newEndIndex);
                         * }
                         * else {
                         *  _pageEndIndex = newEndIndex;
                         * }*/


                        if (newEndIndex < pageMetadata.PageStartIndex)
                        {
                            newEndIndex = pageMetadata.PageStartIndex;
                        }
                        EnsureWithinLimits(ref newEndIndex, 0, collection.Count);
                        pageMetadata.PageEndIndex = newEndIndex;
                    }
                    GUI.Label(rect_OfCountLabel, " of " + (collection.Count - 1));
                }
                else
                {
                    GUI.Label(rect_StartLabel, "Empty collection");
                }



                EditorGUI.BeginDisabledGroup(!(pageMetadata.PageStartIndex > 0));
                if (GUI.Button(rect_DecButton, "<<"))
                {
                    ShiftPageBackward(pageMetadata, pageMetadata.PageEndIndex - pageMetadata.PageStartIndex + 1);
                }
                EditorGUI.EndDisabledGroup();

                EditorGUI.BeginDisabledGroup(!(pageMetadata.PageEndIndex < collection.Count - 1));
                if (GUI.Button(rect_IncButton, ">>"))
                {
                    ShiftPageForward(pageMetadata, pageMetadata.PageEndIndex - pageMetadata.PageStartIndex + 1, collection.Count);
                }
                EditorGUI.EndDisabledGroup();

                adaptor = new PageAdaptor(unpagedAdaptor, pageMetadata.PageStartIndex, pageMetadata.PageEndIndex);
            }

            fiEditorGUI.PushHierarchyMode(false);
            DoEdit(initialRegion, region, label, ref collection, metadata, adaptor);
            fiEditorGUI.PopHierarchyMode();

            OnPostEdit(ref collection, unpagedAdaptor);

            // Keyed collections are wonky. The keys easily go stale. We rebuild the entire
            // collection if anything inside of it has changed.
            if (GUI.changed && IsKeyedCollection)
            {
                try {
                    var newInstance = default(TCollection);
                    EnsureNotNull(ref newInstance);
                    foreach (var node in collection)
                    {
                        newInstance.Add(node);
                    }
                    collection = newInstance;
                } catch (Exception) {
                    Debug.LogError("This was an error when rebuilding the keyed collection. Undo the last edit or the collection will not deserialize.");
                }
            }

            return(collection);
        }