using UnityEngine;
namespace jeanf.validationTools
{
#if UNITY_EDITOR
using jeanf.propertyDrawer;
using UnityEditor;
///
/// Draws a [Validation("...")] field. When the field is unset (null object
/// reference or empty string) and currently required (RequiredIf gate) it turns
/// ORANGE — translucent wash + tinted label + help box with the attribute's
/// message — so the culprit field is obvious at a glance. When set, it draws
/// like a normal field.
/// Cooperates with [DrawIf] on the same field: whichever of the two drawers Unity
/// picks, ConditionalField applies both attributes (hide / grey per DrawIf, orange
/// per Validation). Gate the requirement with RequiredIf on the same condition so
/// the scanner does not flag a field the inspector hides.
///
[CustomPropertyDrawer(typeof(ValidationAttribute))]
public class ValidationDrawer : PropertyDrawer
{
private const float Spacing = 4f;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
=> ConditionalField.GetHeight(property, label, fieldInfo, null, attribute as ValidationAttribute);
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
=> ConditionalField.Draw(position, property, label, fieldInfo, null, attribute as ValidationAttribute);
/// Height of the field, plus the warning block while it needs attention.
internal static float GetHeight(SerializedProperty property, GUIContent label, ValidationAttribute attribute)
{
var propertyHeight = EditorGUI.GetPropertyHeight(property, label, true);
if (!NeedsAttention(property, attribute)) return propertyHeight;
return propertyHeight + HelpBoxHeight() + Spacing * 2f;
}
/// The orange treatment (or a plain field when nothing is wrong).
internal static void Draw(Rect position, SerializedProperty property, GUIContent label, ValidationAttribute attribute)
{
if (!NeedsAttention(property, attribute))
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
// Orange wash behind the whole block: this field needs attention.
EditorGUI.DrawRect(position, ValidationUi.OrangeWash);
var message = attribute?.Text;
if (string.IsNullOrEmpty(message)) message = $"'{property.displayName}' is not assigned.";
var helpRect = new Rect(position.x, position.y + Spacing, position.width, HelpBoxHeight());
EditorGUI.HelpBox(helpRect, message, MessageType.Warning);
var fieldRect = new Rect(position.x, helpRect.yMax + Spacing, position.width,
EditorGUI.GetPropertyHeight(property, label, true));
var previousColor = GUI.backgroundColor;
GUI.backgroundColor = ValidationUi.Orange;
EditorGUI.PropertyField(fieldRect, property, new GUIContent(label.text, label.image, message), true);
GUI.backgroundColor = previousColor;
}
private static float HelpBoxHeight() => EditorGUIUtility.singleLineHeight * 2f;
/// Unset AND currently required (RequiredIf gate, evaluated on the component).
private static bool NeedsAttention(SerializedProperty property, ValidationAttribute attribute)
{
if (!IsUnset(property)) return false;
return ValidationScanner.IsRequired(property.serializedObject.targetObject, attribute);
}
internal static bool IsUnset(SerializedProperty property)
{
switch (property.propertyType)
{
case SerializedPropertyType.ObjectReference: return property.objectReferenceValue == null;
case SerializedPropertyType.String: return string.IsNullOrEmpty(property.stringValue);
default: return false;
}
}
}
#endif
}