Search Unity

Using PropertyDrawers and Enums to switch between extended classes

Discussion in 'Scripting' started by Lachee1, Apr 16, 2014.

  1. Lachee1

    Lachee1

    Joined:
    Aug 21, 2012
    Posts:
    16
    Hello Unity Community,

    I have been working/playing around with unitys PropertyDrawers, trying to make a script to allow me to more easily make my GUI's by using a set of extended classes base of one class called UIElement.

    What I wish to accomplish with this script is to be able to have a array (with buttons to move elements up and down [which will be covered by a editor script] ) with these elements in them and a enum pop above each one to change their type (eg: from button to a label, which will update the variables shown)

    So far it is going well, I have made a UIElement property that is displaying okay (ish) and the enum i am using to switch types is appearing and switchable, however I cannot seem to make it determine the extended version of UIElement i wish to use.

    I realize I might not be able to use this method, and thats okay, I will just stick it one class and a Object array to store variables, but any help / ideas would be awesome.

    Here is some code, to clear it up a bit:

    UIElement Class and extending classes
    Code (csharp):
    1.  
    2. public enum UIType { button = 0, label = 1};
    3.  
    4. [Serializable]
    5. public class UIElement {
    6.     public UIType elementType;
    7.  
    8.     public string name;
    9.  
    10.     public virtual void OnGUI () {}
    11.     public virtual UIType getUIType() { return UIType.label; }
    12. }
    13.  
    14. public class UIButton : UIElement {
    15.     public new UIType elementType = UIType.button;
    16.  
    17.     public Texture2D image;
    18.     public override void OnGUI () {
    19.        
    20.     }
    21.    
    22.     public static void OnInspector(Rect position,  SerializedProperty property) {
    23.         //EditorGUI.PropertyField(position, property.FindPropertyRelative("image"));
    24.         EditorGUI.PropertyField(position, property.FindPropertyRelative("name"));
    25.     }
    26.  
    27.     public static int InspectorLines() {
    28.         return 1;
    29.     }
    30. }
    31.  
    32. public class UILabel : UIElement {
    33.     public new UIType elementType = UIType.label;
    34.  
    35.     public string text;
    36.     public override void OnGUI () {
    37.  
    38.     }
    39.  
    40.     public static void OnInspector(Rect position,  SerializedProperty property) {      
    41.         //EditorGUI.PropertyField(position, property.FindPropertyRelative("text"));
    42.         EditorGUI.PropertyField(position, property.FindPropertyRelative("name"));
    43.     }
    44.  
    45.     public static int InspectorLines() {
    46.         return 1;
    47.     }
    48.  
    49.  

    PropertyDrawer Class:
    Code (csharp):
    1.  
    2.  
    3. [CustomPropertyDrawer(typeof(UIElement))]
    4. public class UIElementDrawer : PropertyDrawer {
    5.     UIType lastType;
    6.     public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
    7.         //Debug.Log(property.FindPropertyRelative("uiType").intValue);
    8.  
    9.         label = EditorGUI.BeginProperty(position, label, property);
    10.        
    11.         position.height = 16;
    12.  
    13.         SerializedProperty elementType = property.FindPropertyRelative("elementType");
    14.         lastType = (UIType) EditorGUI.EnumPopup(position,label,(UIType) elementType.intValue);
    15.         elementType.intValue = (int) lastType;
    16.  
    17.         position.y += 18;
    18.  
    19.         EditorGUI.PropertyField(position, property.FindPropertyRelative("name"));
    20.        
    21.         position.y += 18;
    22.  
    23.         //This works, however I cannot seem to assign it as a specific UIElemen
    24.         switch(lastType) {
    25.         default :
    26.             UIButton.OnInspector(position,property); break;
    27.  
    28.         case UIType.button :
    29.             UIButton.OnInspector(position,property); break;
    30.  
    31.         case UIType.label :
    32.             UILabel.OnInspector(position,property); break;
    33.  
    34.         }
    35.    
    36.         EditorGUI.EndProperty();
    37.     }
    38.  
    39.     public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
    40.         float height = 18F*2F;
    41.  
    42.         switch(lastType) {
    43.         default :
    44.             height += 18F * UIButton.InspectorLines(); break;
    45.            
    46.         case UIType.button :
    47.             height += 18F * UIButton.InspectorLines(); break;
    48.            
    49.         case UIType.label :
    50.             height += 18F * UILabel.InspectorLines(); break;
    51.            
    52.         }
    53.  
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    I think you're lacking a kind of wrapper that would hold your UIElement... Maybe I'm wrong, but I would go;

    Code (csharp):
    1.  
    2. public class UIContainer
    3. {
    4.      public UIType type;
    5.      // When type change, do "element = new UIButton()"...
    6.      public UIElement element;
    7. }
    8.  
     
  3. Lachee1

    Lachee1

    Joined:
    Aug 21, 2012
    Posts:
    16
    That is a good idea, however I don't know how (or even possible) to change the UIElement field using PropertyDrawers as they only return SerializedProperty on FindRelativeProperty.
     
  4. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You could also not use PropertyDrawers.... My experience is extremely limited with them, sorry.
     
  5. Lachee1

    Lachee1

    Joined:
    Aug 21, 2012
    Posts:
    16
    you're right. Any ideas of how the editor code would go as it says in the docs it is not recommended to use 'target' when using OnInspectorGUI(), which is the only way I could think of doing it :|