Search Unity

PropertyDrawer PopUp Overlap and create attributes on the fly

Discussion in 'Scripting' started by Zeldarck, Mar 14, 2019.

  1. Zeldarck

    Zeldarck

    Joined:
    Feb 8, 2017
    Posts:
    10
    Hi,

    I just begin with property drawer, I learn from that post and documentation
    https://forum.unity.com/threads/custom-property-drawer-height-and-width-solved.469692/

    My goal is to have in my property drawer the choice between multiple class, then be able to set up attributes of this class and have the choice between methods of this class. And finnaly be able to fill parameters of the chosen methods.


    So I face 2 problems, I have my system where I can choose a class, then display attributes of this class. But, the popUp for choose the class overlap all the propertys so I am not able to set them :

    Capture.PNG

    Anywhere I click below "condition command" it will display the popUp (even if I want to edit test for example)


    Is someone have an idea on why that happend? :)


    My second problems is to be able to fill parametters of the methods choose on the fly. Is there a mean with property drawer to create attributes which not exists? It's seem odd and I don't think there is a way, but maybe?

    If not I think I will have to declare attributes corresponding to parametters in my class and displays them depends on the parametters of the methods. But it seem dirty and I would like to avoid that


    Thank you :)

    There is my code :

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Reflection;
    6. using System.Linq;
    7. using System;
    8.  
    9. [CustomPropertyDrawer(typeof(Condition))]
    10. public class ConditionEditor : PropertyDrawer
    11. {
    12.     List<string> m_allConditionCommandTypeStrings;
    13.  
    14.     List<System.Type> m_allConditionCommandType;
    15.  
    16.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    17.     {
    18.         m_allConditionCommandTypeStrings = new List<string>();
    19.         m_allConditionCommandType = typeof(ConditionCommand).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ConditionCommand))).ToList();
    20.  
    21.         foreach (System.Type type in m_allConditionCommandType)
    22.         {
    23.             m_allConditionCommandTypeStrings.Add(type.Name);
    24.         }
    25.  
    26.  
    27.         label = EditorGUI.BeginProperty(position, label, property);
    28.  
    29.  
    30.         int indent = EditorGUI.indentLevel;
    31.         EditorGUI.indentLevel = 0;
    32.  
    33.         Rect classRect = new Rect(position.x, position.y, position.width, position.height);
    34.  
    35. //get class selected
    36.         SerializedProperty Command = property.FindPropertyRelative("m_conditionCommand");
    37.  
    38.         UnityEngine.Object obj = Command.objectReferenceValue;
    39.         ConditionCommand actualVal = (obj) as ConditionCommand;
    40.  
    41.         int currIndex = -1;
    42.         if (actualVal != null)
    43.         {
    44.             for (int j = 0; j < m_allConditionCommandTypeStrings.Count; ++j)
    45.             {
    46.                 if (m_allConditionCommandTypeStrings[j] == actualVal.GetType().Name)
    47.                     currIndex = j;
    48.             }
    49.         }
    50.  
    51.  
    52.  
    53.  
    54.  
    55.         EditorGUI.BeginChangeCheck();
    56.  
    57.  
    58. //popup for chosse class
    59.         int newIndex = EditorGUI.Popup(classRect, Command.displayName, currIndex, m_allConditionCommandTypeStrings.ToArray());
    60.  
    61.         if (EditorGUI.EndChangeCheck())
    62.         {
    63. //update class
    64.             Command.objectReferenceValue = ScriptableObject.CreateInstance(m_allConditionCommandType[newIndex]);
    65.         }
    66.  
    67.         ConditionCommand finalValue = Command.objectReferenceValue as ConditionCommand;
    68.  
    69.         if (finalValue != null)
    70.         {
    71. //display class attributes
    72.             EditorGUI.indentLevel = 1;
    73.  
    74.             SerializedObject childObj = new UnityEditor.SerializedObject(finalValue);
    75.  
    76.             Debug.Log("Child number is " + childObj.GetIterator().displayName);
    77.  
    78.             SerializedProperty ite = childObj.GetIterator();
    79.             float prevHeight = EditorGUI.GetPropertyHeight(Command, label, true);
    80.  
    81.             int i = 1;
    82.             while (ite.NextVisible(true))
    83.             {
    84.                 Debug.Log("Child is " + ite.displayName);
    85.                 Rect newRect = new Rect(position.x, position.y + prevHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUI.GetPropertyHeight(ite, label, true));
    86.                 prevHeight += newRect.height + EditorGUIUtility.standardVerticalSpacing;
    87.                 EditorGUI.PropertyField(newRect, ite);
    88.                 ++i;
    89.             }
    90.  
    91. //If we modify attributes, apply change
    92.             childObj.ApplyModifiedProperties();
    93.  
    94. //useless but I let it here as example on how I will do to get methods
    95.          /*    List<string> methodsNames = new List<string>();
    96.             MethodInfo[] methodInfos = m_allConditionCommandType[0].GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
    97.  
    98.  
    99.               for (int j = 0; j < methodInfos.Length; ++j)
    100.                 {
    101.                     Debug.Log("method" + methodInfos[j].Name);
    102.                     methodsNames.Add(methodInfos[j].Name);
    103.                 }
    104.  
    105.               //  Rect newRecte = new Rect(position.x, position.y + prevHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUI.GetPropertyHeight(Command, label, true));
    106.  
    107.                // prevHeight += newRecte.height + EditorGUIUtility.standardVerticalSpacing;
    108.  
    109.  
    110.                 int pilou = EditorGUI.Popup(newRecte, Command.displayName, currIndex, methodsNames.ToArray());*/
    111.  
    112.         }
    113.  
    114.  
    115.         EditorGUI.indentLevel = indent;
    116.  
    117.         EditorGUI.EndProperty();
    118.  
    119.     }
    120.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    121.     {
    122.  
    123.         SerializedObject childObj = new UnityEditor.SerializedObject(property.FindPropertyRelative("m_conditionCommand").objectReferenceValue as ConditionCommand);
    124.         SerializedProperty ite = childObj.GetIterator();
    125.  
    126.         float totalHeight = EditorGUI.GetPropertyHeight(property, label, true) + EditorGUIUtility.standardVerticalSpacing;
    127.         //totalHeight *= 2;
    128.         while (ite.NextVisible(true))
    129.         {
    130.             totalHeight += EditorGUI.GetPropertyHeight(ite, label, true) + EditorGUIUtility.standardVerticalSpacing;
    131.         }
    132.  
    133.         return totalHeight;
    134.     }
    135.  
    136.  
    137.  
    138.  
    139. }
    140.  



    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Reflection;
    5. using System.Linq;
    6. using System;
    7.  
    8. [Serializable]
    9. public class Condition
    10. {
    11.     [SerializeField]
    12.     ConditionCommand m_conditionCommand;
    13. }
    14.  



    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5.  
    6. [Serializable]
    7. public class ConditionCommand : ScriptableObject
    8. {
    9.  
    10.     [SerializeField]
    11.     string test;
    12. }
    13.  


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ConditionKeyValueCommand : ConditionCommand
    6. {
    7.     public bool test2()
    8.     {
    9.         return true;
    10.     }
    11. }
    12.  
     
  2. Zeldarck

    Zeldarck

    Joined:
    Feb 8, 2017
    Posts:
    10
    For the first problem, I finally found the solution.

    As I overrided GetPropertyHeight, the position input of OnGUI was the total height of my property + the property of the class chose. So when I created my popUp rect :

    Code (CSharp):
    1.         Rect classRect = new Rect(position.x, position.y, position.width, position.height);
    2.  
    I should not use the height of position, but only the usefull one for the popUp:

    Code (CSharp):
    1.         Rect classRect = new Rect(position.x, position.y, position.width, EditorGUI.GetPropertyHeight(Command, label, true));
    2.  
     
  3. Zeldarck

    Zeldarck

    Joined:
    Feb 8, 2017
    Posts:
    10
    I have finish a functionnal version of my system :
    https://github.com/Zeldarck/PapyProject/tree/master/Assets/Scripts/Lib/ConditionSystem

    Condition it's what we add as attributes to create function, ConditionEditor is the code

    I didn't success to create "attributes" on fly to fufill parametters of the method choose. So I must have attributes with the same name of my parametters inside my Commands class.

    Have you an idea to avoid that? I thinked at least about a system which can get all the parametters of my file and write in the file the needed attributes, but no idea on how to modify c# from unity, will be my next search