OdinAttributeDrawer<TAttribute>

Base class for attribute drawers. Use this class to create your own custom attribute drawers that will work for all types. Alternatively you can derive from OdinAttributeDrawer<TAttribute, TValue> if you want to only support specific types.

Remember to provide your custom drawer with an OdinDrawerAttributein order for it to be located by the DrawerLocator.

Odin supports the use of GUILayout and takes care of undo for you. It also takes care of multi-selection in many simple cases. Checkout the manual for more information on handling multi-selection.

Also note that Odin does not require that your custom attribute inherits from Unity's PropertyAttribute.

namespace Sirenix.OdinInspector.Editor
{
public abstract class OdinAttributeDrawer<TAttribute> : OdinDrawer
where TAttribute : Attribute
}

Requirements

Namespace: Sirenix.OdinInspector.Editor
Assembly: Sirenix.OdinInspector
Version: 1.0.6.1

See Also

Static Fields

Return Type Definition Description
bool AllowsMultipleAttributes Tells whether or not multiple attributes are allowed.

Properties

Return Type Definition Description
GUICallType GUICallType Drawing properties using GUICallType.GUILayout and overriding DrawPropertyLayout is the default behavior. But you can also draw the property the "good" old Unity way, by overriding and implementing GetRectHeight and DrawPropertyRect. Just make sure to override GUICallType as well and return GUICallType.Rect

Methods

Return Type Definition Description
void DrawPropertyImplementation(InspectorProperty, GUIContent)

Draws the actual property.

This method is called by base.DrawProperty(...) and calls either DrawPropertyLayout or DrawPropertyRect and GetRectHeight depending on the GUICallType.

void DrawPropertyLayout(InspectorProperty, TAttribute, GUIContent) Draws the property with GUILayout support. This method is called by DrawPropertyImplementation if the GUICallType is set to GUILayout, which is the default.
void DrawPropertyRect(Rect, InspectorProperty, TAttribute, GUIContent) Draws the property in the Rect provided. This method does not support the GUILayout, and is only called by DrawPropertyImplementation if GUICallType is set to Rect which is not the default. If the GUICallType is set to Rect, both GetRectHeight and DrawPropertyRect needs to be implemented. If GUICallType is set to GUILayout, implementing DrawPropertyLayout will suffice.
float GetRectHeight(InspectorProperty, TAttribute, GUIContent) Return the GUI height of the property. This method is called by DrawPropertyImplementation if the GUICallType is set to Rect, which is not the default. If the GUICallType is set to Rect, both GetRectHeight and DrawPropertyRect needs to be implemented. If the GUICallType is set to GUILayout, implementing DrawPropertyLayout will suffice.

Example

Example using the OdinAttributeDrawer<TAttribute, TValue>.

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class CustomRangeAttribute : System.Attribute
{
    public float Min;
    public float Max;

    public CustomRangeAttribute(float min, float max)
    {
        this.Min = min;
        this.Max = max;
    }
}

// Remember to wrap your custom attribute drawer within a #if UNITY_EDITOR condition, or locate the file inside an Editor folder.
[OdinDrawer]
public sealed class CustomRangeAttributeDrawer : OdinAttributeDrawer<CustomRangeAttribute, float>
{
    protected override void DrawPropertyLayout(IPropertyValueEntry<float> entry, CustomRangeAttribute attribute, GUIContent label)
    {
        entry.SmartValue = EditorGUILayout.Slider(label, entry.SmartValue, attribute.Min, attribute.Max);
    }
}

// Usage:
public class MyComponent : MonoBehaviour
{
    [CustomRangeAttribute(0, 1)]
    public float MyFloat;
}

Example

Example using the OdinAttributeDrawer<TAttribute>.

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class GUITintColorAttribute : System.Attribute
{
    public Color Color;

    public GUITintColorAttribute(float r, float g, float b, float a = 1)
    {
        this.Color = new Color(r, g, b, a);
    }
}

// Remember to wrap your custom attribute drawer within a #if UNITY_EDITOR condition, or locate the file inside an Editor folder.
[OdinDrawer]
public sealed class GUITintColorAttributeDrawer : OdinAttributeDrawer<GUITintColorAttribute>
{
    protected override void DrawPropertyLayout(InspectorProperty property, GUITintColorAttribute attribute, GUIContent label)
    {
       Color prevColor = GUI.color;
       GUI.color *= attribute.Color;
       this.CallNextDrawer(property, label);
       GUI.color = prevColor;
    }
}

// Usage:
public class MyComponent : MonoBehaviour
{
    [GUITintColor(0, 1, 0)]
    public float MyFloat;
}

Example

Odin uses multiple drawers to draw any given property, and the order in which these drawers are called are defined using the DrawerPriorityAttribute. Your custom drawer injects itself into this chain of drawers based on its DrawerPriorityAttribute. If no DrawerPriorityAttribute is defined, a priority is generated automatically based on the type of the drawer. Each drawer can ether choose to draw the property or not, or pass on the responsibility to the next drawer by calling CallNextDrawer(), as the GUITintColor attribute does in the example above.

This means that there is no guarantee that your drawer will be called, sins other drawers could have a higher priority than yours and choose not to call CallNextDrawer().

To avoid this, you can tell Odin, that your drawer is a PrependDecorator or an AppendDecorator drawer (see !:OdinDrawerBehaviour) as shown in the example shows below. Prepend and append decorators are always drawn and are also ordered by the !:OdinDrawerBehaviour.

Note that Odin's DrawerLocator have full support for generic class constraints, and if that is not enough, you can also add additional type constraints by overriding CanDrawTypeFilter

Also note that all custom property drawers needs to handle cases where the label provided by the DrawPropertyLayout is null, otherwise exceptions will be thrown when in cases where the label is hidden. For instance when [HideLabel] is used, or the property is drawn within a list where labels are also not shown.

// [OdinDrawer(OdinDrawerBehaviour.DrawProperty)] // default
// [OdinDrawer(OdinDrawerBehaviour.AppendDecorator)]
[OdinDrawer(OdinDrawerBehaviour.PrependDecorator)]
[DrawerPriority(DrawerPriorityLevel.AttributePriority)]
public sealed class MyCustomAttributeDrawer<T> : OdinAttributeDrawer<MyCustomAttribute, T> where T : class
{
    public override bool CanDrawTypeFilter(Type type)
    {
        return type != typeof(string);
    }

    protected override void DrawPropertyLayout(IPropertyValueEntry<T> entry, MyCustomAttribute attribute, GUIContent label)
    {
        // Draw property here.
    }
}