|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace NaughtyAttributes.Editor
|
|
|
|
|
|
{
|
|
|
|
|
|
[CanEditMultipleObjects]
|
|
|
|
|
|
[CustomEditor(typeof(UnityEngine.Object), true)]
|
|
|
|
|
|
public class NaughtyInspector : UnityEditor.Editor
|
|
|
|
|
|
{
|
|
|
|
|
|
protected List<NaughtyProperty> _serializedProperties = new List<NaughtyProperty>();
|
|
|
|
|
|
protected List<FieldInfo> _nonSerializedFields;
|
|
|
|
|
|
protected List<PropertyInfo> _nativeProperties;
|
|
|
|
|
|
protected List<MethodInfo> _methods;
|
|
|
|
|
|
|
|
|
|
|
|
protected List<NaughtyProperty> _nonGroupedSerializedProperty;
|
|
|
|
|
|
protected SerializedProperty m_ScriptProperty;
|
|
|
|
|
|
|
|
|
|
|
|
protected List<IGrouping<string, NaughtyProperty>> _groupedSerialzedProperty;
|
|
|
|
|
|
protected List<IGrouping<string, NaughtyProperty>> _foldoutGroupedSerializedProperty;
|
|
|
|
|
|
|
|
|
|
|
|
private Dictionary<string, SavedBool> _foldouts = new Dictionary<string, SavedBool>();
|
|
|
|
|
|
|
|
|
|
|
|
private bool _anyNaughtyAttribute;
|
|
|
|
|
|
|
|
|
|
|
|
protected bool _useCachedMetaAttributes;
|
|
|
|
|
|
protected bool _changeDetected;
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void OnEnable()
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Prepare();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void OnDisable()
|
|
|
|
|
|
{
|
|
|
|
|
|
//cleanup memory
|
|
|
|
|
|
ReorderableListPropertyDrawer.Instance.ClearCache();
|
|
|
|
|
|
|
|
|
|
|
|
_nonSerializedFields.Clear();
|
|
|
|
|
|
_nativeProperties.Clear();
|
|
|
|
|
|
_methods.Clear();
|
|
|
|
|
|
_foldouts.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
_foldoutGroupedSerializedProperty.Clear();
|
|
|
|
|
|
_groupedSerialzedProperty.Clear();
|
|
|
|
|
|
_nonGroupedSerializedProperty.Clear();
|
|
|
|
|
|
_serializedProperties.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
m_ScriptProperty = default;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void Prepare()
|
|
|
|
|
|
{
|
|
|
|
|
|
_nonSerializedFields = ReflectionUtility.GetAllFields(
|
|
|
|
|
|
target, f => f.GetCustomAttributes(typeof(ShowNonSerializedFieldAttribute), true).Length > 0).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
_nativeProperties = ReflectionUtility.GetAllProperties(
|
|
|
|
|
|
target, p => p.GetCustomAttributes(typeof(ShowNativePropertyAttribute), true).Length > 0).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
_methods = ReflectionUtility.GetAllMethods(
|
|
|
|
|
|
target, m => m.GetCustomAttributes(typeof(ButtonAttribute), true).Length > 0).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
GetSerializedProperties(ref _serializedProperties);
|
|
|
|
|
|
|
|
|
|
|
|
_anyNaughtyAttribute = _serializedProperties.Any(p => PropertyUtility.GetAttribute<INaughtyAttribute>(p.serializedProperty) != null);
|
|
|
|
|
|
|
|
|
|
|
|
_nonGroupedSerializedProperty = GetNonGroupedProperties(_serializedProperties).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
//.First(...) doesnt work for some reason because the m_Script field isnt loaded yet I assume
|
|
|
|
|
|
NaughtyProperty[] mScripts = _serializedProperties.Where(p => p.serializedProperty.name.Equals("m_Script")).ToArray();
|
|
|
|
|
|
m_ScriptProperty = mScripts.Length > 0 ? mScripts[0].serializedProperty : null;
|
|
|
|
|
|
|
|
|
|
|
|
_groupedSerialzedProperty = GetGroupedProperties(_serializedProperties).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
_foldoutGroupedSerializedProperty = GetFoldoutProperties(_serializedProperties).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
_useCachedMetaAttributes = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnInspectorGUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
_changeDetected = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (!_anyNaughtyAttribute)
|
|
|
|
|
|
{
|
|
|
|
|
|
DrawDefaultInspector();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DrawSerializedProperties();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DrawNonSerializedFields();
|
|
|
|
|
|
DrawNativeProperties();
|
|
|
|
|
|
DrawButtons();
|
|
|
|
|
|
|
|
|
|
|
|
_useCachedMetaAttributes = !_changeDetected;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void GetSerializedProperties(ref List<NaughtyProperty> outSerializedProperties)
|
|
|
|
|
|
{
|
|
|
|
|
|
outSerializedProperties.Clear();
|
|
|
|
|
|
outSerializedProperties.TrimExcess();
|
|
|
|
|
|
|
|
|
|
|
|
using (var iterator = serializedObject.GetIterator())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (iterator.NextVisible(true))
|
|
|
|
|
|
{
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
outSerializedProperties.Add(
|
|
|
|
|
|
PropertyUtility.CreateNaughtyProperty(
|
|
|
|
|
|
serializedObject.FindProperty(iterator.name)));
|
|
|
|
|
|
}
|
|
|
|
|
|
while (iterator.NextVisible(false));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void DrawSerializedProperties()
|
|
|
|
|
|
{
|
|
|
|
|
|
serializedObject.Update();
|
|
|
|
|
|
|
|
|
|
|
|
if (m_ScriptProperty != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (new EditorGUI.DisabledScope(disabled: true))
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.PropertyField(m_ScriptProperty);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Draw non-grouped serialized properties
|
|
|
|
|
|
foreach (var naughtyProperty in _nonGroupedSerializedProperty)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_useCachedMetaAttributes)
|
|
|
|
|
|
{
|
|
|
|
|
|
naughtyProperty.cachedIsVisible = PropertyUtility.IsVisible(naughtyProperty.showIfAttribute,
|
|
|
|
|
|
naughtyProperty.serializedProperty);
|
|
|
|
|
|
|
|
|
|
|
|
naughtyProperty.cachedIsEnabled = PropertyUtility.IsEnabled(naughtyProperty.readOnlyAttribute, naughtyProperty.enableIfAttribute,
|
|
|
|
|
|
naughtyProperty.serializedProperty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_changeDetected |= NaughtyEditorGUI.PropertyField_Layout(naughtyProperty, includeChildren: true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Draw grouped serialized properties
|
|
|
|
|
|
foreach (var group in _groupedSerialzedProperty)
|
|
|
|
|
|
{
|
|
|
|
|
|
IEnumerable<NaughtyProperty> visibleProperties =
|
|
|
|
|
|
_useCachedMetaAttributes
|
|
|
|
|
|
? group.Where(p => p.cachedIsVisible)
|
|
|
|
|
|
: group.Where(p =>
|
|
|
|
|
|
{
|
|
|
|
|
|
p.cachedIsEnabled = PropertyUtility.IsEnabled(p.readOnlyAttribute, p.enableIfAttribute,
|
|
|
|
|
|
p.serializedProperty);
|
|
|
|
|
|
|
|
|
|
|
|
return p.cachedIsVisible =
|
|
|
|
|
|
PropertyUtility.IsVisible(p.showIfAttribute, p.serializedProperty);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!visibleProperties.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NaughtyEditorGUI.BeginBoxGroup_Layout(group.Key);
|
|
|
|
|
|
foreach (var naughtyProperty in visibleProperties)
|
|
|
|
|
|
{
|
|
|
|
|
|
_changeDetected |= NaughtyEditorGUI.PropertyField_Layout(naughtyProperty, includeChildren: true);
|
|
|
|
|
|
}
|
|
|
|
|
|
NaughtyEditorGUI.EndBoxGroup_Layout();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Draw foldout serialized properties
|
|
|
|
|
|
foreach (var group in _foldoutGroupedSerializedProperty)
|
|
|
|
|
|
{
|
|
|
|
|
|
IEnumerable<NaughtyProperty> visibleProperties =
|
|
|
|
|
|
_useCachedMetaAttributes
|
|
|
|
|
|
? group.Where(p => p.cachedIsVisible)
|
|
|
|
|
|
: group.Where(p =>
|
|
|
|
|
|
{
|
|
|
|
|
|
p.cachedIsEnabled = PropertyUtility.IsEnabled(p.readOnlyAttribute, p.enableIfAttribute,
|
|
|
|
|
|
p.serializedProperty);
|
|
|
|
|
|
|
|
|
|
|
|
return p.cachedIsVisible =
|
|
|
|
|
|
PropertyUtility.IsVisible(p.showIfAttribute, p.serializedProperty);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!visibleProperties.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!_foldouts.ContainsKey(group.Key))
|
|
|
|
|
|
{
|
|
|
|
|
|
_foldouts[group.Key] = new SavedBool($"{target.GetInstanceID()}.{group.Key}", false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_foldouts[group.Key].Value = EditorGUILayout.Foldout(_foldouts[group.Key].Value, group.Key, true);
|
|
|
|
|
|
if (_foldouts[group.Key].Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var naughtyProperty in visibleProperties)
|
|
|
|
|
|
{
|
|
|
|
|
|
_changeDetected |= NaughtyEditorGUI.PropertyField_Layout(naughtyProperty, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void DrawNonSerializedFields(bool drawHeader = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_nonSerializedFields.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (drawHeader)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
|
|
EditorGUILayout.LabelField("Non-Serialized Fields", GetHeaderGUIStyle());
|
|
|
|
|
|
NaughtyEditorGUI.HorizontalLine(
|
|
|
|
|
|
EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var field in _nonSerializedFields)
|
|
|
|
|
|
{
|
|
|
|
|
|
NaughtyEditorGUI.NonSerializedField_Layout(serializedObject.targetObject, field);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void DrawNativeProperties(bool drawHeader = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_nativeProperties.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (drawHeader)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
|
|
EditorGUILayout.LabelField("Native Properties", GetHeaderGUIStyle());
|
|
|
|
|
|
NaughtyEditorGUI.HorizontalLine(
|
|
|
|
|
|
EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var property in _nativeProperties)
|
|
|
|
|
|
{
|
|
|
|
|
|
NaughtyEditorGUI.NativeProperty_Layout(serializedObject.targetObject, property);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void DrawButtons(bool drawHeader = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_methods.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (drawHeader)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
|
|
EditorGUILayout.LabelField("Buttons", GetHeaderGUIStyle());
|
|
|
|
|
|
NaughtyEditorGUI.HorizontalLine(
|
|
|
|
|
|
EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var method in _methods)
|
|
|
|
|
|
{
|
|
|
|
|
|
NaughtyEditorGUI.Button(serializedObject.targetObject, method);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<NaughtyProperty> GetNonGroupedProperties(IEnumerable<NaughtyProperty> properties)
|
|
|
|
|
|
{
|
|
|
|
|
|
return properties.Where(p => PropertyUtility.GetAttribute<IGroupAttribute>(p.serializedProperty) == null && !p.serializedProperty.name.Equals("m_Script"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<IGrouping<string, NaughtyProperty>> GetGroupedProperties(IEnumerable<NaughtyProperty> properties)
|
|
|
|
|
|
{
|
|
|
|
|
|
return properties
|
|
|
|
|
|
.Where(p => PropertyUtility.GetAttribute<BoxGroupAttribute>(p.serializedProperty) != null)
|
|
|
|
|
|
.GroupBy(p => PropertyUtility.GetAttribute<BoxGroupAttribute>(p.serializedProperty).Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<IGrouping<string, NaughtyProperty>> GetFoldoutProperties(IEnumerable<NaughtyProperty> properties)
|
|
|
|
|
|
{
|
|
|
|
|
|
return properties
|
|
|
|
|
|
.Where(p => PropertyUtility.GetAttribute<FoldoutAttribute>(p.serializedProperty) != null)
|
|
|
|
|
|
.GroupBy(p => PropertyUtility.GetAttribute<FoldoutAttribute>(p.serializedProperty).Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static GUIStyle GetHeaderGUIStyle()
|
|
|
|
|
|
{
|
|
|
|
|
|
GUIStyle style = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
|
|
|
|
|
|
style.fontStyle = FontStyle.Bold;
|
|
|
|
|
|
style.alignment = TextAnchor.UpperCenter;
|
|
|
|
|
|
|
|
|
|
|
|
return style;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|