Saturday, 29 March 2014

Unity Inspector Tool Tips and more

When I started working with Unity 3D I looked up adding tool tips to properties in the inspector.  All the results of the searches came with a lot of code and no downloadable simple examples.

I did not spend much time on the subject because I was looking for a quick answer.  I was also probably using the wrong search criterion.



Further along I had a more important requirement that I thought was worth coding because it would save me making mistakes when setting up scenes.  As a consequence, I have leaned enough, very quickly, to create a simple but effective tool tip option for the properties, visible in the inspector.



I don't know if it is because I am using the latest version 4.3 of Unity but my solution does not need much code.  Many of the samples I looked at had huge switch or if statement blocks to allow for different property types.  I was able to use a built in method that replicated the default behaviour and allowed me to add the tool tip.




public class ToolTip : PropertyAttribute
{
    public string TipText = "";

    /// Display text when the mouse is over the label.
    public ToolTip(string message)
    {
 TipText = message;
    }
}





using UnityEditor;
using UnityEngine;
using System;

/// Display a tool tip when the mouse is over the label.
[CustomPropertyDrawer(typeof(ToolTip))]
public class ToolTipDrawer : PropertyDrawer
{
    private ToolTip source { get { return ((ToolTip)attribute); } }

 /// The height returned here must be appropriate for the property
 /// being dawn.
 public override float GetPropertyHeight (SerializedProperty property,
                                          GUIContent label) 
 {
  return GetOriginalHeight (property, label);
 }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
  // Must reset the tip otherwise all labels get the same tooltip displayed!
  string previousTip = label.tooltip;
  if (!string.IsNullOrEmpty (source.TipText))
  {
   label.tooltip = source.TipText;
  }

  // Display the default fields for this property
  EditorGUI.PropertyField (position, property, label, true);

  // Must reset the tip otherwise all labels get the same tooltip displayed!
  label.tooltip = previousTip;
 }

 /// Returns the height of the default control.
 /// 
 /// This can be reused by other property drawers.
 public static float GetOriginalHeight (SerializedProperty prop,
                                        GUIContent label) 
 {
  const float spacing = 3f;
  
  float baseSize = EditorStyles.label.lineHeight;
  
  // Most types only use one line so they work with the base but a few are 
  // multiline and need more work.
  float extraLines = 0f;
  if (prop.propertyType == SerializedPropertyType.Bounds)
  {
   extraLines = EditorStyles.label.lineHeight * 2.2f;
   baseSize = baseSize + extraLines + spacing;
  }
  else if (prop.propertyType == SerializedPropertyType.Rect)
  {
   extraLines = EditorStyles.label.lineHeight * 1f;
   baseSize = baseSize + extraLines + spacing;
  }
  
  return baseSize + spacing;
 }
}



That's it, not much code.

If you don't want to copy and paste, I've included the tool tip code and the code for other property attributes in to a GitHub project called Unity3D Utility Kit.

Download the Utility Kit from:
https://github.com/ThatJCB/Unity3DUtilityKit

The kit includes a test scene to show the usage of the attributes and to prove that they work.

At the moment the property attributes included are:
- A box to display a helpful message, which was my first idea before I got tool tips working.



- The tool tip which displays when the mouse hovers over the label.
- A Regular Expression mask for fields, created by  , many thanks.
- An integer slider that also works with float values to keep whole numbers.
- A divider with an optional heading.
- Scene selection list so you can only enter a scene name that has been included in the build list.
There's some work in progress in there as well and I'll probably add more to the list over time.



That last item, for scene selection, was the reason I started looking at the Property Attributes and Drawers in the first place.

I hope the examples will be useful to others.

2 comments:

Russell said...

If you have custom classes that need to be expanded in the inspector (which will affect the required height), you can also handle SerializedPropertyType.Generic in the function GetOriginalHeight. Something like the following works on very simple classes, assuming a default spacing for children:

else if (prop.propertyType == SerializedPropertyType.Generic)
{
if (prop.isExpanded)
{
extraLines = EditorStyles.label.lineHeight * prop.CountInProperty();
baseSize = baseSize + extraLines + spacing;
}
}

If you want something more robust to handle complex classes with per member spacing, just check the type of each sub-property and adjust the extra lines accordingly. Thanks for uploading the code, I found it helpful.

John C Brown said...

Thank you, I'll try that out.