[FR] KnownPluginList::addToMenu() enhancement

Currently the menu is built but there’s no way to set the tick mark next to the current plugin.

Here are the changes needed to accomplish this:

In juce_KnownPluginList.h

    //==============================================================================
    /** Adds all the plugin types to a popup menu so that the user can select one.

        Depending on the sort method, it may add sub-menus for categories,
        manufacturers, etc.

        Use getIndexChosenByMenu() to find out the type that was chosen.
    */
    void addToMenu (PopupMenu& menu, SortMethod sortMethod, String identifierString = String()) const;

In the implementation file juce_KnownPluginList.cpp

//==============================================================================
void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod, String identifierString) const
{
    ScopedPointer<PluginTree> tree (createTree (sortMethod));
    PluginTreeUtils::addToMenu (*tree, menu, types, identifierString);
}
    static bool addToMenu (const KnownPluginList::PluginTree& tree, PopupMenu& m, const OwnedArray <PluginDescription>& allPlugins, String identifierString = String())
    {
        bool isTicked = false;
    
        for (int i = 0; i < tree.subFolders.size(); ++i)
        {
            const KnownPluginList::PluginTree& sub = *tree.subFolders.getUnchecked(i);

            PopupMenu subMenu;
            isTicked = addToMenu (sub, subMenu, allPlugins, identifierString);
        
            m.addSubMenu (sub.folder, subMenu, true, isTicked);
        }

        for (int i = 0; i < tree.plugins.size(); ++i)
        {
            const PluginDescription* const plugin = tree.plugins.getUnchecked(i);

            String name (plugin->name);

            if (containsDuplicateNames (tree.plugins, name))
                name << " (" << plugin->pluginFormatName << ')';
        
            const bool isItemTicked = plugin->matchesIdentifierString (identifierString);

            m.addItem (allPlugins.indexOf (plugin) + menuIdBase, name, true, isItemTicked);
        
            if (isItemTicked)
                isTicked = true;
        }
    
        return isTicked;
    }

In juce_PopupMenu.h

    void addSubMenu (const String& subMenuName,
                     const PopupMenu& subMenu,
                     bool isEnabled = true,
                     bool isTicked = false);

and in the implementation file juce_PopupMenu.cpp

void PopupMenu::addSubMenu (const String& subMenuName, const PopupMenu& subMenu, bool isActive, bool isTicked)
{
    addSubMenu (subMenuName, subMenu, isActive, nullptr, isTicked, 0);
}

This is backward compatible so won’t break any existing code.

I understand I hold no legal claim to copyright of the code or the changes to the code (or whatever other legalese you need to release you to use the mods).

Thanks,

Rail

Thanks! I’ll add something like this… (There’s no need to change the menu class BTW there are already methods that can add a ticked submenu)

Thanks Jules for the commit – unfortunately your logic for isTicked is off…

This works:

    static bool addToMenu (const KnownPluginList::PluginTree& tree, PopupMenu& m,
                           const OwnedArray<PluginDescription>& allPlugins,
                           const String& currentlyTickedPluginID)
    {
        bool isTicked = false;

        for (int i = 0; i < tree.subFolders.size(); ++i)
        {
            const KnownPluginList::PluginTree& sub = *tree.subFolders.getUnchecked(i);

            PopupMenu subMenu;
            isTicked = addToMenu (sub, subMenu, allPlugins, currentlyTickedPluginID);

            m.addSubMenu (sub.folder, subMenu, true, nullptr, isTicked, 0);
        }

        for (int i = 0; i < tree.plugins.size(); ++i)
        {
            const PluginDescription* const plugin = tree.plugins.getUnchecked(i);

            String name (plugin->name);

            if (containsDuplicateNames (tree.plugins, name))
                name << " (" << plugin->pluginFormatName << ')';

            const bool isItemTicked = plugin->matchesIdentifierString (currentlyTickedPluginID);
        
            if (isItemTicked)
                isTicked = true;

            m.addItem (allPlugins.indexOf (plugin) + menuIdBase, name, true, isItemTicked);
        }

        return isTicked;
    }

Ah, I was trying to fix your logic there, which was incorrect in the first loop, but I didn’t notice that my fix was also not quite right. What I meant was:

static bool addToMenu (const KnownPluginList::PluginTree& tree, PopupMenu& m,
                       const OwnedArray<PluginDescription>& allPlugins,
                       const String& currentlyTickedPluginID)
{
    bool isTicked = false;

    for (int i = 0; i < tree.subFolders.size(); ++i)
    {
        const KnownPluginList::PluginTree& sub = *tree.subFolders.getUnchecked(i);

        PopupMenu subMenu;
        const bool isItemTicked = addToMenu (sub, subMenu, allPlugins, currentlyTickedPluginID);
        isTicked = isTicked || isItemTicked;

        m.addSubMenu (sub.folder, subMenu, true, nullptr, isTicked, 0);
    }

    for (int i = 0; i < tree.plugins.size(); ++i)
    {
        const PluginDescription* const plugin = tree.plugins.getUnchecked(i);

        String name (plugin->name);

        if (containsDuplicateNames (tree.plugins, name))
            name << " (" << plugin->pluginFormatName << ')';

        const bool isItemTicked = plugin->matchesIdentifierString (currentlyTickedPluginID);
        isTicked = isTicked || isItemTicked;

        m.addItem (allPlugins.indexOf (plugin) + menuIdBase, name, true, isItemTicked);
    }

    return isTicked;
}

Hi Jules,

The logic in the first loop is still not right – I sent you a private message with a video

Cheers,

Rail

This’ll work:

    static bool addToMenu (const KnownPluginList::PluginTree& tree, PopupMenu& m,
                           const OwnedArray<PluginDescription>& allPlugins,
                           const String& currentlyTickedPluginID)
    {
        bool isTicked = false;

        for (int i = 0; i < tree.subFolders.size(); ++i)
        {
            const KnownPluginList::PluginTree& sub = *tree.subFolders.getUnchecked(i);
            
            PopupMenu subMenu;
            const bool isItemTicked = addToMenu (sub, subMenu, allPlugins, currentlyTickedPluginID);
            isTicked = isTicked || isItemTicked;
            
            m.addSubMenu (sub.folder, subMenu, true, nullptr, isItemTicked, 0);
        }

        for (int i = 0; i < tree.plugins.size(); ++i)
        {
            const PluginDescription* const plugin = tree.plugins.getUnchecked(i);
            
            String name (plugin->name);
            
            if (containsDuplicateNames (tree.plugins, name))
                name << " (" << plugin->pluginFormatName << ')';
            
            const bool isItemTicked = plugin->matchesIdentifierString (currentlyTickedPluginID);
            isTicked = isTicked || isItemTicked;
            
            m.addItem (allPlugins.indexOf (plugin) + menuIdBase, name, true, isItemTicked);
        }

        return isTicked;
    }

Rail

Yeah, I know - I quickly posted that second version before checking it, but already saw the mistake. Will push a correct version shortly… Thanks!