using Streamingle.Utils.LerpConstraints; using UnityEditor; using UnityEditorInternal; using UnityEngine; namespace Streamingle.Utils.LerpConstraintsEditor { [CustomEditor(typeof(LerpConstraintBase), true)] [CanEditMultipleObjects] public sealed class LerpConstraintEditor : UnityEditor.Editor { private SerializedProperty constraintActive; private SerializedProperty locked; private SerializedProperty weight; private SerializedProperty sources; private SerializedProperty damping; private SerializedProperty updateMode; private SerializedProperty useUnscaledTime; private SerializedProperty snapOnEnable; private ReorderableList sourceList; private bool lerpFollowFoldout = true; private bool settingsFoldout = true; private void OnEnable() { constraintActive = serializedObject.FindProperty("constraintActive"); locked = serializedObject.FindProperty("locked"); weight = serializedObject.FindProperty("weight"); sources = serializedObject.FindProperty("sources"); damping = serializedObject.FindProperty("damping"); updateMode = serializedObject.FindProperty("updateMode"); useUnscaledTime = serializedObject.FindProperty("useUnscaledTime"); snapOnEnable = serializedObject.FindProperty("snapOnEnable"); sourceList = new ReorderableList(serializedObject, sources, true, true, true, true) { drawHeaderCallback = DrawSourceHeader, drawElementCallback = DrawSourceElement, elementHeightCallback = _ => EditorGUIUtility.singleLineHeight + 6f, onAddCallback = OnAddSource }; } public override void OnInspectorGUI() { serializedObject.Update(); DrawCommonSettings(); DrawSourceList(); DrawTypeSettings(); serializedObject.ApplyModifiedProperties(); } private void DrawCommonSettings() { EditorGUILayout.PropertyField(constraintActive, new GUIContent("Constraint Active")); DrawLockField(); EditorGUILayout.Slider(weight, 0f, 1f, new GUIContent("Weight")); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Activate", EditorStyles.miniButton, GUILayout.Width(72f))) { ApplyAction("Activate Lerp Constraint", ActivateConstraint); } if (GUILayout.Button("Zero", EditorStyles.miniButton, GUILayout.Width(56f))) { ZeroOffsets(); } EditorGUILayout.EndHorizontal(); } private void DrawLockField() { EditorGUI.BeginChangeCheck(); var newValue = EditorGUILayout.Toggle(new GUIContent("Lock"), locked.boolValue); if (!EditorGUI.EndChangeCheck()) { return; } serializedObject.ApplyModifiedProperties(); foreach (var selectedTarget in targets) { var constraint = (LerpConstraintBase)selectedTarget; Undo.RecordObject(constraint, "Change Lerp Constraint Lock"); constraint.SetLocked(newValue); EditorUtility.SetDirty(constraint); } serializedObject.Update(); } private void DrawSourceList() { EditorGUILayout.Space(2f); sourceList.DoLayoutList(); EditorGUILayout.Space(4f); } private void DrawTypeSettings() { lerpFollowFoldout = EditorGUILayout.Foldout(lerpFollowFoldout, "Lerp Follow", true); if (lerpFollowFoldout) { using (new EditorGUI.IndentLevelScope()) { EditorGUILayout.PropertyField(damping, new GUIContent("Damping")); EditorGUILayout.PropertyField(updateMode, new GUIContent("Update Mode")); EditorGUILayout.PropertyField(useUnscaledTime, new GUIContent("Use Unscaled Time")); EditorGUILayout.PropertyField(snapOnEnable, new GUIContent("Snap On Enable")); } } settingsFoldout = EditorGUILayout.Foldout(settingsFoldout, GetSettingsTitle(), true); if (!settingsFoldout) { return; } using (new EditorGUI.IndentLevelScope()) { DrawTypeProperties(); } } private void DrawTypeProperties() { if (target is LerpPositionConstraint) { DrawProperties("constrainedAxis", "positionOffset", "offsetInSourceSpace"); } else if (target is LerpRotationConstraint) { DrawProperties("constrainedAxis", "rotationOffset"); } else if (target is LerpScaleConstraint) { DrawProperties("constrainedAxis", "scaleOffset"); } else if (target is LerpParentConstraint) { DrawProperties("constrainedPositionAxis", "positionOffset", "positionOffsetInSourceSpace", "constrainedRotationAxis", "rotationOffset"); } else if (target is LerpAimConstraint) { DrawProperties("aimAxis", "upAxis", "worldUpVector", "rotationOffset"); } else if (target is LerpLookAtConstraint) { DrawProperties("forwardAxis", "worldUpVector", "targetPositionOffset", "rotationOffset"); } } private void DrawProperties(params string[] propertyNames) { for (var i = 0; i < propertyNames.Length; i++) { var property = serializedObject.FindProperty(propertyNames[i]); if (property != null) { EditorGUILayout.PropertyField(property, new GUIContent(ObjectNames.NicifyVariableName(property.name))); } } } private void ApplyAction(string undoName, System.Action action) { serializedObject.ApplyModifiedProperties(); foreach (var selectedTarget in targets) { var constraint = (LerpConstraintBase)selectedTarget; Undo.RecordObject(constraint.transform, undoName); action(constraint); EditorUtility.SetDirty(constraint.transform); } } private void ActivateConstraint(LerpConstraintBase constraint) { Undo.RecordObject(constraint, "Activate Lerp Constraint"); constraint.ActivateConstraint(); EditorUtility.SetDirty(constraint); } private void ZeroOffsets() { serializedObject.ApplyModifiedProperties(); Undo.RecordObjects(targets, "Zero Lerp Constraint Offsets"); SetVector3IfExists("positionOffset", Vector3.zero); SetVector3IfExists("rotationOffset", Vector3.zero); SetVector3IfExists("scaleOffset", Vector3.zero); SetVector3IfExists("targetPositionOffset", Vector3.zero); serializedObject.ApplyModifiedProperties(); } private void SetVector3IfExists(string propertyName, Vector3 value) { var property = serializedObject.FindProperty(propertyName); if (property != null) { property.vector3Value = value; } } private void DrawSourceHeader(Rect rect) { var objectRect = new Rect(rect.x + 14f, rect.y, rect.width - 88f, rect.height); var weightRect = new Rect(rect.xMax - 70f, rect.y, 68f, rect.height); EditorGUI.LabelField(objectRect, "Sources"); EditorGUI.LabelField(weightRect, "Weight"); } private void DrawSourceElement(Rect rect, int index, bool isActive, bool isFocused) { var element = sources.GetArrayElementAtIndex(index); var sourceTransform = element.FindPropertyRelative("sourceTransform"); var sourceWeight = element.FindPropertyRelative("weight"); rect.y += 3f; rect.height = EditorGUIUtility.singleLineHeight; if (sourceTransform == null || sourceWeight == null) { EditorGUI.PropertyField(rect, element, GUIContent.none); return; } var weightWidth = 70f; var gap = 6f; var targetRect = new Rect(rect.x, rect.y, rect.width - weightWidth - gap, rect.height); var weightRect = new Rect(targetRect.xMax + gap, rect.y, weightWidth, rect.height); EditorGUI.PropertyField(targetRect, sourceTransform, GUIContent.none); sourceWeight.floatValue = Mathf.Clamp01(EditorGUI.FloatField(weightRect, sourceWeight.floatValue)); } private void OnAddSource(ReorderableList list) { sources.arraySize++; var element = sources.GetArrayElementAtIndex(sources.arraySize - 1); var sourceTransform = element.FindPropertyRelative("sourceTransform"); var sourceWeight = element.FindPropertyRelative("weight"); if (sourceTransform != null) { sourceTransform.objectReferenceValue = null; } if (sourceWeight != null) { sourceWeight.floatValue = 1f; } } private string GetSettingsTitle() { if (target is LerpLookAtConstraint) { return "Look At"; } var name = target.GetType().Name; name = name.Replace("Lerp", string.Empty).Replace("Constraint", string.Empty); return ObjectNames.NicifyVariableName(name); } } }