using System;
using System.Collections.Generic;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.XR.Hands;
namespace UnityEditor.XR.Hands
{
///
/// Custom editor for an .
///
[CustomEditor(typeof(XRHandSkeletonDriver), true), CanEditMultipleObjects]
public class XRHandSkeletonDriverEditor : BaseXRHandsEditor
{
///
/// Draws a list of joint transform references that draws both the joint and the transform in a single line.
///
class JointTransformReferenceReorderableList : ReorderableList
{
public JointTransformReferenceReorderableList(SerializedObject serializedObject, SerializedProperty serializedProperty)
: base(serializedObject, serializedProperty, true, true, true, true)
{
drawElementCallback = OnDrawListElement;
drawHeaderCallback = OnDrawListHeader;
elementHeight = EditorGUIUtility.singleLineHeight;
}
void OnDrawListHeader(Rect rect)
{
GUI.Label(rect, Contents.jointTransformReferences);
}
void OnDrawListElement(Rect rect, int elementIndex, bool isActive, bool isFocused)
{
var element = serializedProperty.GetArrayElementAtIndex(elementIndex);
rect.yMin += 2;
var width = rect.width;
var middle = rect.xMin + width * 0.5f;
const float padding = 8f;
rect.xMax = middle - padding;
EditorGUI.PropertyField(rect, element.FindPropertyRelative("m_XRHandJointID"), GUIContent.none);
rect.xMax = rect.xMin + width;
rect.xMin = middle;
EditorGUI.PropertyField(rect, element.FindPropertyRelative("m_JointTransform"), GUIContent.none);
}
}
const string k_JointsExpandedStateKey = "XRHands." + nameof(XRHandSkeletonDriverEditor) + ".JointsExpanded";
const string k_FindJointsFromParentUndoMessage = "Find Joints from Parent";
const string k_ScriptPropertyName = "m_Script";
const string k_XRHandTrackingEventsPropertyName = "m_XRHandTrackingEvents";
const string k_JointTransformReferencesPropertyName = "m_JointTransformReferences";
const string k_RootTransformPropertyName = "m_RootTransform";
static readonly string[] k_KnownProperties =
{
k_ScriptPropertyName,
k_XRHandTrackingEventsPropertyName,
k_JointTransformReferencesPropertyName,
k_RootTransformPropertyName,
};
SerializedProperty m_XRHandTrackingEvents;
SerializedProperty m_JointTransformReferences;
SerializedProperty m_RootTransform;
JointTransformReferenceReorderableList m_JointTransformReferencesList;
List m_MissingJointNames = new List();
bool m_DrawHelpBoxForFindingJoints;
string m_ErrorFindingJointsMessage;
bool m_JointsExpanded;
///
/// Contents of GUI elements used by this editor.
///
static class Contents
{
public static readonly GUIContent handTrackingEvents = EditorGUIUtility.TrTextContent("XR Hand Tracking Events");
public static readonly GUIContent jointTransformReferences = EditorGUIUtility.TrTextContent("Joint Transform References");
public static readonly GUIContent parentTransform = EditorGUIUtility.TrTextContent("Root Transform");
public static readonly GUIContent findJoints = EditorGUIUtility.TrTextContent("Find Joints", "Search the root transform's children for transforms that start or end with a joint name.");
public static readonly GUIContent clearJoints = EditorGUIUtility.TrTextContent("Clear");
}
void OnEnable()
{
m_XRHandTrackingEvents = serializedObject.FindProperty(k_XRHandTrackingEventsPropertyName);
m_JointTransformReferences = serializedObject.FindProperty(k_JointTransformReferencesPropertyName);
m_RootTransform = serializedObject.FindProperty(k_RootTransformPropertyName);
m_JointTransformReferencesList = new JointTransformReferenceReorderableList(serializedObject, m_JointTransformReferences);
m_JointsExpanded = SessionState.GetBool(k_JointsExpandedStateKey, false);
}
void OnDisable()
{
SessionState.SetBool(k_JointsExpandedStateKey, m_JointsExpanded);
}
void OnFindJointsButtonPressed()
{
foreach (var targetObject in targets)
{
var skeletonDriver = (XRHandSkeletonDriver)targetObject;
Undo.RecordObject(skeletonDriver, k_FindJointsFromParentUndoMessage);
skeletonDriver.FindJointsFromRoot(m_MissingJointNames);
EditorUtility.SetDirty(skeletonDriver);
if (m_MissingJointNames.Count > 0)
{
m_DrawHelpBoxForFindingJoints = true;
m_ErrorFindingJointsMessage = $"Could not find joints: {string.Join(", ", m_MissingJointNames)}";
}
else
{
m_DrawHelpBoxForFindingJoints = false;
}
}
serializedObject.SetIsDifferentCacheDirty();
}
///
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawInspector();
DrawPropertiesExcluding(serializedObject, k_KnownProperties);
serializedObject.ApplyModifiedProperties();
}
void DrawInspector()
{
DrawScript();
EditorGUILayout.PropertyField(m_XRHandTrackingEvents, Contents.handTrackingEvents, true);
m_JointsExpanded = EditorGUILayout.Foldout(m_JointsExpanded, Contents.jointTransformReferences, true);
if (m_JointsExpanded)
{
using (new EditorGUI.IndentLevelScope())
{
DrawJointTransformsFoldout();
}
}
EditorGUILayout.Space();
}
void DrawJointTransformsFoldout()
{
EditorGUILayout.PropertyField(m_RootTransform, Contents.parentTransform);
using (new EditorGUILayout.HorizontalScope())
{
using (new EditorGUI.DisabledScope(m_RootTransform.objectReferenceValue == null))
{
if (GUILayout.Button(Contents.findJoints))
{
OnFindJointsButtonPressed();
}
}
using (new EditorGUI.DisabledScope(m_JointTransformReferences.arraySize == 0))
{
if (GUILayout.Button(Contents.clearJoints))
{
m_JointTransformReferences.ClearArray();
}
}
}
if (m_DrawHelpBoxForFindingJoints)
{
EditorGUILayout.HelpBox(m_ErrorFindingJointsMessage, MessageType.Warning, true);
}
m_JointTransformReferencesList.DoLayoutList();
}
}
}