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

Question [Unity Editor] OnGUI() update frequency very unreliable when registering mouse position

Discussion in 'Scripting' started by AbandonedCrypt, Jan 14, 2021.

  1. AbandonedCrypt

    AbandonedCrypt

    Joined:
    Apr 13, 2019
    Posts:
    69
    Hey I'm writing a few Editor scripts. Right now I am writing a custom button utility function, as to be able to have completely square, flat buttons. Works like a charm, however I am noticing, that the OnGUI() time step or update frequency seems very unreliable.

    I notice this when hovering over my button, the hover rect sometimes appears the instant i move my mouse over my custom button, but sometimes it takes up to a second or more to appear / register my mouse position.

    Code (CSharp):
    1.  
    2. public static bool FlatButton(Rect rect, Color background, Color hover)
    3. {
    4.     EditorGUI.DrawRect(rect, background);
    5.     if(rect.Contains(Event.current.mousePosition))
    6.     {
    7.         var hoverRect = new Rect(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 1);
    8.         EditorGUI.DrawRect(hoverRect, hover);
    9.         if(Event.current.type == EventType.MouseDown)
    10.         {
    11.             return true;
    12.         }
    13.     }
    14.     return false;
    15. }
    16.  
    17.  
    Is there anything i can do about it?
     
  2. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    It would be as expected that the editor script does not run as frequent as the Update0 function. Considering the inspector does serialization this would be highly inefficient.

    I would recommend using the standard built-in method under GUILayout. And create a custom GUISkin if you are trying to change the behavior of the button.

    With a little more info on what your trying to achieve I can give you some more pointers.
     
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,528
    Well I highly recommend you read through my IMGUI crash course and maybe consult it if you don't understand something. OnGUI, especially in regards to Editor windows or editor UI in general does not update at any interval. The editor generally only repaints when it decides to which is usually after an input event like a mouse down, mouse up but also after the tool tip timeout. OnGUI / OnInspectorGUI / OnSceneGUI are all event processors.

    Note that inside the editor you get MouseMove events. In EditorWindows you only get them when EditorWindow.wantsMouseMove is set to true. As you can read in the documentation, receiving a mouse move event does not automatically repaint the editor window. You have to request a repaint manually.

    Though things like a mouse hover effect is actually an optimised rendering trick by the GUIStyle itself. You may want to look into the actual style states.

    Note that your "button" violates all assumptions about normal buttons. Your button reacts on mousedown. A normal button becomes the hotcontrol at mouse down and only performs a click when a mouse up is happening on the hotcontrol. This is how almost all UI buttons in the world work. This allows the user to cancel a click by moving off the button after the mouse down.
     
  4. AbandonedCrypt

    AbandonedCrypt

    Joined:
    Apr 13, 2019
    Posts:
    69
    Lots of fiddling and solution further down.

    I'm creating a visual menu-bar for my editor window (File, Edit, Window ... yada yada) and i couldnt get a button to skin anything like it, neither fully square nor with a proper hover color.

    I will look into it again.

    Edit: I looked into it again, nothing changed. I removed the borders with the GUIStyle, so i got half a step ahead, however the hover-issue isn't solved at all. If I use the GUIStyle states and set their background (hover, onHover), then I am facing the very same issue of delayed reponse.

    Changed it to MouseUp, note that my "button functionality" was merely implemented to test for event reception.

    EDIT (detail):

    So I created a GUIStyle to get where I wanted to get without writing my own button, still the hover color is extremely delayed!

    I am using this method to initialize a number of GUIStyles, which I can then use:

    Code (CSharp):
    1. private static GUIStyle NavigationStyle(Color background, Color hover)
    2. {
    3.     var style = new GUIStyle(GUI.skin.label);
    4.  
    5.     Color[] pix1 = new Color[] { background };
    6.     Texture2D bg = new Texture2D(1, 1);
    7.     bg.SetPixels(pix1);
    8.     bg.Apply();
    9.     style.normal.background = bg;
    10.  
    11.     Color[] pix2 = new Color[] { hover };
    12.     Texture2D hv = new Texture2D(1, 1);
    13.     hv.SetPixels(pix2);
    14.     hv.Apply();
    15.     style.hover.background = hv;
    16.  
    17.     style.alignment = TextAnchor.MiddleCenter;
    18.     style.margin = new RectOffset(0, 0, 0, 0);
    19.  
    20.     return style;
    21. }
    22.  
    Edit 2:

    And after fiddling some more I finally got a working solution that is performant enough for me to ship it with eventually. I am now checking if the cursor is in the rough vicinity of the buttons and only if so force a repaint.

    Since the buttons are located in the menu-bar on the very top of my window, I am doing this check:

    Code (CSharp):
    1. var rect = new Rect(0, 0, position.width, 50);
    2. if(rect.Contains(Event.current.mousePosition))
    3. {
    4.     Repaint();
    5. }
    6.  
    So the editor will only force a repaint if the cursor is within the top 50 pixels of the editor window, where it won't be for 98% of the target work flow
     
    Last edited: Jan 15, 2021
  5. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    I have a feeling unity overrides some of the GUIStyle properties. I was in a similar situation, this was the best I came up with. Im using the minButton style, but there is also a toolbar style you may like, personally I was not a fan and it took a fair but of fiddle to get a nice border.

    Here are a few lines from the last editor script I wrote...
    Give it a try, maybe something like this can work for you. The buttons use icons instead of text, but you can easily change to suit your needs.

    Each button changes the state of an enum, and you can use the enum to filter what content to display.

    Code (CSharp):
    1. private const float toobarButtonHeight = 30;
    2. Vector2 toolbarScrollPosition = Vector2.zero;
    3. private Color toolbarButtonSelectedColour = new Color(0.47f, 0.75f, 1.0f);
    4. private Color defaultBackgroundColour = default;
    5. public enum EditorViewModes { Runtime, Agent, Gizmos, Events, API }
    6. private GUIContent labelButtonRuntime, labelAgentSettings, labelGizmos, labelEvents, labelAPI = default;
    7.  
    8.  
    9. private void OnEnable()
    10. {
    11.     defaultBackgroundColour = GUI.backgroundColor;
    12.  
    13.     labelButtonRuntime = new GUIContent(Resources.Load<Texture>("rts-agent-toolkit-play-icon"), "Runtime Info / Commands");
    14.     labelAgentSettings = new GUIContent(Resources.Load<Texture>("rts-agent-toolkit-agent-icon"), "Nav Agent Settings");
    15.     labelGizmos = new GUIContent(Resources.Load<Texture>("rts-agent-toolkit-brush-icon"), "Gizmos");
    16.     labelAPI = new GUIContent(Resources.Load<Texture>("rts-agent-toolkit-api-icon"), "Nav Agent API");
    17.     labelEvents = new GUIContent(Resources.Load<Texture>("rts-agent-toolkit-event-icon"), "Scripted Events");
    18. }
    19.  
    20. public override void OnInspectorGUI()
    21. {
    22.     GUIStyle toolbarButtonLeft = new GUIStyle(EditorStyles.miniButtonLeft);
    23.     GUIStyle toolbarButtonMidle = new GUIStyle(EditorStyles.miniButtonMid);
    24.     GUIStyle toolbarButtonRight = new GUIStyle(EditorStyles.miniButtonRight);
    25.     toolbarButtonLeft.fixedHeight = toobarButtonHeight;
    26.     toolbarButtonMidle.fixedHeight = toobarButtonHeight;
    27.     toolbarButtonRight.fixedHeight = toobarButtonHeight;
    28.  
    29.  
    30.     toolbarScrollPosition = GUILayout.BeginScrollView(toolbarScrollPosition);
    31.     {
    32.         GUILayout.BeginHorizontal();
    33.         {
    34.             GUI.backgroundColor = (EditorViewMode == EditorViewModes.Runtime) ? toolbarButtonSelectedColour : defaultBackgroundColour;
    35.             if (GUILayout.Button(labelButtonRuntime, toolbarButtonLeft))
    36.             {
    37.                 EditorViewMode = EditorViewModes.Runtime;
    38.             }
    39.             GUI.backgroundColor = (EditorViewMode == EditorViewModes.Agent) ? toolbarButtonSelectedColour : defaultBackgroundColour;
    40.             if (GUILayout.Button(labelAgentSettings, toolbarButtonMidle))
    41.             {
    42.                 EditorViewMode = EditorViewModes.Agent;
    43.             }
    44.             GUI.backgroundColor = (EditorViewMode == EditorViewModes.Events) ? toolbarButtonSelectedColour : defaultBackgroundColour;
    45.             if (GUILayout.Button(labelEvents, toolbarButtonMidle))
    46.             {
    47.                 EditorViewMode = EditorViewModes.Events;
    48.             }
    49.             GUI.backgroundColor = (EditorViewMode == EditorViewModes.Gizmos) ? toolbarButtonSelectedColour : defaultBackgroundColour;
    50.             if (GUILayout.Button(labelGizmos, toolbarButtonMidle))
    51.             {
    52.                 EditorViewMode = EditorViewModes.Gizmos;
    53.             }
    54.             GUI.backgroundColor = (EditorViewMode == EditorViewModes.API) ? toolbarButtonSelectedColour : defaultBackgroundColour;
    55.             if (GUILayout.Button(labelAPI, toolbarButtonRight))
    56.             {
    57.                 EditorViewMode = EditorViewModes.API;
    58.             }
    59.             GUI.backgroundColor = defaultBackgroundColour;
    60.         }
    61.         GUILayout.EndHorizontal();
    62.     }
    63.     GUILayout.EndScrollView();
    64. }
    65.  
     
    Last edited: Jan 18, 2021