using System; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace VLB { [Serializable] public struct MinMaxRangeFloat : IEquatable { public float minValue { get { return m_MinValue; } } public float maxValue { get { return m_MaxValue; } } public float randomValue { get { return UnityEngine.Random.Range(minValue, maxValue); } } public Vector2 asVector2 { get { return new Vector2(minValue, maxValue); } } public float GetLerpedValue(float lerp01) { return Mathf.Lerp(minValue, maxValue, lerp01); } public MinMaxRangeFloat(float min, float max) { m_MinValue = min; m_MaxValue = max; Debug.Assert(min <= max); } public override bool Equals(object obj) => obj is MinMaxRangeFloat other && this.Equals(other); public bool Equals(MinMaxRangeFloat other) => (m_MinValue == other.m_MinValue) && (m_MaxValue == other.m_MaxValue); public override int GetHashCode() => (m_MinValue, m_MaxValue).GetHashCode(); public static bool operator ==(MinMaxRangeFloat lhs, MinMaxRangeFloat rhs) => lhs.Equals(rhs); public static bool operator !=(MinMaxRangeFloat lhs, MinMaxRangeFloat rhs) => !(lhs == rhs); [SerializeField] float m_MinValue; [SerializeField] float m_MaxValue; } public class MinMaxRangeAttribute : System.Attribute { public float minValue { get; private set; } public float maxValue { get; private set; } public MinMaxRangeAttribute(float min, float max) { minValue = min; maxValue = max; Debug.Assert(min <= max); } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(MinMaxRangeFloat), true)] public class MinMaxRangeFloatPropertyDrawer : PropertyDrawer { static float RoundFloat(float f) { return (float)Math.Round(f * 100f) / 100f; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { label = EditorGUI.BeginProperty(position, label, property); { position = EditorGUI.PrefixLabel(position, label); var propMin = property.FindPropertyRelative("m_MinValue"); Debug.AssertFormat(propMin != null, "Failed to find property 'MinMaxRangeFloat.m_MinValue'"); var propMax = property.FindPropertyRelative("m_MaxValue"); Debug.AssertFormat(propMax != null, "Failed to find property 'MinMaxRangeFloat.m_MaxValue'"); float valueMin = RoundFloat(propMin.floatValue); float valueMax = RoundFloat(propMax.floatValue); float rangeMin = 0.0f, rangeMax = 1.0f; var ranges = (MinMaxRangeAttribute[])fieldInfo.GetCustomAttributes(typeof(MinMaxRangeAttribute), true); if (ranges.Length > 0) { rangeMin = ranges[0].minValue; rangeMax = ranges[0].maxValue; } const float kBoundsFieldWidth = 40.0f; const float kWidthOffset = 5.0f; EditorGUI.showMixedValue = propMin.hasMultipleDifferentValues || propMax.hasMultipleDifferentValues; { EditorGUI.BeginChangeCheck(); { var rectMinValue = new Rect(position); rectMinValue.width = kBoundsFieldWidth; valueMin = EditorGUI.FloatField(rectMinValue, valueMin); position.xMin += kBoundsFieldWidth + kWidthOffset; var reactMaxValue = new Rect(position); reactMaxValue.xMin = reactMaxValue.xMax - kBoundsFieldWidth; valueMax = EditorGUI.FloatField(reactMaxValue, valueMax); position.xMax -= kBoundsFieldWidth + kWidthOffset; EditorGUI.MinMaxSlider(position, ref valueMin, ref valueMax, rangeMin, rangeMax); } if (EditorGUI.EndChangeCheck()) { propMin.floatValue = valueMin; propMax.floatValue = valueMax; } } EditorGUI.showMixedValue = false; } EditorGUI.EndProperty(); } } #endif }