diff --git a/Editor/EnjoinedConfigurableJoint.cs b/Editor/EnjoinedConfigurableJoint.cs index 1ea9f3c..6941cca 100644 --- a/Editor/EnjoinedConfigurableJoint.cs +++ b/Editor/EnjoinedConfigurableJoint.cs @@ -3,6 +3,7 @@ * License: Mozilla Public License Version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/) */ +using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; @@ -11,18 +12,21 @@ namespace JesseStiller.Enjoined { [CanEditMultipleObjects] [CustomEditor(typeof(ConfigurableJoint))] public class EnjoinedConfigurableJoint : Editor { - // Joint properties - private SerializedProperty connectedBody, axis, anchor, autoConfigureConnectedAnchor, connectedAnchor, breakForce, breakTorque, enableCollision, enablePreprocessing; - - // Configurable Joint properties - private SerializedProperty projectionAngle, projectionDistance, projectionMode, slerpDrive, angularYZDrive, angularXDrive, rotationDriveMode, targetAngularVelocity, targetRotation, zDrive, yDrive, xDrive, targetVelocity, targetPosition, angularZLimit, angularYLimit, highAngularXLimit, lowAngularXLimit, linearLimit, linearLimitSpring, angularYZLimitSpring, angularXLimitSpring, angularXMotion, angularYMotion, angularZMotion, zMotion, yMotion, xMotion, secondaryAxis, configuredInWorldSpace, swapBodies; private bool linearLimitFoldoutState = false; - + private ConfigurableJoint joint; + private Dictionary properties = new Dictionary(); + private void OnEnable() { joint = (ConfigurableJoint)serializedObject.targetObject; + SerializedProperty iterator = serializedObject.GetIterator(); + while(iterator.Next(true)) { + // Remove the initial "m_" prefix + properties.Add(iterator.propertyPath.Remove(0, 2), iterator.Copy()); + } + FieldInfo[] fields = typeof(EnjoinedConfigurableJoint).GetFields(BindingFlags.NonPublic | BindingFlags.Instance); foreach(FieldInfo fieldInfo in fields) { if(fieldInfo.FieldType != typeof(SerializedProperty)) continue; @@ -35,13 +39,13 @@ private void OnEnable() { public override void OnInspectorGUI() { serializedObject.Update(); - DrawSerializedProperties(connectedBody, anchor, axis); + DrawSerializedProperties("ConnectedBody", "Anchor", "Axis"); - GUIUtilities.DrawConnectedAnchorProperty(connectedAnchor, autoConfigureConnectedAnchor); + GUIUtilities.DrawConnectedAnchorProperty(properties["ConnectedAnchor"], properties["AutoConfigureConnectedAnchor"]); - EditorGUILayout.PropertyField(secondaryAxis); + EditorGUILayout.PropertyField(properties["SecondaryAxis"]); - MultiPropertyField("Linear Motion", new GUIContent[] { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z") }, xMotion, yMotion, zMotion); + MultiPropertyField("Linear Motion", new GUIContent[] { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z") }, properties["XMotion"], properties["YMotion"], properties["ZMotion"]); /** * Linear Limit @@ -68,22 +72,32 @@ public override void OnInspectorGUI() { joint.linearLimitSpring = linearLimitSpring; } - MultiPropertyField("Angular Motion", new GUIContent[] { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z") }, angularXMotion, angularYMotion, angularZMotion); - + MultiPropertyField("Angular Motion", new GUIContent[] { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z") }, properties["AngularXMotion"], properties["AngularYMotion"], properties["AngularZMotion"]); + /** * Angular Limit */ - DrawSerializedProperties(angularXLimitSpring, lowAngularXLimit, highAngularXLimit, angularYLimit, angularYZLimitSpring, angularYLimit, angularZLimit); - + //DrawSerializedProperties(angularXLimitSpring, lowAngularXLimit, highAngularXLimit, angularYLimit, angularYZLimitSpring, angularYLimit, angularZLimit); + EditorGUILayout.PrefixLabel("X-axis Angular Limit"); + EditorGUI.indentLevel = 1; + float newLowerLimitValue = joint.lowAngularXLimit.limit; + float newUpperLimitValue = joint.highAngularXLimit.limit; + if(GUIUtilities.MinMaxWithFloatFields("Angle", ref newLowerLimitValue, ref newUpperLimitValue, -180f, 180f, 3)) { + properties["LowAngularXLimit.limit"].floatValue = newLowerLimitValue; + properties["HighAngularXLimit.limit"].floatValue = newUpperLimitValue; + } + MultiPropertyField("Bounciness", new string[] { "min", "max" }, properties["LowAngularXLimit.bounciness"], properties["HighAngularXLimit.bounciness"]); + EditorGUI.indentLevel = 0; + /** * Rotation Drive */ - DrawSerializedProperties(rotationDriveMode); + DrawSerializedProperties("RotationDriveMode"); EditorGUI.indentLevel = 1; - if((RotationDriveMode)rotationDriveMode.enumValueIndex == RotationDriveMode.XYAndZ) { - DrawSerializedProperties(angularXDrive, angularYZDrive); + if((RotationDriveMode)properties["RotationDriveMode"].enumValueIndex == RotationDriveMode.XYAndZ) { + DrawSerializedProperties("AngularXDrive", "AngularYZDrive"); } else { - DrawSerializedProperties(slerpDrive); + DrawSerializedProperties("SlerpDrive"); } EditorGUI.indentLevel = 0; @@ -94,10 +108,30 @@ public override void OnInspectorGUI() { DrawDefaultInspector(); } - private void DrawSerializedProperties(params SerializedProperty[] properties) { - foreach(SerializedProperty property in properties) { - EditorGUILayout.PropertyField(property, true, null); + private void DrawSerializedProperties(params string[] propertyNames) { + foreach(string propertyName in propertyNames) { + EditorGUILayout.PropertyField(properties[propertyName], true, null); + } + } + + private static void MultiPropertyField(string label, string[] propertyLabels, params SerializedProperty[] properties) { + Debug.Assert(propertyLabels.Length == properties.Length); + + Rect controlRect = EditorGUILayout.GetControlRect(); + + Rect fillRect = EditorGUI.PrefixLabel(controlRect, new GUIContent(label)); + float propertyCellWidth = (fillRect.width - (properties.Length - 1f) * 2f) / properties.Length; + + float lastLabelWidth = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = 13f; + + Rect cellRect = new Rect(fillRect.x - 1, fillRect.y, propertyCellWidth, fillRect.height); + for(int i = 0; i < properties.Length; i++) { + EditorGUI.PropertyField(cellRect, properties[i], new GUIContent(propertyLabels[i])); + cellRect.x += propertyCellWidth + 2f; } + + EditorGUIUtility.labelWidth = lastLabelWidth; } private static void MultiPropertyField(string label, GUIContent[] propertyLabels, params SerializedProperty[] properties) { diff --git a/Editor/GUIUtilities.cs b/Editor/GUIUtilities.cs index 617f4c5..35d18eb 100644 --- a/Editor/GUIUtilities.cs +++ b/Editor/GUIUtilities.cs @@ -27,6 +27,43 @@ public static void DrawConnectedAnchorProperty(SerializedProperty connectedAncho } } + /// + /// An EditorGUI control with a label, a min/max slider and min/max float fields. + /// + /// Returns a bool indicating if the controls' min/max values have changed or not. + internal static bool MinMaxWithFloatFields(string label, ref float minValue, ref float maxValue, float minValueBoundary, float maxValueBoundary, int significantDigits) { + Rect controlRect = EditorGUILayout.GetControlRect(); + + Rect labelRect = new Rect(controlRect); + labelRect.xMax = EditorGUIUtility.labelWidth + 14; + labelRect.yMin -= 1f; + EditorGUI.LabelField(labelRect, label); + + EditorGUI.BeginChangeCheck(); + Rect fillRect = new Rect(controlRect); + fillRect.xMin = EditorGUIUtility.labelWidth; + + Rect leftRect = new Rect(fillRect); + leftRect.xMax = leftRect.xMin + 50f; + minValue = Utilities.FloorToSignificantDigits(Mathf.Clamp(EditorGUI.FloatField(leftRect, minValue), minValueBoundary, maxValueBoundary), significantDigits); + + Rect middleRect = new Rect(fillRect); + middleRect.xMin = leftRect.xMin + 40; + middleRect.xMax = fillRect.xMax - 40f; + middleRect.y -= 2; + EditorGUI.MinMaxSlider(middleRect, ref minValue, ref maxValue, minValueBoundary, maxValueBoundary); + + Rect rightRect = new Rect(fillRect); + rightRect.xMin = rightRect.xMax - 50; + maxValue = Utilities.FloorToSignificantDigits(Mathf.Clamp(EditorGUI.FloatField(rightRect, maxValue), minValueBoundary, maxValueBoundary), significantDigits); + return EditorGUI.EndChangeCheck(); + } + + internal static void MinMaxPropertyFields(string label, SerializedProperty minProperty, SerializedProperty maxProperty) { + Rect controlRect = EditorGUILayout.GetControlRect(); + + } + internal static void ToggleAndFill(Action toggleControl, Action fillControl, bool enableFillControl, bool enableToggle) { Rect controlRect = EditorGUILayout.GetControlRect(); diff --git a/Editor/Utilities.cs b/Editor/Utilities.cs new file mode 100644 index 0000000..fc2fd33 --- /dev/null +++ b/Editor/Utilities.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System; + +namespace JesseStiller.Enjoined { + internal static class Utilities { + internal static float FloorToSignificantDigits(float number, int numberOfDigits) { + if(number == 0f) return 0f; + + float scale = Mathf.Pow(10, Mathf.Floor(Mathf.Log10(Mathf.Abs(number))) + 1f); + return scale * (float)Math.Round(number / scale, numberOfDigits); + } + } +} \ No newline at end of file diff --git a/Editor/Utilities.cs.meta b/Editor/Utilities.cs.meta new file mode 100644 index 0000000..390e37c --- /dev/null +++ b/Editor/Utilities.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 8224309ea304e8444a3e79c7ae061c1c +timeCreated: 1510712183 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: