//static bool clearedCache; //static BetterEditor() //{ // //if (!clearedCache) // { // clearedCache = true; // MemberDrawersHandler.Instance.ClearCache(); // } //} protected override void OnAwake() { OnAwakeAssertion(); // Fetch visible members { Func <MemberInfo, VisibleMember> newMember = m => new VisibleMember(m, target, target, id); var allMembers = ReflectionUtil.GetMemoizedMembers(targetType); visibleMembers = SerializationLogic.Default.GetVisibleMembers(allMembers).Select(newMember).ToList(); // Initialize view { minimalView = targetType.IsDefined <MinimalViewAttribute>(true); if (minimalView) { visibleMembers = visibleMembers.OrderBy(x => x.DisplayOrder).ToList(); } else { baseCategories = new List <MemberCategory>(); Func <string, float, MemberCategory> newCategory = (path, order) => new MemberCategory(path, new List <ICanBeDrawn>(), order, id, prefs); var basic = targetType.GetCustomAttribute <BasicViewAttribute>(true); if (basic != null) { var c = newCategory(string.Empty, 0f); c.Indent = false; c.HideHeader = true; visibleMembers.OrderBy(x => x.DisplayOrder).Foreach(c.AddMember); baseCategories.Add(c); } else { // Create the intial input from the target's visible members var input = new MemberGroup(visibleMembers, newMember); // Create resolvers var resolvers = new GroupResolver[] { new PatternResolver(), new MemberTypesResolver(), new ReturnTypeResolver(), new ExplicitMemberAddResolver(), new CategoryMembersResolver() }; var core = new CoreResolver(resolvers, () => new MemberGroup(newMember)); Action <DefineCategoryAttribute, MemberCategory> resolve = (def, category) => core.Resolve(input, def).Members.Foreach(category.AddMember); var multiple = targetType.GetCustomAttribute <DefineCategoriesAttribute>(true); var ignored = targetType.GetCustomAttributes <IgnoreCategoriesAttribute>(true); var definitions = targetType.GetCustomAttributes <DefineCategoryAttribute>(true); if (multiple != null) { definitions = definitions.Concat(multiple.names.Select(n => new DefineCategoryAttribute(n, 1000))); } definitions = definitions.Where(d => !ignored.Any(ig => ig.Paths.Contains(d.FullPath))) .ToList(); Func <string, string[]> ParseCategoryPath = fullPath => { int nPaths = fullPath.Split('/').Length; string[] result = new string[nPaths]; for (int i = 0, index = -1; i < nPaths - 1; i++) { index = fullPath.IndexOf('/', index + 1); result[i] = fullPath.Substring(0, index); } result[nPaths - 1] = fullPath; return(result); }; // Order by exclusivity then path lengths var defs = from d in definitions let paths = ParseCategoryPath(d.FullPath) orderby !d.Exclusive //, paths.Length select new { def = d, paths }; Func <MemberCategory, List <MemberCategory> > getParentCats = parent => parent == null ? baseCategories : (from m in parent.Members let cat = m as MemberCategory where cat != null select cat).ToList(); // Parse paths and resolve definitions var categories = new Dictionary <string, MemberCategory>(); foreach (var x in defs) { var paths = x.paths; var d = x.def; MemberCategory parent = null; for (int i = 0; i < paths.Length; i++) { var p = paths[i]; var current = getParentCats(parent).FirstOrDefault(c => c.FullPath == p); if (current == null) { current = newCategory(p, d.DisplayOrder); if (i == 0) { baseCategories.Add(current); } if (parent != null) { parent.AddMember(current); } } categories[p] = current; parent = current; } categories[paths.Last()].ForceExpand = d.ForceExpand; resolve(d, categories[paths.Last()]); categories.Clear(); parent.Members = parent.Members.OrderBy(m => m.DisplayOrder).ToList(); } baseCategories = baseCategories.OrderBy(x => x.DisplayOrder).ToList(); } } script = serializedObject.FindProperty("m_Script"); var disInt = prefs.Ints.ValueOrDefault(id + "display", -1); display = disInt == -1 ? DefaultDisplay : (MembersDisplay)disInt; var field = targetType.Field("_serializationData", Flags.InstancePrivate); if (field == null) { throw new MemberNotFoundException("_serializationData"); } serializationData = new EditorMember(field, target, target, id); OnInitialized(); #if DBG Log(GetType().Name + " for " + target.GetType().Name + " Initialized"); #endif } } }
protected virtual void OnGUI() { #if PROFILE Profiler.BeginSample(targetType.Name + " OnInspectorGUI"); Profiler.BeginSample(targetType.Name + " Header"); #endif if (ShowScriptHeader) { var scriptKey = RuntimeHelper.CombineHashCodes(id, "script".GetHashCode()); gui.Space(3f); using (gui.Horizontal(EditorStyles.toolbarButton)) { gui.Space(10f); foldouts[scriptKey] = gui.Foldout(foldouts[scriptKey]); gui.Space(-12f); if (ScriptField()) // script changed? exit! { return; } } if (foldouts[scriptKey]) { gui.Space(2f); using (gui.Indent(GUI.skin.textField)) { gui.Space(3f); if (targetType.IsDefined <HasRequirementsAttribute>()) { using (gui.Horizontal()) { gui.Space(3f); if (gui.MiniButton("Resolve Requirements", (Layout)null)) { Requirements.Resolve(target, gameObject); } } } gui.Member(_debug); var mask = gui.BunnyMask("Display", _display); { var newValue = (MembersDisplay)mask; if (_display != newValue) { _display = newValue; var displayKey = RuntimeHelper.CombineHashCodes(id, "display"); prefs.Ints[displayKey] = mask; } } var spacing = Mathf.Clamp(gui.Int("Spacing", _spacing), -13, (int)EditorGUIUtility.currentViewWidth / 4); if (_spacing != spacing) { _spacing = spacing; prefs.Ints[id + "spacing".GetHashCode()] = _spacing; gui.RequestResetIfRabbit(); } gui.Member(_serializationData, true); } } } #if PROFILE Profiler.EndSample(); #endif gui.BeginCheck(); #if PROFILE Profiler.BeginSample(targetType.Name + " Members"); #endif for (int i = 0; i < _categories.Count; i++) { var cat = _categories[i]; cat.Display = _display; cat.Spacing = _spacing; cat.gui = gui; cat.HideHeader = (_display & MembersDisplay.Headers) != MembersDisplay.Headers; if ((_display & MembersDisplay.CategorySplitter) != 0) { gui.Splitter(); } cat.Draw(target); } #if PROFILE Profiler.EndSample(); #endif if (gui.HasChanged()) { //Log("setting dirty " + target); EditorUtility.SetDirty(target); } #if PROFILE Profiler.EndSample(); #endif }
protected sealed override void OnGUI() { #if PROFILE Profiler.BeginSample(targetType.Name + " OnInspectorGUI"); Profiler.BeginSample(targetType.Name + " Header"); #endif // Header { string scriptKey = id + "script"; gui.Space(3f); using (gui.Horizontal(EditorStyles.toolbarButton)) { gui.Space(10f); foldouts[scriptKey] = gui.Foldout(foldouts[scriptKey]); gui.Space(-12f); gui.Object("Script", script.objectReferenceValue); } if (foldouts[scriptKey]) { gui.Space(2f); using (gui.Indent(GUI.skin.textField)) { gui.Space(2f); dbg = gui.Toggle("Debug", dbg); var mask = gui.BunnyMask("Display", display); { var newValue = (MembersDisplay)mask; if (display != newValue) { display = newValue; prefs.Ints[id + "display"] = mask; } } gui.Member(serializationData, true); } } } #if PROFILE Profiler.EndSample(); #endif gui.BeginCheck(); #if PROFILE Profiler.BeginSample(targetType.Name + " Members"); #endif if (minimalView) { gui.Space(4f); for (int i = 0; i < visibleMembers.Count; i++) { var vim = visibleMembers[i]; vim.gui = gui; vim.Draw(); } } else { for (int i = 0; i < baseCategories.Count; i++) { var cat = baseCategories[i]; cat.Display = display; cat.gui = gui; cat.Draw(); } } OnBetterGUI(); #if PROFILE Profiler.EndSample(); #endif if (gui.HasChanged()) { EditorUtility.SetDirty(target); } #if PROFILE Profiler.EndSample(); #endif // Fixes somes cases of editor slugishness if (repaintCount < 2) { repaintCount++; Repaint(); } }
private void Initialize() { OnBeforeInitialized(); // Init members _visibleMembers = VFWVisibilityLogic.GetCachedVisibleMembers.Invoke(targetType).ToList(); _categories = new List <MembersCategory>(); Func <string, float, MembersCategory> newCategory = (path, order) => new MembersCategory(path, new List <MemberInfo>(), order, id, prefs); var resolver = new MembersResolution(); var multiple = targetType.GetCustomAttribute <DefineCategoriesAttribute>(true); var definitions = targetType.GetCustomAttributes <DefineCategoryAttribute>(true); if (multiple != null) { definitions = definitions.Concat(multiple.names.Select(n => new DefineCategoryAttribute(n, 1000))); } Func <string, string[]> ParseCategoryPath = fullPath => { int nPaths = fullPath.Split('/').Length; string[] result = new string[nPaths]; for (int i = 0, index = -1; i < nPaths - 1; i++) { index = fullPath.IndexOf('/', index + 1); result[i] = fullPath.Substring(0, index); } result[nPaths - 1] = fullPath; return(result); }; // Order by exclusivity var defs = from d in definitions let paths = ParseCategoryPath(d.FullPath) orderby !d.Exclusive select new { def = d, paths }; Func <MemberInfo, float> getDisplayOrder = member => { var attr = member.GetCustomAttribute <DisplayOrderAttribute>(); return(attr == null ? -1 : attr.displayOrder); }; // Parse paths and resolve definitions var lookup = new Dictionary <string, MembersCategory>(); foreach (var x in defs) { var paths = x.paths; var d = x.def; MembersCategory parent = null; for (int i = 0; i < paths.Length; i++) { var p = paths[i]; var current = (parent == null ? _categories : parent.NestedCategories).FirstOrDefault(c => c.FullPath == p); if (current == null) { current = newCategory(p, d.DisplayOrder); if (i == 0) { _categories.Add(current); } if (parent != null) { parent.NestedCategories.Add(current); } } lookup[p] = current; parent = current; } var last = lookup[paths.Last()]; last.ForceExpand = d.ForceExpand; last.AlwaysHideHeader = d.AlwaysHideHeader; resolver.Resolve(_visibleMembers, d).Foreach(last.AddMember); lookup.Clear(); parent.Members = parent.Members.OrderBy(getDisplayOrder).ToList(); } // filter out empty categories _categories = _categories.Where(x => x.NestedCategories.Count > 0 || x.Members.Count > 0) .OrderBy(x => x.DisplayOrder) .ToList(); for (int i = 0; i < _categories.Count; i++) { var c = _categories[i]; c.RemoveEmptyNestedCategories(); } var displayKey = RuntimeHelper.CombineHashCodes(id, "display"); var displayValue = prefs.Ints.ValueOrDefault(displayKey, -1); var vfwSettings = VFWSettings.GetInstance(); _display = displayValue == -1 ? vfwSettings.DefaultDisplay : (MembersDisplay)displayValue; prefs.Ints[displayKey] = (int)_display; var spacingKey = RuntimeHelper.CombineHashCodes(id, "spacing"); _spacing = prefs.Ints.ValueOrDefault(spacingKey, vfwSettings.DefaultSpacing); prefs.Ints[spacingKey] = _spacing; var field = targetType.GetAllMembers(typeof(MonoBehaviour), Flags.InstancePrivate) .FirstOrDefault(m => m.Name == "_serializationData"); if (field == null) { throw new MemberNotFoundException("_serializationData in " + targetType.Name); } _serializationData = EditorMember.WrapMember(field, target, target, id); field = targetType.GetField("dbg", Flags.InstanceAnyVisibility); if (field == null) { throw new MemberNotFoundException("dbg"); } _debug = EditorMember.WrapMember(field, target, target, id); OnAfterInitialized(); }