Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Prevent clicking on a pre-existing button

Discussion in 'Immediate Mode GUI (IMGUI)' started by CiroContns, Apr 8, 2024.

  1. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    136
    Hey all. I want to prevent clicks on a pre-existing piece of UI I have no control on (specifically, on the Overrides dropdown that is in the Prefab's inspector).

    Screenshot 2024-04-08 alle 00.00.36.png

    The Inspector is in IMGUI.

    I have found a way to draw things in it (see blue box above). I also found the rect of the dropdown.

    However, how do I ensure that when you click on the blue box (or whatever I draw there), the Overrides dropdown doesn't open? I need to stop clicks from going through.

    PS: I have no control over that UI, so I can't use
    GUI.enabled = false;


    Thanks.
     
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    553
    I haven't used IMGUI for ages and currently I can't test it, but an idea, try it and ignore it if it doesn't work. :)
    So what I would try is this:
    - in theory you should get OnGUI event when the user hit the icon: https://docs.unity3d.com/ScriptReference/Event.html Although it is possible that it is per
    MonoBehaviour
    , so it won't happen when other inspectors run...
    - The
    Event.current
    should carry information about that click, find out how to identify it (if you get event about it)
    - Then call the Use() method on it, so it (in theory) doesn't get used by other systems

    Again, I have no idea if it is a working solution or not, just an idea to be tested because currently I can't.
     
    CiroContns likes this.
  3. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,399
    I mean, if you're on anything beyond, what was it, 2021 or 2022(?), then there is some UI Toolkit involved:

    upload_2024-4-8_20-23-43.png

    (Sorry for the large image)

    I believe you can use reflection to get the internal Inspector EditorWindow, and then you could possibly prevent Event propagation through these means as well.
     
  4. OlivierUbi

    OlivierUbi

    Joined:
    Nov 30, 2020
    Posts:
    3
    This is not very pretty but it's working:

    Code (CSharp):
    1. using System;
    2. using System.Reflection;
    3. using UnityEditor;
    4. using UnityEngine;
    5. using Object = UnityEngine.Object;
    6.  
    7. public static class PreventPrefabOverrideWindow
    8. {
    9.     [InitializeOnLoadMethod]
    10.     public static void DrawFilterHeader()
    11.     {
    12.         Editor.finishedDefaultHeaderGUI -= DrawInspectorHeader;
    13.         Editor.finishedDefaultHeaderGUI += DrawInspectorHeader;
    14.     }
    15.  
    16.     private static Type s_prefabOverrideWindowType = Type.GetType("UnityEditor.PrefabOverridesWindow,UnityEditor");
    17.     private static FieldInfo s_windowContentField = typeof(PopupWindow).GetField("m_WindowContent", BindingFlags.Instance | BindingFlags.NonPublic);
    18.  
    19.     private static void DrawInspectorHeader(Editor _obj)
    20.     {
    21.         Object[] popupWindows = Resources.FindObjectsOfTypeAll(typeof (PopupWindow));
    22.         foreach(Object popupWindowAsObject in popupWindows)
    23.         {
    24.             PopupWindow popupWindow = popupWindowAsObject as PopupWindow;
    25.             if (s_windowContentField.GetValue(popupWindow).GetType() == s_prefabOverrideWindowType)
    26.                 popupWindow.Close();
    27.         }
    28.     }
    29. }
    30.  
    Add a headerGUI to catch when a PrefabOverridesWindow is opened and close it instantly.
     
    CiroContns and spiney199 like this.
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,355
    GameObjectInspector is the one drawing the button, specifically in DoPrefabButtons. I can't spot anything in there that's cleverer or cleaner than what @OlivierUbi is suggesting. If you were able to temporarily set m_ButtonStates to not have the CanShowOverrides flag, you could prevent the button from showing up entirely, but even if you fall back to doing that for reflection, I don't quite know what entry point you would use for that.

    It could be, though I'm not sure, that if you draw your blue box on top of the dropdown you want to block, and eat input events (by having it be a button), you might prevent the click from propagating, so it's at least worth trying. You might have to do the pixel offsets manually and then hope real hard that the button position doesn't move :p


    If this was implemented in UITK instead of inside an IMGUIContainer, you could just Q for the dropdown and set it's click handler in like three lines of code, without any need for reflection or digging through the source code. UITK is so good at allowing you to just hack stuff.
     
  6. OlivierUbi

    OlivierUbi

    Joined:
    Nov 30, 2020
    Posts:
    3
    I've already try it and the event is used(eaten) by GameObjectInspector before you could execute any code.

    UITK is a good idea but i'm not an expert.
     
    CiroContns likes this.
  7. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    136
    This worked like a charm!! Thanks!

    I will offer in return my monstruosity of a code to replicate a button that is the same size and position as the Overrides dropdown, which I draw as disabled on top of the dropdown so it communicates to the user that is not clickable :D

    Screenshot 2024-04-08 alle 23.32.18.png

    With this code the button should resize correctly even if the Inspector is stretched. At least in Unity 2022.3.

    Code (CSharp):
    1. // Draw the overlaid button
    2. float currentView = EditorGUIUtility.currentViewWidth;
    3. GUILayout.BeginArea(new Rect(66f, 87f, currentView - 66f - 4f, EditorGUIUtility.singleLineHeight));
    4. GUILayout.BeginHorizontal();
    5.  
    6. GUI.enabled = false;
    7. Color prevContentColor = GUI.contentColor;
    8.  
    9. // Draw the Overrides dropdown button, semi-transparent
    10. GUI.contentColor = Color.clear;
    11. GUILayout.Button("Overridesn");
    12.  
    13. // Draw the other two buttons but invisible
    14. Color prevColor = GUI.color;
    15. Color prevColorBg = GUI.backgroundColor;
    16. GUI.color = Color.clear;
    17. GUI.backgroundColor = Color.clear;
    18.  
    19. GUILayout.Button("",GUILayout.MaxWidth(27), GUILayout.MinWidth(4));
    20. GUILayout.Button(EditorGUIUtility.TrTextContent("Select"), EditorStyles.miniButton);
    21. GUILayout.Button(EditorGUIUtility.TrTextContent("Open"), EditorStyles.miniButton);
    22. GUILayout.EndHorizontal();
    23. GUILayout.EndArea();
    24.  
    25. GUI.enabled = true;
    26. GUI.color = prevColor;
    27. GUI.backgroundColor = prevColorBg;
    28. GUI.contentColor = prevContentColor;
    It can go right after the code to close the dropdown.

    I know there is a cleaner way to create a semi-transparent element than just disabling the GUI, but I couldn't be bothered :D

    And yes, it's not typo... "Overridesn" as text makes a button that is exactly the length of the Overrides Dropdown!
     
    BrunoMikoski, pahe, Baste and 2 others like this.
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,355
    I bet you didn't think this would be one of the hardest part when you sat down to write Black Box, did you?
     
    CiroContns likes this.
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,399
    The amusing part of all this is that there was at least half a dozen ways to accomplish the task at hand.

    Not sure what that says about Unity.
     
  10. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    136
    It's a bit messy, but honestly... that is quite flexible? I'm not sure how many software have this deep level of being able to get your hands dirty and not just add new tools, but override such a fundamental piece as the Game object header. Maybe Blender? (I'm not sure how other game engines fare in this respect)

    Hehe no. But also, when I started the plugin it was all about hiding and locking.

    But it feels like the most powerful aspect of it is revealing "just a little", which brings up the question of how to lock again what you have revealed. That, indeed, is damn hard!
     
    spiney199 likes this.