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. Dismiss Notice

How to calculate required size of VisualElement or at least text width before it is drawn?

Discussion in 'UI Toolkit' started by Xarbrough, Feb 20, 2020.

  1. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    With IMGUI, it was possible to use GUIStyle.CalcSize to calculate the required width of a label. For example:
    GUI.skin.label.CalcSize(guiContent)


    This made it possible to calculate the required size of a popup window before it was opened, for example. Because I knew the number of elements I wanted to draw, I could simply precalculate the size for each element and then set the window width to the minimum size.

    How would I do the same with UIElement Labels or even better arbitrary VisualElements? I know there is the resolvedStyle property, but for this to work, the element need to be renderer on screen already and queried after the GeometryChanged event. This means that my EditorWindow will flicker for one frame when opening.

    Other than that, there is the MeasureTextSize method, but it has the same limitation that the label must be on screen before I can measure it.

    I need this to work on arbitrary labels, because I'm showing a list of GameObject names and want to calculate the widest text label. I can't hardcode the width ahead of time. Alternatively, it would equally well, if it were possible to make the EditorWindow automatically fit the size of its content, but that doesn't seem possible.
     
    Last edited: Feb 20, 2020
    OMGOMGXAXA and BinaryCats like this.
  2. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    I also would like to know how to do this.
     
  3. stan-osipov

    stan-osipov

    Unity Technologies

    Joined:
    Feb 24, 2020
    Posts:
    31
    Unfortunately, to calculate the layout, it needs to be part of the Visual Tree.
     
  4. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    It's been a few months, still learning UI Toolkit and still trying to implement a popup window that fits the size of its content. I still can't get this to work. Does anyone know how to do this with the new system?

    I have a ListView in an EditorWindow. So far, the ListView has flexGrow 1 so that it expands, but this makes the window drive the list, but I want it to be the other way around. I've tried playing with layout settings and the use the GeometryChangedEvent to see if the resolvedStyle showed any value, but it only ever repeated the window size or was zero.

    So, the other approach would be to calculate the space required before opening the window, but there's no method to check how big a label will need to be to fit its text and so on. There must be some way. I believe the GraphView API grows its nodes to fit the title content, but I haven't found where exactly this happens in the source code.
     
  5. Kekito

    Kekito

    Joined:
    Nov 24, 2016
    Posts:
    14
    this would be great to know
     
  6. vejab

    vejab

    Joined:
    Dec 21, 2021
    Posts:
    85
  7. Kekito

    Kekito

    Joined:
    Nov 24, 2016
    Posts:
    14
    Actually just found another way to do it, would work for anything not just text. Scale the window to an unreasonable size (lets say 2000x2000) and after its contents are initialized scale it down to the largest element width (and/or height).
     
    vejab likes this.
  8. SimonDufour

    SimonDufour

    Unity Technologies

    Joined:
    Jun 30, 2020
    Posts:
    515
    MeasureTextSize depends on the font, scale/pixelPerPoint of the panel, so it should provide what you are looking for as long as the inputs are met.

    I think if your font is applied through style, it may still be null before the style's resolution and this is an early exit :

            if (textToMeasure == null || !IsFontAssigned(te))
    return new Vector2(measuredWidth, measuredHeight);


    Setting the font inline would probably get around the early exit, so you could calculate the size earlier.