private static bool Traversal(Inspector inspector, string path, DictionaryGUIState state, int start, int end)
        {
            bool changed    = false;
            var  bucketSize = Math.Max(state.display.bucketSize, 2);
            var  valueType  = state.ValueType();

            if (end - start <= bucketSize)
            {
                for (int index = start; index < end; ++index)
                {
                    changed |= InspectElement(inspector, path, state.display.resultKeys[index], state, valueType);
                }
            }
            else
            {
                // Allow multiple level of bucket, calculate the current step
                int step = bucketSize;
                while (step * bucketSize < end - start)
                {
                    step *= bucketSize;
                }

                for (int inner = start; inner < end; inner += step)
                {
                    int innerEnd = Math.Min(end, inner + step);

                    var innerKeyBegin = state.display.resultKeys[inner];
                    var innerKeyEnd   = state.display.resultKeys[innerEnd - 1];
                    var label         = FormatKeyRange(innerKeyBegin, innerKeyEnd);
                    var foldoutPath   = path + "[" + innerKeyBegin + "~" + innerKeyEnd + "]";

                    inspector.isFoldout[foldoutPath] = GUITools.Foldout(inspector.isFoldout.ContainsKey(foldoutPath) && inspector.isFoldout[foldoutPath], label);
                    if (inspector.isFoldout[foldoutPath])
                    {
                        using (GUITools.Indent())
                        {
                            changed |= Traversal(inspector, path, state, inner, innerEnd);
                        }
                    }
                }
            }

            return(changed);
        }
        public bool InspectInternal(string name, string path, object data,
                                    Type type  = null,
                                    IMark mark = null,
                                    Action <object> OnValueChanged = null)
        {
            if (data != null)
            {
                type = data.GetType();
            }

            GUITools.SetLabelWidth(options.labelWidth);
            VisualizerBase visualizer  = GetVisualizer(type, mark);
            bool           changed     = false;
            object         changedData = data;

            if (visualizer != null)
            {
                string fieldinfo = name;
                var    postfix   = visualizer.GetLabelPostfix(this, data, type);
                if (postfix != null)
                {
                    fieldinfo += postfix;
                }

                if (visualizer.HasChildren())
                {
                    // Note: to avoid infinite expand that may cause by alwaysShowChildren,
                    // If parentAlwaysShowChild, then current node ignores alwaysShowChildren.
                    var  parentAlwaysShowChild = parentIsAlwaysShow.Count > 0 && parentIsAlwaysShow.Peek();
                    bool alwaysShowChildren    = !parentAlwaysShowChild && visualizer.AlwaysShowChildren();
                    if (!alwaysShowChildren)
                    {
                        using (GUITools.HorizontalScope())
                        {
                            var width = options.labelWidth - options.indentOffset * GUITools.GetIndentLevel();
                            using (GUITools.HorizontalScope(width))
                            {
                                isFoldout[path] = GUITools.Foldout(isFoldout.ContainsKey(path) && isFoldout[path], fieldinfo);
                            }
                            changed |= InspectRoot(name, type, ref changedData, visualizer, mark);
                        }
                    }
                    else
                    {
                        changed |= InspectRoot(name, type, ref changedData, visualizer, mark);
                    }

                    if (changedData != null && (alwaysShowChildren || isFoldout[path]))
                    {
                        try
                        {
                            parentIsAlwaysShow.Push(alwaysShowChildren);
                            using (GUITools.Indent())
                                changed |= visualizer.InspectChildren(this, path, ref changedData, type);
                        }
                        finally
                        {
                            parentIsAlwaysShow.Pop();
                        }
                    }
                }
                else
                {
                    changed |= InspectRoot(fieldinfo, type, ref changedData, visualizer, mark);
                }
            }

            if (changed && OnValueChanged != null)
            {
                OnValueChanged(changedData);
            }
            return(changed);
        }