Search Unity

Get Attribute Drawer

Discussion in 'Immediate Mode GUI (IMGUI)' started by BinaryCats, Apr 6, 2016.

  1. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    Hi,

    Im working with this thread:
    http://forum.unity3d.com/threads/streamlined-data-entry.395719/

    Is it possible to get a drawer of an attribute, and invoke the ongui function of that attribute for the property?

    I can get the attribute by doing
    Code (csharp):
    1.  
    2.   foreach(object atr in fieldInfo.GetCustomAttributes(false))
    3.   {
    4. ...
    5. }
    6. //Call last atr draw function
    7.  
    Thanks
     
  2. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    Well it really depends on the context you are in.

    Where are you calling this function from?

    In general, to use the OnGUI of a property drawer, you'll need the serialized property.
    So calling it directly is not something you need. All you really need is to get the serialized property, and then you can just call EditorGUI.PropertyField() which will draw the property based on its drawer
     
  3. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    I am already inside a property drawer ongui. Only one property drawer will get called. I can see the attributes on the property being drawn, but I want to call the drawer for said properties.

    I have an attribute which controls how a member is drawn. Say it makes the background blue. If i wanted to have two attributes on the member, sat blue and range, one will be ignored.
    One solution is that I could look at the attributes and see if one is range, if it is draw as a slider. The other is to make a BluERange attribute. However it would be nice if there was a universal way of doing that. I.e. Calling the other attributes ongui
     
  4. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    So if I'm understanding you properly, you want an OnGUI to respect 2 drawer attributes on the same property? you can't do that (AFAIK). I got around a similar issue by having multiple constructors on my attribute, and just setting some parameters, and using a single drawer that checks all the options and draws what i need out of it.
     
  5. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    That's correct. Im not surprised if you can't. It's just a pain in the ass if you have say 20 different formatting attributes.

    How does the tooltip work? Is that a decorator?
     
  6. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    It's processed internally. If you open the assemblies in ILSpy, you'll notice that there is a tooltip attribute in UnityEngine, but no TooltipDrawer in UnityEditor.
     
  7. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    It might just be handled in the Base class property drawer. As all drawers inherit from it, it would work for all
     
  8. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    Nope it doesn't (I looked). I'm guessing (don't really have time to check right now) that if anything, it is the GUIContent that takes care of that, as it is where the tooltip is stored
     
  9. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    Necroing this thread with an answer. this is pretty useful
    Code (csharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Linq;
    5.  
    6. public abstract class MultiPropertyAttribute : PropertyAttribute
    7. {
    8.     public abstract void OnGUI(Rect position, SerializedProperty property, GUIContent label);
    9. }
    10. public class ColorAttribute : MultiPropertyAttribute
    11. {
    12.     Color Color;
    13.     public ColorAttribute(float R, float G, float B)
    14.     {
    15.         Color = new Color(R, G, B);
    16.     }
    17.     // Draw the property inside the given rect
    18.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    19.     {
    20.         GUI.color = Color;
    21.     }
    22. }
    23. public class NewRangeAttribute : MultiPropertyAttribute
    24. {
    25.     float min;
    26.     float max;
    27.     public NewRangeAttribute(float min, float max)
    28.     {
    29.         this.min = min;
    30.         this.max = max;
    31.     }
    32.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    33.     {
    34.         if (property.propertyType == SerializedPropertyType.Float)
    35.             EditorGUI.Slider(position, property, min, max, label);
    36.         else
    37.             EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
    38.     }
    39. }
    40. [CustomPropertyDrawer(typeof(MultiPropertyAttribute))]
    41. [CustomPropertyDrawer(typeof(NewRangeAttribute))]
    42. public class : MultiPropertyDrawer : PropertyDrawer
    43. {
    44.     // Draw the property inside the given rect
    45.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    46.     {
    47.         NewRangeAttribute range = attribute as NewRangeAttribute;
    48.         // First get the attribute since it contains the range for the slider
    49.         var sorted = fieldInfo.GetCustomAttributes(false).OrderBy(s => ((PropertyAttribute)s).order).ToArray();
    50.         foreach (object atr in sorted)
    51.         {
    52.             if (atr as MultiPropertyAttribute != null)
    53.             {
    54.                 ((MultiPropertyAttribute)atr).OnGUI(position, property, label);
    55.             }
    56.         }
    57.     }
    58. }
    59.  
    useage:
    Code (csharp):
    1.  
    2.     [NewRange(0, 5.0f)]
    3.     public float a = 0.1f;
    4.     [Color(1, 0, 0, order = 0)]
    5.     [NewRange(0, 2.0f,order = 1)]
    6.     public float b = 0.1f;
    7.  


    With this method, rather than creating a new propery drawer for your attribute, you add the attribute to the attribute
    `[CustomPropertyDrawer(typeof(YourNewAttribute))]` to the MultiPropertyDrawer class. Instead you're attribute will need to inherit from MultiPropertyAttribute, and you will need to implement a OnGUI INSIDE THE ATTRIBUTE, not the drawer. you might want to add new methods to the base class that should be implemented.

    order is used to decide what order to draw the attributes in.
     
    FM-Productions and randomdragon like this.