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.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to add the standard 'Object Picker' with UIE

Discussion in 'UI Toolkit' started by LaneFox, Nov 22, 2019.

  1. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    Is there a way to manually draw the standard Object Picker button thing (target button seen to the right side of all object fields) and bind it to a field?
     
  2. pirho_luke

    pirho_luke

    Joined:
    Oct 24, 2017
    Posts:
    21
    Add an ObjectField to where you want it displayed and then call "BindProperty" on it passing in a serialized property referencing the field you would like it bound to!

    Code (CSharp):
    1. var objectField = new ObjectField();
    2. objectField.BindProperty(*serializedPropertyToBindTo*);
     
  3. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    I only want the picker, I don't want the field.
     
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    The functionality to simply open the Object picker is internal. What I can suggest is to create a custom C# VisualElement that contains a ObjectField inside and just hides (via ve.styles.display = DisplayStyle.None) all the elements of the ObjectField you don't want except the picker icon. Then at least the black magic can be contained inside a black box element.
     
  5. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    Thanks for this idea!

    I was pretty skeptical of doing this but it turned out fine. I did have to make an
    ObjectField
    for the easy binding to a property and separate the picker by digging down to fetch the child
    VisualElement 
    "ObjectFieldSelector" and add it to the separate container. After making the
    ObjectField
    invisible and forcing it to 0 size it visually looks like I expected and all the hooks still worked kind of like a proxy for me.

    Fortunately the
    ObjectField
    had bindings with the picker so I could just interact with the field and other element's callbacks to get data back and forth to the picker.
    SetValueWithoutNotify
    was important to keep everything in sync without issues.

    I'm legitimately surprised this worked haha
     
  6. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    Glad it worked. Just a tip that if you set the display to None (ie:
    ve.styles.display = DisplayStyle.None
    in C#,
    display: none;
    in USS), you should not need to set the size to 0. It should just remove it from layout and rendering.
     
  7. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    Nice! Thanks :)
     
  8. phreezie

    phreezie

    Joined:
    Oct 3, 2019
    Posts:
    119
    @LaneFox Apologies for reviving this topic, but would it be possible to share a code snipped for this?
     
  9. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    Code (csharp):
    1.             // build the object field
    2.             m_objField = new ObjectField { objectType = att.SourceType, allowSceneObjects = false };
    3.             m_objField.name = "AD | Hidden Object field";
    4.             m_objField.style.display = DisplayStyle.None;
    5.             m_objField.BindProperty(property);
    6.             m_objField.RegisterValueChangedCallback(OnChangedObject);
    7.  
    8.             // build the picker button (rip it out of the object field)
    9.             VisualElement picker = m_objField[0][1];
    10.             picker.name = "AD | Obj Picker Button";
    11.             picker.style.flexGrow = 0;
    12.             picker.style.flexShrink = 0;
    13.             picker.tooltip = "Pick this asset file manually";
    14.  
    15. [...]
    16.  
    17.             container.Add(m_objField);
    18.             container.Add(picker);
    Ended up moving on to a different solution, but this worked when I made these posts.
     
    phreezie likes this.
  10. phreezie

    phreezie

    Joined:
    Oct 3, 2019
    Posts:
    119
    Thanks!
    container
    became
    contentContainer
    I suppose? It's a member of VisualElement, right? And this you run in the constructor of your new VisualElement?
     
  11. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,390
    Yes :)
     
  12. phreezie

    phreezie

    Joined:
    Oct 3, 2019
    Posts:
    119
    Gotcha, thanks!
     
  13. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,878
    There is a specific public API method for doing this (EditorGUIUtililty.ShowObjectPicker) but UIToolkit appears to break it (I cannot get it to work - UIToolkit blocks the callbacks).

    There is a replacement UITookit-only method that does exactly what we want - but the team has blocked access to it.

    Until someone on UIToolkit fixes this (makes their method public? or ... somehow unblocks/re-enables the existing ShowObjectPicker API?), here's a clean way to bring up the object-picker using reflection. And it's typesafe too, for bonus points!

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Reflection;
    5. using UnityEditor;
    6. using Object = UnityEngine.Object;
    7.  
    8. /// <summary>
    9. /// UIToolkit implemented a private version of "ShowObjectPicker", this invokes it
    10. ///
    11. /// Usage:
    12. /// e.g. to pick a Material:
    13. ///    ((Material)null).ShowObjectPicker<Material>( o => { Debug.Log( "selector closed"+o.name ); }, o => { Debug.Log( "selector updated"+o.name ); } );
    14. ///
    15. /// </summary>
    16. public static class WorkaroundUnityUIToolkitBrokenObjectSelector
    17. {
    18.     public static void ShowObjectPicker<T>( this T initialValue, Action<T> OnSelectorClosed, Action<T> OnSelectionChanged ) where T : UnityEngine.Object
    19.     {
    20.         ShowObjectPicker<T>( OnSelectorClosed, OnSelectionChanged, initialValue );
    21.     }
    22.  
    23.     public static void ShowObjectPicker<T>( Action<T> OnSelectorClosed, Action<T> OnSelectionChanged, T initialValueOrNull = null ) where T : UnityEngine.Object
    24.     {
    25.         var hiddenType = typeof(Editor).Assembly.GetType( "UnityEditor.ObjectSelector" );
    26.         var ps = hiddenType.GetProperties( BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
    27.         PropertyInfo piGet = hiddenType.GetProperty( "get", BindingFlags.Public | BindingFlags.Static );
    28.         var os = piGet.GetValue( null );
    29.  
    30.         MethodInfo miShow = hiddenType.GetMethod( "Show", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[]
    31.         {
    32.             typeof(T),
    33.             typeof(    System.Type),
    34.             typeof(UnityEngine.Object),
    35.             typeof(bool),
    36.             typeof(List<int>),
    37.             typeof(Action<UnityEngine.Object>),
    38.             typeof(Action<UnityEngine.Object>)
    39.         }, new ParameterModifier[0] );
    40.         //Action<UnityEngine.Object> onSelectorClosed = o => { Debug.Log( "selector closed"+o.name ); };
    41.         //Action<UnityEngine.Object> onSelectedUpdated = o => { Debug.Log( "selector updated"+o.name ); };
    42.         miShow.Invoke( os, new object[]
    43.             {
    44.                 initialValueOrNull,
    45.                 typeof(T),
    46.                 null,
    47.                 false,
    48.                 null,
    49.                 OnSelectorClosed,
    50.                 OnSelectionChanged,
    51.             }
    52.         );
    53.     }
    54. }
    55.  
     
    Last edited: Feb 4, 2022
    FM-Productions likes this.
  14. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,878
    Small update: I'm now maintaining that code as part of the Asset Publishers Forks (snippets of code that asset publishers need, some of which are useful for game/app devs, but most people wont need): https://github.com/adamgit/PublishersFork