forked from Shardstone/trail-into-darkness
added more utilty packges
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Author: Dimitry, PixeyeHQ
|
||||
// Project : UNITY FOLDOUT
|
||||
// https://github.com/PixeyeHQ/InspectorFoldoutGroup
|
||||
// Contacts : Pix - ask@pixeye.games
|
||||
// Website : http://www.pixeye.games
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace InspectorToolkit
|
||||
{
|
||||
public class FoldoutAttribute : PropertyAttribute
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly bool FoldEverything;
|
||||
|
||||
/// <summary>Adds the property to the specified foldout group.</summary>
|
||||
/// <param name="name">Name of the foldout group.</param>
|
||||
/// <param name="foldEverything">Toggle to put all properties to the specified group</param>
|
||||
public FoldoutAttribute(string name, bool foldEverything = false)
|
||||
{
|
||||
FoldEverything = foldEverything;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace InspectorToolkit.Internal
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
|
||||
public class FoldoutAttributeHandler
|
||||
{
|
||||
|
||||
|
||||
private readonly Dictionary<string, CacheFoldProp> _cacheFoldouts = new Dictionary<string, CacheFoldProp>();
|
||||
private readonly List<SerializedProperty> _props = new List<SerializedProperty>();
|
||||
private bool _initialized;
|
||||
|
||||
private readonly IGUILayoutPropertyField guiLayoutPropertyField;
|
||||
|
||||
private readonly UnityEngine.Object _target;
|
||||
private readonly SerializedObject _serializedObject;
|
||||
|
||||
|
||||
public bool OverrideInspector => _props.Count > 0;
|
||||
|
||||
public FoldoutAttributeHandler(UnityEngine.Object target, SerializedObject serializedObject, IGUILayoutPropertyField guiLayoutPropertyField)
|
||||
{
|
||||
_target = target;
|
||||
_serializedObject = serializedObject;
|
||||
this.guiLayoutPropertyField = guiLayoutPropertyField;
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
if (_target == null) return;
|
||||
|
||||
foreach (var c in _cacheFoldouts)
|
||||
{
|
||||
EditorPrefs.SetBool(string.Format($"{c.Value.Attribute.Name}{c.Value.Properties[0].name}{_target.name}"), c.Value.Expanded);
|
||||
c.Value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_serializedObject.Update();
|
||||
Setup();
|
||||
}
|
||||
|
||||
public void OnInspectorGUI()
|
||||
{
|
||||
Header();
|
||||
Body();
|
||||
|
||||
_serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void Header()
|
||||
{
|
||||
using (new EditorGUI.DisabledScope("m_Script" == _props[0].propertyPath))
|
||||
{
|
||||
//EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(_props[0], true);
|
||||
//EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
private void Body()
|
||||
{
|
||||
foreach (var pair in _cacheFoldouts)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(StyleFramework.Box);
|
||||
Foldout(pair.Value);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUI.indentLevel = 0;
|
||||
}
|
||||
|
||||
for (var i = 1; i < _props.Count; i++) {
|
||||
SerializedProperty prop = _props[i];
|
||||
|
||||
guiLayoutPropertyField.GUILayoutPropertyField(prop);
|
||||
}
|
||||
}
|
||||
|
||||
private void Foldout(CacheFoldProp cache)
|
||||
{
|
||||
cache.Expanded = EditorGUILayout.Foldout(cache.Expanded, cache.Attribute.Name, true, StyleFramework.FoldoutHeader);
|
||||
var rect = GUILayoutUtility.GetLastRect();
|
||||
rect.x -= 18;
|
||||
rect.y -= 4;
|
||||
rect.height += 8;
|
||||
rect.width += 18;
|
||||
EditorGUI.LabelField(rect, GUIContent.none, EditorStyles.helpBox);
|
||||
|
||||
if (cache.Expanded)
|
||||
{
|
||||
EditorGUILayout.Space(2);
|
||||
|
||||
foreach (SerializedProperty property in cache.Properties)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(StyleFramework.BoxChild);
|
||||
guiLayoutPropertyField.GUILayoutPropertyField(
|
||||
property,
|
||||
new GUIContent(ObjectNames.NicifyVariableName(property.name), property.tooltip),
|
||||
true);
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
FoldoutAttribute prevFold = default;
|
||||
|
||||
var length = EditorTypes.GetFields(_target, out var objectFields);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
#region FOLDERS
|
||||
|
||||
var fold = Attribute.GetCustomAttribute(objectFields[i], typeof(FoldoutAttribute)) as FoldoutAttribute;
|
||||
CacheFoldProp c;
|
||||
if (fold == null)
|
||||
{
|
||||
if (prevFold != null && prevFold.FoldEverything)
|
||||
{
|
||||
if (!_cacheFoldouts.TryGetValue(prevFold.Name, out c))
|
||||
{
|
||||
_cacheFoldouts.Add(prevFold.Name,
|
||||
new CacheFoldProp {Attribute = prevFold, Types = new HashSet<string> {objectFields[i].Name}});
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Types.Add(objectFields[i].Name);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
prevFold = fold;
|
||||
|
||||
if (!_cacheFoldouts.TryGetValue(fold.Name, out c))
|
||||
{
|
||||
var expanded = EditorPrefs.GetBool(string.Format($"{fold.Name}{objectFields[i].Name}{_target.name}"), false);
|
||||
_cacheFoldouts.Add(fold.Name,
|
||||
new CacheFoldProp {Attribute = fold, Types = new HashSet<string> {objectFields[i].Name}, Expanded = expanded});
|
||||
}
|
||||
else c.Types.Add(objectFields[i].Name);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
var property = _serializedObject.GetIterator();
|
||||
var next = property.NextVisible(true);
|
||||
if (next)
|
||||
{
|
||||
do
|
||||
{
|
||||
HandleFoldProp(property);
|
||||
} while (property.NextVisible(false));
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private void HandleFoldProp(SerializedProperty prop)
|
||||
{
|
||||
bool shouldBeFolded = false;
|
||||
|
||||
foreach (var pair in _cacheFoldouts)
|
||||
{
|
||||
if (pair.Value.Types.Contains(prop.name))
|
||||
{
|
||||
var pr = prop.Copy();
|
||||
shouldBeFolded = true;
|
||||
pair.Value.Properties.Add(pr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldBeFolded == false)
|
||||
{
|
||||
var pr = prop.Copy();
|
||||
_props.Add(pr);
|
||||
}
|
||||
}
|
||||
|
||||
private class CacheFoldProp
|
||||
{
|
||||
public HashSet<string> Types = new HashSet<string>();
|
||||
public readonly List<SerializedProperty> Properties = new List<SerializedProperty>();
|
||||
public FoldoutAttribute Attribute;
|
||||
public bool Expanded;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Properties.Clear();
|
||||
Types.Clear();
|
||||
Attribute = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class StyleFramework
|
||||
{
|
||||
public static readonly GUIStyle Box;
|
||||
public static readonly GUIStyle BoxChild;
|
||||
public static readonly GUIStyle FoldoutHeader;
|
||||
|
||||
static StyleFramework()
|
||||
{
|
||||
FoldoutHeader = new GUIStyle(EditorStyles.foldout);
|
||||
FoldoutHeader.overflow = new RectOffset(-10, 0, 3, 0);
|
||||
FoldoutHeader.padding = new RectOffset(20, 0, 0, 0);
|
||||
FoldoutHeader.margin = new RectOffset(0, 0, 0, 2);
|
||||
FoldoutHeader.border = new RectOffset(2, 2, 2, 2);
|
||||
|
||||
Box = new GUIStyle(GUI.skin.box);
|
||||
Box.padding = new RectOffset(18, 0, 4, 0);
|
||||
|
||||
BoxChild = new GUIStyle(GUI.skin.box);
|
||||
BoxChild.padding = new RectOffset(0, 0, 0, 0);
|
||||
BoxChild.margin = new RectOffset(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static class EditorTypes
|
||||
{
|
||||
private static readonly Dictionary<int, List<FieldInfo>> Fields = new Dictionary<int, List<FieldInfo>>(FastComparable.Default);
|
||||
private static readonly Dictionary<int, List<PropertyInfo>> Properties = new Dictionary<int, List<PropertyInfo>>(FastComparable.Default);
|
||||
|
||||
public static int GetFields(Object target, out List<FieldInfo> objectFields)
|
||||
{
|
||||
var t = target.GetType();
|
||||
var hash = t.GetHashCode();
|
||||
|
||||
if (!Fields.TryGetValue(hash, out objectFields))
|
||||
{
|
||||
var typeTree = GetTypeTree(t);
|
||||
objectFields = target.GetType()
|
||||
.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
|
||||
.OrderByDescending(x => typeTree.IndexOf(x.DeclaringType))
|
||||
.ToList();
|
||||
Fields.Add(hash, objectFields);
|
||||
}
|
||||
|
||||
return objectFields.Count;
|
||||
}
|
||||
|
||||
public static int GetProperties(Object target, out List<PropertyInfo> objectProperties) {
|
||||
var t = target.GetType();
|
||||
var hash = t.GetHashCode();
|
||||
|
||||
if(!Properties.TryGetValue(hash, out objectProperties)) {
|
||||
var typeTree = GetTypeTree(t);
|
||||
objectProperties = target.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
|
||||
.OrderByDescending(x => typeTree.IndexOf(x.DeclaringType))
|
||||
.ToList();
|
||||
Properties.Add(hash, objectProperties);
|
||||
}
|
||||
|
||||
return objectProperties.Count;
|
||||
}
|
||||
|
||||
static IList<Type> GetTypeTree(Type t)
|
||||
{
|
||||
var types = new List<Type>();
|
||||
while (t.BaseType != null)
|
||||
{
|
||||
types.Add(t);
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class FastComparable : IEqualityComparer<int>
|
||||
{
|
||||
public static readonly FastComparable Default = new FastComparable();
|
||||
|
||||
public bool Equals(int x, int y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
public int GetHashCode(int obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user