| @@ -74,6 +74,11 @@ public: | |||
| ~PluginWindow() | |||
| { | |||
| if (owner.activeGenericUI == this) | |||
| owner.activeGenericUI = 0; | |||
| else | |||
| owner.activeUI = 0; | |||
| setContentComponent (0); | |||
| } | |||
| @@ -85,7 +90,6 @@ public: | |||
| void closeButtonPressed() | |||
| { | |||
| owner.activeUI = 0; | |||
| delete this; | |||
| } | |||
| @@ -100,7 +104,8 @@ FilterInGraph::FilterInGraph (FilterGraph& owner_, AudioPluginInstance* const fi | |||
| filter (filter_), | |||
| uid (0), | |||
| processedAudio (1, 1), | |||
| activeUI (0) | |||
| activeUI (0), | |||
| activeGenericUI (0) | |||
| { | |||
| lastX = 100 + Random::getSystemRandom().nextInt (400); | |||
| lastY = 100 + Random::getSystemRandom().nextInt (400); | |||
| @@ -108,6 +113,7 @@ FilterInGraph::FilterInGraph (FilterGraph& owner_, AudioPluginInstance* const fi | |||
| FilterInGraph::~FilterInGraph() | |||
| { | |||
| delete activeGenericUI; | |||
| delete activeUI; | |||
| delete filter; | |||
| } | |||
| @@ -118,21 +124,37 @@ void FilterInGraph::setPosition (double newX, double newY) throw() | |||
| y = jlimit (0.0, 1.0, newY); | |||
| } | |||
| void FilterInGraph::showUI() | |||
| void FilterInGraph::showUI (bool useGenericUI) | |||
| { | |||
| if (activeUI == 0) | |||
| if (! useGenericUI) | |||
| { | |||
| Component* ui = filter->createEditorIfNeeded(); | |||
| if (activeUI == 0) | |||
| { | |||
| Component* ui = filter->createEditorIfNeeded(); | |||
| if (ui == 0) | |||
| ui = new GenericAudioFilterEditor (filter); | |||
| if (ui == 0) | |||
| return showUI (true); | |||
| ui->setName (filter->getName()); | |||
| activeUI = new PluginWindow (ui, *this); | |||
| ui->setName (filter->getName()); | |||
| activeUI = new PluginWindow (ui, *this); | |||
| } | |||
| if (activeUI != 0) | |||
| activeUI->toFront (true); | |||
| } | |||
| else | |||
| { | |||
| if (activeGenericUI == 0) | |||
| { | |||
| Component* ui = new GenericAudioFilterEditor (filter); | |||
| ui->setName (filter->getName()); | |||
| activeGenericUI = new PluginWindow (ui, *this); | |||
| } | |||
| if (activeUI != 0) | |||
| activeUI->toFront (true); | |||
| if (activeGenericUI != 0) | |||
| activeGenericUI->toFront (true); | |||
| } | |||
| } | |||
| void FilterInGraph::prepareBuffers (int blockSize) | |||
| @@ -87,7 +87,7 @@ public: | |||
| uint32 uid; | |||
| //============================================================================== | |||
| void showUI(); | |||
| void showUI (bool useGenericUI); | |||
| double getX() const throw() { return x; } | |||
| double getY() const throw() { return y; } | |||
| @@ -111,6 +111,7 @@ private: | |||
| friend class PluginWindow; | |||
| Component* activeUI; | |||
| Component* activeGenericUI; | |||
| int lastX, lastY; | |||
| MidiBuffer outputMidi; | |||
| @@ -145,6 +145,9 @@ public: | |||
| PopupMenu m; | |||
| m.addItem (1, "Delete this filter"); | |||
| m.addItem (2, "Disconnect all pins"); | |||
| m.addSeparator(); | |||
| m.addItem (3, "Show plugin UI"); | |||
| m.addItem (4, "Show all parameters"); | |||
| const int r = m.show(); | |||
| @@ -157,6 +160,13 @@ public: | |||
| { | |||
| graph.disconnectFilter (filterID); | |||
| } | |||
| else if (r == 3 || r == 4) | |||
| { | |||
| const FilterInGraph::Ptr f (graph.getFilterForUID (filterID)); | |||
| if (f != 0) | |||
| f->showUI (r == 4); | |||
| } | |||
| } | |||
| } | |||
| @@ -189,7 +199,7 @@ public: | |||
| const FilterInGraph::Ptr f (graph.getFilterForUID (filterID)); | |||
| if (f != 0) | |||
| f->showUI(); | |||
| f->showUI (false); | |||
| } | |||
| else if (! e.mouseWasClicked()) | |||
| { | |||
| @@ -127,6 +127,8 @@ MainHostWindow::MainHostWindow() | |||
| knownPluginList.addChangeListener (this); | |||
| addKeyListener (commandManager->getKeyMappings()); | |||
| Process::setPriority (Process::HighPriority); | |||
| } | |||
| MainHostWindow::~MainHostWindow() | |||
| @@ -36,10 +36,56 @@ | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterBase.cpp" | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterEditor.cpp" | |||
| #include "juce_AudioPluginInstance.h" | |||
| //============================================================================== | |||
| #include "juce_AudioPluginInstance.h" | |||
| AudioPluginInstance::AudioPluginInstance() | |||
| { | |||
| internalAsyncUpdater = new InternalAsyncUpdater (*this); | |||
| initialiseInternal (this); | |||
| } | |||
| AudioPluginInstance::~AudioPluginInstance() | |||
| { | |||
| delete internalAsyncUpdater; | |||
| } | |||
| void AudioPluginInstance::addListener (AudioPluginParameterListener* const newListener) throw() | |||
| { | |||
| listeners.addIfNotAlreadyThere (newListener); | |||
| } | |||
| void AudioPluginInstance::removeListener (AudioPluginParameterListener* const listenerToRemove) throw() | |||
| { | |||
| listeners.removeValue (listenerToRemove); | |||
| } | |||
| void AudioPluginInstance::internalAsyncCallback() | |||
| { | |||
| changedParamLock.enter(); | |||
| Array <int> changed; | |||
| changed.swapWithArray (changedParams); | |||
| changedParamLock.exit(); | |||
| for (int j = 0; j < changed.size(); ++j) | |||
| { | |||
| const int paramIndex = changed.getUnchecked (j); | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| AudioPluginParameterListener* const l = (AudioPluginParameterListener*) listeners.getUnchecked(i); | |||
| if (paramIndex >= 0) | |||
| l->audioPluginParameterChanged (this, paramIndex); | |||
| else | |||
| l->audioPluginChanged (this); | |||
| i = jmin (i, listeners.size()); | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| bool JUCE_CALLTYPE AudioPluginInstance::getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info) | |||
| @@ -76,7 +122,34 @@ bool JUCE_CALLTYPE AudioPluginInstance::getCurrentPositionInfo (AudioFilterBase: | |||
| return true; | |||
| } | |||
| void JUCE_CALLTYPE AudioPluginInstance::informHostOfParameterChange (int /*index*/, float /*newValue*/) | |||
| void JUCE_CALLTYPE AudioPluginInstance::informHostOfParameterChange (int index, float /*newValue*/) | |||
| { | |||
| queueChangeMessage (index); | |||
| } | |||
| void JUCE_CALLTYPE AudioPluginInstance::updateHostDisplay() | |||
| { | |||
| queueChangeMessage (-1); | |||
| } | |||
| void AudioPluginInstance::queueChangeMessage (const int index) throw() | |||
| { | |||
| const ScopedLock sl (changedParamLock); | |||
| changedParams.addIfNotAlreadyThere (index); | |||
| if (! internalAsyncUpdater->isTimerRunning()) | |||
| internalAsyncUpdater->startTimer (1); | |||
| } | |||
| //============================================================================== | |||
| AudioPluginInstance::InternalAsyncUpdater::InternalAsyncUpdater (AudioPluginInstance& owner_) | |||
| : owner (owner_) | |||
| { | |||
| } | |||
| void AudioPluginInstance::InternalAsyncUpdater::timerCallback() | |||
| { | |||
| stopTimer(); | |||
| owner.internalAsyncCallback(); | |||
| } | |||
| @@ -33,6 +33,27 @@ | |||
| #define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| #include "../../../audio plugins/wrapper/juce_AudioFilterBase.h" | |||
| class AudioPluginInstance; | |||
| //============================================================================== | |||
| class AudioPluginParameterListener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~AudioPluginParameterListener() {} | |||
| //============================================================================== | |||
| /** Receives a callback when a parameter is changed. */ | |||
| virtual void audioPluginParameterChanged (AudioPluginInstance* plugin, | |||
| int parameterIndex) = 0; | |||
| /** Called to indicate that something else in the plugin has changed, like its | |||
| program, number of parameters, etc. | |||
| */ | |||
| virtual void audioPluginChanged (AudioPluginInstance* plugin) = 0; | |||
| }; | |||
| //============================================================================== | |||
| @@ -55,7 +76,7 @@ public: | |||
| Make sure that you delete any UI components that belong to this plugin before | |||
| deleting the plugin. | |||
| */ | |||
| virtual ~AudioPluginInstance() {} | |||
| virtual ~AudioPluginInstance(); | |||
| //============================================================================== | |||
| /** Returns the plugin's name. */ | |||
| @@ -109,14 +130,45 @@ public: | |||
| */ | |||
| virtual int getSamplesLatency() const = 0; | |||
| //============================================================================== | |||
| /** Adds a listener that will be called when one of this plugin's parameters changes. */ | |||
| void addListener (AudioPluginParameterListener* const newListener) throw(); | |||
| /** Removes a previously added listener. */ | |||
| void removeListener (AudioPluginParameterListener* const listenerToRemove) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| AudioPluginInstance() {} | |||
| VoidArray listeners; | |||
| CriticalSection changedParamLock; | |||
| Array <int> changedParams; | |||
| class InternalAsyncUpdater : public Timer | |||
| { | |||
| public: | |||
| InternalAsyncUpdater (AudioPluginInstance& owner); | |||
| ~InternalAsyncUpdater() {} | |||
| void timerCallback(); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| AudioPluginInstance& owner; | |||
| }; | |||
| InternalAsyncUpdater* internalAsyncUpdater; | |||
| void internalAsyncCallback(); | |||
| void queueChangeMessage (const int index) throw(); | |||
| AudioPluginInstance(); | |||
| bool JUCE_CALLTYPE getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info); | |||
| void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue); | |||
| void JUCE_CALLTYPE updateHostDisplay(); | |||
| }; | |||
| @@ -34,20 +34,24 @@ | |||
| //============================================================================== | |||
| class FilterParameterPropertyComp : public PropertyComponent | |||
| class FilterParameterPropertyComp : public PropertyComponent, | |||
| public AudioPluginParameterListener | |||
| { | |||
| public: | |||
| FilterParameterPropertyComp (AudioPluginInstance* const filter_, | |||
| FilterParameterPropertyComp (const String& name, | |||
| AudioPluginInstance* const filter_, | |||
| const int index_) | |||
| : PropertyComponent (filter_->getParameterName (index_)), | |||
| : PropertyComponent (name), | |||
| filter (filter_), | |||
| index (index_) | |||
| { | |||
| addAndMakeVisible (slider = new PluginSlider (filter_, index_)); | |||
| filter->addListener (this); | |||
| } | |||
| ~FilterParameterPropertyComp() | |||
| { | |||
| filter->removeListener (this); | |||
| deleteAllChildren(); | |||
| } | |||
| @@ -56,6 +60,16 @@ public: | |||
| slider->setValue (filter->getParameter (index), false); | |||
| } | |||
| void audioPluginChanged (AudioPluginInstance*) | |||
| { | |||
| } | |||
| void audioPluginParameterChanged (AudioPluginInstance*, int parameterIndex) | |||
| { | |||
| if (parameterIndex == index) | |||
| refresh(); | |||
| } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -76,6 +90,7 @@ private: | |||
| setRange (0.0, 1.0, 0.0); | |||
| setSliderStyle (Slider::LinearBar); | |||
| setTextBoxIsEditable (false); | |||
| setScrollWheelEnabled (false); | |||
| } | |||
| ~PluginSlider() | |||
| @@ -120,7 +135,11 @@ GenericAudioFilterEditor::GenericAudioFilterEditor (AudioPluginInstance* const f | |||
| for (int i = 0; i < numParams; ++i) | |||
| { | |||
| FilterParameterPropertyComp* const pc = new FilterParameterPropertyComp (filter, i); | |||
| String name (filter->getParameterName (i)); | |||
| if (name.trim().isEmpty()) | |||
| name = "Unnamed"; | |||
| FilterParameterPropertyComp* const pc = new FilterParameterPropertyComp (name, filter, i); | |||
| params.add (pc); | |||
| totalHeight += pc->getPreferredHeight(); | |||
| } | |||
| @@ -48,6 +48,10 @@ | |||
| #define _clearfp() | |||
| #endif | |||
| BEGIN_JUCE_NAMESPACE | |||
| extern void juce_callAnyTimersSynchronously(); | |||
| END_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| const int fxbVersionNum = 1; | |||
| @@ -288,15 +292,17 @@ public: | |||
| void close() | |||
| { | |||
| _fpreset(); // (doesn't do any harm) | |||
| if (hModule != 0) | |||
| { | |||
| try | |||
| __try | |||
| { | |||
| _fpreset(); // (doesn't do any harm) | |||
| FreeLibrary (hModule); | |||
| } | |||
| catch (...) | |||
| {} | |||
| __finally | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -612,6 +618,7 @@ VSTPluginInstance::~VSTPluginInstance() | |||
| {} | |||
| } | |||
| module = 0; | |||
| effect = 0; | |||
| } | |||
| @@ -1409,7 +1416,9 @@ AudioFilterEditor* JUCE_CALLTYPE VSTPluginInstance::createEditor() | |||
| //============================================================================== | |||
| void VSTPluginInstance::handleAsyncUpdate() | |||
| { | |||
| // called asynchronously to indicate that the plugin's parameters have changed.. | |||
| // indicates that something about the plugin has changed.. | |||
| if (callbacks != 0) | |||
| callbacks->updateHostDisplay(); | |||
| } | |||
| //============================================================================== | |||
| @@ -1786,7 +1795,8 @@ VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, Vs | |||
| switch (opcode) | |||
| { | |||
| case audioMasterAutomate: | |||
| // index = param num, opt = value | |||
| if (callbacks != 0) | |||
| callbacks->informHostOfParameterChange (index, opt); | |||
| break; | |||
| case audioMasterProcessEvents: | |||
| @@ -1807,14 +1817,24 @@ VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, Vs | |||
| break; | |||
| case audioMasterIdle: | |||
| Thread::sleep (1); | |||
| if (! isTimerRunning()) | |||
| startTimer (50); | |||
| if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread()) | |||
| { | |||
| ++insideVSTCallback; | |||
| #if JUCE_MAC | |||
| if (getActiveEditor() != 0) | |||
| dispatch (effEditIdle, 0, 0, 0, 0); | |||
| if (getActiveEditor() != 0) | |||
| dispatch (effEditIdle, 0, 0, 0, 0); | |||
| #endif | |||
| const MessageManagerLock mml; | |||
| juce_callAnyTimersSynchronously(); | |||
| handleUpdateNowIfNeeded(); | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); | |||
| --insideVSTCallback; | |||
| } | |||
| break; | |||
| case audioMasterUpdateDisplay: | |||
| @@ -845,6 +845,11 @@ protected: | |||
| SetControlValue (index + 2, floatToLong (newValue)); | |||
| } | |||
| void JUCE_CALLTYPE updateHostDisplay() | |||
| { | |||
| // xxx is there an RTAS equivalent? | |||
| } | |||
| //============================================================================== | |||
| private: | |||
| AudioFilterBase* juceFilter; | |||
| @@ -144,6 +144,10 @@ void AudioFilterStreamer::informHostOfParameterChange (int index, float newValue | |||
| } | |||
| void JUCE_CALLTYPE AudioFilterStreamer::updateHostDisplay() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| AudioFilterStreamingDeviceManager::AudioFilterStreamingDeviceManager() | |||
| @@ -73,6 +73,7 @@ public: | |||
| bool JUCE_CALLTYPE getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info); | |||
| void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue); | |||
| void JUCE_CALLTYPE updateHostDisplay(); | |||
| juce_UseDebuggingNewOperator | |||
| @@ -101,9 +101,7 @@ static uint32 lastMasterIdleCall = 0; | |||
| BEGIN_JUCE_NAMESPACE | |||
| extern void juce_callAnyTimersSynchronously(); | |||
| #if JUCE_MAC | |||
| extern void juce_macDoPendingRepaintsNow(); | |||
| #elif JUCE_LINUX | |||
| #if JUCE_LINUX | |||
| extern Display* display; | |||
| extern bool juce_postMessageToSystemQueue (void* message); | |||
| #endif | |||
| @@ -809,6 +807,11 @@ public: | |||
| setParameterAutomated (index, newValue); | |||
| } | |||
| void JUCE_CALLTYPE updateHostDisplay() | |||
| { | |||
| updateDisplay(); | |||
| } | |||
| bool canParameterBeAutomated (VstInt32 index) | |||
| { | |||
| return filter->isParameterAutomatable ((int) index); | |||
| @@ -38,8 +38,8 @@ AudioFilterBase::AudioFilterBase() | |||
| blockSize (0), | |||
| numInputChannels (0), | |||
| numOutputChannels (0), | |||
| suspended (false), | |||
| callbacks (0), | |||
| suspended (false), | |||
| activeEditor (0) | |||
| { | |||
| } | |||
| @@ -67,6 +67,12 @@ void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | |||
| setParameter (parameterIndex, newValue); | |||
| } | |||
| void JUCE_CALLTYPE AudioFilterBase::updateHostDisplay() | |||
| { | |||
| if (callbacks != 0) | |||
| callbacks->updateHostDisplay(); | |||
| } | |||
| bool AudioFilterBase::isParameterAutomatable (int /*index*/) const | |||
| { | |||
| return true; | |||
| @@ -407,6 +407,13 @@ public: | |||
| */ | |||
| virtual bool isParameterAutomatable (int index) const; | |||
| /** The filter can call this when something (apart from a parameter value) has changed. | |||
| It sends a hint to the host that something like the program, number of parameters, | |||
| etc, has changed, and that it should update itself. | |||
| */ | |||
| void JUCE_CALLTYPE updateHostDisplay(); | |||
| //============================================================================== | |||
| /** Returns the number of preset programs the filter supports. | |||
| @@ -492,6 +499,10 @@ public: | |||
| virtual ~FilterNativeCallbacks() {} | |||
| virtual bool JUCE_CALLTYPE getCurrentPositionInfo (CurrentPositionInfo& info) = 0; | |||
| virtual void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue) = 0; | |||
| /** Callback to indicate that something (other than a parameter) has changed in the | |||
| filter, such as its current program, parameter list, etc. */ | |||
| virtual void JUCE_CALLTYPE updateHostDisplay() = 0; | |||
| }; | |||
| @@ -534,6 +545,8 @@ protected: | |||
| double sampleRate; | |||
| /** @internal */ | |||
| int blockSize, numInputChannels, numOutputChannels; | |||
| /** @internal */ | |||
| FilterNativeCallbacks* callbacks; | |||
| private: | |||
| friend class JuceVSTWrapper; | |||
| @@ -546,8 +559,6 @@ private: | |||
| CriticalSection callbackLock; | |||
| bool suspended; | |||
| FilterNativeCallbacks* callbacks; | |||
| AudioFilterEditor* activeEditor; | |||
| }; | |||
| @@ -271,7 +271,7 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| if (chosen.getFileExtension().isEmpty()) | |||
| chosen = chosen.withFileExtension (fileExtension); | |||
| return saveAs (f, false, false, true); | |||
| return saveAs (chosen, false, false, true); | |||
| } | |||
| return userCancelledSave; | |||
| @@ -128,6 +128,7 @@ Slider::Slider (const String& name) | |||
| popupDisplayEnabled (false), | |||
| menuEnabled (false), | |||
| menuShown (false), | |||
| scrollWheelEnabled (true), | |||
| valueBox (0), | |||
| incButton (0), | |||
| decButton (0), | |||
| @@ -298,13 +299,13 @@ void Slider::hideTextBox (const bool discardCurrentEditorContents) | |||
| } | |||
| } | |||
| void Slider::setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease) | |||
| void Slider::setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease) throw() | |||
| { | |||
| sendChangeOnlyOnRelease = onlyNotifyOnRelease; | |||
| } | |||
| void Slider::setPopupDisplayEnabled (const bool enabled, | |||
| Component* const parentComponentToUse) | |||
| Component* const parentComponentToUse) throw() | |||
| { | |||
| popupDisplayEnabled = enabled; | |||
| parentForPopupDisplay = parentComponentToUse; | |||
| @@ -534,13 +535,13 @@ void Slider::setMaxValue (double newValue, const bool sendUpdateMessage, const b | |||
| } | |||
| void Slider::setDoubleClickReturnValue (const bool isDoubleClickEnabled, | |||
| const double valueToSetOnDoubleClick) | |||
| const double valueToSetOnDoubleClick) throw() | |||
| { | |||
| doubleClickToValue = isDoubleClickEnabled; | |||
| doubleClickReturnValue = valueToSetOnDoubleClick; | |||
| } | |||
| double Slider::getDoubleClickReturnValue (bool& isEnabled_) const | |||
| double Slider::getDoubleClickReturnValue (bool& isEnabled_) const throw() | |||
| { | |||
| isEnabled_ = doubleClickToValue; | |||
| return doubleClickReturnValue; | |||
| @@ -622,11 +623,16 @@ void Slider::enablementChanged() | |||
| repaint(); | |||
| } | |||
| void Slider::setPopupMenuEnabled (const bool menuEnabled_) | |||
| void Slider::setPopupMenuEnabled (const bool menuEnabled_) throw() | |||
| { | |||
| menuEnabled = menuEnabled_; | |||
| } | |||
| void Slider::setScrollWheelEnabled (const bool enabled) throw() | |||
| { | |||
| scrollWheelEnabled = enabled; | |||
| } | |||
| //============================================================================== | |||
| void Slider::labelTextChanged (Label* label) | |||
| { | |||
| @@ -1268,28 +1274,33 @@ void Slider::mouseDoubleClick (const MouseEvent&) | |||
| } | |||
| } | |||
| void Slider::mouseWheelMove (const MouseEvent&, float wheelIncrementX, float wheelIncrementY) | |||
| void Slider::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) | |||
| { | |||
| if (isEnabled() | |||
| && (maximum > minimum) | |||
| && ! isMouseButtonDownAnywhere()) | |||
| if (scrollWheelEnabled && isEnabled()) | |||
| { | |||
| if (valueBox != 0) | |||
| valueBox->hideEditor (false); | |||
| if (maximum > minimum && ! isMouseButtonDownAnywhere()) | |||
| { | |||
| if (valueBox != 0) | |||
| valueBox->hideEditor (false); | |||
| const double proportionDelta = (wheelIncrementX != 0 ? -wheelIncrementX : wheelIncrementY) * 0.15f; | |||
| const double currentPos = valueToProportionOfLength (currentValue); | |||
| const double newValue = proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)); | |||
| const double proportionDelta = (wheelIncrementX != 0 ? -wheelIncrementX : wheelIncrementY) * 0.15f; | |||
| const double currentPos = valueToProportionOfLength (currentValue); | |||
| const double newValue = proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)); | |||
| double delta = (newValue != currentValue) | |||
| ? jmax (fabs (newValue - currentValue), interval) : 0; | |||
| double delta = (newValue != currentValue) | |||
| ? jmax (fabs (newValue - currentValue), interval) : 0; | |||
| if (currentValue > newValue) | |||
| delta = -delta; | |||
| if (currentValue > newValue) | |||
| delta = -delta; | |||
| sendDragStart(); | |||
| setValue (snapValue (currentValue + delta, false), true, true); | |||
| sendDragEnd(); | |||
| sendDragStart(); | |||
| setValue (snapValue (currentValue + delta, false), true, true); | |||
| sendDragEnd(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| Component::mouseWheelMove (e, wheelIncrementX, wheelIncrementY); | |||
| } | |||
| } | |||
| @@ -427,7 +427,7 @@ public: | |||
| @see getDoubleClickReturnValue | |||
| */ | |||
| void setDoubleClickReturnValue (const bool isDoubleClickEnabled, | |||
| const double valueToSetOnDoubleClick); | |||
| const double valueToSetOnDoubleClick) throw(); | |||
| /** Returns the values last set by setDoubleClickReturnValue() method. | |||
| @@ -436,7 +436,7 @@ public: | |||
| @see setDoubleClickReturnValue | |||
| */ | |||
| double getDoubleClickReturnValue (bool& isEnabled) const; | |||
| double getDoubleClickReturnValue (bool& isEnabled) const throw(); | |||
| //============================================================================== | |||
| /** Tells the slider whether to keep sending change messages while the user | |||
| @@ -447,7 +447,7 @@ public: | |||
| will be continuously sent as they drag it while the mouse button is still | |||
| held down. | |||
| */ | |||
| void setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease); | |||
| void setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease) throw(); | |||
| /** If enabled, this gives the slider a pop-up bubble which appears while the | |||
| slider is being dragged. | |||
| @@ -462,7 +462,7 @@ public: | |||
| you'll have to add it to a parent component instead). | |||
| */ | |||
| void setPopupDisplayEnabled (const bool isEnabled, | |||
| Component* const parentComponentToUse); | |||
| Component* const parentComponentToUse) throw(); | |||
| /** If this is set to true, then right-clicking on the slider will pop-up | |||
| a menu to let the user change the way it works. | |||
| @@ -471,7 +471,13 @@ public: | |||
| things like velocity sensitivity, and for rotary sliders, whether they | |||
| use a linear or rotary mouse-drag to move them. | |||
| */ | |||
| void setPopupMenuEnabled (const bool menuEnabled); | |||
| void setPopupMenuEnabled (const bool menuEnabled) throw(); | |||
| /** This can be used to stop the mouse scroll-wheel from moving the slider. | |||
| By default it's enabled. | |||
| */ | |||
| void setScrollWheelEnabled (const bool enabled) throw(); | |||
| //============================================================================== | |||
| /** Callback to indicate that the user is about to start dragging the slider. | |||
| @@ -682,7 +688,7 @@ private: | |||
| bool editableText : 1, doubleClickToValue : 1; | |||
| bool isVelocityBased : 1, rotaryStop : 1, incDecButtonsSideBySide : 1; | |||
| bool sendChangeOnlyOnRelease : 1, popupDisplayEnabled : 1; | |||
| bool menuEnabled : 1, menuShown : 1, mouseWasHidden : 1, incDecDragged : 1; | |||
| bool menuEnabled : 1, menuShown : 1, mouseWasHidden : 1, incDecDragged : 1, scrollWheelEnabled : 1; | |||
| Font font; | |||
| Label* valueBox; | |||
| Button* incButton; | |||