@@ -13,32 +13,38 @@ | |||
//============================================================================== | |||
JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor* ownerFilter) | |||
: AudioProcessorEditor (ownerFilter) | |||
: AudioProcessorEditor (ownerFilter), | |||
midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard), | |||
infoLabel (String::empty), | |||
gainLabel ("", "Throughput level:"), | |||
delayLabel ("", "Delay:"), | |||
gainSlider ("gain"), | |||
delaySlider ("delay") | |||
{ | |||
addAndMakeVisible (gainSlider = new Slider ("gain")); | |||
gainSlider->setSliderStyle (Slider::Rotary); | |||
gainSlider->addListener (this); | |||
gainSlider->setRange (0.0, 1.0, 0.01); | |||
Label* l = new Label ("", "Throughput level:"); | |||
l->attachToComponent (gainSlider, false); | |||
l->setFont (Font (11.0f)); | |||
addAndMakeVisible (delaySlider = new Slider ("delay")); | |||
delaySlider->setSliderStyle (Slider::Rotary); | |||
delaySlider->addListener (this); | |||
delaySlider->setRange (0.0, 1.0, 0.01); | |||
l = new Label ("", "Delay:"); | |||
l->attachToComponent (delaySlider, false); | |||
l->setFont (Font (11.0f)); | |||
// create and add the midi keyboard component.. | |||
addAndMakeVisible (midiKeyboard | |||
= new MidiKeyboardComponent (ownerFilter->keyboardState, | |||
MidiKeyboardComponent::horizontalKeyboard)); | |||
// 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); | |||
// add a label that will display the current timecode and status.. | |||
addAndMakeVisible (infoLabel = new Label (String::empty, String::empty)); | |||
infoLabel->setColour (Label::textColourId, Colours::blue); | |||
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)); | |||
@@ -53,7 +59,6 @@ JuceDemoPluginAudioProcessorEditor::JuceDemoPluginAudioProcessorEditor (JuceDemo | |||
JuceDemoPluginAudioProcessorEditor::~JuceDemoPluginAudioProcessorEditor() | |||
{ | |||
deleteAllChildren(); | |||
} | |||
//============================================================================== | |||
@@ -65,12 +70,12 @@ void JuceDemoPluginAudioProcessorEditor::paint (Graphics& g) | |||
void JuceDemoPluginAudioProcessorEditor::resized() | |||
{ | |||
infoLabel->setBounds (10, 4, 400, 25); | |||
gainSlider->setBounds (20, 60, 150, 40); | |||
delaySlider->setBounds (200, 60, 150, 40); | |||
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); | |||
midiKeyboard.setBounds (4, getHeight() - keyboardHeight - 4, getWidth() - 8, keyboardHeight); | |||
resizer->setBounds (getWidth() - 16, getHeight() - 16, 16, 16); | |||
@@ -89,25 +94,25 @@ void JuceDemoPluginAudioProcessorEditor::timerCallback() | |||
if (lastDisplayedPosition != newPos) | |||
displayPositionInfo (newPos); | |||
gainSlider->setValue (ourProcessor->gain, false); | |||
delaySlider->setValue (ourProcessor->delay, false); | |||
gainSlider.setValue (ourProcessor->gain, false); | |||
delaySlider.setValue (ourProcessor->delay, false); | |||
} | |||
// This is our Slider::Listener callback, when the user drags a slider. | |||
void JuceDemoPluginAudioProcessorEditor::sliderValueChanged (Slider* slider) | |||
{ | |||
if (slider == gainSlider) | |||
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()); | |||
(float) gainSlider.getValue()); | |||
} | |||
else if (slider == delaySlider) | |||
else if (slider == &delaySlider) | |||
{ | |||
getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::delayParam, | |||
(float) delaySlider->getValue()); | |||
(float) delaySlider.getValue()); | |||
} | |||
} | |||
@@ -169,5 +174,5 @@ void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHea | |||
else if (pos.isPlaying) | |||
displayText << " (playing)"; | |||
infoLabel->setText (displayText, false); | |||
infoLabel.setText (displayText, false); | |||
} |
@@ -34,11 +34,11 @@ public: | |||
void sliderValueChanged (Slider*); | |||
private: | |||
MidiKeyboardComponent* midiKeyboard; | |||
Label* infoLabel; | |||
Slider* gainSlider; | |||
Slider* delaySlider; | |||
ResizableCornerComponent* resizer; | |||
MidiKeyboardComponent midiKeyboard; | |||
Label infoLabel, gainLabel, delayLabel; | |||
Slider gainSlider; | |||
Slider delaySlider; | |||
ScopedPointer<ResizableCornerComponent> resizer; | |||
ComponentBoundsConstrainer resizeLimits; | |||
AudioPlayHead::CurrentPositionInfo lastDisplayedPosition; | |||
@@ -21988,6 +21988,12 @@ struct AudioThumbnail::MinMaxValue | |||
return maxValue > minValue; | |||
} | |||
inline int getPeak() const throw() | |||
{ | |||
return jmax (std::abs ((int) minValue), | |||
std::abs ((int) maxValue)); | |||
} | |||
inline void read (InputStream& input) | |||
{ | |||
minValue = input.readByte(); | |||
@@ -22186,6 +22192,7 @@ class AudioThumbnail::ThumbData | |||
{ | |||
public: | |||
ThumbData (const int numThumbSamples) | |||
: peakLevel (-1) | |||
{ | |||
ensureSize (numThumbSamples); | |||
} | |||
@@ -22232,6 +22239,8 @@ public: | |||
void write (const MinMaxValue* const source, const int startIndex, const int numValues) | |||
{ | |||
resetPeak(); | |||
if (startIndex + numValues > data.size()) | |||
ensureSize (startIndex + numValues); | |||
@@ -22241,8 +22250,29 @@ public: | |||
dest[i] = source[i]; | |||
} | |||
void resetPeak() | |||
{ | |||
peakLevel = -1; | |||
} | |||
int getPeak() | |||
{ | |||
if (peakLevel < 0) | |||
{ | |||
for (int i = 0; i < data.size(); ++i) | |||
{ | |||
const int peak = data[i].getPeak(); | |||
if (peak > peakLevel) | |||
peakLevel = peak; | |||
} | |||
} | |||
return peakLevel; | |||
} | |||
private: | |||
Array <MinMaxValue> data; | |||
int peakLevel; | |||
void ensureSize (const int thumbSamples) | |||
{ | |||
@@ -22619,6 +22649,16 @@ bool AudioThumbnail::isFullyLoaded() const throw() | |||
return numSamplesFinished >= totalSamples - samplesPerThumbSample; | |||
} | |||
float AudioThumbnail::getApproximatePeak() const | |||
{ | |||
int peak = 0; | |||
for (int i = channels.size(); --i >= 0;) | |||
peak = jmax (peak, channels.getUnchecked(i)->getPeak()); | |||
return jlimit (0, 127, peak) / 127.0f; | |||
} | |||
void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | |||
double endTime, int channelNum, float verticalZoomFactor) | |||
{ | |||
@@ -36682,10 +36722,10 @@ public: | |||
: graph (graph_), | |||
orderedNodes (orderedNodes_) | |||
{ | |||
nodeIds.add (zeroNodeID); // first buffer is read-only zeros | |||
nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros | |||
channels.add (0); | |||
midiNodeIds.add (zeroNodeID); | |||
midiNodeIds.add ((uint32) zeroNodeID); | |||
for (int i = 0; i < orderedNodes.size(); ++i) | |||
{ | |||
@@ -36969,7 +37009,7 @@ private: | |||
if (midiNodeIds.getUnchecked(i) == freeNodeID) | |||
return i; | |||
midiNodeIds.add (freeNodeID); | |||
midiNodeIds.add ((uint32) freeNodeID); | |||
return midiNodeIds.size() - 1; | |||
} | |||
else | |||
@@ -36978,7 +37018,7 @@ private: | |||
if (nodeIds.getUnchecked(i) == freeNodeID) | |||
return i; | |||
nodeIds.add (freeNodeID); | |||
nodeIds.add ((uint32) freeNodeID); | |||
channels.add (0); | |||
return nodeIds.size() - 1; | |||
} | |||
@@ -37018,7 +37058,7 @@ private: | |||
nodeIds.getUnchecked(i), | |||
channels.getUnchecked(i))) | |||
{ | |||
nodeIds.set (i, freeNodeID); | |||
nodeIds.set (i, (uint32) freeNodeID); | |||
} | |||
} | |||
@@ -37029,7 +37069,7 @@ private: | |||
midiNodeIds.getUnchecked(i), | |||
AudioProcessorGraph::midiChannelIndex)) | |||
{ | |||
midiNodeIds.set (i, freeNodeID); | |||
midiNodeIds.set (i, (uint32) freeNodeID); | |||
} | |||
} | |||
} | |||
@@ -40198,8 +40238,7 @@ void Component::setVisible (bool shouldBeVisible) | |||
if (! shouldBeVisible) | |||
{ | |||
if (currentlyFocusedComponent == this | |||
|| isParentOf (currentlyFocusedComponent)) | |||
if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) | |||
{ | |||
if (parentComponent_ != 0) | |||
parentComponent_->grabKeyboardFocus(); | |||
@@ -41074,32 +41113,18 @@ Component* Component::removeChildComponent (const int index) | |||
childComponentList_.remove (index); | |||
child->parentComponent_ = 0; | |||
if (childShowing) | |||
// (NB: there are obscure situations where a childShowing = false, but it still has the focus) | |||
if (currentlyFocusedComponent == child || child->isParentOf (currentlyFocusedComponent)) | |||
{ | |||
JUCE_TRY | |||
{ | |||
if ((currentlyFocusedComponent == child) | |||
|| child->isParentOf (currentlyFocusedComponent)) | |||
{ | |||
// get rid first to force the grabKeyboardFocus to change to us. | |||
giveAwayFocus(); | |||
grabKeyboardFocus(); | |||
} | |||
} | |||
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
catch (const std::exception& e) | |||
{ | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); | |||
} | |||
catch (...) | |||
{ | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); | |||
} | |||
#endif | |||
SafePointer<Component> thisPointer (this); | |||
giveAwayFocus(); | |||
if (thisPointer == 0) | |||
return child; | |||
if (childShowing) | |||
grabKeyboardFocus(); | |||
} | |||
child->internalHierarchyChanged(); | |||
@@ -42545,14 +42570,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() | |||
void Component::giveAwayFocus() | |||
{ | |||
// use a copy so we can clear the value before the call | |||
SafePointer<Component> componentLosingFocus (currentlyFocusedComponent); | |||
Component* const componentLosingFocus = currentlyFocusedComponent; | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
if (componentLosingFocus != 0) | |||
componentLosingFocus->internalFocusLoss (focusChangedDirectly); | |||
Desktop::getInstance().triggerFocusCallback(); | |||
} | |||
bool Component::isMouseOver (const bool includeChildren) const | |||
@@ -64,7 +64,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 1 | |||
#define JUCE_MINOR_VERSION 52 | |||
#define JUCE_BUILDNUMBER 105 | |||
#define JUCE_BUILDNUMBER 106 | |||
/** Current Juce version number. | |||
@@ -28178,9 +28178,9 @@ private: | |||
bool isDisabledFlag : 1; | |||
bool childCompFocusedFlag : 1; | |||
bool dontClipGraphicsFlag : 1; | |||
#if JUCE_DEBUG | |||
#if JUCE_DEBUG | |||
bool isInsidePaintCall : 1; | |||
#endif | |||
#endif | |||
}; | |||
union | |||
@@ -29126,18 +29126,19 @@ private: | |||
class InternalTimerThread; | |||
/** | |||
Repeatedly calls a user-defined method at a specified time interval. | |||
Makes repeated callbacks to a virtual method at a specified time interval. | |||
A Timer's timerCallback() method will be repeatedly called at a given | |||
interval. Initially when a Timer object is created, they will do nothing | |||
until the startTimer() method is called, then the message thread will | |||
start calling it back until stopTimer() is called. | |||
interval. When you create a Timer object, it will do nothing until the | |||
startTimer() method is called, which will cause the message thread to | |||
start making callbacks at the specified interval, until stopTimer() is called | |||
or the object is deleted. | |||
The time interval isn't guaranteed to be precise to any more than maybe | |||
10-20ms, and the intervals may end up being much longer than requested if the | |||
system is busy. Because it's the message thread that is doing the callbacks, | |||
any messages that take a significant amount of time to process will block | |||
all the timers for that period. | |||
system is busy. Because the callbacks are made by the main message thread, | |||
anything that blocks the message queue for a period of time will also prevent | |||
any timers from running until it can carry on. | |||
If you need to have a single callback that is shared by multiple timers with | |||
different frequencies, then the MultiTimer class allows you to do that - its | |||
@@ -32741,6 +32742,12 @@ public: | |||
/** Returns true if the low res preview is fully generated. */ | |||
bool isFullyLoaded() const throw(); | |||
/** Returns the highest level in the thumbnail. | |||
Note that because the thumb only stores low-resolution data, this isn't | |||
an accurate representation of the highest value, it's only a rough approximation. | |||
*/ | |||
float getApproximatePeak() const; | |||
/** Returns the hash code that was set by setSource() or setReader(). */ | |||
int64 getHashCode() const; | |||
@@ -62,6 +62,12 @@ struct AudioThumbnail::MinMaxValue | |||
return maxValue > minValue; | |||
} | |||
inline int getPeak() const throw() | |||
{ | |||
return jmax (std::abs ((int) minValue), | |||
std::abs ((int) maxValue)); | |||
} | |||
inline void read (InputStream& input) | |||
{ | |||
minValue = input.readByte(); | |||
@@ -262,6 +268,7 @@ class AudioThumbnail::ThumbData | |||
{ | |||
public: | |||
ThumbData (const int numThumbSamples) | |||
: peakLevel (-1) | |||
{ | |||
ensureSize (numThumbSamples); | |||
} | |||
@@ -308,6 +315,8 @@ public: | |||
void write (const MinMaxValue* const source, const int startIndex, const int numValues) | |||
{ | |||
resetPeak(); | |||
if (startIndex + numValues > data.size()) | |||
ensureSize (startIndex + numValues); | |||
@@ -317,8 +326,29 @@ public: | |||
dest[i] = source[i]; | |||
} | |||
void resetPeak() | |||
{ | |||
peakLevel = -1; | |||
} | |||
int getPeak() | |||
{ | |||
if (peakLevel < 0) | |||
{ | |||
for (int i = 0; i < data.size(); ++i) | |||
{ | |||
const int peak = data[i].getPeak(); | |||
if (peak > peakLevel) | |||
peakLevel = peak; | |||
} | |||
} | |||
return peakLevel; | |||
} | |||
private: | |||
Array <MinMaxValue> data; | |||
int peakLevel; | |||
void ensureSize (const int thumbSamples) | |||
{ | |||
@@ -700,6 +730,16 @@ bool AudioThumbnail::isFullyLoaded() const throw() | |||
return numSamplesFinished >= totalSamples - samplesPerThumbSample; | |||
} | |||
float AudioThumbnail::getApproximatePeak() const | |||
{ | |||
int peak = 0; | |||
for (int i = channels.size(); --i >= 0;) | |||
peak = jmax (peak, channels.getUnchecked(i)->getPeak()); | |||
return jlimit (0, 127, peak) / 127.0f; | |||
} | |||
void AudioThumbnail::drawChannel (Graphics& g, const Rectangle<int>& area, double startTime, | |||
double endTime, int channelNum, float verticalZoomFactor) | |||
{ | |||
@@ -177,6 +177,12 @@ public: | |||
/** Returns true if the low res preview is fully generated. */ | |||
bool isFullyLoaded() const throw(); | |||
/** Returns the highest level in the thumbnail. | |||
Note that because the thumb only stores low-resolution data, this isn't | |||
an accurate representation of the highest value, it's only a rough approximation. | |||
*/ | |||
float getApproximatePeak() const; | |||
/** Returns the hash code that was set by setSource() or setReader(). */ | |||
int64 getHashCode() const; | |||
@@ -546,10 +546,10 @@ public: | |||
: graph (graph_), | |||
orderedNodes (orderedNodes_) | |||
{ | |||
nodeIds.add (zeroNodeID); // first buffer is read-only zeros | |||
nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros | |||
channels.add (0); | |||
midiNodeIds.add (zeroNodeID); | |||
midiNodeIds.add ((uint32) zeroNodeID); | |||
for (int i = 0; i < orderedNodes.size(); ++i) | |||
{ | |||
@@ -835,7 +835,7 @@ private: | |||
if (midiNodeIds.getUnchecked(i) == freeNodeID) | |||
return i; | |||
midiNodeIds.add (freeNodeID); | |||
midiNodeIds.add ((uint32) freeNodeID); | |||
return midiNodeIds.size() - 1; | |||
} | |||
else | |||
@@ -844,7 +844,7 @@ private: | |||
if (nodeIds.getUnchecked(i) == freeNodeID) | |||
return i; | |||
nodeIds.add (freeNodeID); | |||
nodeIds.add ((uint32) freeNodeID); | |||
channels.add (0); | |||
return nodeIds.size() - 1; | |||
} | |||
@@ -884,7 +884,7 @@ private: | |||
nodeIds.getUnchecked(i), | |||
channels.getUnchecked(i))) | |||
{ | |||
nodeIds.set (i, freeNodeID); | |||
nodeIds.set (i, (uint32) freeNodeID); | |||
} | |||
} | |||
@@ -895,7 +895,7 @@ private: | |||
midiNodeIds.getUnchecked(i), | |||
AudioProcessorGraph::midiChannelIndex)) | |||
{ | |||
midiNodeIds.set (i, freeNodeID); | |||
midiNodeIds.set (i, (uint32) freeNodeID); | |||
} | |||
} | |||
} | |||
@@ -33,7 +33,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 1 | |||
#define JUCE_MINOR_VERSION 52 | |||
#define JUCE_BUILDNUMBER 105 | |||
#define JUCE_BUILDNUMBER 106 | |||
/** Current Juce version number. | |||
@@ -31,18 +31,19 @@ class InternalTimerThread; | |||
//============================================================================== | |||
/** | |||
Repeatedly calls a user-defined method at a specified time interval. | |||
Makes repeated callbacks to a virtual method at a specified time interval. | |||
A Timer's timerCallback() method will be repeatedly called at a given | |||
interval. Initially when a Timer object is created, they will do nothing | |||
until the startTimer() method is called, then the message thread will | |||
start calling it back until stopTimer() is called. | |||
interval. When you create a Timer object, it will do nothing until the | |||
startTimer() method is called, which will cause the message thread to | |||
start making callbacks at the specified interval, until stopTimer() is called | |||
or the object is deleted. | |||
The time interval isn't guaranteed to be precise to any more than maybe | |||
10-20ms, and the intervals may end up being much longer than requested if the | |||
system is busy. Because it's the message thread that is doing the callbacks, | |||
any messages that take a significant amount of time to process will block | |||
all the timers for that period. | |||
system is busy. Because the callbacks are made by the main message thread, | |||
anything that blocks the message queue for a period of time will also prevent | |||
any timers from running until it can carry on. | |||
If you need to have a single callback that is shared by multiple timers with | |||
different frequencies, then the MultiTimer class allows you to do that - its | |||
@@ -470,8 +470,7 @@ void Component::setVisible (bool shouldBeVisible) | |||
if (! shouldBeVisible) | |||
{ | |||
if (currentlyFocusedComponent == this | |||
|| isParentOf (currentlyFocusedComponent)) | |||
if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) | |||
{ | |||
if (parentComponent_ != 0) | |||
parentComponent_->grabKeyboardFocus(); | |||
@@ -1358,32 +1357,18 @@ Component* Component::removeChildComponent (const int index) | |||
childComponentList_.remove (index); | |||
child->parentComponent_ = 0; | |||
if (childShowing) | |||
// (NB: there are obscure situations where a childShowing = false, but it still has the focus) | |||
if (currentlyFocusedComponent == child || child->isParentOf (currentlyFocusedComponent)) | |||
{ | |||
JUCE_TRY | |||
{ | |||
if ((currentlyFocusedComponent == child) | |||
|| child->isParentOf (currentlyFocusedComponent)) | |||
{ | |||
// get rid first to force the grabKeyboardFocus to change to us. | |||
giveAwayFocus(); | |||
grabKeyboardFocus(); | |||
} | |||
} | |||
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
catch (const std::exception& e) | |||
{ | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); | |||
} | |||
catch (...) | |||
{ | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); | |||
} | |||
#endif | |||
SafePointer<Component> thisPointer (this); | |||
giveAwayFocus(); | |||
if (thisPointer == 0) | |||
return child; | |||
if (childShowing) | |||
grabKeyboardFocus(); | |||
} | |||
child->internalHierarchyChanged(); | |||
@@ -2854,14 +2839,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() | |||
void Component::giveAwayFocus() | |||
{ | |||
// use a copy so we can clear the value before the call | |||
SafePointer<Component> componentLosingFocus (currentlyFocusedComponent); | |||
Component* const componentLosingFocus = currentlyFocusedComponent; | |||
currentlyFocusedComponent = 0; | |||
Desktop::getInstance().triggerFocusCallback(); | |||
if (componentLosingFocus != 0) | |||
componentLosingFocus->internalFocusLoss (focusChangedDirectly); | |||
Desktop::getInstance().triggerFocusCallback(); | |||
} | |||
//============================================================================== | |||
@@ -2171,9 +2171,9 @@ private: | |||
bool isDisabledFlag : 1; | |||
bool childCompFocusedFlag : 1; | |||
bool dontClipGraphicsFlag : 1; | |||
#if JUCE_DEBUG | |||
#if JUCE_DEBUG | |||
bool isInsidePaintCall : 1; | |||
#endif | |||
#endif | |||
}; | |||
union | |||