Search Unity

Inspector - Enum/dropdown box hide/show variables

Discussion in 'Scripting' started by alph, Mar 24, 2011.

  1. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    Is it possible to program which variables should be shown in the inspector according to what is chosen in a dropdown?

    Example:
    Code (csharp):
    1. public enum Types { Type1, Type2 };
    2. public Types type; // This will create the dropdown in the inspector
    3. public int type1Var; // only show if type == Types.Type1
    4. public int type2Var; // only show if type == Types.Type2
    5.  
     
  2. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    You can add the HideInEditor attribute or just declare your variable as private (or protected).

    But you want the visibility conditional, well I can guess, but maybe it works if you use a public interface and for each type create a class based upon this interface, class A would contain type1Var and class B would contain type2Var.

    If the editor GUI is smart enough it should work.
     
  3. Fenrisul

    Fenrisul

    Joined:
    Jan 2, 2010
    Posts:
    618
    Your best bet is to use a CustomEditor for that kind of specific control in my opinion.
     
  4. Mr.Jwolf

    Mr.Jwolf

    Joined:
    Jan 30, 2011
    Posts:
    11
    Heya, I have tried to come up with a solution to your problem. The solution is to create a CustomEditor, but i have tried to make i more generic and easiere to use.
    My solution uses reflection from C#.

    It works by using one line for each field you want to show/hide.

    You use this method:
    Code (csharp):
    1.  
    2. /// <summary>
    3. /// Use this function to set when witch fields should be visible.
    4. /// </summary>
    5. /// <param name='enumFieldName'>
    6. /// The name of the Enum field. (in your case that is "type")
    7. /// </param>
    8. /// <param name='enumValue'>
    9. /// When the Enum value is this in the editor, the field is visible.
    10. /// </param>
    11. /// <param name='fieldName'>
    12. /// The Field name that should only be visible when the chosen enum value is set.
    13. /// </param>
    14. void ShowOnEnum(string enumFieldName,string enumValue,string fieldName)
    15. {...}
    16.  

    In your case it would look like:
    Code (csharp):
    1.  
    2. ShowOnEnum("type","Type1","type1Var"); //type1Var is only visible when type == Type1
    3. ShowOnEnum("type","Type2","type2Var"); //type2Var is only visible when type == Type2
    4.  


    The full C# code.
    You take all the code below an copy/paste it into a C# file.
    What you have to change is the script it is a custom editor for "[CustomEditor( typeof(YOURSCRIPT) )]" and the name of the class "public class YOURSCRIPTEditor : Editor".
    You will need one Custom Editor Class for each Script you want this functionality in.
    REMEMBER: You have to put the CustomEditors (code below) in the "Assets/Editor/" folder.

    Code (csharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Reflection;
    7.  
    8.  
    9. [CustomEditor( typeof(YOURSCRIPT) )]
    10. [CanEditMultipleObjects]
    11. public class YOURSCRIPTEditor : Editor
    12. {
    13.  
    14.     //Add the ShowOnEnum methods in here
    15.     private void SetFieldCondition()
    16.     {  
    17.  
    18.         ShowOnEnum("type","Type1","type1Var"); //type1Var is only visible when type == Type1
    19.         ShowOnEnum("type","Type2","type2Var"); //type2Var is only visible when type == Type2
    20.        
    21.     }
    22.  
    23.     /////////////////////////////////////////////////////////
    24.     /// DO NOT TOUCH THE REST
    25.     /// If you make changes, it is at your own risk.
    26.     /// Made by JWolf 13 / 6 - 2012
    27.     /////////////////////////////////////////////////////////
    28.        
    29.    
    30.     /// <summary>
    31.     /// Use this function to set when witch fields should be visible.
    32.     /// </summary>
    33.     /// <param name='enumFieldName'>
    34.     /// The name of the Enum field. (in your case that is "type")
    35.     /// </param>
    36.     /// <param name='enumValue'>
    37.     /// When the Enum value is this in the editor, the field is visible.
    38.     /// </param>
    39.     /// <param name='fieldName'>
    40.     /// The Field name that should only be visible when the chosen enum value is set.
    41.     /// </param>
    42.     private void ShowOnEnum(string enumFieldName,string enumValue,string fieldName)
    43.     {
    44.         p_FieldCondition newFieldCondition = new p_FieldCondition(){
    45.             p_enumFieldName = enumFieldName,
    46.             p_enumValue = enumValue,
    47.             p_fieldName = fieldName,
    48.             p_isValid = true
    49.            
    50.         };
    51.        
    52.        
    53.         //Valildating the "enumFieldName"
    54.         newFieldCondition.p_errorMsg ="";
    55.         FieldInfo enumField = target.GetType().GetField(newFieldCondition.p_enumFieldName);
    56.         if(enumField==null)
    57.         {
    58.             newFieldCondition.p_isValid = false;
    59.             newFieldCondition.p_errorMsg = "Could not find a enum-field named: '"+enumFieldName+"' in '"+target+"'. Make sure you have spelled the field name for the enum correct in the script '"+this.ToString()+"'";
    60.         }
    61.        
    62.         //Valildating the "enumValue"
    63.         if(newFieldCondition.p_isValid)
    64.         {
    65.            
    66.             var currentEnumValue = enumField.GetValue(target);
    67.             var enumNames =currentEnumValue.GetType().GetFields();
    68.             //var enumNames =currentEnumValue.GetType().GetEnumNames();
    69.             bool found = false;
    70.             foreach(FieldInfo enumName in enumNames)
    71.             {
    72.                 if(enumName.Name == enumValue)
    73.                 {
    74.                     found = true;
    75.                     break;
    76.                 }
    77.             }
    78.            
    79.             if(!found)
    80.             {
    81.                 newFieldCondition.p_isValid = false;
    82.                 newFieldCondition.p_errorMsg = "Could not find the enum value: '"+enumValue+"' in the enum '"+currentEnumValue.GetType().ToString()+"'. Make sure you have spelled the value name correct in the script '"+this.ToString()+"'";
    83.             }
    84.         }
    85.        
    86.         //Valildating the "fieldName"
    87.         if(newFieldCondition.p_isValid)
    88.         {
    89.             FieldInfo fieldWithCondition = target.GetType().GetField(fieldName);
    90.             if(fieldWithCondition == null)
    91.             {
    92.                 newFieldCondition.p_isValid = false;
    93.                 newFieldCondition.p_errorMsg = "Could not find the field: '"+fieldName+"' in '"+target+"'. Make sure you have spelled the field name correct in the script '"+this.ToString()+"'";
    94.             }
    95.         }
    96.        
    97.         if(!newFieldCondition.p_isValid)
    98.         {
    99.             newFieldCondition.p_errorMsg += "\nYour error is within the Custom Editor Script to show/hide fields in the inspector depending on the an Enum."+
    100.                     "\n\n"+this.ToString()+": "+newFieldCondition.ToStringFunction()+"\n";
    101.         }
    102.        
    103.         fieldConditions.Add(newFieldCondition);
    104.     }
    105.    
    106.    
    107.     private List<p_FieldCondition> fieldConditions;
    108.     public void OnEnable ()
    109.     {
    110.         fieldConditions = new List<p_FieldCondition>();
    111.         SetFieldCondition();
    112.     }
    113.    
    114.    
    115.    
    116.     public override void OnInspectorGUI ()
    117.     {
    118.    
    119.         // Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
    120.         serializedObject.Update ();
    121.        
    122.        
    123.         var obj = serializedObject.GetIterator ();
    124.        
    125.  
    126.         if (obj.NextVisible (true)) {
    127.    
    128.             // Loops through all visiuble fields
    129.             do {
    130.                 bool shouldBeVisible = true;
    131.                 // Tests if the field is a field that should be hidden/shown due to the enum value
    132.                 foreach(var fieldCondition in fieldConditions)
    133.                 {
    134.                     //If the fieldcondition isn't valid, display an error msg.
    135.                     if(! fieldCondition.p_isValid)
    136.                     {
    137.                         Debug.LogError(fieldCondition.p_errorMsg);
    138.                     }
    139.                     else if(fieldCondition.p_fieldName == obj.name)
    140.                     {
    141.                         FieldInfo enumField = target.GetType().GetField(fieldCondition.p_enumFieldName);
    142.                         var currentEnumValue = enumField.GetValue(target);
    143.                         //If the enum value isn't equal to the wanted value the field will be set not to show
    144.                         if(currentEnumValue.ToString() != fieldCondition.p_enumValue)
    145.                         {
    146.                             shouldBeVisible = false;
    147.                             break;
    148.                         }                      
    149.                     }
    150.                 }
    151.                
    152.                 if(shouldBeVisible)
    153.                     EditorGUILayout.PropertyField (obj, true);
    154.                
    155.                
    156.             } while(obj.NextVisible (false));
    157.         }
    158.  
    159.    
    160.         // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
    161.         serializedObject.ApplyModifiedProperties ();
    162.        
    163.     }
    164.    
    165.    
    166.    
    167.     private class p_FieldCondition
    168.     {
    169.         public string p_enumFieldName{get;set;}
    170.         public string p_enumValue{get;set;}
    171.         public string p_fieldName{get;set;}
    172.         public bool p_isValid{get;set;}
    173.         public string p_errorMsg{get;set;}
    174.        
    175.         public string ToStringFunction()
    176.         {
    177.             return "'"+p_enumFieldName+"', '"+p_enumValue+"', '"+p_fieldName+"'.";
    178.         }
    179.     }
    180. }
    181.  
    182.  
    You don't tell it that "type" is a enum of type "Types", this is one of the powers of reflection.

    Hope it helps.

    PS: I know this thread is old(dead?), but I had the same problem a few times and always ended up looking at this thread. I hope it may help others.
     
    Last edited: Jun 13, 2012
  5. shortlin

    shortlin

    Joined:
    Oct 30, 2014
    Posts:
    22
    Sorry to take the old thread up.
    It's very helpfull to me to use Mr.Jwolf's methods
    but I have a question.when I want to claim the inspector values to my class.
    I want to package the the values.
    How it work?

    I try to claim

    showOnEnum("myclass.type","Type1","myclass.type1Var");

    It's error
     
    Last edited: Dec 19, 2014
  6. tekodragoon

    tekodragoon

    Joined:
    Sep 21, 2016
    Posts:
    1
    Excellent work. Still useful. A great thanks
     
  7. Kevin__h

    Kevin__h

    Joined:
    Nov 16, 2015
    Posts:
    38
    Unfortunately it doesn't work for me for some reason, it's not giving any errors yet it's not showing my variable fields :'(

    EDIT: Apparently it does work, you just can't show the same field for 2 different enum types.
     
  8. Kennai

    Kennai

    Joined:
    Nov 1, 2018
    Posts:
    27
    replace code

    Code (CSharp):
    1. //If the enum value isn't equal to the wanted value the field will be set not to show
    2. if (currentEnumValue.ToString() != fieldCondition.p_enumValue)
    3. {
    4.   shouldBeVisible = false;
    5.   break;
    6. }
    with

    Code (CSharp):
    1. //If the enum value isn't equal to the wanted value the field will be set not to show
    2. if (currentEnumValue.ToString() != fieldCondition.p_enumValue)
    3.   shouldBeVisible = false;
    4. else
    5. {
    6.   shouldBeVisible = true;
    7.   break;
    8. }
     
    mrwhip likes this.
  9. Adamund

    Adamund

    Joined:
    Jul 12, 2013
    Posts:
    4
    Thank you very much. This was very useful for me to understand a bit more how editor scripts work.
    Any reason why it is named specifically for Enumerators and not any generic field? Would I have to create my own ShowOnBool(string boolFieldName,string boolValue,string boolName) if I wanted to test a bool?

    Thanks,
     
  10. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Yup.

    I've got a similar thing on GitHub, you can look at it and check if it's useful for you. It's got support for enums, bools, and checking if assigned objects are null/not null.
     
    sonerpayne, Donken, shortlin and 3 others like this.
  11. Adamund

    Adamund

    Joined:
    Jul 12, 2013
    Posts:
    4
    Thank you, Baste. I will definitely check that out.
     
    Saydus likes this.
  12. Foulcloud

    Foulcloud

    Joined:
    Mar 23, 2014
    Posts:
    19
    Baste, thanks for this. Everything works great except if my field to hide is a class that inherits from Monobehaviour. Errors produced - Null reference at HideIfAttributeDrawer.cs:76. Any suggestions? I don't need this to use inheritance or see anything inside the class.
     
    Last edited: Oct 28, 2020
    RiyadhRiseUp likes this.
  13. rimkchouic

    rimkchouic

    Joined:
    Jun 26, 2020
    Posts:
    6
    Great tool @Baste, thanks. :)
     
  14. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    Please don't pointlessly necro a thread, it's against the Unity Community Code of Conduct. You can just as easily press the Like button on their post instead of Replying.
     
    adikecapan likes this.
  15. adikecapan

    adikecapan

    Joined:
    Jun 21, 2019
    Posts:
    7

    Amazing, i hope there is another one that can support with non-Monobehaviour, in my case, it is for variable class script