private static void RebuildDisplayIfNeed(DictionaryGUIState state, Inspector.Options options)
        {
            if (state.display == null ||
                Event.current.type == EventType.Layout && (state.searchInput.changed || IsKeyChanged(state, options) ||
                                                           state.display.bucketSize != options.listBucketSize ||
                                                           state.display.sort != options.sortFields))
            {
                var display = new DictionaryDisplay();
                display.keys       = state.Keys(options);
                display.bucketSize = options.listBucketSize;
                display.sort       = options.sortFields;

                if (!string.IsNullOrEmpty(state.searchInput.text))
                {
                    display.resultKeys = FilterKeys(display.keys, state.searchInput);
                }
                else
                {
                    display.resultKeys = display.keys;
                }

                if (options.sortFields)
                {
                    display.resultKeys = Sorted(display.resultKeys);
                }
                state.display = display;
            }
        }
 private static void ClearSearchInput(DictionaryGUIState state)
 {
     if (state.searchInput != null && !string.IsNullOrEmpty(state.searchInput.text))
     {
         state.searchInput.text    = "";
         state.searchInput.changed = true;
     }
 }
        private static void DrawSearchInput(DictionaryGUIState state, Inspector.Options options)
        {
            if (state.searchInput == null)
            {
                state.searchInput = new SearchInputState();
            }

            if (state.Size() < options.showSearchAtSize)
            {
                ClearSearchInput(state);
                return;
            }

            var now = DateTime.Now;
            SearchInputState input = state.searchInput;

            using (GUITools.Indent())
            {
                using (GUITools.HorizontalScope())
                {
                    var newInput = GUITools.TextField("Search: ", input.text ?? "");
                    if (newInput != input.text)
                    {
                        input.text           = newInput;
                        input.lastTextChange = now;
                        if (input.inputStart.Ticks == 0)
                        {
                            input.inputStart = now;
                        }
                    }
                    else
                    {
                        if (Math.Abs((now - input.lastTextChange).TotalSeconds) > 0.5)
                        {
                            input.inputStart = new DateTime();
                        }
                    }

                    if (input.text != input.filter &&
                        (
                            input.inputStart.Ticks == 0 ||
                            Math.Abs((now - input.lastFilterChange).TotalSeconds) > 1 &&
                            Math.Abs((now - input.inputStart).TotalSeconds) > 1
                        ))
                    {
                        input.changed          = true;
                        input.filter           = input.text;
                        input.lastFilterChange = DateTime.Now;
                    }
                    else
                    {
                        input.changed = false;
                    }
                }
            }
        }
        // 如果数据发生了修改,则返回true。
        //
        // parser用于解析dict对象
        public static bool EditDict(Inspector inspector, string path, object dict, IDictParser parser)
        {
            UpdateCheck();

            DictionaryGUIState state = GetOrCreateCachedState(path, dict, parser);

            DrawSearchInput(state, inspector.options);
            RebuildDisplayIfNeed(state, inspector.options);

            return(Traversal(inspector, path, state, 0, state.display.resultKeys.Length));
        }
        private static DictionaryGUIState GetOrCreateCachedState(string path, object dict, IDictParser parser)
        {
            if (!guiCache.ContainsKey(path))
            {
                guiCache[path] = new DictionaryGUIState();
            }

            var cached = guiCache[path];

            if (cached.dict == null || cached.dict.Target != dict)
            {
                cached.dict = new WeakReference(dict);
            }
            cached.parser    = parser;
            cached.lastVisit = DateTime.Now;
            return(cached);
        }
        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);
        }
        private static bool InspectElement(Inspector inspector, string path, object key, DictionaryGUIState state, Type dictValueType)
        {
            object value     = state.Get(key);
            Type   valueType = value != null?value.GetType() : dictValueType;

            string fullName = key != null?key.ToString() : "null";

            return(inspector.Inspect(CutName(fullName), path + "." + fullName, value, valueType, null, v =>
            {
                if (value != v)
                {
                    state.Set(key, v);
                }
            }));
        }
 private static bool IsKeyChanged(DictionaryGUIState state, Inspector.Options options)
 {
     return(state.display != null && !ArrayEqual(state.display.keys, state.Keys(options)));
 }