modular-avatar/Editor/Inspector/AvatarObjectReferenceDrawer.cs

150 lines
6.0 KiB
C#
Raw Normal View History

using UnityEditor;
using UnityEngine;
2022-11-11 12:39:58 +08:00
namespace nadena.dev.modular_avatar.core.editor
{
[CustomPropertyDrawer(typeof(AvatarObjectReference))]
internal class AvatarObjectReferenceDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
2022-10-23 04:04:25 +08:00
if (CustomGUI(position, property, label)) return;
2022-11-11 12:39:58 +08:00
2022-10-23 04:04:25 +08:00
var xButtonSize = EditorStyles.miniButtonRight.CalcSize(new GUIContent("x"));
var xButtonRect = new Rect(position.xMax - xButtonSize.x, position.y, xButtonSize.x, position.height);
position = new Rect(position.x, position.y, position.width - xButtonSize.x, position.height);
2022-10-23 04:04:25 +08:00
property = property.FindPropertyRelative(nameof(AvatarObjectReference.referencePath));
2022-10-23 04:04:25 +08:00
position = EditorGUI.PrefixLabel(position, label);
2022-10-23 04:04:25 +08:00
using (var scope = new ZeroIndentScope())
{
EditorGUI.LabelField(position,
string.IsNullOrEmpty(property.stringValue) ? "(null)" : property.stringValue);
}
}
private bool CustomGUI(Rect position, SerializedProperty property, GUIContent label)
{
var color = GUI.contentColor;
property = property.FindPropertyRelative(nameof(AvatarObjectReference.referencePath));
try
{
var avatarTransform = findContainingAvatarTransform(property);
if (avatarTransform == null) return false;
bool isRoot = property.stringValue == AvatarObjectReference.AVATAR_ROOT;
bool isNull = string.IsNullOrEmpty(property.stringValue);
Transform target;
if (isNull) target = null;
else if (isRoot) target = avatarTransform;
else target = avatarTransform.Find(property.stringValue);
var labelRect = position;
position = EditorGUI.PrefixLabel(position, label);
labelRect.width = position.x - labelRect.x;
var nullContent = GUIContent.none;
2022-10-20 10:42:33 +08:00
using (var scope = new ZeroIndentScope())
{
2022-10-20 10:42:33 +08:00
if (target != null || isNull)
{
2022-10-20 10:42:33 +08:00
EditorGUI.BeginChangeCheck();
var newTarget = EditorGUI.ObjectField(position, nullContent, target, typeof(Transform), true);
if (EditorGUI.EndChangeCheck())
{
2022-10-20 10:42:33 +08:00
if (newTarget == null)
{
property.stringValue = "";
}
else if (newTarget == avatarTransform)
2022-10-20 10:42:33 +08:00
{
property.stringValue = AvatarObjectReference.AVATAR_ROOT;
}
else
{
var relPath =
RuntimeUtil.RelativePath(avatarTransform.gameObject, ((Transform) newTarget).gameObject);
2022-10-20 10:42:33 +08:00
if (relPath == null) return true;
property.stringValue = relPath;
}
}
}
2022-10-20 10:42:33 +08:00
else
{
// For some reason, this color change retroactively affects the prefix label above, so draw our own
// label as well (we still want the prefix label for highlights, etc).
EditorGUI.LabelField(labelRect, label);
2022-10-20 10:42:33 +08:00
GUI.contentColor = new Color(0, 0, 0, 0);
EditorGUI.BeginChangeCheck();
var newTarget = EditorGUI.ObjectField(position, nullContent, target, typeof(Transform), true);
GUI.contentColor = color;
2022-10-20 10:42:33 +08:00
if (EditorGUI.EndChangeCheck())
{
2022-10-20 10:42:33 +08:00
if (newTarget == null)
{
property.stringValue = "";
}
else if (newTarget == avatarTransform)
2022-10-20 10:42:33 +08:00
{
property.stringValue = AvatarObjectReference.AVATAR_ROOT;
}
else
{
var relPath =
RuntimeUtil.RelativePath(avatarTransform.gameObject, ((Transform) newTarget).gameObject);
2022-10-20 10:42:33 +08:00
if (relPath == null) return true;
property.stringValue = relPath;
}
}
else
{
2022-10-20 10:42:33 +08:00
GUI.contentColor = Color.red;
EditorGUI.LabelField(position, property.stringValue);
}
}
2022-10-20 10:42:33 +08:00
return true;
}
}
finally
{
GUI.contentColor = color;
}
}
private static Transform findContainingAvatarTransform(SerializedProperty property)
{
// Find containing object, and from that the avatar
if (property.serializedObject == null) return null;
Transform commonAvatar = null;
var targets = property.serializedObject.targetObjects;
for (int i = 0; i < targets.Length; i++)
{
var obj = targets[i] as Component;
if (obj == null) return null;
var transform = obj.transform;
var avatar = RuntimeUtil.FindAvatarTransformInParents(transform);
if (i == 0)
{
if (avatar == null) return null;
commonAvatar = avatar;
}
else if (commonAvatar != avatar) return null;
}
return commonAvatar;
}
}
}