Component setOpaque and setAlpha

Painting doesn’t work correctly if setOpaque(true) and a parent component has setAlpha (0.5f) set. There is a check here:

if (child.isOpaque() && child.componentTransparency == 0)
{
    g.excludeClipRegion (newClip + delta);
    wasClipped = true;
}

But this test is not enough, you can’t just test if the component has an alpha of 0, you need to go up the component hierarchy and make sure all the parents are alpha 0 as well.

I believe it should be fixed like this: reFX: Fix drawing of opaque components · reFX/JUCE@6302f18 · GitHub

1 Like

I think I have a simple repro where you can see the effects of this - it’s an inner frame with setOpaque (true) inside an outer frame with both setOpaque (false) and setAlpha < 1.0f.

Toggling the outer frame opacity will often result in cached artifacts, e.g:
image

Here’s the code:

#include <juce_gui_extra/juce_gui_extra.h>
#include <functional>

class MainComponent   : public juce::Component
{
public:
    MainComponent()
    {
        setSize (200, 300);

        addAndMakeVisible (&outer);
        outer.setColour (juce::Colours::white);
        outer.setOpaque (false); // we're going to toggle the alpha of this

        outer.addAndMakeVisible (&inner);
        inner.setColour (juce::Colours::yellow);
        inner.setOpaque (true); // this will always be full alpha

        addAndMakeVisible (&button);
        button.setButtonText ("press");

        mouseListener.listenTo (button);
        mouseListener.setMouseDown (
            [this]()
            {
                float newAlpha = outer.getAlpha() == 1.0f ? 0.5f : 1.0f;
                outer.setAlpha (newAlpha);
            });
    }

    void paint (juce::Graphics& g) override
    {
        g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
    }

    void resized() override
    {
        outer.setBounds ({50, 50, 100, 100});
        inner.setBounds ({25, 0, 50, 100});
        button.setBounds ({50, 200, 100, 50});
    }

private:
    //==============================================================================
    class Block : public juce::Component
    {
    public:
        void setColour (juce::Colour c) { colour = c; }

    private:
        void paint (juce::Graphics& g) override { g.fillAll (colour); }
        juce::Colour colour;
    };

    class MouseListener : public juce::MouseListener
    {
    public:
        MouseListener() {}
        void listenTo (juce::Component& c) { c.addMouseListener (this, false); }
        void setMouseDown (std::function<void()> onDown) { onMouseDown = onDown; }
        void mouseDown (const juce::MouseEvent&) override { onMouseDown(); }

    private:
        std::function<void()> onMouseDown;
    };

    Block outer;
    Block inner;
    juce::TextButton button;
    MouseListener mouseListener;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

In practice this means you can’t use setOpaque (true) on any component if you can’t be sure the entire hierarchy is also opaque. Is this correct?

1 Like

Here is the latest fix for the issue: reFX: Fix drawing of opaque components · reFX/JUCE@6302f18 · GitHub

Changes to juce broke my previous fix. Any chance of getting this integrated into mainline juce?

2 Likes

Any chance of someone from the JUCE team taking a look and advising whether they can repro and if so, if it’s something they consider worth fixing?

It would help to know to if we need to avoid these situations totally.

Thanks!

Any chance of getting any kind of feedback from the JUCE team on this, even if it’s just to say it’s not a priority to fix?

Thanks,

Steve.

1 Like

This is on our radar, but there won’t be any related changes in the next point release.

Thanks for the response Reuben. When it bubbles up, let me know if there’s anything I can do to help.

@anthony-nicholls would you expect this to be fixed in Component: Improve opaque component checks · juce-framework/JUCE@961ff32 · GitHub ?

I just had a merge conflict updating my juce branch, so I removed my changes. I tested the program by @unlinked1 and I’m not seeing the issue.

Yes I came across this issue while doing the changes, I think there is a unit test in Component that captures this now too.

1 Like