Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Draw the entire Component reference in Inspector

Discussion in 'Scripting' started by Threeyes, Jun 7, 2018.

  1. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    71
    Can we directly draw the reference of a Component so that we don't have to jump between multi objects? Just like we can just 'Ctrl+Click' the Texture in Material and a temp Preview Window will pop up:
    20180607114919.png


    Here's the outcome I want to achieve, if we want to check the reference of "DoTweenAnimation", just 'Ctrl+Click' the field and a new Inspector Window will showup:
    Component Reference.png


    2018-6-14:
    After checking the Unity C# Source Code, I find that 'Texture click to show preview' is achieve throuth the follow scripts:
    UnityCsReference\Editor\Mono\GUI\ObjectField.cs (Draw the tiny texture)
    Editor\Mono\GUI\PopupWindowWithoutFocus.cs (Draw the popup window)


    2018-6-19:
    Thanks to @Baste , I finally make a Windows that is acceptable, It can basiclly preview every component.

    The next step is to finding a way that we don't have to specify [Attribute] for every property, So I am looking for a way to check the Event state, whenever a mouse is clicking a Editor property field, the Popup Windows will showup.Thanks guys!
     
    Last edited: Jun 19, 2018
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,021
    What do you mean by "reference to the component"? Do you want to draw the component's source code? Or it's inspector?
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,130
    I believe they want to draw the inspector for the referenced component.

    In which case, technically, yes you can. You'd have to write a custom editor/propertydrawer for it, but it's doable.

    Personally I'd do it as a PropertyDrawer for a PropertyAttribute. You'd draw the ObjectField first, and then create a SerializedObject from the referenced object, and then draw the editor for that.

    Here's a very VERY basic example (the drawing of the other inspector could use some glamming up, especially if you want to allow the referenced components custom inspector to work):

    The PropertyAttribute:
    Code (csharp):
    1.  
    2. public class ComponentRefInspectorAttribute : PropertyAttribute
    3. {
    4.  
    5. }
    6.  
    The PropertyDrawer:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections.Generic;
    5.  
    6. [CustomPropertyDrawer(typeof(ComponentRefInspectorAttribute))]
    7. public class ComponentRefInspectorPropertyDrawer : PropertyDrawer
    8. {
    9.  
    10.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    11.     {
    12.         float h = EditorGUIUtility.singleLineHeight;
    13.  
    14.         if(property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue != null)
    15.         {
    16.             h += EditorGUIUtility.singleLineHeight;
    17.             var so = new SerializedObject(property.objectReferenceValue);
    18.             var iterator = so.GetIterator();
    19.             for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false)
    20.             {
    21.                 h += EditorGUI.GetPropertyHeight(iterator, true);
    22.             }
    23.         }
    24.         return h;
    25.     }
    26.  
    27.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    28.     {
    29.         if(property.propertyType != SerializedPropertyType.ObjectReference)
    30.         {
    31.             EditorGUI.LabelField(position, "Mismatched PropertyDrawer.");
    32.             return;
    33.         }
    34.  
    35.         var obj = property.objectReferenceValue;
    36.         var objRect = GetRect(ref position, EditorGUIUtility.singleLineHeight);
    37.         EditorGUI.ObjectField(objRect, property, label);
    38.  
    39.         if(obj != null)
    40.         {
    41.             var headerRect = GetRect(ref position, EditorGUIUtility.singleLineHeight);
    42.             EditorGUI.LabelField(headerRect, "Component Ref");
    43.  
    44.             var so = new SerializedObject(property.objectReferenceValue);
    45.             var iterator = so.GetIterator();
    46.             for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false)
    47.             {
    48.                 float h = EditorGUI.GetPropertyHeight(iterator, true);
    49.                 Rect r = GetRect(ref position, h);
    50.                 EditorGUI.PropertyField(r, iterator);
    51.             }
    52.         }
    53.     }
    54.  
    55.     private static Rect GetRect(ref Rect position, float height)
    56.     {
    57.         var result = new Rect(position.xMin, position.yMin, position.width, height);
    58.         position = new Rect(position.xMin, position.yMin + height, position.width, Mathf.Max(0f, position.height - height));
    59.         return result;
    60.     }
    61.  
    62. }
    63.  
    Visual:
    ComponetRefDrawer.png

    Like I said though, it doesn't play well with components that have custom inspectors (like Transform, or any that you've custom written). It also could do with some other visuals to make it stand out that you're editing a referenced object and not the self (like put a box around it).

    I just slapped this script together in like 45 seconds as a proof of concept.

    Build from there.
     
    Threeyes likes this.
  4. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    71
    I want to draw it on a new popup window, and it will be great if we don't have to write editor code for each Component:confused:

    PS: I update a new Photo on the First post that show's the idea.
     
    Last edited: Jun 10, 2018
  5. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    71
    Thank's! I know this kind of method, but like you said, it require a lot of coding. So I wonder, could we just "Cut" a part of Inspector, or just popup a temp Inspector, that may become more easier.

    PS: I update a new Photo on the First post that show's the idea.
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,021
    So the window is easy. You create an Editor for the target object with Editor.CreateEditor, pass it to a new EditorWindow, and have that window draw the editor.

    The complex part is having it open when you ctrl+click it. Adding a little button next to the property through a property drawer is easier.
     
    Threeyes likes this.
  7. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    71
    Thanks! I will try that and share the code later:)
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,021
    No need, I made it. It was an interesting thing for a Sunday morning. Give me ten minutes and I'll pop it on Github.

    EDIT: unless you want to make it yourself. I'll pop it up on Github anyways, might be interesting for someone else.

    EDIT2: Linky
     
    Last edited: Jun 10, 2018
  9. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    71
    :eek:Oh… snap! A billion thanks coz the Editor Scripting is killing me! I am pretty sure it will be a wonderful feature!


    PS:After a little test, I find that very convenient! But not sure if there is the problem of my Unity Version(mine is Unity2018.1.1f1), it seems that once you click and open the 'PopupEditor Window' then click another property, the window won't refresh.

    Also, a little suggestion:
    • If the Window is flowing, then once the mouse click empty space, it will vanish.
    • If the Window is docking, then it will stay still.
     
    Last edited: Jun 10, 2018