Search Unity

Focus Rings for "modal" dialogs (How to change Focus Rings?)

Discussion in 'UI Toolkit' started by Lance-Grooms, May 12, 2020.

  1. Lance-Grooms

    Lance-Grooms

    Joined:
    Mar 24, 2016
    Posts:
    26
    I'm simulating "modal" popup dialogs (in code). Works fine except for the tab-based focus ring. Tabbing will cycle through the "modal" dialog elements and then start traversing "background" elements not part of the dialog.

    Documentation is pretty non-existent on this topic. But is there any way to restrict the focus-ring to a specific visual element (as opposed to the root panel)?
     
  2. pawelduda

    pawelduda

    Joined:
    Feb 1, 2019
    Posts:
    45
    @Lance-Grooms I know this is almost year ago, but have you found a solution for this?
     
  3. Stealcase

    Stealcase

    Joined:
    Feb 26, 2018
    Posts:
    11
    Bumping for interest.

    I need to be able to control the order of navigation of elements. For a couple of different use-cases:
    • Needing to navigate two menus on the same screen, where one is vertical and the other is horizontal (Maybe solvable by assigning the TabIndex property?)
    • Needing to create a menu navigation that DOESN'T loop to the top again. Currently default behaviour is to loop through all navigable elements.
    • Needing to create an element that gets exclusive rights to the focus, and focus ring looping on those elements, similar to @Lance-Grooms. I don't want the user to be navigating on elements behind the temporary modal popup.

    How do I do this?
    It seems like I the intended design of UI Toolkit is for people to inherit from VisualElement when they need extended behaviour.
    And Visual Element implements the abstract class called "Focusable", which has a FocusController which has a constructor taking an IFocusable but(!) it only has a getter, no setter.

    As far as I can see, I can't create my own focus logic, because I can't create a new FocusController with an IFocusable in the constructor.

    Otherwise, I have to create my own custom base VisualElement, implementing
    Focusable, IStylePropertyAnimations, ITransform, ITransitionAnimations, IExperimentalFeatures, IVisualElementScheduler, IResolvedStyle, etc.

    But that seems really like too much work for something like this.

    Does anyone have an alternative? Or am I thinking about this the wrong way?


    Other questions I have:
    1. How can I use the FocusIndex? I assume this could help me solve some of my issues.
    2. I can set the TabIndex, but that controls the Tabbing behaviour, not navigation up and down/left and right.
    The focusIndex is a property in the UXML traits, but doesn't show up in the inspector, and since I can't look at the source code, I can't see if it is related to the Focusable property, or how it relates to the FocusRing.

    https://docs.unity3d.com/2022.2/Doc...VisualElementFocusRing-defaultFocusOrder.html
    https://docs.unity3d.com/2022.2/Doc...ents.VisualElement.UxmlTraits-focusIndex.html
     
    dlorre likes this.
  4. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    699
    I didn't know there was a focusIndex, that would explain why the gamepad navigation does not work well with tabindex.

    The best I could do to solve these focus issues has been to create panels and set everything outside of the panel to focusable = false.

    ETA: I've done a quick check and setting focusIndex="<number>" in the UXML seems to work.
     
    Last edited: Mar 22, 2022
    Stealcase likes this.
  5. Midiphony-panda

    Midiphony-panda

    Joined:
    Feb 10, 2020
    Posts:
    243
    You could register for NavigationEvents like NavigationMoveEvent.

    When the navigation event doesn't match your expected behaviour, you could stop its propagation :
    Code (CSharp):
    1. private void OnTricklingNavigationMoveEvent(NavigationMoveEvent evt)
    2. {
    3.     evt.PreventDefault();
    4.     evt.StopPropagation();
    5. }
    You can also give Focus() to an element in particular.


    That's an alternative, but I'd be happy to know better ones :D
     
    fanto_ep and Enrico-Monese like this.
  6. cb0d

    cb0d

    Joined:
    Mar 18, 2022
    Posts:
    20
    Bumping to see if there are any updates regarding customizing the focus navigation for gamepad.

    Does the latest 2022 release of Unity have notable improvements with this regard? Using 2021.3, gamepad navigation is very messy and difficult with UI Toolkit.
     
  7. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    699
    This is the reply I got from Unity:
    I have tried various methods, such as one similar to this one (except I don't send to root but to the control active in focusController) but the behaviour is different on 2021, 2022 and 2023 versions of Unity. 2021 does not even have NavigationEvent.Direction.Next but you can try sending a Keyboard tab event.

    Code (csharp):
    1.  
    2. #if UNITY_2022_1_OR_NEWER
    3.                 ev = NavigationMoveEvent.GetPooled(NavigationMoveEvent.Direction.Next);
    4. #else
    5.                 ev = KeyDownEvent.GetPooled('\t', KeyCode.Tab, EventModifiers.None);
    6. #endif
    7. ...
    8.  
    9. #if UNITY_2022_1_OR_NEWER
    10.                 ev = NavigationMoveEvent.GetPooled(NavigationMoveEvent.Direction.Previous);
    11. #else
    12.                 ev = KeyDownEvent.GetPooled('\t', KeyCode.Tab, EventModifiers.Shift);
    13. #endif
    14.  
    Also, I used to change the Move part in the EventSystem from UI/Navigate to None (new input system), but now I change the default action like so:

    upload_2022-9-6_11-55-18.png

    And it works (on 2023.1.0a6). The issue is that if you don't change this then the gamepad will respond to anything that looks like an arrow (left stick, right stick and d-pad).

    However this is tricky because using the TAB key will cycle every element while the using the Navigation Move will cycle only the elements inside the same group like so:
    Unity_VcAr1GB4Uu.gif

    The close button is ignored by the gamepad because the 3 buttons are grouped under a VisualElement.

    Code (csharp):
    1.  
    2.     <ui:VisualElement name="pgn-menu" class="ui-panel window-panel">
    3.         <ui:VisualElement name="top-bar" class="flex-row panel-top-bar">
    4.             <ui:Label text="PGN" display-tooltip-when-elided="true" class="title-label" />
    5.             <ui:Button display-tooltip-when-elided="true" tabindex="1" name="close" class="close-button h2w" />
    6.         </ui:VisualElement>
    7.         <ui:VisualElement name="buttons" class="buttons">
    8.             <ui:Button display-tooltip-when-elided="true" tabindex="2" name="button-games" class="nav-button round-corner" />
    9.             <ui:Button display-tooltip-when-elided="true" tabindex="3" name="button-save" class="nav-button round-corner" />
    10.             <ui:Button display-tooltip-when-elided="true" tabindex="4" name="button-edit-tags" class="nav-button round-corner" />
    11.         </ui:VisualElement>
    12.     </ui:VisualElement>
    13.  
     
    Last edited: Sep 6, 2022
  8. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    699
    I just figured out that with the gamepad, EventDirection.Down works better than EventDirection.Next for controls like sliders.