Skip to content

Instantly share code, notes, and snippets.

@deebrol
Last active November 6, 2024 03:30
Show Gist options
  • Save deebrol/02f61b7611fd4eca923776077b92dfc2 to your computer and use it in GitHub Desktop.
Save deebrol/02f61b7611fd4eca923776077b92dfc2 to your computer and use it in GitHub Desktop.
Property Drawer for Unity used to show or hide the Field depending on certain conditions
// DONT PUT IN EDITOR FOLDER
using System;
using UnityEngine;
/// <summary>
/// Attribute used to show or hide the Field depending on certain conditions
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class ShowWhenAttribute : PropertyAttribute {
public readonly string conditionFieldName;
public readonly object comparationValue;
public readonly object[] comparationValueArray;
/// <summary>
/// Attribute used to show or hide the Field depending on certain conditions
/// </summary>
/// <param name="conditionFieldName">Name of the bool condition Field</param>
public ShowWhenAttribute(string conditionFieldName)
{
this.conditionFieldName = conditionFieldName;
}
/// <summary>
/// Attribute used to show or hide the Field depending on certain conditions
/// </summary>
/// <param name="conditionFieldName">Name of the Field to compare (bool, enum, int or float)</param>
/// <param name="comparationValue">Value to compare</param>
public ShowWhenAttribute(string conditionFieldName, object comparationValue = null)
{
this.conditionFieldName = conditionFieldName;
this.comparationValue = comparationValue;
}
/// <summary>
/// Attribute used to show or hide the Field depending on certain conditions
/// </summary>
/// <param name="conditionFieldName">Name of the Field to compare (bool, enum, int or float)</param>
/// <param name="comparationValueArray">Array of values to compare (only for enums)</param>
public ShowWhenAttribute(string conditionFieldName, object[] comparationValueArray = null)
{
this.conditionFieldName = conditionFieldName;
this.comparationValueArray = comparationValueArray;
}
}
// PUT IN EDITOR FOLDER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(ShowWhenAttribute))]
public class ShowWhenDrawer : PropertyDrawer
{
private bool showField = true;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
ShowWhenAttribute attribute = (ShowWhenAttribute) this.attribute;
SerializedProperty conditionField = property.serializedObject.FindProperty(attribute.conditionFieldName);
// We check that exist a Field with the parameter name
if (conditionField == null)
{
ShowError(position, label, "Error getting the condition Field. Check the name.");
return;
}
switch (conditionField.propertyType)
{
case SerializedPropertyType.Boolean:
try
{
bool comparationValue = attribute.comparationValue == null || (bool)attribute.comparationValue;
showField = conditionField.boolValue == comparationValue;
}
catch
{
ShowError(position, label, "Invalid comparation Value Type");
return;
}
break;
case SerializedPropertyType.Enum:
object paramEnum = attribute.comparationValue;
object[] paramEnumArray = attribute.comparationValueArray;
if ( paramEnum == null && paramEnumArray == null)
{
ShowError(position, label, "The comparation enum value is null");
return;
}
else if (IsEnum(paramEnum))
{
if (!CheckSameEnumType(new[] {paramEnum.GetType()}, property.serializedObject.targetObject.GetType(), conditionField.propertyPath))
{
ShowError(position, label, "Enum Types doesn't match");
return;
}
else
{
string enumValue = Enum.GetValues(paramEnum.GetType()).GetValue(conditionField.enumValueIndex).ToString();
if (paramEnum.ToString() != enumValue)
showField = false;
else
showField = true;
}
}
else if (IsEnum(paramEnumArray))
{
if (!CheckSameEnumType(paramEnumArray.Select(x => x.GetType()), property.serializedObject.targetObject.GetType(), conditionField.propertyPath))
{
ShowError(position, label, "Enum Types doesn't match");
return;
}
else
{
string enumValue = Enum.GetValues(paramEnumArray[0].GetType()).GetValue(conditionField.enumValueIndex).ToString();
if (paramEnumArray.All(x => x.ToString() != enumValue))
showField = false;
else
showField = true;
}
}
else
{
ShowError(position, label, "The comparation enum value is not an enum");
return;
}
break;
case SerializedPropertyType.Integer:
case SerializedPropertyType.Float:
string stringValue;
bool error = false;
float conditionValue = 0;
if (conditionField.propertyType == SerializedPropertyType.Integer)
conditionValue = conditionField.intValue;
else if (conditionField.propertyType == SerializedPropertyType.Float)
conditionValue = conditionField.floatValue;
try
{
stringValue = (string)attribute.comparationValue;
}
catch
{
ShowError(position, label, "Invalid comparation Value Type");
return;
}
if (stringValue.StartsWith("=="))
{
float? value = GetValue(stringValue, "==");
if (value == null)
error = true;
else
showField = conditionValue == value;
}
else if (stringValue.StartsWith("!="))
{
float? value = GetValue(stringValue, "!=");
if (value == null)
error = true;
else
showField = conditionValue != value;
}
else if (stringValue.StartsWith("<="))
{
float? value = GetValue(stringValue, "<=");
if (value == null)
error = true;
else
showField = conditionValue <= value;
}
else if (stringValue.StartsWith(">="))
{
float? value = GetValue(stringValue, ">=");
if (value == null)
error = true;
else
showField = conditionValue >= value;
}
else if (stringValue.StartsWith("<"))
{
float? value = GetValue(stringValue, "<");
if (value == null)
error = true;
else
showField = conditionValue < value;
}
else if (stringValue.StartsWith(">"))
{
float? value = GetValue(stringValue, ">");
if (value == null)
error = true;
else
showField = conditionValue > value;
}
if (error)
{
ShowError(position, label, "Invalid comparation instruction for Int or float value");
return;
}
break;
default:
ShowError(position, label, "This type has not supported.");
return;
}
if (showField)
EditorGUI.PropertyField(position, property, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (showField)
return EditorGUI.GetPropertyHeight(property);
else
return -EditorGUIUtility.standardVerticalSpacing;
}
/// <summary>
/// Return if the object is enum and not null
/// </summary>
private static bool IsEnum(object obj)
{
return obj != null && obj.GetType().IsEnum;
}
/// <summary>
/// Return if all the objects are enums and not null
/// </summary>
private static bool IsEnum(object[] obj)
{
return obj != null && obj.All(o => o.GetType().IsEnum);
}
/// <summary>
/// Check if the field with name "fieldName" has the same class as the "checkTypes" classes through reflection
/// </summary>
private static bool CheckSameEnumType(IEnumerable<Type> checkTypes, Type classType, string fieldName)
{
FieldInfo memberInfo;
string[] fields = fieldName.Split('.');
if (fields.Length > 1)
{
memberInfo = classType.GetField(fields[0]);
for (int i = 1; i < fields.Length; i++)
{
memberInfo = memberInfo.FieldType.GetField(fields[i]);
}
}
else
memberInfo = classType.GetField(fieldName);
if (memberInfo != null)
return checkTypes.All(x => x == memberInfo.FieldType);
return false;
}
private void ShowError(Rect position, GUIContent label, string errorText)
{
EditorGUI.LabelField(position, label, new GUIContent(errorText));
showField = true;
}
/// <summary>
/// Return the float value in the content string removing the remove string
/// </summary>
private static float? GetValue(string content, string remove)
{
string removed = content.Replace(remove, "");
try
{
return float.Parse(removed);
}
catch
{
return null;
}
}
}
using System;
using UnityEngine;
public class ShowWhenExample : MonoBehaviour
{
#region Bool Region
[Header("Check with BOOL")]
public bool show;
[ShowWhen("show")]
public float numberWhenTrue;
[ShowWhen("show", false)]
public Vector3 vector3WhenFalse;
[ShowWhen("show")]
public float[] arrayWhenTrue = {1, 2, 3};
[Serializable]
public class ArrayClass
{
public Color[] colorArray = {Color.red, Color.blue, Color.green};
}
[ShowWhen("show")]
public ArrayClass workaroundForArrayWhenTrue;
[Serializable]
public class CustomClass
{
public float floatValue = 99;
public string stringValue = "string";
}
[ShowWhen("show", true)]
public CustomClass customClass;
[ShowWhen("show", "error")]
public string stringErrorComparationValueType;
#endregion
#region Enum Region
public enum EaseType
{
Linear,
OutQuad,
InOutQuint
}
public enum OtherEnum
{
Enum1
}
[Space(20), Header("Check with ENUM")]
public EaseType easeType;
[ShowWhen("easeType", EaseType.Linear)]
public string stringWhenLinear = "Linear";
[ShowWhen("easeType", new object[]{EaseType.Linear, EaseType.OutQuad})]
public string stringWhenLinearAndOutQuad = "LinearAndOutQuad";
[ShowWhen("easeType", EaseType.InOutQuint)]
public string stringWhenInOutQuint = "InOutQuint";
[ShowWhen("easeType")]
public string stringErrorNeedParam;
[ShowWhen("easeType",5)]
public string stringErrorNotEnum;
public OtherEnum otherEnum;
[ShowWhen("otherEnum", new object[]{OtherEnum.Enum1, EaseType.Linear})]
public string stringErrorWrongEnumType;
#endregion
#region Int Region
[Space(20), Header("Check with INT")]
public int intValue;
[ShowWhen("intValue", ">5")]
public string stringWhenGreaterThan5 = "Greater Than 5";
[ShowWhen("intValue", ">3+5")]
public string stringErrorNotKnownOperation;
#endregion
#region Float Region
[Space(20), Header("Check with FLOAT")]
public float floatValue;
[ShowWhen("floatValue", "!=2")]
public GameObject showWhenOtherThan2;
[ShowWhen("floatValueError", ">5")]
public string stringErrorParameterNotKnown;
[ShowWhen("stringErrorParameterNotKnown", ">+5")]
public string stringErrorTypeNotSupported;
#endregion
}
@RoxDevvv
Copy link

RoxDevvv commented Nov 6, 2024

it would be nice if we can set multiple conditions
[ShowWhen("condition1"),ShowWhen("condition2"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment