| @@ -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 | |||