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 How to create a dropdown menu for an overlay toolbar

Discussion in 'UI Toolkit' started by CiroContns, Jul 22, 2023.

  1. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    74
    Hey all, I've been trying to create a dropdown menu to include in an Overlay toolbar. The dropdown is meant to be showing a bitmask, so the user can enable/disable a bunch of categories.

    I've tried using
    EditorToolbarDropdown
    , but I can't figure out how to create a dropdown for it using UI Toolkit. The example here shows using
    GenericMenu
    , which could be ok, but I need a more specific bitmask dropdown and I don't want to build it myself.
    Is it even possible to have a dropdown using UI Toolkit, and how to position it correctly so it's right under the dropdown?

    I've tried using UI Toolkit's
    MaskField
    . That kind of gives me what I want, except that it seems to be made for Inspectors, rather than Overlays. It's too horizontal, and when visualised in a vertical toolbar, it makes it too wide.
    I found out how to hide the label (using
    this[0][0].style.display = DisplayStyle.None;
    ), but in doing so, when the dropdown opens, the elements within are cut.

    Screenshot 2023-07-22 alle 23.00.39.png

    Can I apply a style only to the dropdown, to make it larger? Or even better, to become as wide as the widest element in it?
    That would be my preferred solution.

    So yeah, one of the two, preferably the second so I can just piggyback on the MaskField class, which does what I need. If anyone has a pointer...

    Thanks!
     
  2. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    74
  3. KillHour

    KillHour

    Joined:
    Oct 25, 2015
    Posts:
    47
    I actually ran into a similar problem, so this thread is timely. I'm using a PopupField inside an element that has a scale applied to it. When the scale is the default, the popup looks fine.

    Popup1.PNG

    But if the containing element is scaled, the popup field is sized to the new dropdown object but the contents aren't scaled - so they overflow the container and can't be read.

    Popup2.PNG

    Because the callback that generates the menu is marked as internal, there's no way to change this behavior and it makes popup fields useless in any context that could be scaled.

    The core issue is bigger than just this one element. Way too much functionality is hidden behind internal fields and classes that can't be overridden. It would be relatively simple to override that callback to implement some custom scaling logic, but instead I'm forced to reinvent the wheel with a whole new dropdown system from scratch. I don't understand why a UI framework that is supposed to be composable and flexible is locked down to make it impossible to derive custom child classes for any built-in functionality. Even worse, all of the code is under the reference license, so I can't even fork the package or duplicate the parent class inside my own assembly.
     
    CiroContns likes this.
  4. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,281
    CiroContns likes this.
  5. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    74
    Oh that's great to hear! In that case, I'd just style the dropdown button and let the dropdown open to its full width. Fingers crossed.

    Sadly it doesn't solve @KillHour's scale issue - but I think that one is also a bug? Maybe needs to be reported.
     
  6. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    74
    Been going crazy about this! I tried to trick the system by artificially making the perceived box larger, by forcing the width of the dropdown itself to something bigger, then setting its margin negative and padding to something big to account for it... nothing.
    The dropdown's width will always adjust to the element's width...

    Also tried the way of attaching to an event (like
    RegisterCallback<ClickEvent>(OnClick);
    ) to temproarily make the width bigger, let the dropdown open, and force the width back to its original value. This seems to work - maybe, but I can't seem to intercept the right event.
     
  7. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    At this point, wouldn't it be easier to make your own menu with GenericMenu. You don't even have to create your own custom element for this if you don't want to; you could just intercept PointerDownEvent/KeyboardDownEvent on the TrickleDown phase, Stop Immediate Propagation, PreventDefault , and show your generic menu. You can use the DropDown method with the worldBound property of your element to show it right bellow the element.

    EDIT
    About the event, I think the events you need to intercept are PointerDownEvent, and KeydownEvent. Changing the width just for an instant can be very glitchy, though.
     
    CiroContns likes this.
  8. CiroContns

    CiroContns

    Unity Legend

    Joined:
    Jan 28, 2008
    Posts:
    74
    I never replied! But thanks a lot for the details answer, Oscar.
    I ended up recreating a dropdown using GenericMenu. It feels very clunky (you need to rebuild the list EVERY TIME), but it works!

    Screenshot 2023-08-03 alle 16.52.53.png

    Also pretty annoying that every time you click on an item, the list closes. But I don't think there's a way to prevent that.
     
    oscarAbraham likes this.
  9. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Glad you were able to make it work! :)

    :/ Yeah... That's a bad thing about GenericMenu.

    If you want a workaround for this workaround, you could use a UnityEditor.PopupWindow with a custom PopupWindowContent. I think this only works with IMGUI, and the code is a bit verbose, but it's doable. You create a child class of PopupWindowContent. There you override GetWindowSize where you calculate the height and width of your popup manually. Then you override OnGUI; it may seem like you can't use GUILayout because it receives a Rect as a parameter, but you can use it. You can use a GUI.Toggle or GUILayout.Toggle call for each entry in your menu. Then, when the field is clicked, you call PopupWindow.Show with the worldbound of your field and instance of your custom Content class.

    Or you could create a custom EditorWindow class and use EditorWindow.ShowAsDropdown. You pass the worldbound of your field and the desired size for the window. With this approach, you can use UIToolkit to do it. UIToolkit requires a bit more code to implement this because you'd need to handle binding and updating each toggle you add for each entry in the menu, but it's doable.

    To be honest, I'm not sure how much this is worth the trouble. I'd say part of it depends on how long Unity will take to fix this, but I bet you have a much better idea than me about that.

    I wish you luck with this. I know a good amount of using UITK for Editor stuff, so if you get stuck with something related to it, feel free to send me a direct message in the forums (sometimes I miss threads in the forums). I love what you did with the Community Projects and then with Gigaya; it was helpful for me at the time.
     
    Last edited: Aug 7, 2023