Retain Tooltip Attribute within a Custom Attribute?

I made a simple little custom attribute that I use to place short fields or checkboxes in the same line in the editor window.
It’s an easy way to quickly save space without having to write a full blown custom editor.

But… it doesn’t retain the Tooltip.

Is there an easy way to do this?

Here is usage and code:

[Split1(true, 50)]
[Tooltip("Yadda yadda yadda.")]
public bool alpha;
[Split2(true, 50, 18f)]
[Tooltip("Yadda yadda yadda.")]
public bool beta;
using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomPropertyDrawer (typeof (Split1Attribute))]
public class Split1Drawer : PropertyDrawer {

    public override void OnGUI ( Rect position, SerializedProperty property, GUIContent label ) {
        Split1Attribute Attribute = (Split1Attribute)attribute;
        float percent = Attribute.splitPercent * .01f;

        float padding = 5f; // space on either side of split line
        float split = ( position.width * percent ) - padding;
        float length = (Attribute.showLabel == true) ? split * .5f : split;
        float height = GetPropertyHeight( property, GUIContent.none );

        Rect labelRect = new Rect ( position.x,                         position.y,         length,            height );
        Rect valueRect = new Rect ( position.x + split - length,         position.y,         length,            height );

        if ( Attribute.showLabel == true ) {
            EditorGUI.LabelField( labelRect, label.text, EditorStyles.label );
        }
        EditorGUI.PropertyField( valueRect, property, GUIContent.none );
    }
}



[CustomPropertyDrawer (typeof (Split2Attribute))]
public class Split2Drawer : PropertyDrawer {

    public override float GetPropertyHeight ( SerializedProperty property, GUIContent label ) {
        return -2f; // remove vertical padding and don't create a new line
    }

    public override void OnGUI ( Rect position, SerializedProperty property, GUIContent label ) {
        Split2Attribute Attribute = (Split2Attribute)attribute;
        float percent = Attribute.splitPercent * .01f;

        float padding = 5f; // space on either side of split line
        float split = ( position.width * percent ) - padding;
        float invertSplit = ( position.width * (1f - percent) ) - padding;
        float invertLength = (Attribute.showLabel == true) ? invertSplit * .5f : invertSplit;
        float start = position.x + split + ( padding * 2f );

        Rect labelRect = new Rect ( start,                                     position.y - Attribute.height,         invertLength,            Attribute.height-2f );
        Rect valueRect = new Rect ( start + invertSplit - invertLength,     position.y - Attribute.height,         invertLength,            Attribute.height-2f );

        if ( Attribute.showLabel == true ) {
            EditorGUI.LabelField( labelRect, label.text, EditorStyles.label );
        }
        EditorGUI.PropertyField( valueRect, property, GUIContent.none );
    }
}

(As a side note: For the Split2 attribute, I’d love to automatically get the line height of the previous field, but I didn’t see any way to do it. So right now, it’s simply manually passed as an argument.)

1 Like

Ok, I ended up making what amounts to an overload on the PropertyAttribute scripts to allow for the optional inclusion of a string for tooltips. Seems to work, but I feel like there is a more “proper” way to do this.

1 Like

To restore the original tooltip to the label, on your PropertyDrawer OnGUI method, add these lines:

var tooltipAttribute = fieldInfo.GetAttribute<TooltipAttribute>();
label.tooltip = tooltipAttribute != null ? tooltipAttribute.tooltip : "";

Found the right answer here.

Looks like the original issues is simply marked as “won fix”, without any detail.

The source of the confusion is that Unity applies the tooltip to the label in EditorGUI.BeginProperty. So all you have to do is:

label = EditorGUI.BeginProperty(position, label, property);

2 Likes

I stumbled across this issue with the new PropertyScope, so I would like to add how to do the same thing with the new API:

[CustomPropertyDrawer(typeof(MyClassType))]
public class MyPropertyDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        using (var propertyScope = new EditorGUI.PropertyScope(position, label, property))
        {
            // Assign the GUIContent from the PropertyScope back to the label. This includes the tooltip.
            label = propertyScope.content;

            // Drawing code here...
            EditorGUI.PropertyField(position, property, label);
        }
    }
}

I’ve got an updated solution for Unity 2018.2, where the api has apparently changed a bit.

string tooltip;
var attributes = fieldInfo.GetCustomAttributes(typeof(TooltipAttribute), true);
if (attributes != null && attributes.Length > 0) {
    tooltip = ((TooltipAttribute)attributes[0]).tooltip;
} else {
    tooltip = null;
}
label.tooltip = tooltip;
1 Like

The API didn’t change, @Novack is using an extension method.

Heya @z3nth10n , no I was not using an extension method :slight_smile:
Indeed seems like GetAttribute() is not available anymore, I had to adjust my code in a similar way.

Oh, ok, I didn’t know… I created an extension method to do this:

        /// <summary>
        /// Gets the attributes from fields inside of class from Type selected.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static T[] GetAttributesFromFieldsIn<T>(this Type type)
            where T : class
        {
            return type.GetFields().Select(f => f.GetCustomAttributes(typeof(T), true)).Select(o => o.Select(t => t as T)).SelectMany(t => t).ToArray();
        }

Example of use:

TooltipAttribute[] tooltips = null;

if (tooltips == null)
                tooltips = typeof(ClassThatContainsTooltips).GetAttributesFromFieldsIn<TooltipAttribute>();
1 Like