Hover not working all the time.

My UXML Doc contains a simple scheme to indicate “Current Layer” using Labels, and a column of Buttons to allow the user to select values 1-9. My problem is when I start the game, layer “1” is open. While Layer “1” is open, the value selection Buttons don’t react to their hover style and are not clickable. I try to demonstrate this in the following video:

I wish I knew how to narrate my video in OBS, but as I’m unable to do that I’ll try to describe the problem demonstrated here:

  • When the game starts, the Yellow 1 Label under the “FRONT” label reflects that the game begins in Layer “1”. Also notice, that when the mouse hovers up and down over the column of numbers “value selectors” 1-9, just to the left of the Layer Indicator, no hover style is seen.

  • When I first switch to Layer 2, the hover style on the value selectors is still not working.

  • When I switch back to Layer 1, the hover style still doesn’t work.

  • Then, when I switch back to Layer 2 (or any layer other than 1), the hover style takes effect, as witnessed by the Yellow Border appearing around the Button under the mouse.

  • Layer 1 does not Hover or Click in any case.

  • Incidentally in my case, “No Hover Style” means the Buttons are also unclickable.

This is my UXML DOCUMENT:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="project://database/Assets/UI/LAYER%20INDICATORS/LayerIndicatorStyles.uss?fileID=7433441132597879392&guid=7eb8a1b669c8746488bb3a06fffcb4af&type=3#LayerIndicatorStyles" />
    <ui:VisualElement style="flex-grow: 1; height: 100%;">
        <ui:VisualElement name="Background" class="LayerIndicator" style="flex-grow: 1; margin-left: 66%; height: 80%; width: 20%; background-color: rgba(0, 0, 0, 0.79); margin-bottom: 5%; flex-direction: row;">
            <ui:VisualElement name="ValueContainer" style="flex-grow: 1; flex-direction: row-reverse; -unity-text-align: middle-center; width: -496px; height: 100%;">
                <ui:VisualElement style="flex-grow: 1;">
                    <ui:Label tabindex="-1" parse-escape-sequences="true" display-tooltip-when-elided="true" name="lblCurSide" class="LayerIndicator" style="color: rgb(255, 240, 6); height: 15%; width: 100%;" />
                    <ui:VisualElement style="flex-grow: 1;">
                        <ui:VisualElement name="LayerIndicators" style="flex-grow: 1; flex-direction: row;">
                            <ui:VisualElement name="InputSelectorsColumn" style="flex-grow: 1; width: 20%; height: 100%; align-items: center;">
                                <ui:Button text="1" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose1" class="InputSelectorButton inputSelectorButyton" />
                                <ui:Button text="2" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose2" class="InputSelectorButton" />
                                <ui:Button text="3" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose3" class="InputSelectorButton" />
                                <ui:Button text="4" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose4" class="InputSelectorButton" />
                                <ui:Button text="5" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose5" class="InputSelectorButton" />
                                <ui:Button text="6" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose6" class="InputSelectorButton" />
                                <ui:Button text="7" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose7" class="InputSelectorButton" />
                                <ui:Button text="8" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose8" class="InputSelectorButton" />
                                <ui:Button text="9" parse-escape-sequences="false" display-tooltip-when-elided="true" name="cmdChoose9" class="InputSelectorButton" />
                            </ui:VisualElement>
                            <ui:VisualElement name="LayerIndicatorsColumn" style="flex-grow: 1; width: 80%; height: 100%;">
                                <ui:VisualElement name="Row1" style="flex-grow: 1; width: 100%; height: 100%; -unity-background-image-tint-color: rgb(0, 0, 0); flex-direction: row;">
                                    <ui:Label tabindex="-1" text="1" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num1" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="2" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num2" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="3" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num3" class="LayerIndicator" />
                                </ui:VisualElement>
                                <ui:VisualElement name="Row2" style="flex-grow: 1; width: 100%; height: 100%; -unity-background-image-tint-color: rgb(0, 0, 0); flex-direction: row;">
                                    <ui:Label tabindex="-1" text="4" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num4" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="5" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num5" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="6" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num6" class="LayerIndicator" />
                                </ui:VisualElement>
                                <ui:VisualElement name="Row3" style="flex-grow: 1; width: 100%; height: 100%; -unity-background-image-tint-color: rgb(0, 0, 0); flex-direction: row;">
                                    <ui:Label tabindex="-1" text="7" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num7" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="8" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num8" class="LayerIndicator" />
                                    <ui:Label tabindex="-1" text="9" parse-escape-sequences="true" display-tooltip-when-elided="true" name="Num9" class="LayerIndicator" />
                                </ui:VisualElement>
                            </ui:VisualElement>
                        </ui:VisualElement>
                    </ui:VisualElement>
                </ui:VisualElement>
            </ui:VisualElement>
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>

