2
\$\begingroup\$

How can I make one condition visible in the inspector window if another is true and hidden if false? For example, if isLightON = true then isLightBright should be visible else if isLightON = false then isLightBright should be hidden. I know this is suppose to be done using editor coding but not sure exactly how it is to be done.

\$\endgroup\$
  • \$\begingroup\$ After a 10 seconds Google search: link1, link2, link3, link4 (should I continue?) \$\endgroup\$ – Hellium Apr 4 '18 at 14:52
  • \$\begingroup\$ @Hellium no, but maybe try not to be a jerk. Posting the links is fine, but treating new members poorly is just very, very poor form. \$\endgroup\$ – 3Dave Apr 4 '18 at 22:59
4
\$\begingroup\$

The links Hellium shared seem to all go about this by defining a custom editor to draw the whole inspector view for the object. This certainly works, but it can get a bit laborious for more complicated components. If you want to use these hidden attributes on a bunch of different types, then you end up re-writing and maintaining a lot of boilerplate.

I wanted to find something I could just slap on when I wanted something hidden. Something like...

public bool isLightOn = false;

[ConditionalProperty("isLightOn")]
public float brightness;

The idea is we'll pass to ConditionalPropertyAttribute the name of the bool that should control this property's visibility, then use that to decide whether to draw the control. (If you wanted to get really fancy, we could extend this to support expressions, like "myIntValue > 5" or "valueA != valueB")

Here I've defined a custom property attribute to mark the sometimes-drawn fields and store the criteria we'll use to decide whether to draw them:

public class ConditionalPropertyAttribute : PropertyAttribute {

    public string condition;

    public ConditionalPropertyAttribute(string condition) {
        this.condition = condition;
    }
}

And then, in an Editor\ folder, created a custom property drawer to control how fields with this attribute are dawn (or not):

using UnityEditor;

[CustomPropertyDrawer(typeof(ConditionalPropertyAttribute))]
public class ConditionalPropertyDrawer : PropertyDrawer {

    // Determine whether this field should be visible.
    // (We could probably do some caching here...)
    bool ShouldShow(SerializedProperty property) {
        var conditionAttribute = (ConditionalPropertyAttribute)attribute;
        string conditionPath = conditionAttribute.condition;

        // If this property is defined inside a nested type 
        // (like a struct inside a MonoBehaviour), look for
        // our condition field inside the same nested instance.
        string thisPropertyPath = property.propertyPath;
        int last = thisPropertyPath.LastIndexOf('.');
        if (last > 0) {            
            string containerPath = thisPropertyPath.Substring(0, last + 1);
            conditionPath = containerPath + conditionPath;
        }

        // Get the SerializedProperty representing the field that is our criterion.
        var conditionProperty = property.serializedObject.FindProperty(conditionPath);

        // For now, we'll only support bool criteria, and default to visible if there's a problem.
        if (conditionProperty == null || conditionProperty.type != "bool")
            return true;

        // Use the condition property's boolean value to drive visibility.
        return conditionProperty.boolValue;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        if(ShouldShow(property))
            EditorGUI.PropertyField(position, property, label, true);
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
        if (ShouldShow(property)) {            
            // Provision the normal vertical spacing for this control.
            return EditorGUI.GetPropertyHeight(property, label, true);
        } else {
            // Collapse the unseen derived property.
            return -EditorGUIUtility.standardVerticalSpacing;            
        }
    }
}

What I like about this approach is I only need to write the above attribute & drawer once, and they work for any number of hidden fields in any number of types, and the fields I'm hiding can be of any type the Inspector knows how to draw, including elements of arrays. So the maintenance for adding/changing scripts is much lower than writing custom editors for every type that wants to hide some things.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.