Labels are getting their width set to 0

Hello everyone,
I think I managed to find a bug in UI Toolkit code. When I create nested PropertyField inside 2-column (or more) layout then Label width gets set to 0. Debugger says it’s inline, so I guess some internal Unity script sets that value.
I made minimal example, starting with script code:

using UnityEngine;

[System.Serializable]
public struct ExampleStruct
{
    public int value;
}

public class BugScript : MonoBehaviour
{
    public ExampleStruct Example;

}

It’s just simple class with struct. Next is editor:

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


[CustomPropertyDrawer(typeof(ExampleStruct))]
public class ExampleStructEditor : PropertyDrawer
{
    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        var container = new VisualElement()
        {
            style =
                {
                    flexDirection = FlexDirection.Row
                }
        };

        var key = new Label()
        {
            text = "Some text, just to fill the gap",
            style =
            {
                width = Length.Percent(45)
            }
        };

        var propertyField = new PropertyField(property)
        {
            label = "Some property",
            style =
            {
                width = Length.Percent(50),
            }
        };

        container.Add(key);
        container.Add(propertyField);

        return container;
    }
}

This looks like this:
9903438--1430673--upload_2024-6-22_10-6-14.png
As you can see, label isn’t visible at all (however label item is there). I’ve tried to update width on geometry event, this works fine as long as you don’t mouseover property, which reverts it back to above picture. Example code and how it looks like until you mouseover the element:

[CreatePropertyGUI function body...]      
        propertyField.RegisterCallback<GeometryChangedEvent>(UpdateSize);

        return container;
    }

    private void UpdateSize(EventBase e)
    {
        var propertyField = e.currentTarget as PropertyField;
        var labels = propertyField.Query<VisualElement>(className: "unity-label").ToList();
        labels.ForEach(label =>
        {
            if (label.ClassListContains("unity-foldout__text"))
                return;

            label.style.width = Length.Percent(15);

            foreach (VisualElement sibling in label.parent.Children())
            {
                if (sibling == label)
                    continue;

                sibling.style.width = Length.Percent(84);
            }
        });
    }

9903438--1430676--upload_2024-6-22_10-9-36.png
I’ve tried reading UnityCsReference, I think I found script that resized the labels:

Based on this script, I’ve tried setting “–unity-property-field-label-base-min-width”, without any luck.
Do you know if I do something incorrectly? Or maybe it’s a known bug with some workaround? I’ve tried googling it and searching the forums, but I didn’t find anything useful.

1 Like

Hi, thanks for the heads up. I was able to replicate this behavior easily. I’d say this is a bug.

Maybe you could report this bug to Unity. You can do it by going to Help → Report a bug… in the top menu bar. It will open a window in which you can add a description of the bug, and some files you may want to include for Unity to be able to replicate this bug. The clearer you are, the faster they can take care of it. I recommend including the files for the example you shared here, a brief description of how the bug works, the steps necessary to reproduce the bug with your example, and a link to this forum thread.

That said, Unity may say that this behavior is expected. That aligned fields in the inspector resize all their labels so they end in the same place, and your column starts way past the point where labels should end in the inspector. Which is kind of a bad design for a feature IMO :(. A feature that interferes with horizontal layouts so much surely deserves to be worked on. It at least needs a way to be opted out. So, if they tell you this behavior is expected, maybe you could tell them something like that, and maybe it would convince them. Who knows :/.

A possible workaround could be to add an element with the classes “unity-inspector-element” and “unity-inspector-main-container” as your second column. This should trick the BaseField into believing that second column is the whole inspector.

1 Like

Columns are not really something we support with the field alignment indeed and fields are aligned by default in the inspector.
I think you would need to either:

  • remove the class name for alignment altogether (remove .unity-base-field__aligned from their field), or
  • Like oscarAbraham said, change the inspector element to specify it is the context for alignment (add .unity-inspector-element and .unity-inspector-main-container)

Both are sub optimal, but exposing better alignment primitives/api would be considered a new feature and will probably not make it to the priorities. (Especially since this need to also consider interactions with property drawers in IMGUI).

2 Likes

Thanks for the replies. Indeed setting .unity-inspector-* classes does work, but I guess it may have some further consequences for drawing. I’ll check solution from Simon as well. Hopefully at some point this feature makes its way into official release.
In meantime I discovered MultiColumnListView element. It’s really poorly documented, but I came up with similar design as in my original post, however in case you wondered - it also doesn’t work.
I’ll leave the code here for people searching for solutions:

    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        var columns = new Columns
        {
            new Column()
            {
                name = "Name",
                title = "Name",
                width = Length.Percent(45)
            },
            new Column()
            {
                name = "Value",
                title = "Value",
                width = Length.Percent(50)
            }
        };
        var container = new MultiColumnListView(columns);
        var properties = new List<SerializedProperty>
        {
            property.FindPropertyRelative("value")
        };
        container.itemsSource = properties;

        container.columns["Name"].makeCell = () => new Label();
        container.columns["Value"].makeCell = () => new PropertyField();

        container.columns["Name"].bindCell = (VisualElement element, int index) =>
            (element as Label).text = property.name;
        container.columns["Value"].bindCell = (VisualElement element, int index) =>
        {
            var propertyField = element as PropertyField;
            propertyField.bindingPath = properties.ElementAt(index).propertyPath;
            propertyField.Bind(property.serializedObject);
        };

        return container;
    }

9908415--1431756--upload_2024-6-25_19-50-30.png

Hi. Thank you for this information. In case it helps, I’d like to make a brief attempt at persuasion to maybe give it a little more priority to this matter:

  • The need for making horizontal layouts in custom inspectors isn’t uncommon enough to disregard. Tables and rows are often present in game dev tools. IMGUI supports horizontal layouts in Inspectors; it’s sad that it’s harder to do them in UITK. UITK is supposed to be more flexible than IMGUI.
  • It wouldn’t be hard to add official support for custom alignment areas, an official way to do the workaround I suggested. There could be a USS class that’s called something like alignment-container. This would not only help in situations like OP’s, but it would also bring field alignment support to custom EditorWindows. I often need ratio aligned labels in my EditorWindows, and it’s harder to do that in UITK than it was in IMGUI.

Ideally, I’d love a way of stopping PropertyFields from altering labels’ width, or even better, a way to set the exact desired label width. But I guess it’s harder to do that in a way that covers all edge cases well enough. I can understand that being a low priority. That said, maybe not many people would be too bothered if it worked somewhat differently for IMGUI fields; it wouldn’t be the default behavior, anyway, and IMGUI fields already present differences over UITK.

On the other hand, the feature I mentioned in point 2 would at least solve many layout problems, it can be done with a few lines of code, and it works for both IMGUI and UITK properties. I feel like it should be much easier to consider.

I don’t think it would have any consequences for drawing you aren’t expecting. The bad thing I can see for this solution is that it isn’t officially supported, so it could stop working some years later when you upgrade Unity.

The problem with removing the alignment class is that you need to remove it from the fields generated inside the PropertyField. You’d have to wait until the PropertyField has created its content, look for aligned fields in there, and then fix them. By the time you get access to those fields, the label will have already been resized, so you’d have to set their new width with code. And you wouldn’t be able to use the special USS properties you mentioned to control their ratios dynamically. It’s doable, but it’s a bit more complicated.

1 Like