PopupMenu border in the LnF classes?

Hi,
I’ve trouble finding where I can hack the lookandfeel so that I can suppress the border of a PopupMenu’s panel (see screenshot below). Any idea?
All the best

PopupMenu::LookAndFeelMethods::drawPopupMenuBackground() ?

Sadly not, it does not create the border I’d like to suppress:

void LookAndFeel_V3::drawPopupMenuBackground (Graphics& g, int width, int height)
{
    g.fillAll (findColour (PopupMenu::backgroundColourId));
    ignoreUnused (width, height);

   #if ! JUCE_MAC
    g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f));
    g.drawRect (0, 0, width, height);
   #endif
}
1 Like

If this is mac and the PopupMenu is in a new Window then could this just be the drop shadow OS X creates for each window?

Yeah, hard to tell from the picture, but it sounds like the default OSX window border

Something strange is that a ComboBox’s PopupMenu has no such border but a real shadow…

OK FOUND: the difference with the ComboBox was that I used withParentComponent:

… m.showMenuAsync(PopupMenu::Options().withParentComponent(getParentComponent()) …

Removing it removes the border.

1 Like

So if the popupmenu has a parent then we can’t do anything about this border?
no way to change its colour or thickness?

Does anybody know the answer? Trying to get rid of the border on a popup menu that has a parent component

I know this is an old thread, but replying as this just stung me and the info may be useful for others.

The border size of PopupMenu can be set with PopupMenu::LookAndFeelMethods::getPopupMenuBorderSize().

However, if you have a custom LookAndFeel for your component tree a PopupMenu will not “inherit” this regardless of whether showMenuAsync() is called with PopupMenu::Options().withParentComponent() or not. This is because even when withParentComponent() is called, the PopupMenu doesn’t get added to the specified parent until its ItemComponent have been constructed and resized (which is where the border size takes effect).

So… the solutions are either:

  1. Set your custom LookAndFeel to be the default look and feel with LookAndFeel::setDefaultLookAndFeel()
  2. Explicitly set the PopupMenu to use your custom LookAndFeel prior to calling showMenuAsync()
3 Likes

Sorry to revive an old thread, but this appears to be talking about the same thing as the issue I am experiencing.

I have an issue with Popup menus that some kind of phantom box shows up in the menu ONLY when I use PopupMenu::Options().withParentComponent(...)

withParentComponent: (note subtle line around the ‘profile’ text)
image

Without this options call:
image

I’ve traced the apperance of this line back to a call to
MenuWindow::paintOverChildren() in juce_PopupMenu.cpp#297
which calls ResizableWindow::LookAndFeelMethods::drawResizableFrame(...) if parentComponent is not null.

Is this simply a mistake? I’m not sure why it’s calling an unrelated Component’s LookAndFeel methods or what purpose it would serve.

If it’s intentional, is there a way I can supress it and keep a decent border size around my popup?

Thanks,
Dave

I think this is deliberate, and is intended to adjust the appearance of the popup ‘window’ so that it has similar styling to other window-like things. That being said, it definitely doesn’t work well when the borders are very wide.

In this case, perhaps you could provide a custom implementation of drawResizableFrame which only paints the outer pixels of the view, regardless of the border size which is passed. e.g.

void MyLookAndFeel::drawResizableFrame (Graphics& g, int w, int h, const BorderSize<int>& border)
{
    if (border.isEmpty())
        return;

    const Rectangle<int> fullSize (0, 0, w, h);

    Graphics::ScopedSaveState ss (g);

    auto centreArea = border.subtractedFrom (fullSize);
    g.excludeClipRegion (centreArea);

    g.setColour (Colour (0x50000000));
    g.drawRect (fullSize);

    g.setColour (Colour (0x19000000));
    g.drawRect (fullSize.reduced (1));
}
3 Likes

Thanks for the response Reuk,
I see how your solution works, this is similar to the workaround I settled on. Though I would need a look and feel just for the popupmenu(s) if I wanted them to have a different border to other components with borders.

I was wondering if the draw code in PopupMenu::paintOverChildren() could be handled by a LookAndFeel method itself?
i.e. PopupMenu::paintOverChildren() calls a new method: PopupMenu::LookAndFeelMethods::drawBorderOverMenu()

As that way the look and feel can define whether it delegates to lf.drawResizableFrame or not?

Thanks again,
Dave

For those still running into issues with this, this is the part of the JUCE code that caused the issue for me:

void LookAndFeel_V2::drawPopupMenuBackground (Graphics& g, int width, int height)
{
    auto background = findColour (PopupMenu::backgroundColourId);

    g.fillAll (background);
    g.setColour (background.overlaidWith (Colour (0x2badd8e6)));

    for (int i = 0; i < height; i += 3)
        g.fillRect (0, i, width, 1);

   #if ! JUCE_MAC
    g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f));
    g.drawRect (0, 0, width, height);
   #endif
}

Making a custom LookAndFeel class and overriding drawPopupMenuBackground solved it for me :slight_smile:

Hi all,

I’m still facing the “white border” issue on iOS. I’ve tried making my own LnF just for a specific PopupMenu, and everything I do works, except from the “getPopupMenuBorderSize”, that I’ve overridden to return 0 but the border is still there.

This happens only on iOS and only for PopupMenus, not for Comboboxes (that actually use PopupMenus, strange…), on desktop the border is not visible, as I expected.

Overriding “drawPopupMenuBackground” did nothing to the border (but changed the background, so the method is actually called).

Is there something I can do to remove that border?

The part that causes the problem is this, I believe, in PopupMenu::MenuWindow::paintOverChildren():

        if (options.getParentComponent())
            lf.drawResizableFrame (g, getWidth(), getHeight(),
                                   BorderSize<int> (getLookAndFeel().getPopupMenuBorderSizeWithOptions (options)));

drawResizableFrame() does some stuff like cutting out the centreArea from the clipRegion, drawing an extra outline, etc. You could try to override that as explained in a previous response.

I ended up modifying the juce code directly (paintOverChildren), to do this instead, and now standalone popups look the same as my comboboxes:

    if (options.getParentComponent())
    {
        g.setColour(lf.findColour(ComboBox::outlineColourId));
        g.drawRect (0, 0, getWidth(), getHeight());
    }

Thank you, in the end I’ve done a mix of both solutions, overriding drawResizableFrame in a custom LnF, with inside the code you have placed directly in the JUCE codebase (basically drawing a rectangle)