Editor scene objects pipette

Hi. Could we have a nice editor scene objects pipette in order to fill script properties easily?

It’s so convinient feature for devs who work with large scenes.
I have attached the example video where that pipette is used.

2 Likes

bump

i guess it would also need highlighting current mouse over target,
so that user knows what object is going to get picked?

and somehow need to pick objects under object objects too…(which is quite difficult in unity scene editor currently, it seems to pick all kind of objects, until you get the correct one after 10 clicks…)

Wow. Nice ideas!

Any news about this must-have feature from Unity dev?

Bump. Must-have feature for scenes with many game objects and parents

Bump

Hello IAndrewNovak, thanks for making the feature request. To make sure I’m capturing this properly, essentially you’d want an alternate way for the Object Picker to select an object, which would allow you simply select it from the scene?

In the future, I’d recommend using our public roadmap for submitting feature requests, that way it ends up directly in our inbox.

Cheers.

Hi Benoitd. Thanks for your reply :slight_smile:

Yes, you are right. I strongly need the possibility to fill up the script properties by clicking objects in the scene.

I have more than 1000 game objects in the scene. Many of them have separate parents and are so hard to find and fill scripts properties by drag and drop or find by name. The pipette will be so much help for me and the Unity community.

Have a nice day.

Hi benoitd_unity
Any news about this feature from Unity Team?
Also I send a feature info via roadmap

Bump

@IAndrewNovak , there’s no purpose in bumping this every few days or weeks. New features flow into the pipeline and can take a year or two, because they have a backlog of other priorities.

@benoitd_unity , Unity has never been particularly clear, or rather I should say has often been quite contradictory, about where people should submit feature requests. “Just post them on the forum, we read those.” “Put them on the roadmap.” “Vote on what is important to you because we have no idea how to prioritize since we don’t dogfood.” You need a much more obvious and official page labeled ADD YOUR FEATURE REQUESTS HERE, and moreso, you need to back that up with commentary and clarity on what will be done.

I’ve 100% seen editor tools out there that do this, though I can’t find it with a quick search. I know I’ve seen youtube vids with folks using this as part of their editor toolbox.

Thanks guys for the reply.
I bumped this post while this super cool feature not available in Unity for me and other Unity community.
If you used a pipette at last once in other apps, you understand why I want to implement this on the native side of Unity

Any news?

Bump

Bumping this thread doesn’t do anything mate. The forums are not for feature requests.

I’m 100% sure assets for this exist out there as well, or you can implement this yourself. That’s going to be the faster option than waiting for Unity to do it. Make it yourself and move on.

Hi. Forum for feature requests (check available tags in the title). I can’t make this tool, but if I could, I want the Unity team to give such a beautiful tool to the whole community.

Instead of contradicting me, I would appreciate your support. I do it not for myself but for everyone

The tag is there from the days of yore. The Unity devs seldom if ever do feature requests through the forum anymore.

I attempted to make this before but didn’t have any luck. After a good amount of research I did manage to get something working nicely without any real hacks.

First, your little attribute:

#if UNITY_EDITOR
namespace LBG.EditorUtils
{
   using System;
   using UnityEngine;

   /// <summary>
   /// Apply this attribute to <see cref="GameObject"/> and <see cref="Component"/> fields
   /// to be able to pick them from the scene.
   /// </summary>
   [System.Diagnostics.Conditional("UNITY_EDITOR")]
   [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
   public sealed class ScenePipetteAttribute : PropertyAttribute { }
}

And then the actual property drawer:

namespace LBG.EditorUtils.Editor
{
    using System;
    using UnityEngine;
    using UnityEditor;
    using UnityEngine.UIElements;

    [CustomPropertyDrawer(typeof(ScenePipetteAttribute))]
    internal sealed class ScenePipettePropertyDrawer : PropertyDrawer, IDisposable
    {
        #region Internal Members

        private Type _propertyType = null;
        private bool _pipetteMode = false;

        private bool _isGameObjectType = false;
        private bool _isComponentType = false;

        private EventCallback<MouseDownEvent> _onMouseDown;
        private SerializedProperty _property;

        private readonly GUIContent _buttonContent;
        private readonly Texture2D _pipetteTexture;

        #endregion

        #region Constructor

