They don't get the repaint call when windows overlap the plugin, or when the host is minimized and restored.
This is confirmed in v3.02 with no modifications.
To test I made a couple of adjustments to JuceDemoPlugin
PluginEditor.h
/*
==============================================================================
This file was auto-generated by the Jucer!
It contains the basic startup code for a Juce application.
==============================================================================
*/
#ifndef __PLUGINEDITOR_H_4ACCBAA__
#define __PLUGINEDITOR_H_4ACCBAA__
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
class OpenGLTestComp;
//==============================================================================
/** This is the editor component that our filter will display.
*/
class JuceDemoPluginAudioProcessorEditor : public AudioProcessorEditor,
public SliderListener,
public Timer
{
public:
JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor* ownerFilter);
~JuceDemoPluginAudioProcessorEditor();
//==============================================================================
void timerCallback() override;
void paint (Graphics&) override;
void resized() override;
void sliderValueChanged (Slider*) override;
private:
MidiKeyboardComponent midiKeyboard;
Label infoLabel, gainLabel, delayLabel;
Slider gainSlider, delaySlider;
ScopedPointer<ResizableCornerComponent> resizer;
ComponentBoundsConstrainer resizeLimits;
ScopedPointer<OpenGLTestComp> oglComp;
AudioPlayHead::CurrentPositionInfo lastDisplayedPosition;
JuceDemoPluginAudioProcessor* getProcessor() const
{
return static_cast <JuceDemoPluginAudioProcessor*> (getAudioProcessor());
}
void displayPositionInfo (const AudioPlayHead::CurrentPositionInfo& pos);
};
#endif // __PLUGINEDITOR_H_4ACCBAA__
PluginEditor.cpp
/*
==============================================================================
This file was auto-generated by the Jucer!
It contains the basic startup code for a Juce application.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
class OpenGLTestComp : public OpenGLRenderer, public Component
{
public:
OpenGLTestComp()
{
if(! context.isAttached())
{
context.setRenderer(this);
context.setComponentPaintingEnabled(false);
context.attachTo(*this);
}
}
~OpenGLTestComp()
{
context.detach();
}
void openGLContextClosing()
{
}
void renderOpenGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.f, 0.f, 0.f);
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(getWidth() / 2, 0);
glVertex2f(getWidth() / 2, getHeight());
glVertex2f(0, getHeight());
glEnd();
}
void newOpenGLContextCreated()
{
}
private:
OpenGLContext context;
};
//==============================================================================
JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor* ownerFilter)
: AudioProcessorEditor (ownerFilter),
midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard),
infoLabel (String::empty),
gainLabel ("", "Throughput level:"),
delayLabel ("", "Delay:"),
gainSlider ("gain"),
delaySlider ("delay")
{
// add some sliders..
addAndMakeVisible (&gainSlider);
gainSlider.setSliderStyle (Slider::Rotary);
gainSlider.addListener (this);
gainSlider.setRange (0.0, 1.0, 0.01);
addAndMakeVisible (&delaySlider);
delaySlider.setSliderStyle (Slider::Rotary);
delaySlider.addListener (this);
delaySlider.setRange (0.0, 1.0, 0.01);
// add some labels for the sliders..
gainLabel.attachToComponent (&gainSlider, false);
gainLabel.setFont (Font (11.0f));
delayLabel.attachToComponent (&delaySlider, false);
delayLabel.setFont (Font (11.0f));
// add the midi keyboard component..
addAndMakeVisible (&midiKeyboard);
addAndMakeVisible(oglComp = new OpenGLTestComp());
// add a label that will display the current timecode and status..
addAndMakeVisible (&infoLabel);
infoLabel.setColour (Label::textColourId, Colours::blue);
// add the triangular resizer component for the bottom-right of the UI
addAndMakeVisible (resizer = new ResizableCornerComponent (this, &resizeLimits));
resizeLimits.setSizeLimits (150, 150, 800, 300);
// set our component's initial size to be the last one that was stored in the filter's settings
setSize (ownerFilter->lastUIWidth,
ownerFilter->lastUIHeight);
startTimer (50);
}
JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor()
{
}
//==============================================================================
void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g)
{
g.setGradientFill (ColourGradient (Colours::white, 0, 0,
Colours::grey, 0, (float) getHeight(), false));
g.fillAll();
}
void JuceDemoPluginAudioProcessorEditor::resized()
{/*
infoLabel.setBounds (10, 4, 400, 25);
gainSlider.setBounds (20, 60, 150, 40);
delaySlider.setBounds (200, 60, 150, 40);
const int keyboardHeight = 70;
midiKeyboard.setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight);
resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16);*/
oglComp->setBounds(getLocalBounds().reduced(20, 20));
getProcessor()->lastUIWidth = getWidth();
getProcessor()->lastUIHeight = getHeight();
}
//==============================================================================
// This timer periodically checks whether any of the filter's parameters have changed...
void JuceDemoPluginAudioProcessorEditor::timerCallback()
{
JuceDemoPluginAudioProcessor* ourProcessor = getProcessor();
AudioPlayHead::CurrentPositionInfo newPos (ourProcessor->lastPosInfo);
if (lastDisplayedPosition != newPos)
displayPositionInfo (newPos);
gainSlider.setValue (ourProcessor->gain, dontSendNotification);
delaySlider.setValue (ourProcessor->delay, dontSendNotification);
}
// This is our Slider::Listener callback, when the user drags a slider.
void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider)
{
if (slider == &gainSlider)
{
// It's vital to use setParameterNotifyingHost to change any parameters that are automatable
// by the host, rather than just modifying them directly, otherwise the host won't know
// that they've changed.
getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::gainParam,
(float) gainSlider.getValue());
}
else if (slider == &delaySlider)
{
getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::delayParam,
(float) delaySlider.getValue());
}
}
//==============================================================================
// quick-and-dirty function to format a timecode string
static const String timeToTimecodeString (const double seconds)
{
const double absSecs = fabs (seconds);
const int hours = (int) (absSecs / (60.0 * 60.0));
const int mins = ((int) (absSecs / 60.0)) % 60;
const int secs = ((int) absSecs) % 60;
String s (seconds < 0 ? "-" : "");
s << String (hours).paddedLeft ('0', 2) << ":"
<< String (mins) .paddedLeft ('0', 2) << ":"
<< String (secs) .paddedLeft ('0', 2) << ":"
<< String (roundToInt (absSecs * 1000) % 1000).paddedLeft ('0', 3);
return s;
}
// quick-and-dirty function to format a bars/beats string
static const String ppqToBarsBeatsString (double ppq, double /*lastBarPPQ*/, int numerator, int denominator)
{
if (numerator == 0 || denominator == 0)
return "1|1|0";
const int ppqPerBar = (numerator * 4 / denominator);
const double beats = (fmod (ppq, ppqPerBar) / ppqPerBar) * numerator;
const int bar = ((int) ppq) / ppqPerBar + 1;
const int beat = ((int) beats) + 1;
const int ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5));
String s;
s << bar << '|' << beat << '|' << ticks;
return s;
}
// Updates the text in our position label.
void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHead::CurrentPositionInfo& pos)
{
lastDisplayedPosition = pos;
String displayText;
displayText.preallocateBytes (128);
displayText << String (pos.bpm, 2) << " bpm, "
<< pos.timeSigNumerator << '/' << pos.timeSigDenominator
<< " - " << timeToTimecodeString (pos.timeInSeconds)
<< " - " << ppqToBarsBeatsString (pos.ppqPosition, pos.ppqPositionOfLastBarStart,
pos.timeSigNumerator, pos.timeSigDenominator);
if (pos.isRecording)
displayText << " (recording)";
else if (pos.isPlaying)
displayText << " (playing)";
infoLabel.setText (displayText, dontSendNotification);
}
