Dismiss PopupMenu when focus changes

How can I dissmiss all active menus when a user clicks away from the plugin GUI? As far as I can tell there is no callback that is recieved that allows me to determine that the focus has changed or that a click occured outside of the plugin window. Without this check users can move the plugin window after a menu has been clicked and the menu doesn't move with he plugin window or get dismissed!

For now I have it that i reguarly call getScreenPosition() in the editor to check if the editors window has been moved, if it has I call PopupMenu::dismissAllActiveMenus. However that is hardly an ideal solution and I've noticed Cytomic plugins have managed to solve this issue and they are using JUCE.

Alternatively it would be nice to have a wrapper class that allows the use of OS context menus.

Previously reported.

https://forum.juce.com/t/combobox-modalcallbackfunction

I have a modified PopupMenu and ComboBox class which work… but Jules wouldn’t be happy with my implementation.

Rail

Thank you for the reply.

At first appearence, looking at your final solution, it seems covering the edge cases Jules mentions wouldn't be too difficult. I would probably add a virtual method to ComponentPeer something like shouldDismissMenusOnFocusLoss(), have the default implementation return true and override the method for any ComponetPeer classes that it causes an issue for. I haven't actually looked into this yet so maybe there is a good reason that can't be done, or an edge case that I'm not considering.

In regards to "why it would be a good idea", is because the menus should act 'exactly' as users expect them to act, they should at the very least replicate the basic funcionality of the a system menu; In my opinion, anything else will have a negative impact on user experience.

Sorry to dig up an old thread, but we’re having trouble wrangling PopupMenu in our plugins. Is there a solution for dismissing a PopupMenu when a plugin window moves that doesn’t use a modal loop or require polling getScreenPosition()?

EDIT: polling getScreenPosition() isn’t really viable either because it doesn’t seem to update when the plugin window is being dragged.

The best solution is to set the popup as child of your plugin editor (or your main component or something) :
menu.showMenu (PopupMenu::Options().withParentComponent (&guthzPluginEditor))

edit: ah, note that it won’t dismiss the popup when you move the window, instead the popup will move with it. I think it’s a fine behaviour but perhaps not what you want?

Thanks! That’s interesting. Moving with the window would be just fine — basically anything that doesn’t leave a hanging popup floating in the middle of nowhere.

Would making it a child of the main component mean that it couldn’t display outside the bounds of the plugin window?

yes, the bounds would be constrained by the parent comp.
otherwise, regarding the dismiss when the window is moving I used a code like that in the past (a bit hacky, but that should work) :

void timerCallback() override
{
    if (topComp == nullptr)
        topComp = pluginEditor->getTopLevelComponent();

    if (topComp != nullptr)
    {
        if (ComponentPeer* peer = topComp->getPeer())
        {
            const Point<float> point = peer->localToGlobal (Point<float>());

            if (point != previousPoint)
            {
                 previousPoint = point;
                 PopupMenu::dismissAllActiveMenus();
            }
        }
    }
}

I really like your plugins btw.

Thanks! That’s essentially what I tried, but localToGlobal wasn’t updating while the window was being dragged. Is that what you’re seeing as well?

indeed, it’s not updating continuously while the mouse is dragged, it seems it’s updated just when the mouse movement stops.

Posting again here because some beta testers have reported this behavior to us as a bug. I was hoping it would be something no one would notice or care about, but that appears to not be the case.

Is there nothing that JUCE could do to fix the floating-in-mid-air PopupMenu issue?

1 Like

ever find a nice solution for this? timers or anything else seems bit no bueno

1 Like

I’ve been looking for a solution to this issue for almost a year now! To my knowledge, there are 3 problems with running Popup Menus asynchronously (what is recommended for plugins).

  1. As mentioned in this thread, moving the plugin window via dragging from the title bar does not dismiss open popup menus. The solution to make the popup a child of the plugin editor solves part of the problem but creates new ones when considering that it is now constrained to the bounds of the plugin editor. Displaying a large menu from a small plugin will frustrate users as they will have to scroll to find the option they want rather than seeing everything as expected.

  2. Closing the plugin while a popup menu is open does not dismiss the menu (on OSX) and causes a crash in most DAWs on both OSs. This is a major bug that should be investigated by the JUCE team because it is crashing DAWs and there is seemingly no way to handle it. I’ve tried adding “PopupMenu::dismissAllActiveMenus()” in the destructors of classes that use the popup menu and that does not help. Please let me know if you have a solution to this!

  3. Popup menus do not hide if I click somewhere off the menu that is not on the plugin or another app (ie: anywhere on the DAW itself). Since it does not hide it also means that it often gets in the way of other windows or tasks that a user may be using in the DAW. I already posted about this here: showMenuAsync() does not hide when clicked outside but received no response.

All this is to say that the behaviour of popup menus in plugins is not standard. Any reasonable user would expect that if they have a popup menu open, then clicking anywhere else on the screen will hide that popup menu. I’ve started looking into building my own popup menu dialog that takes the focus and is on top when opened, and (using focusLost()) will detect when focus is taken away and hides. However, I’m hesitant to commit to this direction because trying to build a popup menu that sizes correctly to fit in the bounds of the component and displays all submenus, icons, and other features that juce::PopupMenu has, and handles the result asynchronously sounds like such a nightmare… JUCE team, can you please take a look at fixing these issues so I don’t have to spend weeks essentially recreating your PopupMenu class to get one basic function that I need out of it… Many thanks!

3 Likes