Search Unity

Bug There're inconsistencies with the FocusOutEvent and UI style between Unity 2021 and Unity 2022

Discussion in 'UI Toolkit' started by SolarianZ, May 24, 2023.

  1. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    I have created an animation marker editor. When you right-click on the timeline with the mouse, an "Add Marker" option pops up. Clicking on "Add Marker" opens the marker editor. If you click outside the marker editor, the marker editor box disappears. However, there are inconsistencies between Unity 2021 and Unity 2022.

    Problem 1:
    FocusOutEvent.relatedTarget
    always returns
    null
    .


    upload_2023-5-24_10-37-23.png

    In Unity 2021, the UI works as expected:

    upload_2023-5-24_10-34-34.gif

    However, in Unity 2022, the UI does not work as expected because
    FocusOutEvent.relatedTarget
    always returns
    null
    instead of obtaining the new UI element that has mouse focus:

    upload_2023-5-24_10-35-13.gif
     
  2. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Problem 2: UI size and position inconsistency.

    After commenting out the code that causes the UI to close in the previous problem, I found that the size and position of the UI is also inconsistent between Unity 2021 and Unity 2022.

    Code (CSharp):
    1. private void OnPanelLostFocus(FocusOutEvent evt)
    2. {
    3.     // In Unity 2021.3, the evt.relatedTarget is the element that gains the focus.
    4.     // In Unity 2022.2, the evt.relatedTarget is always null.
    5.     //var element = evt.relatedTarget as VisualElement;
    6.     //if (IsElementInPanel(element))
    7.     //{
    8.     //    return;
    9.     //}
    10.  
    11.     //parent.Remove(this);
    12. }
    The code for setting the UI style is as follows:

    Code (CSharp):
    1. public EditorElement(string name, float time, Action<string, float> onSubmit)
    2. {
    3.     m_onSubmit = onSubmit;
    4.  
    5.     style.translate = new Translate(Length.Percent(-50), Length.Percent(-50), 0);
    6.     style.position = Position.Absolute;
    7.     style.top = Length.Percent(50);
    8.     style.left = Length.Percent(50);
    9.     style.flexDirection = FlexDirection.Row;
    10.     style.backgroundColor = new Color(60f / 255, 60f / 255, 60f / 255, 1f);
    11.     style.paddingLeft = 1;
    12.     style.paddingRight = 1;
    13.     style.paddingTop = 2;
    14.     style.paddingBottom = 2;
    15.     style.borderTopLeftRadius = 3;
    16.     style.borderTopRightRadius = 3;
    17.     style.borderBottomLeftRadius = 3;
    18.     style.borderBottomRightRadius = 3;
    19.  
    20.     // Name field
    21.     m_nameField = new TextField
    22.     {
    23.         value = name,
    24.         isDelayed = true,
    25.         style =
    26.         {
    27.             minWidth = 40,
    28.         }
    29.     };
    30.     Add(m_nameField);
    31.  
    32.     // Time field
    33.     m_timeField = new FloatField
    34.     {
    35.         value = time,
    36.         isDelayed = true,
    37.         style =
    38.         {
    39.             minWidth = 40,
    40.         }
    41.     };
    42.     Add(m_timeField);
    43.  
    44.     // Submit button
    45.     m_submitButton = new Button(TrySubmit)
    46.     {
    47.         text = "Ok",
    48.     };
    49.     Add(m_submitButton);
    50.  
    51.     RegisterCallback<FocusOutEvent>(OnPanelLostFocus);
    52. }

    In Unity 2021, the UI looks like this:

    upload_2023-5-24_10-44-16.png

    In Unity 2022, some adjustments need to be made to the UI in order to be visible:

    upload_2023-5-24_10-45-21.gif
     
  3. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
  4. cpalma-unity

    cpalma-unity

    Unity Technologies

    Joined:
    Nov 30, 2020
    Posts:
    110
  5. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
  6. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Hi, I read your posts and, although I don't have a solution for your specific issues, I kept thinking that you could use an EditorWindow as a workaround. It could even be an improvement. You can use ShowPopup to show a custom window without any borders, that can't be moved or resized, that closes when it loses focus.

    EDIT
    Sorry, it doesn't close automatically when it loses focus. You'd have to close it in OnLostFocus, but that's easy. The one that closes automatically when it loses focus is ShowAsDropDown, which may also be useful to you.
     
    Last edited: May 30, 2023
    SolarianZ likes this.
  7. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Hi @oscarAbraham , thank you for your advice, it is very helpful!!
     
    oscarAbraham likes this.
  8. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Hi @oscarAbraham ,

    I have tried using the EditorWindow solution, but the position of the EditorWindow cannot be set to the mouse position, especially when using dual screens. Do you have any suggestions?

    Thank you!

    upload_2023-5-31_12-2-29.gif
     
  9. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    No worries : ).

    So, the solution I know is to use GUIUtility.GUIToScreenPoint. You can pass the mouse position to get it relative to screen coordinates. You can also pass any world position from your UI, e.g. an element's worldBound or a position obtained with LocalToWorld. World positions and mouse event positions in UITK are relative to the whole EditorWindow, GUIToScreenPoint converts them to screen space.

    I think the call to GUIToScreenPoint must be done while Unity is processing the window that contains your UI, so as long as you call it from a UI Toolkit event callback, you should be fine.

    There may be another way that's more integrated with UITK, but if it exists, I don't know it.

    Anyway, you'd probably need to cache the mouse position in screen coordinates before showing your context menu. Something like:
    screenMousePosition = GUIUtility.GUIToScreenPoint(evt.mousePosition);
    Then, when you want to show your custom editor window, you set its position property to that cached
    screenMousePosition
    before calling the Show method.
     
    SolarianZ likes this.
  10. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    Resolved! The correct approach should be to use the
    GUIUtility.GUIToScreenPoint()
    method to convert the coordinates. I previously used the wrong method.
     
  11. SolarianZ

    SolarianZ

    Joined:
    Jun 13, 2017
    Posts:
    237
    What a coincidence, haha! I also found this method. Thank you again!!
     
    oscarAbraham likes this.