Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by thricedotted · Aug 11, 2018 at 07:50 PM · editorinspectoreditor-scriptingeditorwindow

Creating an Inspector view that only changes on scene hierarchy selection or asset selection

I have a project architecture that relies ScriptableObject assets that are attached to GameObjects in the scene. Working with this architecture involves making changes to both scene objects and the assets that are attached to them.

What I would like to do is have two Inspector windows -- one which only displays objects that I have selected in the scene hierarchy, and another which only displays objects I have selected from my project assets.

Some workarounds I have seen include using two vanilla Inspector panes and locking one of them -- this is workable and what I'm currently doing, but extremely inconvenient. I've also seen inline ScriptableObject drawers, but since the SOs I am using correspond to things like shared variables, I would like to keep them separated in their own Inspector window to maintain the distinction between data set on a scene object versus data stored in a SO asset.

Does anybody have any insight into how one would go about creating an Inspector window that only shows scene or asset objects? Or does such a tool exist already? (I've looked at the Unity reference code, but an 1800+ line class is... a bit much for my brain to parse through right now.)

Thanks in advance for any help!

![alt text]Two inspectors -- top for scene objects, bottom for assets[1]

[1]: /storage/temp/122528-twoinspectors.png

twoinspectors.png (48.5 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by stektpotet · Aug 16, 2018 at 11:32 PM

It can be done...

However it's not the easiest thing to make:


All things in unity that derive from the type Object has the capability to be viewed in an Editor/Inspector . This is shown in the script reference documentation for the `Editor`-class (Specifically the CreateEditor()-function)


Using this to our advantage we can, by obtaining the selected objects in both the project view, scene view and hierarchy view, create an editor for the selected Object!


perfect! - right?


Well... turns out it's not that easy...

The first problem is that the Editor object itself merely acts as an interface to drawing the UI that's done by the inspector. so we'll need to manually make the different calls to the elements of the UI we want drawn.

Secondly, there's the bigger problem of GameObjects and how their inspectors work - You see as a gameobject contains a set of all the different components attached, the InspectorWindow needs to iterate over all the components in order to create a full representation of the gameobject in the inspector. Unity does this by using an Editor-object for each of the components attached to the gameobject and sequentially calling the editor-objects' OnInspectorGUI()-methods.


Approach:

  1. We need to create an EditorWindow that listens to selection changes in order to notify that we want to edit something selected if the selected item is a gameobject in the scene or an asset in the project
    • This can be achieved using the Selection.selectionChanged-callback and use Selection.GetFiltered(...) - to filter the selection for only assets/gameobjects

  2. We need to use the selected item (preferrably items[plural]) to create editor objects that hold the UI
    • Provided we get the notification from the callback, that something in our selection is changed, we can update a field containing the Editor-object we're using to interface the UI for said object. we basically say something along the lines of targetEditor = Editor.CreateEditor(filteredObjects) (notice: plural filteredObjects - we can make an editor that targets multiple objects at the same time)

  3. We need to make UI calls through the editor Object in a sensible order to get results that look like the inspector.
    • this might be considered a bit tricky depending on how much like the normal inspector you want your inspector to look. Specifically the preview-part of an inspector is more difficult to achieve here, as we need to manage the resizing of it manually


I got started doing some of it, there's still a few kinks in it here and there (specifically: I've disallowed usage of the FilteredInpector for multi-GameObject editing because it's a tough job to validate that selected gameobjects have all the same components and then make an editor for the components combined)

Anyways, here it is:

 using UnityEditor;
 using UnityEngine;
 using System.Linq;

 class FilteredInspector : EditorWindow
 {

     [System.Flags]
     enum Filter
     {
         GameObjects = 0,
         Assets = 1
     }

     Filter selectionFilter = Filter.Assets;
     Vector2 scrollPosition;
     Editor targetEditor;
     Editor[] componentEditors;
     //EDITOR STUFF
     float previewHeight = 100;
     Texture2D[] icons = new Texture2D[2];
     bool[] foldouts;

     [MenuItem("Window/Filtered Inspector")]
     public static void OpenWindow()
     {
         var window = CreateInstance<FilteredInspector>(); //Allows multiple instances
         window.titleContent = new GUIContent("Filtered Inspector", EditorGUIUtility.FindTexture("d_UnityEditor.InspectorWindow"));
         window.icons[0] = EditorGUIUtility.FindTexture("SceneAsset Icon");
         window.icons[1] = EditorGUIUtility.FindTexture("Folder Icon");
         window.minSize = new Vector2(250, 250);
         window.Show();
         window.OnSelectionChange();
     }

     private void OnEnable()
     {
         Selection.selectionChanged += OnSelectionChange;
     }
     private void OnDisable()
     {
         Selection.selectionChanged -= OnSelectionChange;
     }

     private void OnSelectionChange()
     {

         Object[] objects;
         if (selectionFilter == Filter.GameObjects)
         {
             objects = Selection.GetFiltered(typeof(GameObject), SelectionMode.ExcludePrefab | SelectionMode.OnlyUserModifiable | SelectionMode.Editable);
             if (objects.Length > 0)
             {
                 if (objects.Length > 1) { Debug.LogWarning("Multi Object selection only supported for Assets, not scene objects"); return; }

                 var components = ((GameObject)objects[0]).GetComponents<Component>().Where(c => c != null && (c.hideFlags & HideFlags.HideInInspector) != HideFlags.HideInInspector).ToArray(); //get all components that are not hidden
                 componentEditors = new Editor[components.Length];
                 foldouts = new bool[components.Length];
                 for (int i = 0; i < components.Length; i++)
                 {
                     componentEditors[i] = Editor.CreateEditor(components[i]);
                     foldouts[i] = true;
                 }

             }
         }
         else
         {
             objects = Selection.GetFiltered(typeof(Object), SelectionMode.Assets);
         }
         if (objects.Length > 0)
             targetEditor = Editor.CreateEditor(objects);
         Repaint();
     }

     private void OnGUI()
     {
         GUILayout.BeginHorizontal();
         GUILayout.FlexibleSpace();
         GUILayout.Label("Inspector Mode", "HeaderLabel");
         int newFilterMode = GUILayout.Toolbar((int)selectionFilter, icons, "Command");
         if (selectionFilter != (Filter)newFilterMode)
         {
             selectionFilter = (Filter)newFilterMode;
             OnSelectionChange();
         }
         GUILayout.FlexibleSpace();
         GUILayout.EndHorizontal();
         if (targetEditor != null)
         {
             scrollPosition = GUILayout.BeginScrollView(scrollPosition);
             targetEditor.DrawHeader();
             EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
             targetEditor.OnInspectorGUI();
             if (targetEditor.target is GameObject)
             {
                 EditorGUIUtility.hierarchyMode = true;
                 for (int i = 0; i < componentEditors.Length; i++)
                 {
                     if (i != 0)
                     {
                         EditorGUIUtility.labelWidth = 120;
                         EditorGUI.indentLevel = 1;
                     }
                     else { EditorGUIUtility.labelWidth = 50; }
                     Editor e = componentEditors[i];

                     Rect foldoutRect =EditorGUILayout.GetControlRect(GUILayout.Height(20));
                     //Rect foldoutRect = GUILayoutUtility.GetLastRect();
                     foldoutRect.x -= 14;
                     foldoutRect.width += 18;
                     GUI.Box(foldoutRect, GUIContent.none, "IN Title");

                     foldoutRect.y += 2;
                     foldoutRect.height -= 2;

                     System.Reflection.PropertyInfo enableProperty = e.target.GetType().GetProperty("enabled"); //hack to obtain whether or not the component can be disabled

                     if (enableProperty != null)
                     {
                         foldoutRect.x += 20;
                         foldoutRect.width -= 20;
                         float width = foldoutRect.width;
                         foldoutRect.width = 16;
                         enableProperty.SetValue(e.target, GUI.Toggle(foldoutRect, ((bool)enableProperty.GetValue(e.target, null)), GUIContent.none, "IN Toggle"), null);
                         foldoutRect.x -= 20;
                         foldoutRect.width = width;
                     }
                     foldoutRect.x += 2;
                     foldouts[i] = GUI.Toggle(foldoutRect, foldouts[i], GUIContent.none, "IN Foldout");
                     foldoutRect.x += 18;
                     foldoutRect.width -= 20;
                     if (enableProperty != null)
                     {
                         foldoutRect.x += 20;
                         foldoutRect.width -= 20;
                     }

                     GUI.Label(foldoutRect, new GUIContent(ObjectNames.NicifyVariableName(e.target.GetType().Name), AssetPreview.GetMiniTypeThumbnail(e.target.GetType())), "IN TitleText");

                     if (foldouts[i])
                     {
                         e.OnInspectorGUI();
                     }
                 }
                 EditorGUI.indentLevel = 0;

                 EditorGUIUtility.hierarchyMode = false;
             }
             EditorGUILayout.EndVertical();
             if (targetEditor.HasPreviewGUI()) //This part need some work in order to work like the real inspector. Currently there's it's not resizable
             {
                 GUILayout.FlexibleSpace();
                 GUILayout.BeginHorizontal(EditorStyles.toolbar);
                 GUILayout.Label(targetEditor.GetPreviewTitle(), "WindowBottomResize");
                 targetEditor.OnPreviewSettings();
                 GUILayout.EndHorizontal();
                 targetEditor.DrawPreview(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, previewHeight));

             }
             GUILayout.EndScrollView();
         }
     }
 }


End Result

Preview


Hope this proves useful

Stektpotet


capture.png (52.5 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

193 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to Undo a bool on an EditorWindow 1 Answer

Unity Android Build Publishing Settings are not saved When changed with Preset or by script 0 Answers

Unity Editor: Node window and Node Manage Window 0 Answers

GUI.Window. Wanting to allow clickthrough 0 Answers

Loading Json from Resources via Editor Script 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges