Search Unity

Question UIToolkit Event blocked by IMGUIContainer

Discussion in 'UI Toolkit' started by suxiaodong, Mar 9, 2023.

  1. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    Hi, if I want to add a keyboard short-cut for my custom Editor Window, I will write codes like:
    Code (CSharp):
    1. rootVisualElement.focusable = true;
    2. rootVisualElement.RegisterCallback<KeyDownEvent>(evt =>
    3. {
    4.     // check evt.KeyCode and do something
    5. });
    But it does not work in below case.
    - I have a IMGUIContainer to draw something in my window, which take some area.
    - When I click in the area first, then I can't receive KeyDownEvent anymore until I click in other area in window.

    What should I do to make my short-cut work correctly?
    And I don't want to reference the child element of type IMGUIContainer from root element, bacause there would be more than one or many.

    Thanks!
     
  2. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I'd try passing TrickleDown.TrickleDown as the second parameter to RegisterCallback. That will make your callback receive the KeyDownEvent before IMGUIContainer has a chance to process it.
     
  3. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    upload_2023-3-10_11-40-54.png
    Code (CSharp):
    1. IMGUIContainer imguiContainer = new IMGUIContainer(() =>
    2. {
    3.     GUILayout.Label("IMGUIArea", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
    4.  
    5.     if (Event.current.type == EventType.KeyDown)
    6.     {
    7.         Debug.Log("IMGUIArea " + Event.current.keyCode);
    8.     }
    9. });
    10. imguiContainer.RegisterCallback<KeyDownEvent>(evt =>
    11. {
    12.     Debug.Log("IMGUI KeyDownEvent " + evt.keyCode);
    13. });
    14.  
    15. rootVisualElement.focusable = true;
    16. rootVisualElement.pickingMode = PickingMode.Position;
    17. rootVisualElement.RegisterCallback<KeyDownEvent>(evt =>
    18. {
    19.     Debug.Log("Root KeyDownEvent " + evt.keyCode);
    20. }, TrickleDown.TrickleDown);
    Thanks for your reply! I have tried that way and it doesn't work.

    The only way I found now is to set the pickingMode of IMGUIContainer to PickingMode.Ignore, but then the "IMGUIArea event" turn to missing, which is not what I want.

     
  4. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    What confusing me is there is not an "evt.Use()" or "evt.StopPropagation()" at anywhere, seems like the event just pass to the IMGUIContainer itself , rather than the VisualElement Tree.
     
  5. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Hm, that does sound weird. How does your VisualElement hierarchy look?
     
  6. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    It's quite simple. The test window only did “rootVisualElement.Add(imguiContainer)”
    upload_2023-3-14_15-5-4.png
     
  7. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    It looks quite simple. I'm not sure what's going on. Keyboard events typically target the focused element, which should trigger a callback in the root element when using TrickleDown. I imagine there's a problem when IMGUIContainers are the target of a keyboard event, as they are not technically the focused element, but something inside them.

    I could offer some ideas for a workaround if you tell us more about your use case. For example, Unity has a very powerful system for defining keyboard shortcuts; you could use the ShortcutAttribute with your window's type as the context to define shortcuts that only work in your window.
     
  8. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    Sorry for my latency replay. I's not sure if I got you, Is that what you mean?
    Code (CSharp):
    1. [Shortcut("MyWindow/Save", typeof(MyWindow), KeyCode.S, ShortcutModifiers.Ctrl)]
    2.         private static void OnShortCut(ShortcutArguments arguments)
    3.         {
    4.             if (arguments.context is MyWindow)
    5.             {
    6.                 //something
    7.             }
    8.         }
    But there is a conflict shown :
    upload_2023-3-16_18-33-12.png

    What I want to do at the beginning is customize my saving process. To save temporary data edited by the user as a set of target data.

    Thanks again!
     
  9. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    No problem; happy to help :). That was what I meant, but your desired shortcut collides with one already defined by Unity.

    Some questions: What kind of data are you saving? Where are you currently saving it? How temporary is this data?
     
  10. suxiaodong

    suxiaodong

    Joined:
    Jul 26, 2019
    Posts:
    6
    In my case, there would be 3 steps
    - Read asset file and make a copy of that.
    - Make some pre modifications this copy to make the data from runtime friendly to edit friendly
    - Only when you click "save" button in MyWindow, the original asset would be modified with data changes and post-modifications

    So I can't just use normal save. The asset has related with others. And I want to make sure the asset is correctly for runtime use, so it's not like a "configure - save" but a "configure - compile"