0
\$\begingroup\$

I'm following the "Create a Custom Inspector" car and tire example that Unity has in their documentation for UI Toolkit, but I'm trying to modify it in a specific way and I'm coming up short (whether or not it is a "good" way is beyond the scope of the question). Essentially, I'd like to take the editor display for an array and make it accessible by a single button that opens a PopupWindow in the editor, displaying the information for all four tires. I'd also like to make sure that the array is not reorderable, and if possible, I'd like to have it not act like a foldout in the PopupWindow.

I've managed to get this so far:

a sort-of functional popup behind a Button that does not display the information from TireSpecs.cs

In Car.cs, I have the following:

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEditor.UIElements;

public class Car : MonoBehaviour
{
    public string myMake = "Ford";
    public int myYearBuilt = 2001;
    public Color myColor = new Color(0.5725f, 0.525f, 0.3875f, 1.0f);

    public TireSpecsArrayWrapper myTires = new TireSpecsArrayWrapper()
    {
        Tires = new TireSpecs[4]
    };

    public ActualTireDetails tireOptions;
}

In TireSpecs.cs, I have the following:

using System;
using UnityEngine;

[Serializable]
public class TireSpecs
{
    public float myAirPressure = 35.0f;
    public int myProfileDepth = 4;

    public TireSpecs(float airPressure, int profileDepth)
    {
        myAirPressure = airPressure;
        myProfileDepth = profileDepth;
    }
}

In TireSpecsArrayWrapper.cs, I have the following:

using System;
using UnityEngine;

[Serializable]
public class TireSpecsArrayWrapper
{
    public TireSpecs[] Tires; 
}

And my PropertyDrawer, TirePropertyDrawer.cs, is structured like this (has been edited to reflect changes below):

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEditor.UIElements;
using System.Collections.Generic;

[CustomPropertyDrawer(typeof(TireSpecsArrayWrapper))]
public class TirePropertyDrawer : PropertyDrawer
{
    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        var container = new VisualElement();

        SerializedProperty tireProperties = property.FindPropertyRelative("Tires");

        var button = new Button(() => ShowPopup(container, tireProperties)) { text = "View Tire Specifications" };
        container.Add(button);

        return container;
    }

    void ShowPopup(VisualElement anchor, SerializedProperty property)
    {
        UnityEngine.UIElements.PopupWindow popup = new UnityEngine.UIElements.PopupWindow();
        popup.style.flexGrow = 200;
        popup.style.height = new StyleLength(Length.Percent(100));
        popup.style.flexDirection = FlexDirection.Column;

        if (property != null && property.isArray)
        {
            Debug.Log($"Array Size: {property.arraySize}");

            for (int i = 0; i < property.arraySize; i++)
            {
                Debug.Log($"Array index = {i}");
                SerializedProperty arrayElement = property.GetArrayElementAtIndex(i);
                VisualElement arrayElementContainer = new VisualElement();
                arrayElementContainer.style.flexDirection = FlexDirection.Column;

                arrayElementContainer.Add(new Label($"Tire #{i + 1}: "));

                CreatePropertyField(arrayElementContainer, arrayElement, "airPressure", "Air Pressure (psi):");
                CreatePropertyField(arrayElementContainer, arrayElement, "profileDepth", "Profile Depth (mm):");

                arrayElementContainer.style.paddingTop = 8;
                arrayElementContainer.style.paddingRight = 8;
                arrayElementContainer.style.paddingBottom = 8;
                arrayElementContainer.style.paddingLeft = 8;

                popup.Add(arrayElementContainer);
            }
        }

        var button = new Button(() => anchor.Remove(popup)) { text = "Close Popup" };
        popup.Add(button);
        anchor.Add(popup);
    }

    private void CreatePropertyField(VisualElement elementContainer, SerializedProperty parentProperty, string propertyName, string label)
    {
        SerializedProperty property = parentProperty.FindPropertyRelative(propertyName);
        PropertyField field = new PropertyField(property, label);
        field.BindProperty(property);
        field.style.flexGrow = 1;
        field.style.paddingTop = 2;
        field.style.paddingRight = 2;
        field.style.paddingBottom = 2;
        field.style.paddingLeft = 2;
        field.style.minHeight = 16;
        field.style.flexDirection = FlexDirection.Column;
        elementContainer.Add(field);
    } 
}

EDIT: After consulting with some folks, I've managed to get it to this stage:

an update of the .gif above, where the popup window now properly displays some text, but not the fields from TireSpecs.cs

EDIT 2: I've now managed to get close to what I'm looking for visually and functionally, but I'm not certain that what I have is behaving entirely as intended. Getting to this point involved creating a wrapper class for TireSpecs.cs to allow the PropertyDrawer to target the array directly. Scripts have been updated to reflect changes; the styling especially could use some work, but outside of that, is there a way to improve my script(s)?

a close visual match for the sort of thing that I'm trying to make with the popup window and array; there is now only one button which, when clicked, displays the array information

\$\endgroup\$

0

You must log in to answer this question.

Browse other questions tagged .