Graphically:

Here is my USS

.LayerIndicator {
    color: rgb(0, 0, 0);
    -unity-font-style: bold;
    margin-top: 0;
    margin-right: 0;
    margin-bottom: 0;
    margin-left: 0;
    width: 33%;
    height: 20%;
    -unity-text-align: middle-center;
    font-size: 60px;
    border-left-color: rgba(255, 253, 0, 0);
    border-right-color: rgba(255, 253, 0, 0);
    border-top-color: rgba(255, 253, 0, 0);
    border-bottom-color: rgba(255, 253, 0, 0);
    border-top-width: 20px;
    border-right-width: 20px;
    border-bottom-width: 20px;
    border-left-width: 20px;
    background-color: rgba(56, 56, 56, 0);
}

.button {
    border-width: 0;
    background-color: rgba(0, 0, 0, 0);
    border-color: color.yellow;
}

.InputSelectorButton {
    font-size: 30px;
    width: 40px;
    height: 10%;
    margin-top: 0;
    margin-bottom: 5px;
    border-top-left-radius: 15px;
    border-top-right-radius: 15px;
    border-bottom-right-radius: 15px;
    border-bottom-left-radius: 15px;
    border-top-width: 12px;
    border-right-width: 12px;
    border-bottom-width: 12px;
    border-left-width: 12px;
}

Button:hover {
    border-left-color: rgba(255, 244, 0, 255);
    border-right-color: rgba(255, 244, 0, 255);
    border-top-color: rgba(255, 244, 0, 255);
    border-bottom-color: rgba(255, 244, 0, 255);
    border-top-width: 15px;
    border-right-width: 15px;
    border-bottom-width: 15px;
    border-left-width: 15px;
    border-top-left-radius: 15px;
    border-top-right-radius: 15px;
    border-bottom-right-radius: 15px;
    border-bottom-left-radius: 15px;
}

And my c#

using System;
using System.Collections;
using System.Collections.Generic;

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UIElements;

public class LayerIndicators : MonoBehaviour
{
    // Start is called before the first frame update
    VisualElement _root;
    Label[] _layerNumbers; // the layer indicator Labels
    Button[] _userChoiceButtons;

    // Buttons so the user can select values 1-9

    Label _lblCurSide; // Label displaying the current Side.
    private void OnEnable()
    {
        _layerNumbers = new Label[g.PSIZE + 1];
        _userChoiceButtons = new Button[g.PSIZE + 1];

        _root = GetComponent<UIDocument>().rootVisualElement;
        for (int i = 1; i <= g.PSIZE; i++)
        {
            _layerNumbers[i] = _root.Q<Label>($"Num{i}");
            _layerNumbers[i].visible = false;
            _userChoiceButtons[i] = _root.Q<Button>($"cmdChoose{i}");
            _userChoiceButtons[i].clicked += createSelectionButtonHandler(_userChoiceButtons[i]);
        }
        _lblCurSide = _root.Q<Label>("lblCurSide");
    }

    private Action createSelectionButtonHandler(Button cmd)
    {
        return handleClick;

        void handleClick()
        {
            int iValue = int.Parse(cmd.name.Substring(cmd.name.Length - 1));
            g.SelectedValue = iValue;
            highlightSelectedValue(cmd);
        }
    }

    private void Update()
    {
        int currentLayer = SuperKube.LayerManager.CurLayer + 1;  // CurLayer is base 0.
        _lblCurSide.text = SuperKube.Rotation.Face.ToString();
        if (g.SelectedValue > 0)
            highlightSelectedValue(_userChoiceButtons[g.SelectedValue]);
        /// Show the current Layer as a visible, Yellow Number,
        /// hide the rest of the Layer Labels.
        for (int i = 1; i <= g.PSIZE; i++)
        {
            bool isVisible = i == currentLayer;
             _layerNumbers[i].visible = isVisible;
            _layerNumbers[i].style.color = isVisible ? Color.yellow : Color.clear;

        }
    }



