[BUG] AudioDeviceSelectorComponent and general ListBox paint() problem

JUCE 8.0.4, testing on MacOS

  1. The AudioDeviceSelectorComponent does not display the “no MIDI inputs” message when there are no MIDI Inputs. It is supposed to display the message “(No MIDI inputs available)”, but instead the box is blank.

You can see this in the DemoRunner > AudioSettings Demo, by running it with No MIDI Devices connected to the computer.

This is what it is supposed to look like:

  1. This may not seem like a big deal, but the larger issue here is that NOTHING you do in an override of the ListBox::paint() method will actually be shown because the Viewport’s paint() method erases it immediately (if the ListView::backgroundColourId is opaque). Details:

The ‘noItemsMessage’ is supposed to be painted in the ListBox::paint() override for AudioDeviceSelectorComponent::MidiInputSelectorComponentListBox:

class AudioDeviceSelectorComponent::MidiInputSelectorComponentListBox final : public ListBox,
                                                                              private ListBoxModel
{
    void paint (Graphics& g) override
    {
        ListBox::paint (g);

        if (items.isEmpty())
        {
            g.setColour (Colours::grey);
            g.setFont (0.5f * (float) getRowHeight());
            g.drawText (noItemsMessage,
                        0, 0, getWidth(), getHeight() / 2,
                        Justification::centred, true);
        }
    }

But what happens is whatever is drawn by this paint method is immediately erased by the paint() method of the ListBox’s ViewPort, which happens after it:

class ListBox::ListViewport final : public Viewport,
                                    private Timer
{
    void paint (Graphics& g) override
    {
         if (isOpaque())
            g.fillAll (owner.findColour (ListBox::backgroundColourId));
    }

The ViewPort is set to be opaque based on whether the ListBox::backgroundColourID is opaque, as handled by ListBox::colourChanged() below. Commenting out the second line, I recompiled the DemoRunner and it shows the correct second image above.

void ListBox::colourChanged()
{
    setOpaque (findColour (backgroundColourId).isOpaque());
//    viewport->setOpaque (isOpaque());
    repaint();
}

You can also workaround this by specifying a color for ListBox::backGroundColourId that is a tiny bit transparent, i.e. 0xfeffffff, but that’s a kluge.

I discovered this while implementing my own MIDI Port Manager, using code based on the ListBox in the AudioDeviceSelectorComponent. I don’t understand why the ViewPort is painting anything period. Or if it needs to paint, why it happens after the ListBox::paint().