Several PopupMenu Look and feel

Hello, I would like to have different look and feel for popupmenu in the general menu bar of my app or in others widget. But I don’t understand how. Because the only way I find to change it, is to set the general look application look and feel. Is it possible ?

It could help you…

1 Like

You can call setLookAndFeel() on any component object, so if you create two LookAndFeel objects (one for the menu bar popup, and one for the widgets popup) and customise each of them, you can have two different appearances. Hope that helps!

2 Likes

As far as I know, we don’t have access to the actual PopupMenu component. It’s hidden by the PopupMenu class interface. Am I missing some getters ?

Thank you ! Reading this thread I found out that even though the PopupMenu isn’t a component, there’s a look and feel setter on it !

2 Likes

PopupMenu is indeed no Component, because it is rather a Window (but a special one, a Woundow would be a Component…)

Instead there are the PopupMenu::Options where you can get the targetComponent and pull the options (colours and lookAndFeel) from.

Unfortunately the old LookAndFeels were not updated to do so, but if you write your own LookAndFeel you get access to the PopupMenu::Options and you can do things like:

juce::Colour JuceLookAndFeel_V3::findPopupColour (int colourId, juce::Component* target)
{
    if (target)
        return target->findColour (colourId);

    return findColour (colourId);
}

And add the targetComponent whenever you need a colour in the PopupMenu:

    auto* target = options.getTargetComponent();

    g.fillAll (findPopupColour (isHighlighted ? juce::PopupMenu::highlightedBackgroundColourId
                                              : juce::PopupMenu::backgroundColourId,
                                target));

Hope that helps

2 Likes

Actually, this is the size of the items and the font size I want to change, isn’t it possible using the PopupMenu::setLookAndFeel ?

void getIdealPopupMenuItemSize(const String& text, bool isSeparator, int standardMenuItemHeight, int& idealWidth, int& idealHeight) override;

Font getPopupMenuFont() override;

Maybe I should just use CustomItem for this purpose ?

In my case i have overridden the LnF functions for the PopupMenu at global scope.
I switch between ComboBox and MenuBar inside the implementation.
It is more convenient since it is the only difference required for now in my app.

If you need to customize each widget i guess that you can define various LnF.
You could use getRootMenu / setLookAndFeel functions to do attach them.
Note that i didn’t tested that stuff.
It was the approach i wanted to try before to change my mind.

I don’t know if there is a better way.

public:
    juce::Font getPopupMenuFont() override;
    
    void drawPopupMenuBackground (juce::Graphics&, int, int) override;

    void drawPopupMenuBackgroundWithOptions (juce::Graphics&,
        int,
        int,
        const juce::PopupMenu::Options&) override;

    int getPopupMenuBorderSize() override
    {
        return 0;
    }
    
    void getIdealPopupMenuItemSize (const juce::String&,
        const bool,
        int,
        int&,
        int&) override;
    
    void drawPopupMenuItemWithOptions (juce::Graphics&,
        const juce::Rectangle<int>&,
        bool,
        const juce::PopupMenu::Item&,
        const juce::PopupMenu::Options&) override;
void LookAndFeel::drawPopupMenuItemWithOptions (juce::Graphics& g,
    const juce::Rectangle<int>& area,
    bool  isHighlighted,
    const juce::PopupMenu::Item& i,
    const juce::PopupMenu::Options& options)
{
    const bool hasSubMenu = (i.subMenu != nullptr) && (i.itemID == 0 || i.subMenu->getNumItems() > 0);
    const bool isComboBox = (dynamic_cast<juce::ComboBox*> (options.getTargetComponent()) != nullptr);

    drawPopupMenuItemProceed (g,
        area,
        i.isSeparator,
        i.isEnabled,
        isHighlighted,
        i.isTicked,
        hasSubMenu,
        isComboBox,
        i.text,
        i.shortcutKeyDescription);
}

WIP :

1 Like