    /// <summary>
    /// highlight currently selected value (for setting of
    /// UserValues and Candidates.) by giving it a thick, yellow
    /// border.
    /// </summary>
    private void highlightSelectedValue(Button cmd)
    {

        for (int i = 1; i < g.PSIZE + 1; i++)
        {
            setBorderWidths(_userChoiceButtons[i], 0);
        }
        setBorderWidths(cmd, 15);
    }

    /// <summary>
    /// Set Passed Button's border width and color.
    /// to highlight currently selected Value for setting of user
    /// values to holes and candidates.
    /// </summary>
    ///
    /// <param name="cmd"></param>
    /// <param name="width"></param>
    private void setBorderWidths(Button cmd, int width)
    {
        cmd.style.borderBottomWidth = width;
        cmd.style.borderTopWidth = width;
        cmd.style.borderLeftWidth = width;
        cmd.style.borderRightWidth = width;
        if (width > 0)
        {
            cmd.style.borderRightColor = Color.yellow;
            cmd.style.borderTopColor = Color.yellow;
            cmd.style.borderBottomColor = Color.yellow;
            cmd.style.borderLeftColor = Color.yellow;
            cmd.style.borderBottomLeftRadius = width;
            cmd.style.borderTopRightRadius = width;
            cmd.style.borderTopLeftRadius = width;
            cmd.style.borderBottomRightRadius = width;
        }
        else
            cmd.style.borderRightColor = Color.clear;
    }
}

I am desperately seeking advice on why my Column of Buttons isn’t clickable or hoverable in Layer 1.

Thank you for any thoughts you might have.

Rosco-y

There is probably a invisible visual element with picking mode set. As this happen in the editor, you should be able to open up the UITK debugger (window->UI Toolkit->Debugger) and use the “pick element” function when you are not able to select the element to see what element is considered “on top”.

If picking does not work, you could go through the hierarchy element by element starting from the bottom, as the element that come after in the list are on top of the previous one. If you don’t need to receive any event on the element that covers the item, there will be no side effect of setting picking mode= ignore on it. The setting is not propagated to children that would need to receive the events.

Don’t hesitate to ask any follow-up questions. The first time going through this can be surprising.

1 Like

Mixing inline styles with styles coming from style sheets will be confusing, once a style is set from code, it will always override the one coming in from your style sheet. Consider defining states in your stylesheet then using these to swap styles: AddToClassList/RemoveFromClassList/EnableInClassList/ToggleInClassList.

I also recommend reading about the selector specificity rules here:

1 Like

I tried to use the UI Toolkit Debugger to find VisualElements used as Containers that had their pickingMode = position.
I found that nearly all, if not all of them had their pickingMode = position, and in Edit mode I toggled them to ignore.

I thought I saw some success because when I initially tried hovering over my buttons, the VisualElement that contained them seemed to get picked a lot (it flashed a lot.)

After Setting that VisualElement’s pickingMode to ignore, the Buttons seem to get picked when I hover over them in the editor. However, I’m not seeing any improvement at RunTime.:

https://www.youtube.com/watch?v=bMUJLHVokx8

Additionally, when you toggle a property in the debugger and hit Ctl+S to save, is that supposed to save the changed properties?

Thank you very much!

Rosco-y

My hypothesis is that you just changed the value in the debugger. The debugger modify only the in-memory representation of the UI that get generated from the underlying asset and code. The changes will not persist: just entering and leaving play-mode will probably revert to the old behavior and values. You will have to change your source asset so that it is reflected in the player. That is also where the recommendation from Mathieu would apply.

There is no way to save what is changed through the debugger.

1 Like

Thanks!

I renamed my VisualEmements in the UI Builder, and modified the source:

  VisualElement[] _visualElements; // Visual Elements used as containers.
