275 lines
10 KiB
C#

using Streamingle.Utils.RoughConstraints;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace Streamingle.Utils.RoughConstraintsEditor
{
[CustomEditor(typeof(RoughConstraintBase), true)]
[CanEditMultipleObjects]
public sealed class RoughConstraintEditor : 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 roughFollowFoldout = 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 Rough 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 = (RoughConstraintBase)selectedTarget;
Undo.RecordObject(constraint, "Change Rough Constraint Lock");
constraint.SetLocked(newValue);
EditorUtility.SetDirty(constraint);
}
serializedObject.Update();
}
private void DrawSourceList()
{
EditorGUILayout.Space(2f);
sourceList.DoLayoutList();
EditorGUILayout.Space(4f);
}
private void DrawTypeSettings()
{
roughFollowFoldout = EditorGUILayout.Foldout(roughFollowFoldout, "Rough Follow", true);
if (roughFollowFoldout)
{
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 RoughPositionConstraint)
{
DrawProperties("constrainedAxis", "positionOffset", "offsetInSourceSpace");
}
else if (target is RoughRotationConstraint)
{
DrawProperties("constrainedAxis", "rotationOffset");
}
else if (target is RoughScaleConstraint)
{
DrawProperties("constrainedAxis", "scaleOffset");
}
else if (target is RoughParentConstraint)
{
DrawProperties("constrainedPositionAxis", "positionOffset", "positionOffsetInSourceSpace", "constrainedRotationAxis", "rotationOffset");
}
else if (target is RoughAimConstraint)
{
DrawProperties("aimAxis", "upAxis", "worldUpVector", "rotationOffset");
}
else if (target is RoughLookAtConstraint)
{
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<RoughConstraintBase> action)
{
serializedObject.ApplyModifiedProperties();
foreach (var selectedTarget in targets)
{
var constraint = (RoughConstraintBase)selectedTarget;
Undo.RecordObject(constraint.transform, undoName);
action(constraint);
EditorUtility.SetDirty(constraint.transform);
}
}
private void ActivateConstraint(RoughConstraintBase constraint)
{
Undo.RecordObject(constraint, "Activate Rough Constraint");
constraint.ActivateConstraint();
EditorUtility.SetDirty(constraint);
}
private void ZeroOffsets()
{
serializedObject.ApplyModifiedProperties();
Undo.RecordObjects(targets, "Zero Rough 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 RoughLookAtConstraint)
{
return "Look At";
}
var name = target.GetType().Name;
name = name.Replace("Rough", string.Empty).Replace("Constraint", string.Empty);
return ObjectNames.NicifyVariableName(name);
}
}
}