Last active
November 6, 2024 03:30
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
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
I don't like to upload add-ons to the project that contain more than I need.
I have odin, but I prefer to use scripts that do only one task. hiding in the inspector is one of the important and necessary things, sometimes it is more convenient than using SerialzeReference