private void OnEnable()
{
    _visualElements = new VisualElement[VIELEMENTS + 1];
    _root = GetComponent<UIDocument>().rootVisualElement;


        /*******************************************************************************
         * I just added this for loop to set the VisualElement's pickingMode = Ignore.
         *******************************************************************************/
        for (int i = 1; i <= VIELEMENTS; i++)
        {
            _visualElements[i] = _root.Q<VisualElement>($"vi{i}");
            _visualElements[i].pickingMode = PickingMode.Ignore;
        }

Unfortunately, I’m still seeing no change in functionality.

I’ll work on Mathieu’s recommendation for awhile

fingers crossed (wound up in a knot, actually)

Rosco-y

Mathieu,

Thank you very much for your input.

I think this is the only case where I’m modifying my styles in code:

 /// <summary>
    /// highlight currently selected value (for setting of
    /// UserValues and Candidates.) by giving it a thick, yellow
    /// border.
    /// </summary>
    private void highlightSelectedValue(Button cmd)
    {
        for (int i = 1; i < g.PSIZE + 1; i++)
        {
            setBorderWidths(_userChoiceButtons[i], 0);
        }
        setBorderWidths(cmd, 15);
    }
    /// <summary>
    /// Set Passed Button's border width and color.
    /// to highlight currently selected Value for setting of user
    /// values to holes and candidates.
    /// </summary>
    ///
    /// <param name="cmd"></param>
    /// <param name="width"></param>
    private void setBorderWidths(Button cmd, int width)
    {
        cmd.style.borderBottomWidth = width;
        cmd.style.borderTopWidth = width;
        cmd.style.borderLeftWidth = width;
        cmd.style.borderRightWidth = width;
        if (width > 0)
        {
            cmd.style.borderRightColor = Color.yellow;
            cmd.style.borderTopColor = Color.yellow;
            cmd.style.borderBottomColor = Color.yellow;
            cmd.style.borderLeftColor = Color.yellow;
            cmd.style.borderBottomLeftRadius = width;
            cmd.style.borderTopRightRadius = width;
            cmd.style.borderTopLeftRadius = width;
            cmd.style.borderBottomRightRadius = width;
        }
        else
            cmd.style.borderRightColor = Color.clear;
    }

Are you recommending I stop using highlightSelectedValue() and replace it with one of your recommended UNITY Supplied methods: AddToClassList/RemoveFromClassList/EnableInClassList/ToggleInClassList ?

If so, which of these methods would be your natural choice?

Thank You Again

Rosco-y

NOTE: highlightSelectedValue does approximately what my Button:hover Style does.

Mathieu:

Thank you for your reply–I’m struggling to understand the notion of “VisualElement ClassLists”, (specifically, “What are they?”) can you please point me to some documentation that clears this up?

In the scripting API I searched for “VisualElement ClassList” and this is what I got:

9917565--1433889--ClassList.png

Thank you for any help you can give!

Rosco-y

Classes as in USS styles. Something you add or remove via code with VisualElement.AddToClassList: Unity - Scripting API: UIElements.VisualElement.AddToClassList or the opposite.

It has to do the styles you outline in USS styles: Unity - Manual: Introduction to USS It’s how you add or remove them via code.

Thank You!

I mocked up a scene with the exact same UIDocument, and the UI works perfectly–it seems I’m doing something behind the scenes (pardon the pun) that is breaking my UI. For the life of me I can’t understand how I’m breaking it, but at least I have a theory to chase.

Thanks again,

Rosco-y

I’m now following your recommendation entirely I have a Button_Focus class in my styles:

.Button_Focus {
    border-left-color: rgb(255, 244, 0);
    border-right-color: rgb(255, 244, 0);
    border-top-color: rgb(255, 244, 0);
    border-bottom-color: rgb(255, 244, 0);
    border-top-width: 15px;
    border-right-width: 15px;
    border-bottom-width: 15px;
    border-left-width: 15px;
    border-top-left-radius: 15px;
    border-top-right-radius: 15px;
    border-bottom-right-radius: 15px;
    border-bottom-left-radius: 15px;
}

And I’m using VisualElement.EnableInClassList() to use this class:

 /// <summary>
   /// highlight currently selected value (for setting of
   /// UserValues and Candidates.) by giving it a thick, yellow
   /// border.
   /// </summary>
   private void highlightSelectedValue(Button cmd)
   {
       int selectedValue = int.Parse(cmd.name.Substring((cmd.name.Length - 1)));
       for (int i = 1; i < g.PSIZE + 1; i++)
       {
           _selectedValueButtons[i].EnableInClassList("Button_Focus", i == selectedValue);
       }
   }

I’ve walked through my sources to ensure that I’m no longer setting my styles in code, except to reference
my StyleSheet class in the above manner. Can you suggest other things I can try?

Thank you,
rosco-y