        public ScenePipettePropertyDrawer() : base()
        {
            _pipetteTexture = (Texture2D)EditorGUIUtility.Load("d_color_picker");
            _buttonContent = new GUIContent(_pipetteTexture);
        }

        #endregion

        #region Property Drawer Overrides

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            return 0f;
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            Event e = Event.current;

            // have to do this during layout as field info/serialized property
            // aren't available before hand
            if (e.type == EventType.Layout)
            {
                var fieldInfo = this.fieldInfo;
                _propertyType = fieldInfo.FieldType;
                _isGameObjectType = typeof(GameObject).IsAssignableFrom(_propertyType);
                _isComponentType = typeof(Component).IsAssignableFrom(_propertyType);
            }

            if (_pipetteMode == true && e.keyCode == KeyCode.Escape)
            {
                this.ExitPipetteMode();
            }

            if (property.propertyType != SerializedPropertyType.ObjectReference)
            {
                EditorGUILayout.PropertyField(property, label);
                return;
            }

            if (_isGameObjectType == false && _isComponentType == false)
            {
                EditorGUILayout.PropertyField(property, label);
                return;
            }

            using (new EditorGUILayout.HorizontalScope())
            {
                Color c = GUI.color;
                GUI.color = _pipetteMode ? Color.yellow : c;

                EditorGUILayout.ObjectField(property);

                if (GUILayout.Button(_buttonContent, GUILayout.MaxWidth(22f)))
                {
                    this.EnterPipetteMode(property);
                }

                GUI.color = c;
            }
        }

        #endregion

        #region Internal Methods

        private void EnterPipetteMode(SerializedProperty property)
        {
            _pipetteMode = true;
            _property = property;
            _onMouseDown = new EventCallback<MouseDownEvent>(HandleSceneViewMouseClick);

            SceneView.duringSceneGui += HandleSceneGUI;
            foreach (SceneView sv in SceneView.sceneViews)
            {
                sv.rootVisualElement.RegisterCallback(_onMouseDown, TrickleDown.NoTrickleDown);
            }
        }

        private void HandleSceneViewMouseClick(MouseDownEvent e)
        {
            Vector3 mousePos = e.originalMousePosition;
            var po = HandleUtility.PickGameObject(mousePos, true);

            if (po != null)
            {
                if (_isGameObjectType == true)
                {
                    _property.objectReferenceValue = po;
                }
                else if (_isComponentType == true)
                {
                    if (po.TryGetComponent(_propertyType, out Component component))
                    {
                        _property.objectReferenceValue = component;
                    }
                }

                _property.serializedObject.ApplyModifiedProperties();
            }

            this.ExitPipetteMode();
        }

        private void HandleSceneGUI(SceneView sceneView)
        {
            // this prevent selection in the scene while pipette mode is active
            int id = GUIUtility.GetControlID(FocusType.Passive);
            HandleUtility.AddDefaultControl(id);
        }

        private void ExitPipetteMode()
        {
            _pipetteMode = false;
            SceneView.duringSceneGui -= HandleSceneGUI;
            foreach (SceneView sv in SceneView.sceneViews)
            {
                sv.rootVisualElement.UnregisterCallback(_onMouseDown);
            }
        }

        void IDisposable.Dispose()
        {
            if (_pipetteMode == true)
            {
                this.ExitPipetteMode();
            }
        }

        #endregion
    }
}
#endif

And the tool in action: https://i.gyazo.com/7cb85d4beeffe05e7b267424e37de909.mp4

There’s a certain sense of irony of an IMGUI drawer using UI toolkit to handle part of it’s functionality. This was done on 2022.3.12f1.

Edit: I will add that the IDisposable support only works from this version onwards as well.

Certainly a lot that could be improved upon. Would like to change the cursor but the pipette texture isn’t set up for it (maybe a way to draw the texture near the cursor?). I certainly would like to open the floor to any and all suggestions.

If I improve upon it I’ll pose some updates. Maybe make a repo out of it.

1 Like

I disagree. Tags are useful and I see how the Unity team reacts.
Also, I sent the feature request via RoadMap too.

Thanks. That works perfectly! I found an issue with the show override property no as Bold for prefab.

Door - is pipette property. Display - default

9442367--1324778--upload_2023-10-31_15-13-56.png