PropertyDrawer gives strange results about the position and width of rect.

I cannot understand why this PropertyDrawer gives strange results about the position and width of rect.

[CustomPropertyDrawer(typeof(MinMaxSliderAttribute))]
    public class MinMaxSliderPropertyDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            MinMaxSliderAttribute minMaxSliderAttribute = (MinMaxSliderAttribute)attribute;

            if (property.propertyType == SerializedPropertyType.Vector2)
            {
                // Draw the label
                Rect controlRect = EditorGUI.PrefixLabel(position, label);
                float sliderPadding = 5f;
                float floatFieldWidth = EditorGUIUtility.fieldWidth;
                float sliderWidth = controlRect.width - 2f * (floatFieldWidth + sliderPadding);

                Rect minFloatFieldRect = new Rect(
                    controlRect.x,
                    controlRect.y,
                    floatFieldWidth,
                    controlRect.height);

                Rect sliderRect = new Rect(
                    controlRect.x + floatFieldWidth + sliderPadding,
                    controlRect.y,
                    sliderWidth,
                    controlRect.height);

                Rect maxFloatFieldRect = new Rect(
                    controlRect.x + floatFieldWidth + sliderWidth + 2f * sliderPadding,
                    controlRect.y,
                    floatFieldWidth,
                    controlRect.height);

                // Draw the slider
                EditorGUI.BeginChangeCheck();

                Vector2 sliderValue = property.vector2Value;

                EditorGUI.MinMaxSlider(sliderRect, ref sliderValue.x, ref sliderValue.y, minMaxSliderAttribute.MinValue, minMaxSliderAttribute.MaxValue);

                sliderValue.x = EditorGUI.FloatField(minFloatFieldRect, sliderValue.x);
                sliderValue.x = Mathf.Clamp(sliderValue.x, minMaxSliderAttribute.MinValue, Mathf.Min(minMaxSliderAttribute.MaxValue, sliderValue.y));

                sliderValue.y = EditorGUI.FloatField(maxFloatFieldRect, sliderValue.y);
                sliderValue.y = Mathf.Clamp(sliderValue.y, Mathf.Max(minMaxSliderAttribute.MinValue, sliderValue.x), minMaxSliderAttribute.MaxValue);

                if (EditorGUI.EndChangeCheck())
                {
                    property.vector2Value = sliderValue;
                }
            }
            else
            {
                base.OnGUI(position, property, label);
            }
        }
    }

133443-v1.png

And after I add an offset range of 30f. Everything looks good.

   [CustomPropertyDrawer(typeof(MinMaxSliderAttribute))]
    public class MinMaxSliderPropertyDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            MinMaxSliderAttribute minMaxSliderAttribute = (MinMaxSliderAttribute)attribute;

            if (property.propertyType == SerializedPropertyType.Vector2)
            {
                // Draw the label
                Rect controlRect = EditorGUI.PrefixLabel(position, label);
                controlRect.x -= 30f;
                float sliderPadding = 5f;
                float floatFieldWidth = EditorGUIUtility.fieldWidth + 30f;
                float sliderWidth = controlRect.width - 2f * (floatFieldWidth + sliderPadding) + 90f;

                Rect minFloatFieldRect = new Rect(
                    controlRect.x,
                    controlRect.y,
                    floatFieldWidth,
                    controlRect.height);

                Rect sliderRect = new Rect(
                    controlRect.x + floatFieldWidth + sliderPadding - 30f,
                    controlRect.y,
                    sliderWidth,
                    controlRect.height);

                Rect maxFloatFieldRect = new Rect(
                    controlRect.x + floatFieldWidth + sliderWidth + 2f * sliderPadding - 60f,
                    controlRect.y,
                    floatFieldWidth,
                    controlRect.height);

                // Draw the slider
                EditorGUI.BeginChangeCheck();

                Vector2 sliderValue = property.vector2Value;

                EditorGUI.MinMaxSlider(sliderRect, ref sliderValue.x, ref sliderValue.y, minMaxSliderAttribute.MinValue, minMaxSliderAttribute.MaxValue);

            sliderValue.x = EditorGUI.FloatField(minFloatFieldRect, sliderValue.x);
            sliderValue.x = Mathf.Clamp(sliderValue.x, minMaxSliderAttribute.MinValue, Mathf.Min(minMaxSliderAttribute.MaxValue, sliderValue.y));

            sliderValue.y = EditorGUI.FloatField(maxFloatFieldRect, sliderValue.y);
            sliderValue.y = Mathf.Clamp(sliderValue.y, Mathf.Max(minMaxSliderAttribute.MinValue, sliderValue.x), minMaxSliderAttribute.MaxValue);

            if (EditorGUI.EndChangeCheck())
            {
                property.vector2Value = sliderValue;
            }
        }
        else
        {
            base.OnGUI(position, property, label);
        }
    }
}

133442-v2.png

Can you tell me where I was wrong?

I guess this is related to the indent of the nested elements. For example the PrefixLabel method will add EditorGUI.indent to the x position. However the returned rect will always start at the same position.

Note that EditorGUI.indent is just a property which returns EditorGUI.indentLevel * 15f. The indentLevel is increased by the any code that displays nested elements. Most controls will use the indent level as well. The FloatField for example uses this internally:

return EditorGUI.DoFloatField(EditorGUI.s_RecycledEditor, EditorGUI.IndentedRect(position), new Rect(0f, 0f, 0f, 0f), controlID, value, EditorGUI.kFloatFieldFormatString, style, false);

Note that the IndentedRect method just does add the indent value to the x value and subract it from the width:

public static Rect IndentedRect(Rect source)
{
	float indent = EditorGUI.indent;
	return new Rect(source.x + indent, source.y, source.width - indent, source.height);
}

The FloatField that takes also a label does the splitting beforehand and calls the internal “DoFloatField” without the indent but with the calculated content rect.

The only proper way I know to “remove” any indent is to save the old indentLevel value in a local variable, set the indentLevel to 0, draw your content and restore the indentLevel to the old value.