Search Unity

Tooltip for Classes

Discussion in 'Editor & General Support' started by MichaelKaimanaTaylor, Jul 10, 2019.

  1. MichaelKaimanaTaylor

    MichaelKaimanaTaylor

    Joined:
    Feb 26, 2019
    Posts:
    17
    Hello everyone,

    I'm currently working a couple of projects with many scripts. I was wondering if there was a way to make a tooltip (commonly used for variables) work for the entire class/script where I can see the tool tip from the editor?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. //CLASS TOOLTIP HERE
    6. public class TestScript : MonoBehaviour {
    7.  
    8.     [Tooltip("Used for Testing Tooltips")]
    9.     public float testFloat;
    10. }
    11.  
    Sincerely, Michael Taylor
     
  2. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    483
    No, the Unity Tooltip attribute is only valid for fields. It is possible to define your own attribute type which also works on class types, but it requires extra code and has some manual quirks about it. Here is a barebones example of how this could work:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEditor;
    5. using UnityEngine;
    6.  
    7. [ClassTooltip("This is my class description.")]
    8. public class MyTestScript : MonoBehaviour
    9. {
    10.  
    11. }
    12.  
    13. [AttributeUsage(AttributeTargets.Class)]
    14. public class ClassTooltip : PropertyAttribute
    15. {
    16.     public readonly string description;
    17.  
    18.     public ClassTooltip(string description)
    19.     {
    20.         this.description = description;
    21.     }
    22. }
    23.  
    24. [CustomEditor(typeof(MyTestScript), editorForChildClasses: true)]
    25. public class MyTooltipDrawer : Editor
    26. {
    27.     string tooltip;
    28.  
    29.     private void OnEnable()
    30.     {
    31.         var attributes = target.GetType().GetCustomAttributes(inherit: false);
    32.         foreach(var attr in attributes)
    33.         {
    34.             if(attr is ClassTooltip tooltip)
    35.             {
    36.                 this.tooltip = tooltip.description;
    37.             }
    38.         }
    39.     }
    40.     public override void OnInspectorGUI()
    41.     {
    42.         EditorGUILayout.LabelField(tooltip);
    43.         base.OnInspectorGUI();
    44.     }
    45. }
    46.  
    ClassTooltip.PNG

    You see, the issue is, that you probably want the tooltips to work for any MonoBehaviour type, but you need to draw the tooltip text in a custom editor. This means you either need to repeat the drawing code in every custom editor, or use an editor base class or even try to define a base editor for MonoBehaviour and derive all other custom editor from that one. It should work, but there will be a few edge cases here and there, I assume.
     
    MichaelKaimanaTaylor likes this.
  3. MichaelKaimanaTaylor

    MichaelKaimanaTaylor

    Joined:
    Feb 26, 2019
    Posts:
    17
    I see. I think I can work with this and find a way to make it more convenient. Thank you Xarbrough!
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,121
    I'd argue that if you're going to have to make a custom inspector anyways, you could just do:

    Code (csharp):
    1. [CustomEditor(typeof(MyTestScript))]
    2. public class MyTooltipDrawer : Editor
    3. {
    4.     public override void OnInspectorGUI()
    5.     {
    6.         EditorGUILayout.LabelField("your tooltip goes here");
    7.         base.OnInspectorGUI();
    8.     }
    9. }
     
  5. MichaelKaimanaTaylor

    MichaelKaimanaTaylor

    Joined:
    Feb 26, 2019
    Posts:
    17
    Forgive me if this's a stupid question. Is there a way to have universal class for the typeof so to speak? I have a lot of scripts in my project handling little bits. Hoping to find a way to not have to make custom editor class for each and every script I have in my project. Or am I misunderstanding the code?
     
  6. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    483
    You can create a custom editor for the most basic type of your scripts, e.g. MonoBehaviour. Here is some more code which demonstrates how this system could be used to make ClassTooltip work similar to regular Unity Tooltip attributes. But, as I said, it still requires special care in some case.

    upload_2019-7-11_16-7-16.png

    There are two MonoBehaviour components. ComponentA is simply a MonoBehaviour with nothing in it but the ClassTooltip attribute:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [ClassTooltip("This is the description of ComponentA. It doesn't do anything.")]
    4. public class ComponentA : MonoBehaviour
    5. {
    6.  
    7. }
    ComponentB is a MonoBehaviour which also has a custom editor (custom inspector), which needs to derive from a special custom base editor class to keep the ClassTooltip working:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. [ClassTooltip("This is the description of ComponentB. It does absolutely nothing, but it has a custom editor.")]
    5. public class ComponentB : MonoBehaviour
    6. {
    7.  
    8. }
    9.  
    10. [CustomEditor(typeof(ComponentB))]
    11. public class ComponentBEditor : MonoBehaviourBaseEditor
    12. {
    13.     public override void OnInspectorGUI()
    14.     {
    15.         base.OnInspectorGUI();
    16.         EditorGUILayout.HelpBox("This is my additional helpbox representing some custom inspector code.", MessageType.Info);
    17.     }
    18. }
    And then we have our MonoBehaviourBaseEditor class which draws a custom property drawer for all MonoBehaviour types in the project that do not have a custom editor automatically. If a MonoBehaviour does have a custom editor, this editor needs to derive from our editor base class for the tooltip to work.

    Code (CSharp):
    1. using System;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. [CustomEditor(typeof(MonoBehaviour), editorForChildClasses: true)]
    6. public class MonoBehaviourBaseEditor : Editor
    7. {
    8.     private string tooltipText;
    9.  
    10.     private void OnEnable()
    11.     {
    12.         var attributes = target.GetType().GetCustomAttributes(inherit: false);
    13.         foreach (var attr in attributes)
    14.         {
    15.             if (attr is ClassTooltip tooltip)
    16.             {
    17.                 this.tooltipText = tooltip.description;
    18.                 break;
    19.             }
    20.         }
    21.     }
    22.  
    23.     public override void OnInspectorGUI()
    24.     {
    25.         EditorGUILayout.LabelField(this.tooltipText);
    26.         base.OnInspectorGUI();
    27.     }
    28. }
    29.  
    30. [AttributeUsage(AttributeTargets.Class)]
    31. public class ClassTooltip : PropertyAttribute
    32. {
    33.     public readonly string description;
    34.  
    35.     public ClassTooltip(string description)
    36.     {
    37.         this.description = description;
    38.     }
    39. }
    It does work quite good, if you are okay with all custom inspectors deriving from this base class. We can also optimize the reflection for getting the class attribute description text and improve the drawing for the tooltip GUI.

    However, all in all, similar to what Baste is saying, I wouldn't actually recommend this for use in development. A tooltip text is only helpful the first time you need to learn something or to remind you about how something works. This is better placed on documentation pages, I think, because it only clutters up the view 90% of development time. Also, it's a pretty strong decision to enforce this common base class for all MonoBehaviour editors. And then you will always have cases where somebody forgets to derive from it and has to figure out why the tooltip is not working and all kinds of tiny issues.