| @@ -615,6 +615,8 @@ | |||
| 848170B110809E00008FEC33 /* juce_XmlElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E9D6104036D6006A1807 /* juce_XmlElement.cpp */; }; | |||
| 848170B210809E00008FEC33 /* juce_ZipFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E996104036D6006A1807 /* juce_ZipFile.cpp */; }; | |||
| 8481730F10832513008FEC33 /* juce_TargetPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 8481730E10832513008FEC33 /* juce_TargetPlatform.h */; }; | |||
| 84842F9510F6559300490977 /* juce_Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84BA603E10F2017A001D9D70 /* juce_Value.cpp */; }; | |||
| 84842F9610F6559400490977 /* juce_Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 84BA603F10F2017A001D9D70 /* juce_Value.h */; }; | |||
| 8484E9A5103C958A008B7C6C /* juce_mac_NativeCode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8484E9A4103C958A008B7C6C /* juce_mac_NativeCode.mm */; }; | |||
| 8484E9BE103C9595008B7C6C /* juce_mac_AppleRemote.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8484E9A6103C9595008B7C6C /* juce_mac_AppleRemote.mm */; }; | |||
| 8484E9BF103C9595008B7C6C /* juce_mac_AudioCDBurner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8484E9A7103C9595008B7C6C /* juce_mac_AudioCDBurner.mm */; }; | |||
| @@ -655,6 +657,8 @@ | |||
| 84AF419B10F0008E0035D74F /* juce_ScopedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84AF3FE710EF9FF30035D74F /* juce_ScopedPointer.h */; }; | |||
| 84B2053E10D535EC008B4A79 /* juce_ValueTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 843D4A3A10D3C54500624BA6 /* juce_ValueTree.h */; }; | |||
| 84B2053F10D535EC008B4A79 /* juce_ValueTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843D4A3910D3C54500624BA6 /* juce_ValueTree.cpp */; }; | |||
| 84BA604010F2017A001D9D70 /* juce_Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84BA603E10F2017A001D9D70 /* juce_Value.cpp */; }; | |||
| 84BA604110F2017A001D9D70 /* juce_Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 84BA603F10F2017A001D9D70 /* juce_Value.h */; }; | |||
| 84D0F00C109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */; }; | |||
| 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */; }; | |||
| 84F1E6E710403605006A1807 /* juce_Application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E6DC10403605006A1807 /* juce_Application.cpp */; }; | |||
| @@ -1264,6 +1268,8 @@ | |||
| 84AB91FA10A078190048FC39 /* juce_CPlusPlusCodeTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_CPlusPlusCodeTokeniser.h; path = components/code_editor/juce_CPlusPlusCodeTokeniser.h; sourceTree = "<group>"; }; | |||
| 84AB927110A082E30048FC39 /* juce_CodeTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_CodeTokeniser.h; path = components/code_editor/juce_CodeTokeniser.h; sourceTree = "<group>"; }; | |||
| 84AF3FE710EF9FF30035D74F /* juce_ScopedPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_ScopedPointer.h; sourceTree = "<group>"; }; | |||
| 84BA603E10F2017A001D9D70 /* juce_Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_Value.cpp; sourceTree = "<group>"; }; | |||
| 84BA603F10F2017A001D9D70 /* juce_Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_Value.h; sourceTree = "<group>"; }; | |||
| 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = juce_mac_CoreGraphicsContext.mm; sourceTree = "<group>"; }; | |||
| 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_HeapBlock.h; sourceTree = "<group>"; }; | |||
| 84F1E6DC10403605006A1807 /* juce_Application.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Application.cpp; path = ../../src/application/juce_Application.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -2176,6 +2182,8 @@ | |||
| 84AF3FE710EF9FF30035D74F /* juce_ScopedPointer.h */, | |||
| 84F1E8DC10403671006A1807 /* juce_SortedSet.h */, | |||
| 84F1E8DD10403671006A1807 /* juce_SparseSet.h */, | |||
| 84BA603E10F2017A001D9D70 /* juce_Value.cpp */, | |||
| 84BA603F10F2017A001D9D70 /* juce_Value.h */, | |||
| 843D4A3910D3C54500624BA6 /* juce_ValueTree.cpp */, | |||
| 843D4A3A10D3C54500624BA6 /* juce_ValueTree.h */, | |||
| 84F1E8DE10403671006A1807 /* juce_Variant.cpp */, | |||
| @@ -3216,6 +3224,7 @@ | |||
| 84B2053E10D535EC008B4A79 /* juce_ValueTree.h in Headers */, | |||
| 84AB6F6E10EF948B00117E64 /* juce_HeapBlock.h in Headers */, | |||
| 84AF419B10F0008E0035D74F /* juce_ScopedPointer.h in Headers */, | |||
| 84842F9610F6559400490977 /* juce_Value.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -3542,6 +3551,7 @@ | |||
| 843D4A3C10D3C54500624BA6 /* juce_ValueTree.h in Headers */, | |||
| 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */, | |||
| 84AF3FE810EF9FF30035D74F /* juce_ScopedPointer.h in Headers */, | |||
| 84BA604110F2017A001D9D70 /* juce_Value.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -3889,6 +3899,7 @@ | |||
| 844BB95C10C5579A00DF5536 /* juce_FillType.cpp in Sources */, | |||
| 844BB95E10C557A600DF5536 /* juce_mac_CoreGraphicsContext.mm in Sources */, | |||
| 84B2053F10D535EC008B4A79 /* juce_ValueTree.cpp in Sources */, | |||
| 84842F9510F6559300490977 /* juce_Value.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -4180,6 +4191,7 @@ | |||
| 84AB91FF10A078190048FC39 /* juce_CPlusPlusCodeTokeniser.cpp in Sources */, | |||
| 84F29A9F10C2EFA5005014DF /* juce_FillType.cpp in Sources */, | |||
| 843D4A3B10D3C54500624BA6 /* juce_ValueTree.cpp in Sources */, | |||
| 84BA604010F2017A001D9D70 /* juce_Value.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -1117,6 +1117,10 @@ | |||
| RelativePath="..\..\..\src\containers\juce_ReferenceCountedObject.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\containers\juce_ScopedPointer.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\containers\juce_SortedSet.h" | |||
| > | |||
| @@ -1125,6 +1129,14 @@ | |||
| RelativePath="..\..\..\src\containers\juce_SparseSet.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\containers\juce_Value.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\containers\juce_Value.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\containers\juce_ValueTree.cpp" | |||
| > | |||
| @@ -385,8 +385,6 @@ public: | |||
| shouldDeleteEditor = false; | |||
| speakerIn = kSpeakerArrEmpty; | |||
| speakerOut = kSpeakerArrEmpty; | |||
| speakerInChans = 0; | |||
| speakerOutChans = 0; | |||
| numInChans = JucePlugin_MaxNumInputChannels; | |||
| numOutChans = JucePlugin_MaxNumOutputChannels; | |||
| @@ -1019,26 +1017,49 @@ public: | |||
| return filter != 0 && filter->isParameterAutomatable ((int) index); | |||
| } | |||
| class ChannelConfigComparator | |||
| { | |||
| public: | |||
| static int compareElements (const short* const first, const short* const second) | |||
| { | |||
| if (first[0] < second[0]) | |||
| return -1; | |||
| else if (first[0] > second[0]) | |||
| return 1; | |||
| else if (first[1] < second[1]) | |||
| return -1; | |||
| else if (first[1] > second[1]) | |||
| return 1; | |||
| return 0; | |||
| } | |||
| }; | |||
| bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, | |||
| VstSpeakerArrangement* pluginOutput) | |||
| { | |||
| const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; | |||
| short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; | |||
| Array <short*> channelConfigsSorted; | |||
| ChannelConfigComparator <short*> comp; | |||
| for (int i = 0; i < numElementsInArray (channelConfigs); ++i) | |||
| channelConfigsSorted.addSorted (comp, channelConfigs[i]); | |||
| for (int i = channelConfigsSorted.size(); --i >= 0;) | |||
| { | |||
| bool configMono = (channelConfigs[i][1] == 1) && (pluginOutput->type == kSpeakerArrMono); | |||
| bool configStereo = (channelConfigs[i][1] == 2) && (pluginOutput->type == kSpeakerArrStereo); | |||
| bool inCountMatches = (channelConfigs[i][0] == pluginInput->numChannels); | |||
| bool outCountMatches = (channelConfigs[i][1] == pluginOutput->numChannels); | |||
| const short* const config = channelConfigsSorted.getUnchecked(i); | |||
| bool inCountMatches = (config[0] == pluginInput->numChannels); | |||
| bool outCountMatches = (config[1] == pluginOutput->numChannels); | |||
| if ((configMono || configStereo) && inCountMatches && outCountMatches) | |||
| if (inCountMatches && outCountMatches) | |||
| { | |||
| speakerIn = (VstSpeakerArrangementType) pluginInput->type; | |||
| speakerOut = (VstSpeakerArrangementType) pluginOutput->type; | |||
| speakerInChans = pluginInput->numChannels; | |||
| speakerOutChans = pluginOutput->numChannels; | |||
| numInChans = speakerInChans; | |||
| numOutChans = speakerOutChans; | |||
| filter->setPlayConfigDetails (speakerInChans, speakerOutChans, | |||
| filter->setPlayConfigDetails (numInChans, numOutChans, | |||
| filter->getSampleRate(), | |||
| filter->getBlockSize()); | |||
| return true; | |||
| @@ -1392,7 +1413,6 @@ private: | |||
| bool firstProcessCallback; | |||
| int diffW, diffH; | |||
| VstSpeakerArrangementType speakerIn, speakerOut; | |||
| int speakerInChans, speakerOutChans; | |||
| int numInChans, numOutChans; | |||
| HeapBlock <float*> channels; | |||
| VoidArray tempChannels; // see note in processReplacing() | |||
| @@ -381,11 +381,32 @@ static Component* createSlidersPage() | |||
| for (i = 7; i <= 10; ++i) | |||
| { | |||
| sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); | |||
| sliders[i]->setMinValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); | |||
| sliders[i]->setMaxValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); | |||
| sliders[i]->setPopupDisplayEnabled (true, page); | |||
| } | |||
| /* Here, we'll create a Value object, and tell a bunch of our sliders to use it as their | |||
| value source. By telling them all to share the same Value, they'll stay in sync with | |||
| each other. | |||
| We could also optionally keep a copy of this Value elsewhere, and by changing it, | |||
| cause all the sliders to automatically update. | |||
| */ | |||
| Value sharedValue; | |||
| sharedValue = Random::getSystemRandom().nextDouble() * 100; | |||
| for (i = 0; i < 7; ++i) | |||
| sliders[i]->getValueObject().referTo (sharedValue); | |||
| // ..and now we'll do the same for all our min/max slider values.. | |||
| Value sharedValueMin, sharedValueMax; | |||
| sharedValueMin = Random::getSystemRandom().nextDouble() * 60.0; | |||
| sharedValueMax = Random::getSystemRandom().nextDouble() * 60.0 + 40.0; | |||
| for (i = 7; i <= 10; ++i) | |||
| { | |||
| sliders[i]->getMinValueObject().referTo (sharedValueMin); | |||
| sliders[i]->getMaxValueObject().referTo (sharedValueMax); | |||
| } | |||
| // Create a description label... | |||
| Label* label = new Label (T("hint"), T("Try right-clicking on a slider for an options menu. \n\nAlso, holding down CTRL while dragging will turn on a slider's velocity-sensitive mode")); | |||
| label->setBounds (20, 245, 350, 150); | |||
| page->addAndMakeVisible (label); | |||
| @@ -8132,7 +8132,7 @@ private: | |||
| forEachXmlChildElement (*myParentXml, child) | |||
| { | |||
| if (child->hasTagName ("FOO")) | |||
| if (child->hasTagName (T("FOO"))) | |||
| doSomethingWithXmlElement (child); | |||
| } | |||
| @@ -8188,12 +8188,12 @@ private: | |||
| Here's an example of parsing some elements: @code | |||
| // check we're looking at the right kind of document.. | |||
| if (myElement->hasTagName ("ANIMALS")) | |||
| if (myElement->hasTagName (T("ANIMALS"))) | |||
| { | |||
| // now we'll iterate its sub-elements looking for 'giraffe' elements.. | |||
| forEachXmlChildElement (*myElement, e) | |||
| { | |||
| if (e->hasTagName ("GIRAFFE")) | |||
| if (e->hasTagName (T("GIRAFFE"))) | |||
| { | |||
| // found a giraffe, so use some of its attributes.. | |||
| @@ -11105,11 +11105,11 @@ private: | |||
| /********* End of inlined file: juce_SparseSet.h *********/ | |||
| #endif | |||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | |||
| #ifndef __JUCE_VALUE_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ValueTree.h *********/ | |||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | |||
| #define __JUCE_VALUETREE_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_Value.h *********/ | |||
| #ifndef __JUCE_VALUE_JUCEHEADER__ | |||
| #define __JUCE_VALUE_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_Variant.h *********/ | |||
| #ifndef __JUCE_VARIANT_JUCEHEADER__ | |||
| @@ -11338,51 +11338,9 @@ private: | |||
| #endif // __JUCE_VARIANT_JUCEHEADER__ | |||
| /********* End of inlined file: juce_Variant.h *********/ | |||
| /********* Start of inlined file: juce_UndoManager.h *********/ | |||
| #ifndef __JUCE_UNDOMANAGER_JUCEHEADER__ | |||
| #define __JUCE_UNDOMANAGER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeBroadcaster.h *********/ | |||
| #ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | |||
| #define __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeListenerList.h *********/ | |||
| #ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ | |||
| #define __JUCE_CHANGELISTENERLIST_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeListener.h *********/ | |||
| #ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| #define __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| /** | |||
| Receives callbacks about changes to some kind of object. | |||
| Many objects use a ChangeListenerList to keep a set of listeners which they | |||
| will inform when something changes. A subclass of ChangeListener | |||
| is used to receive these callbacks. | |||
| Note that the major difference between an ActionListener and a ChangeListener | |||
| is that for a ChangeListener, multiple changes will be coalesced into fewer | |||
| callbacks, but ActionListeners perform one callback for every event posted. | |||
| @see ChangeListenerList, ChangeBroadcaster, ActionListener | |||
| */ | |||
| class JUCE_API ChangeListener | |||
| { | |||
| public: | |||
| /** Destructor. */ | |||
| virtual ~ChangeListener() {} | |||
| /** Overridden by your subclass to receive the callback. | |||
| @param objectThatHasChanged the value that was passed to the | |||
| ChangeListenerList::sendChangeMessage() method | |||
| */ | |||
| virtual void changeListenerCallback (void* objectThatHasChanged) = 0; | |||
| }; | |||
| #endif // __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| /********* End of inlined file: juce_ChangeListener.h *********/ | |||
| /********* Start of inlined file: juce_AsyncUpdater.h *********/ | |||
| #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| #define __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_MessageListener.h *********/ | |||
| #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ | |||
| @@ -11507,6 +11465,313 @@ public: | |||
| #endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ | |||
| /********* End of inlined file: juce_MessageListener.h *********/ | |||
| /** | |||
| Has a callback method that is triggered asynchronously. | |||
| This object allows an asynchronous callback function to be triggered, for | |||
| tasks such as coalescing multiple updates into a single callback later on. | |||
| Basically, one or more calls to the triggerAsyncUpdate() will result in the | |||
| message thread calling handleAsyncUpdate() as soon as it can. | |||
| */ | |||
| class JUCE_API AsyncUpdater | |||
| { | |||
| public: | |||
| /** Creates an AsyncUpdater object. */ | |||
| AsyncUpdater() throw(); | |||
| /** Destructor. | |||
| If there are any pending callbacks when the object is deleted, these are lost. | |||
| */ | |||
| virtual ~AsyncUpdater(); | |||
| /** Causes the callback to be triggered at a later time. | |||
| This method returns immediately, having made sure that a callback | |||
| to the handleAsyncUpdate() method will occur as soon as possible. | |||
| If an update callback is already pending but hasn't happened yet, calls | |||
| to this method will be ignored. | |||
| It's thread-safe to call this method from any number of threads without | |||
| needing to worry about locking. | |||
| */ | |||
| void triggerAsyncUpdate() throw(); | |||
| /** This will stop any pending updates from happening. | |||
| If called after triggerAsyncUpdate() and before the handleAsyncUpdate() | |||
| callback happens, this will cancel the handleAsyncUpdate() callback. | |||
| */ | |||
| void cancelPendingUpdate() throw(); | |||
| /** If an update has been triggered and is pending, this will invoke it | |||
| synchronously. | |||
| Use this as a kind of "flush" operation - if an update is pending, the | |||
| handleAsyncUpdate() method will be called immediately; if no update is | |||
| pending, then nothing will be done. | |||
| */ | |||
| void handleUpdateNowIfNeeded(); | |||
| /** Called back to do whatever your class needs to do. | |||
| This method is called by the message thread at the next convenient time | |||
| after the triggerAsyncUpdate() method has been called. | |||
| */ | |||
| virtual void handleAsyncUpdate() = 0; | |||
| private: | |||
| class AsyncUpdaterInternal : public MessageListener | |||
| { | |||
| public: | |||
| AsyncUpdaterInternal() throw() {} | |||
| ~AsyncUpdaterInternal() {} | |||
| void handleMessage (const Message&); | |||
| AsyncUpdater* owner; | |||
| private: | |||
| AsyncUpdaterInternal (const AsyncUpdaterInternal&); | |||
| const AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); | |||
| }; | |||
| AsyncUpdaterInternal internalAsyncHandler; | |||
| bool asyncMessagePending; | |||
| }; | |||
| #endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| /********* End of inlined file: juce_AsyncUpdater.h *********/ | |||
| /** | |||
| Represents a shared variant value. | |||
| A Value object contains a reference to a var object, and can get and set its value. | |||
| Listeners can be attached to be told when the value is changed. | |||
| The Value class is a wrapper around a shared, reference-counted underlying data | |||
| object - this means that multiple Value objects can all refer to the same piece of | |||
| data, allowing all of them to be notified when any of them changes it. | |||
| The base class of Value contains a simple var object, but subclasses can be | |||
| created that map a Value onto any kind of underlying data, e.g. | |||
| ValueTree::getPropertyAsValue() returns a Value object that is a wrapper | |||
| for one of its properties. | |||
| */ | |||
| class JUCE_API Value | |||
| { | |||
| public: | |||
| /** Creates an empty Value, containing a void var. */ | |||
| Value(); | |||
| /** Creates a Value that refers to the same value as another one. | |||
| Note that this doesn't make a copy of the other value - both this and the other | |||
| Value will share the same underlying value, so that when either one alters it, both | |||
| will see it change. | |||
| */ | |||
| Value (const Value& other); | |||
| /** Creates a Value that is set to the specified value. */ | |||
| Value (const var& initialValue); | |||
| /** Destructor. */ | |||
| ~Value(); | |||
| /** Returns the current value. */ | |||
| const var getValue() const; | |||
| /** Returns the current value. */ | |||
| operator const var() const; | |||
| /** Sets the current value. | |||
| You can also use operator= to set the value. | |||
| If there are any listeners registered, they will be notified of the | |||
| change asynchronously. | |||
| */ | |||
| void setValue (const var& newValue); | |||
| /** Sets the current value. | |||
| This is the same as calling setValue(). | |||
| If there are any listeners registered, they will be notified of the | |||
| change asynchronously. | |||
| */ | |||
| const Value& operator= (const var& newValue); | |||
| /** Makes this object refer to the same underlying value as another one. | |||
| */ | |||
| void referTo (const Value& valueToReferTo); | |||
| /** | |||
| */ | |||
| bool refersToSameSourceAs (const Value& other) const; | |||
| /** | |||
| */ | |||
| bool operator== (const Value& other) const; | |||
| /** | |||
| */ | |||
| bool operator!= (const Value& other) const; | |||
| /** Receives callbacks when a Value object changes. | |||
| @see Value::addListener | |||
| */ | |||
| class JUCE_API Listener | |||
| { | |||
| public: | |||
| Listener() {} | |||
| virtual ~Listener() {} | |||
| /** Called when a Value object is changed. | |||
| Note that the Value object passed as a parameter may not be exactly the same | |||
| object that you registered the listener with - it might be a copy that refers | |||
| to the same underlying ValueSource. To find out, you can call Value::refersToSameSourceAs(). | |||
| */ | |||
| virtual void valueChanged (Value& value) = 0; | |||
| }; | |||
| /** Adds a listener to receive callbacks when the value changes. | |||
| The listener is added to this specific Value object, and not to the shared | |||
| object that it refers to. When this object is deleted, all the listeners will | |||
| be lost, even if other references to the same Value still exist. So when you're | |||
| adding a listener, make sure that you add it to a ValueTree instance that will last | |||
| for as long as you need the listener. In general, you'd never want to add a listener | |||
| to a local stack-based ValueTree, but more likely to one that's a member variable. | |||
| @see removeListener | |||
| */ | |||
| void addListener (Listener* const listener); | |||
| /** Removes a listener that was previously added with addListener(). */ | |||
| void removeListener (Listener* const listener); | |||
| /** | |||
| Used internally by the Value class as the base class for its shared value objects. | |||
| The Value class is essentially a reference-counted pointer to a shared instance | |||
| of a ValueSource object. If you're feeling adventurous, you can create your own custom | |||
| ValueSource classes to allow Value objects to represent your own custom data items. | |||
| */ | |||
| class JUCE_API ValueSource : public ReferenceCountedObject, | |||
| public AsyncUpdater | |||
| { | |||
| public: | |||
| ValueSource(); | |||
| virtual ~ValueSource(); | |||
| /** Returns the current value of this object. */ | |||
| virtual const var getValue() const = 0; | |||
| /** Changes the current value. | |||
| This must also trigger a change message if the value actually changes. | |||
| */ | |||
| virtual void setValue (const var& newValue) = 0; | |||
| /** Delivers a change message to all the listeners that are registered with | |||
| this value. | |||
| If dispatchSynchronously is true, the method will call all the listeners | |||
| before returning; otherwise it'll dispatch a message and make the call later. | |||
| */ | |||
| void sendChangeMessage (const bool dispatchSynchronously); | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| friend class Value; | |||
| SortedSet <Value*> valuesWithListeners; | |||
| void handleAsyncUpdate(); | |||
| ValueSource (const ValueSource&); | |||
| const ValueSource& operator= (const ValueSource&); | |||
| }; | |||
| /** @internal */ | |||
| explicit Value (ValueSource* const valueSource); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| friend class ValueSource; | |||
| ReferenceCountedObjectPtr <ValueSource> value; | |||
| SortedSet <Listener*> listeners; | |||
| void callListeners(); | |||
| // This is disallowed to avoid confusion about whether it should | |||
| // do a by-value or by-reference copy. | |||
| const Value& operator= (const Value& other); | |||
| }; | |||
| #endif // __JUCE_VALUE_JUCEHEADER__ | |||
| /********* End of inlined file: juce_Value.h *********/ | |||
| #endif | |||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ValueTree.h *********/ | |||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | |||
| #define __JUCE_VALUETREE_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_UndoManager.h *********/ | |||
| #ifndef __JUCE_UNDOMANAGER_JUCEHEADER__ | |||
| #define __JUCE_UNDOMANAGER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeBroadcaster.h *********/ | |||
| #ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | |||
| #define __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeListenerList.h *********/ | |||
| #ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ | |||
| #define __JUCE_CHANGELISTENERLIST_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_ChangeListener.h *********/ | |||
| #ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| #define __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| /** | |||
| Receives callbacks about changes to some kind of object. | |||
| Many objects use a ChangeListenerList to keep a set of listeners which they | |||
| will inform when something changes. A subclass of ChangeListener | |||
| is used to receive these callbacks. | |||
| Note that the major difference between an ActionListener and a ChangeListener | |||
| is that for a ChangeListener, multiple changes will be coalesced into fewer | |||
| callbacks, but ActionListeners perform one callback for every event posted. | |||
| @see ChangeListenerList, ChangeBroadcaster, ActionListener | |||
| */ | |||
| class JUCE_API ChangeListener | |||
| { | |||
| public: | |||
| /** Destructor. */ | |||
| virtual ~ChangeListener() {} | |||
| /** Overridden by your subclass to receive the callback. | |||
| @param objectThatHasChanged the value that was passed to the | |||
| ChangeListenerList::sendChangeMessage() method | |||
| */ | |||
| virtual void changeListenerCallback (void* objectThatHasChanged) = 0; | |||
| }; | |||
| #endif // __JUCE_CHANGELISTENER_JUCEHEADER__ | |||
| /********* End of inlined file: juce_ChangeListener.h *********/ | |||
| /********* Start of inlined file: juce_ScopedLock.h *********/ | |||
| #ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ | |||
| #define __JUCE_SCOPEDLOCK_JUCEHEADER__ | |||
| @@ -12078,111 +12343,119 @@ public: | |||
| Like an XmlElement, each ValueTree node has a type, which you can access with | |||
| getType() and hasType(). | |||
| */ | |||
| ValueTree (const String& type) throw(); | |||
| ValueTree (const String& type); | |||
| /** Creates a reference to another ValueTree. */ | |||
| ValueTree (const ValueTree& other) throw(); | |||
| ValueTree (const ValueTree& other); | |||
| /** Makes this object reference another node. */ | |||
| const ValueTree& operator= (const ValueTree& other) throw(); | |||
| const ValueTree& operator= (const ValueTree& other); | |||
| /** Destructor. */ | |||
| ~ValueTree() throw(); | |||
| ~ValueTree(); | |||
| /** Returns true if both this and the other tree node refer to the same underlying structure. | |||
| Note that this isn't a value comparison - two independently-created trees which | |||
| contain identical data are not considered equal. | |||
| */ | |||
| bool operator== (const ValueTree& other) const throw(); | |||
| bool operator== (const ValueTree& other) const; | |||
| /** Returns true if this and the other node refer to different underlying structures. | |||
| Note that this isn't a value comparison - two independently-created trees which | |||
| contain identical data are not considered equal. | |||
| */ | |||
| bool operator!= (const ValueTree& other) const throw(); | |||
| bool operator!= (const ValueTree& other) const; | |||
| /** Returns true if this node refers to some valid data. | |||
| It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range | |||
| call to getChild(). | |||
| */ | |||
| bool isValid() const throw() { return object != 0; } | |||
| bool isValid() const { return object != 0; } | |||
| /** Returns a deep copy of this tree and all its sub-nodes. */ | |||
| ValueTree createCopy() const throw(); | |||
| ValueTree createCopy() const; | |||
| /** Returns the type of this node. | |||
| The type is specified when the ValueTree is created. | |||
| @see hasType | |||
| */ | |||
| const String getType() const throw(); | |||
| const String getType() const; | |||
| /** Returns true if the node has this type. | |||
| The comparison is case-sensitive. | |||
| */ | |||
| bool hasType (const String& typeName) const throw(); | |||
| bool hasType (const String& typeName) const; | |||
| /** Returns the value of a named property. | |||
| If no such property has been set, this will return a void variant. | |||
| You can also use operator[] to get a property. | |||
| @see var, setProperty, hasProperty | |||
| */ | |||
| const var getProperty (const var::identifier& name) const throw(); | |||
| const var getProperty (const var::identifier& name) const; | |||
| /** Returns the value of a named property. | |||
| If no such property has been set, this will return a void variant. This is the same as | |||
| calling getProperty(). | |||
| @see getProperty | |||
| */ | |||
| const var operator[] (const var::identifier& name) const throw(); | |||
| const var operator[] (const var::identifier& name) const; | |||
| /** Changes a named property of the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| @see var, getProperty, removeProperty | |||
| */ | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); | |||
| /** Returns true if the node contains a named property. */ | |||
| bool hasProperty (const var::identifier& name) const throw(); | |||
| bool hasProperty (const var::identifier& name) const; | |||
| /** Removes a property from the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager); | |||
| /** Removes all properties from the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeAllProperties (UndoManager* const undoManager) throw(); | |||
| void removeAllProperties (UndoManager* const undoManager); | |||
| /** Returns the total number of properties that the node contains. | |||
| @see getProperty. | |||
| */ | |||
| int getNumProperties() const throw(); | |||
| int getNumProperties() const; | |||
| /** Returns the identifier of the property with a given index. | |||
| @see getNumProperties | |||
| */ | |||
| const var::identifier getPropertyName (int index) const throw(); | |||
| const var::identifier getPropertyName (int index) const; | |||
| /** Returns a Value object that can be used to control and respond to one of the tree's properties. | |||
| The Value object will maintain a reference to this tree, and will use the undo manager when | |||
| it needs to change the value. Attaching a Value::Listener to the value object will provide | |||
| callbacks whenever the property changes. | |||
| */ | |||
| Value getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const; | |||
| /** Returns the number of child nodes belonging to this one. | |||
| @see getChild | |||
| */ | |||
| int getNumChildren() const throw(); | |||
| int getNumChildren() const; | |||
| /** Returns one of this node's child nodes. | |||
| If the index is out of range, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChild (int index) const throw(); | |||
| ValueTree getChild (int index) const; | |||
| /** Looks for a child node with the speficied type name. | |||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChildWithName (const String& type) const throw(); | |||
| ValueTree getChildWithName (const String& type) const; | |||
| /** Looks for the first child node that has the speficied property value. | |||
| @@ -12192,7 +12465,7 @@ public: | |||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; | |||
| /** Adds a child to this node. | |||
| @@ -12205,36 +12478,36 @@ public: | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void addChild (ValueTree child, int index, UndoManager* const undoManager) throw(); | |||
| void addChild (ValueTree child, int index, UndoManager* const undoManager); | |||
| /** Removes the specified child from this node's child-list. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager) throw(); | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager); | |||
| /** Removes a child from this node's child-list. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeChild (const int childIndex, UndoManager* const undoManager) throw(); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager); | |||
| /** Removes all child-nodes from this node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeAllChildren (UndoManager* const undoManager) throw(); | |||
| void removeAllChildren (UndoManager* const undoManager); | |||
| /** Returns true if this node is anywhere below the specified parent node. | |||
| This returns true if the node is a child-of-a-child, as well as a direct child. | |||
| */ | |||
| bool isAChildOf (const ValueTree& possibleParent) const throw(); | |||
| bool isAChildOf (const ValueTree& possibleParent) const; | |||
| /** Returns the parent node that contains this one. | |||
| If the node has no parent, this will return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getParent() const throw(); | |||
| ValueTree getParent() const; | |||
| /** Creates an XmlElement that holds a complete image of this node and all its children. | |||
| @@ -12242,14 +12515,14 @@ public: | |||
| be used to recreate a similar node by calling fromXml() | |||
| @see fromXml | |||
| */ | |||
| XmlElement* createXml() const throw(); | |||
| XmlElement* createXml() const; | |||
| /** Tries to recreate a node from its XML representation. | |||
| This isn't designed to cope with random XML data - for a sensible result, it should only | |||
| be fed XML that was created by the createXml() method. | |||
| */ | |||
| static ValueTree fromXml (const XmlElement& xml) throw(); | |||
| static ValueTree fromXml (const XmlElement& xml); | |||
| /** Stores this tree (and all its children) in a binary format. | |||
| @@ -12258,11 +12531,11 @@ public: | |||
| It's much faster to load/save your tree in binary form than as XML, but | |||
| obviously isn't human-readable. | |||
| */ | |||
| void writeToStream (OutputStream& output) throw(); | |||
| void writeToStream (OutputStream& output); | |||
| /** Reloads a tree from a stream that was written with writeToStream(). | |||
| */ | |||
| static ValueTree readFromStream (InputStream& input) throw(); | |||
| static ValueTree readFromStream (InputStream& input); | |||
| /** Listener class for events that happen to a ValueTree. | |||
| @@ -12275,21 +12548,34 @@ public: | |||
| /** Destructor. */ | |||
| virtual ~Listener() {} | |||
| /** This method is called when one or more of the properties of this node have changed. */ | |||
| virtual void valueTreePropertyChanged (ValueTree& tree) = 0; | |||
| /** This method is called when one of the properties of this node has been changed. */ | |||
| virtual void valueTreePropertyChanged (ValueTree& tree, const var::identifier& property) = 0; | |||
| /** This method is called when one or more of the children of this node have been added or removed. */ | |||
| virtual void valueTreeChildrenChanged (ValueTree& tree) = 0; | |||
| /** This method is called when this node has been added or removed from a parent node. */ | |||
| virtual void valueTreeParentChanged() = 0; | |||
| virtual void valueTreeParentChanged (ValueTree& tree) = 0; | |||
| }; | |||
| /** Adds a listener to receive callbacks when this node is changed. */ | |||
| void addListener (Listener* listener) throw(); | |||
| /** Adds a listener to receive callbacks when this node is changed. | |||
| The listener is added to this specific ValueTree object, and not to the shared | |||
| object that it refers to. When this object is deleted, all the listeners will | |||
| be lost, even if other references to the same ValueTree still exist. And if you | |||
| use the operator= to make this refer to a different ValueTree, any listeners will | |||
| begin listening to changes to the new tree instead of the old one. | |||
| When you're adding a listener, make sure that you add it to a ValueTree instance that | |||
| will last for as long as you need the listener. In general, you'd never want to add a | |||
| listener to a local stack-based ValueTree, and would usually add one to a member variable. | |||
| @see removeListener | |||
| */ | |||
| void addListener (Listener* listener); | |||
| /** Removes a listener that was previously added with addListener(). */ | |||
| void removeListener (Listener* listener) throw(); | |||
| void removeListener (Listener* listener); | |||
| juce_UseDebuggingNewOperator | |||
| @@ -12297,16 +12583,16 @@ private: | |||
| friend class ValueTreeSetPropertyAction; | |||
| friend class ValueTreeChildChangeAction; | |||
| class SharedObject : public ReferenceCountedObject | |||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedObject (const String& type) throw(); | |||
| SharedObject (const SharedObject& other) throw(); | |||
| ~SharedObject() throw(); | |||
| SharedObject (const String& type); | |||
| SharedObject (const SharedObject& other); | |||
| ~SharedObject(); | |||
| struct Property | |||
| { | |||
| Property (const var::identifier& name, const var& value) throw(); | |||
| Property (const var::identifier& name, const var& value); | |||
| var::identifier name; | |||
| var value; | |||
| @@ -12315,24 +12601,29 @@ private: | |||
| const String type; | |||
| OwnedArray <Property> properties; | |||
| ReferenceCountedArray <SharedObject> children; | |||
| SortedSet <Listener*> listeners; | |||
| SortedSet <ValueTree*> valueTreesWithListeners; | |||
| SharedObject* parent; | |||
| void sendPropertyChangeMessage(); | |||
| void sendPropertyChangeMessage (const var::identifier& property); | |||
| void sendChildChangeMessage(); | |||
| void sendParentChangeMessage(); | |||
| const var getProperty (const var::identifier& name) const throw(); | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); | |||
| bool hasProperty (const var::identifier& name) const throw(); | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); | |||
| void removeAllProperties (UndoManager* const undoManager) throw(); | |||
| bool isAChildOf (const SharedObject* const possibleParent) const throw(); | |||
| ValueTree getChildWithName (const String& type) const throw(); | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); | |||
| void addChild (SharedObject* child, int index, UndoManager* const undoManager) throw(); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager) throw(); | |||
| void removeAllChildren (UndoManager* const undoManager) throw(); | |||
| XmlElement* createXml() const throw(); | |||
| const var getProperty (const var::identifier& name) const; | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); | |||
| bool hasProperty (const var::identifier& name) const; | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager); | |||
| void removeAllProperties (UndoManager* const undoManager); | |||
| bool isAChildOf (const SharedObject* const possibleParent) const; | |||
| ValueTree getChildWithName (const String& type) const; | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; | |||
| void addChild (SharedObject* child, int index, UndoManager* const undoManager); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager); | |||
| void removeAllChildren (UndoManager* const undoManager); | |||
| XmlElement* createXml() const; | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| const SharedObject& operator= (const SharedObject&); | |||
| }; | |||
| friend class SharedObject; | |||
| @@ -12340,8 +12631,13 @@ private: | |||
| typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | |||
| ReferenceCountedObjectPtr <SharedObject> object; | |||
| SortedSet <Listener*> listeners; | |||
| ValueTree (SharedObject* const object_) throw(); | |||
| void deliverPropertyChangeMessage (const var::identifier& property); | |||
| void deliverChildChangeMessage(); | |||
| void deliverParentChangeMessage(); | |||
| ValueTree (SharedObject* const object_); | |||
| }; | |||
| #endif // __JUCE_VALUETREE_JUCEHEADER__ | |||
| @@ -25633,92 +25929,6 @@ public: | |||
| #ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ | |||
| #define __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ | |||
| /********* Start of inlined file: juce_AsyncUpdater.h *********/ | |||
| #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| #define __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| /** | |||
| Has a callback method that is triggered asynchronously. | |||
| This object allows an asynchronous callback function to be triggered, for | |||
| tasks such as coalescing multiple updates into a single callback later on. | |||
| Basically, one or more calls to the triggerAsyncUpdate() will result in the | |||
| message thread calling handleAsyncUpdate() as soon as it can. | |||
| */ | |||
| class JUCE_API AsyncUpdater | |||
| { | |||
| public: | |||
| /** Creates an AsyncUpdater object. */ | |||
| AsyncUpdater() throw(); | |||
| /** Destructor. | |||
| If there are any pending callbacks when the object is deleted, these are lost. | |||
| */ | |||
| virtual ~AsyncUpdater(); | |||
| /** Causes the callback to be triggered at a later time. | |||
| This method returns immediately, having made sure that a callback | |||
| to the handleAsyncUpdate() method will occur as soon as possible. | |||
| If an update callback is already pending but hasn't happened yet, calls | |||
| to this method will be ignored. | |||
| It's thread-safe to call this method from any number of threads without | |||
| needing to worry about locking. | |||
| */ | |||
| void triggerAsyncUpdate() throw(); | |||
| /** This will stop any pending updates from happening. | |||
| If called after triggerAsyncUpdate() and before the handleAsyncUpdate() | |||
| callback happens, this will cancel the handleAsyncUpdate() callback. | |||
| */ | |||
| void cancelPendingUpdate() throw(); | |||
| /** If an update has been triggered and is pending, this will invoke it | |||
| synchronously. | |||
| Use this as a kind of "flush" operation - if an update is pending, the | |||
| handleAsyncUpdate() method will be called immediately; if no update is | |||
| pending, then nothing will be done. | |||
| */ | |||
| void handleUpdateNowIfNeeded(); | |||
| /** Called back to do whatever your class needs to do. | |||
| This method is called by the message thread at the next convenient time | |||
| after the triggerAsyncUpdate() method has been called. | |||
| */ | |||
| virtual void handleAsyncUpdate() = 0; | |||
| private: | |||
| class AsyncUpdaterInternal : public MessageListener | |||
| { | |||
| public: | |||
| AsyncUpdaterInternal() throw() {} | |||
| ~AsyncUpdaterInternal() {} | |||
| void handleMessage (const Message&); | |||
| AsyncUpdater* owner; | |||
| private: | |||
| AsyncUpdaterInternal (const AsyncUpdaterInternal&); | |||
| const AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); | |||
| }; | |||
| AsyncUpdaterInternal internalAsyncHandler; | |||
| bool asyncMessagePending; | |||
| }; | |||
| #endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ | |||
| /********* End of inlined file: juce_AsyncUpdater.h *********/ | |||
| /********* Start of inlined file: juce_Desktop.h *********/ | |||
| #ifndef __JUCE_DESKTOP_JUCEHEADER__ | |||
| #define __JUCE_DESKTOP_JUCEHEADER__ | |||
| @@ -42583,7 +42793,8 @@ class JUCE_API Slider : public Component, | |||
| public SettableTooltipClient, | |||
| private AsyncUpdater, | |||
| private ButtonListener, | |||
| private LabelListener | |||
| private LabelListener, | |||
| private Value::Listener | |||
| { | |||
| public: | |||
| @@ -42868,6 +43079,14 @@ public: | |||
| /** Returns the slider's current value. */ | |||
| double getValue() const; | |||
| /** Returns the Value object that represents the slider's current position. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMaxValue, getMinValueObject | |||
| */ | |||
| Value& getValueObject() { return currentValue; } | |||
| /** Sets the limits that the slider's value can take. | |||
| @param newMinimum the lowest value allowed | |||
| @@ -42904,6 +43123,14 @@ public: | |||
| */ | |||
| double getMinValue() const; | |||
| /** For a slider with two or three thumbs, this returns the lower of its values. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMinValue, getMaxValueObject | |||
| */ | |||
| Value& getMinValueObject() { return valueMin; } | |||
| /** For a slider with two or three thumbs, this sets the lower of its values. | |||
| This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | |||
| @@ -42938,6 +43165,14 @@ public: | |||
| */ | |||
| double getMaxValue() const; | |||
| /** For a slider with two or three thumbs, this returns the higher of its values. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMaxValue, getMinValueObject | |||
| */ | |||
| Value& getMaxValueObject() { return valueMax; } | |||
| /** For a slider with two or three thumbs, this sets the lower of its values. | |||
| This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | |||
| @@ -43223,10 +43458,13 @@ protected: | |||
| void handleAsyncUpdate(); | |||
| /** @internal */ | |||
| void colourChanged(); | |||
| /** @internal */ | |||
| void valueChanged (Value& value); | |||
| private: | |||
| SortedSet <void*> listeners; | |||
| double currentValue, valueMin, valueMax; | |||
| Value currentValue, valueMin, valueMax; | |||
| double lastCurrentValue, lastValueMin, lastValueMax; | |||
| double minimum, maximum, interval, doubleClickReturnValue; | |||
| double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | |||
| double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | |||
| @@ -254,24 +254,24 @@ MidiMessage::MidiMessage (const uint8* src, | |||
| const MidiMessage& MidiMessage::operator= (const MidiMessage& other) throw() | |||
| { | |||
| if (this == &other) | |||
| return *this; | |||
| timeStamp = other.timeStamp; | |||
| size = other.size; | |||
| message = other.message; | |||
| if (this != &other) | |||
| { | |||
| timeStamp = other.timeStamp; | |||
| size = other.size; | |||
| message = other.message; | |||
| if (data != (uint8*) &message) | |||
| juce_free (data); | |||
| if (data != (uint8*) &message) | |||
| juce_free (data); | |||
| if (other.data != (uint8*) &other.message) | |||
| { | |||
| data = (uint8*) juce_malloc (size); | |||
| memcpy (data, other.data, size); | |||
| } | |||
| else | |||
| { | |||
| data = (uint8*) &message; | |||
| if (other.data != (uint8*) &other.message) | |||
| { | |||
| data = (uint8*) juce_malloc (size); | |||
| memcpy (data, other.data, size); | |||
| } | |||
| else | |||
| { | |||
| data = (uint8*) &message; | |||
| } | |||
| } | |||
| return *this; | |||
| @@ -293,12 +293,16 @@ int MidiMessage::getChannel() const throw() | |||
| bool MidiMessage::isForChannel (const int channel) const throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| return ((data[0] & 0xf) == channel - 1) | |||
| && ((data[0] & 0xf0) != 0xf0); | |||
| } | |||
| void MidiMessage::setChannel (const int channel) throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| if ((data[0] & 0xf0) != (uint8) 0xf0) | |||
| data[0] = (uint8) ((data[0] & (uint8)0xf0) | |||
| | (uint8)(channel - 1)); | |||
| @@ -372,7 +376,7 @@ const MidiMessage MidiMessage::aftertouchChange (const int channel, | |||
| const int noteNum, | |||
| const int aftertouchValue) throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| jassert (((unsigned int) noteNum) <= 127); | |||
| jassert (((unsigned int) aftertouchValue) <= 127); | |||
| @@ -396,7 +400,7 @@ int MidiMessage::getChannelPressureValue() const throw() | |||
| const MidiMessage MidiMessage::channelPressureChange (const int channel, | |||
| const int pressure) throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| jassert (((unsigned int) pressure) <= 127); | |||
| return MidiMessage (0xd0 | jlimit (0, 15, channel - 1), | |||
| @@ -416,7 +420,7 @@ int MidiMessage::getProgramChangeNumber() const throw() | |||
| const MidiMessage MidiMessage::programChange (const int channel, | |||
| const int programNumber) throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| return MidiMessage (0xc0 | jlimit (0, 15, channel - 1), | |||
| programNumber & 0x7f); | |||
| @@ -435,7 +439,7 @@ int MidiMessage::getPitchWheelValue() const throw() | |||
| const MidiMessage MidiMessage::pitchWheel (const int channel, | |||
| const int position) throw() | |||
| { | |||
| jassert (channel > 0 && channel <= 16); | |||
| jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 | |||
| jassert (((unsigned int) position) <= 0x3fff); | |||
| return MidiMessage (0xe0 | jlimit (0, 15, channel - 1), | |||
| @@ -0,0 +1,217 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_Value.h" | |||
| //============================================================================== | |||
| Value::ValueSource::ValueSource() | |||
| { | |||
| } | |||
| Value::ValueSource::~ValueSource() | |||
| { | |||
| } | |||
| void Value::ValueSource::sendChangeMessage (const bool synchronous) | |||
| { | |||
| if (synchronous) | |||
| { | |||
| for (int i = valuesWithListeners.size(); --i >= 0;) | |||
| { | |||
| Value* const v = valuesWithListeners[i]; | |||
| if (v != 0) | |||
| v->callListeners(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| triggerAsyncUpdate(); | |||
| } | |||
| } | |||
| void Value::ValueSource::handleAsyncUpdate() | |||
| { | |||
| sendChangeMessage (true); | |||
| } | |||
| //============================================================================== | |||
| class SimpleValueSource : public Value::ValueSource | |||
| { | |||
| public: | |||
| SimpleValueSource() | |||
| { | |||
| } | |||
| SimpleValueSource (const var& initialValue) | |||
| : value (initialValue) | |||
| { | |||
| } | |||
| ~SimpleValueSource() | |||
| { | |||
| } | |||
| const var getValue() const | |||
| { | |||
| return value; | |||
| } | |||
| void setValue (const var& newValue) | |||
| { | |||
| if (newValue != value) | |||
| { | |||
| value = newValue; | |||
| sendChangeMessage (false); | |||
| } | |||
| } | |||
| private: | |||
| var value; | |||
| SimpleValueSource (const SimpleValueSource&); | |||
| const SimpleValueSource& operator= (const SimpleValueSource&); | |||
| }; | |||
| //============================================================================== | |||
| Value::Value() | |||
| : value (new SimpleValueSource()) | |||
| { | |||
| } | |||
| Value::Value (ValueSource* const value_) | |||
| : value (value_) | |||
| { | |||
| jassert (value_ != 0); | |||
| } | |||
| Value::Value (const var& initialValue) | |||
| : value (new SimpleValueSource (initialValue)) | |||
| { | |||
| } | |||
| Value::Value (const Value& other) | |||
| : value (other.value) | |||
| { | |||
| } | |||
| const Value& Value::operator= (const Value& other) | |||
| { | |||
| value = other.value; | |||
| return *this; | |||
| } | |||
| Value::~Value() | |||
| { | |||
| if (listeners.size() > 0) | |||
| value->valuesWithListeners.removeValue (this); | |||
| } | |||
| //============================================================================== | |||
| const var Value::getValue() const | |||
| { | |||
| return value->getValue(); | |||
| } | |||
| void Value::setValue (const var& newValue) | |||
| { | |||
| value->setValue (newValue); | |||
| } | |||
| const Value& Value::operator= (const var& newValue) | |||
| { | |||
| value->setValue (newValue); | |||
| return *this; | |||
| } | |||
| void Value::referTo (const Value& valueToReferTo) | |||
| { | |||
| if (valueToReferTo.value != value) | |||
| { | |||
| if (listeners.size() > 0) | |||
| { | |||
| value->valuesWithListeners.removeValue (this); | |||
| valueToReferTo.value->valuesWithListeners.add (this); | |||
| } | |||
| value = valueToReferTo.value; | |||
| callListeners(); | |||
| } | |||
| } | |||
| bool Value::refersToSameSourceAs (const Value& other) const | |||
| { | |||
| return value == other.value; | |||
| } | |||
| bool Value::operator== (const Value& other) const | |||
| { | |||
| return value == other.value || value->getValue() == other.getValue(); | |||
| } | |||
| bool Value::operator!= (const Value& other) const | |||
| { | |||
| return value != other.value && value->getValue() != other.getValue(); | |||
| } | |||
| //============================================================================== | |||
| void Value::addListener (Listener* const listener) | |||
| { | |||
| if (listener != 0) | |||
| { | |||
| if (listeners.size() == 0) | |||
| value->valuesWithListeners.add (this); | |||
| listeners.add (listener); | |||
| } | |||
| } | |||
| void Value::removeListener (Listener* const listener) | |||
| { | |||
| listeners.removeValue (listener); | |||
| if (listeners.size() == 0) | |||
| value->valuesWithListeners.removeValue (this); | |||
| } | |||
| void Value::callListeners() | |||
| { | |||
| Value valueCopy (*this); // Use a copy in case this object gets deleted by a callback | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| Listener* const l = listeners[i]; | |||
| if (l != 0) | |||
| l->valueChanged (valueCopy); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -0,0 +1,214 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_VALUE_JUCEHEADER__ | |||
| #define __JUCE_VALUE_JUCEHEADER__ | |||
| #include "juce_Variant.h" | |||
| #include "../events/juce_AsyncUpdater.h" | |||
| #include "juce_ReferenceCountedObject.h" | |||
| #include "juce_SortedSet.h" | |||
| //============================================================================== | |||
| /** | |||
| Represents a shared variant value. | |||
| A Value object contains a reference to a var object, and can get and set its value. | |||
| Listeners can be attached to be told when the value is changed. | |||
| The Value class is a wrapper around a shared, reference-counted underlying data | |||
| object - this means that multiple Value objects can all refer to the same piece of | |||
| data, allowing all of them to be notified when any of them changes it. | |||
| The base class of Value contains a simple var object, but subclasses can be | |||
| created that map a Value onto any kind of underlying data, e.g. | |||
| ValueTree::getPropertyAsValue() returns a Value object that is a wrapper | |||
| for one of its properties. | |||
| */ | |||
| class JUCE_API Value | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates an empty Value, containing a void var. */ | |||
| Value(); | |||
| /** Creates a Value that refers to the same value as another one. | |||
| Note that this doesn't make a copy of the other value - both this and the other | |||
| Value will share the same underlying value, so that when either one alters it, both | |||
| will see it change. | |||
| */ | |||
| Value (const Value& other); | |||
| /** Creates a Value that is set to the specified value. */ | |||
| Value (const var& initialValue); | |||
| /** Destructor. */ | |||
| ~Value(); | |||
| //============================================================================== | |||
| /** Returns the current value. */ | |||
| const var getValue() const; | |||
| /** Returns the current value. */ | |||
| operator const var() const; | |||
| /** Sets the current value. | |||
| You can also use operator= to set the value. | |||
| If there are any listeners registered, they will be notified of the | |||
| change asynchronously. | |||
| */ | |||
| void setValue (const var& newValue); | |||
| /** Sets the current value. | |||
| This is the same as calling setValue(). | |||
| If there are any listeners registered, they will be notified of the | |||
| change asynchronously. | |||
| */ | |||
| const Value& operator= (const var& newValue); | |||
| /** Makes this object refer to the same underlying value as another one. | |||
| */ | |||
| void referTo (const Value& valueToReferTo); | |||
| /** | |||
| */ | |||
| bool refersToSameSourceAs (const Value& other) const; | |||
| /** | |||
| */ | |||
| bool operator== (const Value& other) const; | |||
| /** | |||
| */ | |||
| bool operator!= (const Value& other) const; | |||
| //============================================================================== | |||
| /** Receives callbacks when a Value object changes. | |||
| @see Value::addListener | |||
| */ | |||
| class JUCE_API Listener | |||
| { | |||
| public: | |||
| Listener() {} | |||
| virtual ~Listener() {} | |||
| /** Called when a Value object is changed. | |||
| Note that the Value object passed as a parameter may not be exactly the same | |||
| object that you registered the listener with - it might be a copy that refers | |||
| to the same underlying ValueSource. To find out, you can call Value::refersToSameSourceAs(). | |||
| */ | |||
| virtual void valueChanged (Value& value) = 0; | |||
| }; | |||
| /** Adds a listener to receive callbacks when the value changes. | |||
| The listener is added to this specific Value object, and not to the shared | |||
| object that it refers to. When this object is deleted, all the listeners will | |||
| be lost, even if other references to the same Value still exist. So when you're | |||
| adding a listener, make sure that you add it to a ValueTree instance that will last | |||
| for as long as you need the listener. In general, you'd never want to add a listener | |||
| to a local stack-based ValueTree, but more likely to one that's a member variable. | |||
| @see removeListener | |||
| */ | |||
| void addListener (Listener* const listener); | |||
| /** Removes a listener that was previously added with addListener(). */ | |||
| void removeListener (Listener* const listener); | |||
| //============================================================================== | |||
| /** | |||
| Used internally by the Value class as the base class for its shared value objects. | |||
| The Value class is essentially a reference-counted pointer to a shared instance | |||
| of a ValueSource object. If you're feeling adventurous, you can create your own custom | |||
| ValueSource classes to allow Value objects to represent your own custom data items. | |||
| */ | |||
| class JUCE_API ValueSource : public ReferenceCountedObject, | |||
| public AsyncUpdater | |||
| { | |||
| public: | |||
| ValueSource(); | |||
| virtual ~ValueSource(); | |||
| /** Returns the current value of this object. */ | |||
| virtual const var getValue() const = 0; | |||
| /** Changes the current value. | |||
| This must also trigger a change message if the value actually changes. | |||
| */ | |||
| virtual void setValue (const var& newValue) = 0; | |||
| /** Delivers a change message to all the listeners that are registered with | |||
| this value. | |||
| If dispatchSynchronously is true, the method will call all the listeners | |||
| before returning; otherwise it'll dispatch a message and make the call later. | |||
| */ | |||
| void sendChangeMessage (const bool dispatchSynchronously); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| friend class Value; | |||
| SortedSet <Value*> valuesWithListeners; | |||
| void handleAsyncUpdate(); | |||
| ValueSource (const ValueSource&); | |||
| const ValueSource& operator= (const ValueSource&); | |||
| }; | |||
| //============================================================================== | |||
| /** @internal */ | |||
| explicit Value (ValueSource* const valueSource); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| friend class ValueSource; | |||
| ReferenceCountedObjectPtr <ValueSource> value; | |||
| SortedSet <Listener*> listeners; | |||
| void callListeners(); | |||
| // This is disallowed to avoid confusion about whether it should | |||
| // do a by-value or by-reference copy. | |||
| const Value& operator= (const Value& other); | |||
| }; | |||
| #endif // __JUCE_VALUE_JUCEHEADER__ | |||
| @@ -35,7 +35,7 @@ class ValueTreeSetPropertyAction : public UndoableAction | |||
| { | |||
| public: | |||
| ValueTreeSetPropertyAction (const ValueTree::SharedObjectPtr& target_, const var::identifier& name_, | |||
| const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) throw() | |||
| const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) | |||
| : target (target_), name (name_), newValue (newValue_), | |||
| isAddingNewProperty (isAddingNewProperty_), | |||
| isDeletingProperty (isDeletingProperty_) | |||
| @@ -89,7 +89,7 @@ class ValueTreeChildChangeAction : public UndoableAction | |||
| { | |||
| public: | |||
| ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_, | |||
| const ValueTree::SharedObjectPtr& newChild_) throw() | |||
| const ValueTree::SharedObjectPtr& newChild_) | |||
| : target (target_), | |||
| child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]), | |||
| childIndex (childIndex_), | |||
| @@ -136,12 +136,12 @@ private: | |||
| //============================================================================== | |||
| ValueTree::SharedObject::SharedObject (const String& type_) throw() | |||
| ValueTree::SharedObject::SharedObject (const String& type_) | |||
| : type (type_), parent (0) | |||
| { | |||
| } | |||
| ValueTree::SharedObject::SharedObject (const SharedObject& other) throw() | |||
| ValueTree::SharedObject::SharedObject (const SharedObject& other) | |||
| : type (other.type), parent (0) | |||
| { | |||
| int i; | |||
| @@ -155,7 +155,7 @@ ValueTree::SharedObject::SharedObject (const SharedObject& other) throw() | |||
| children.add (new SharedObject (*other.children.getUnchecked(i))); | |||
| } | |||
| ValueTree::SharedObject::~SharedObject() throw() | |||
| ValueTree::SharedObject::~SharedObject() | |||
| { | |||
| jassert (parent == 0); // this should never happen unless something isn't obeying the ref-counting! | |||
| @@ -168,27 +168,37 @@ ValueTree::SharedObject::~SharedObject() throw() | |||
| } | |||
| } | |||
| ValueTree::SharedObject::Property::Property (const var::identifier& name_, const var& value_) throw() | |||
| ValueTree::SharedObject::Property::Property (const var::identifier& name_, const var& value_) | |||
| : name (name_), value (value_) | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void ValueTree::SharedObject::sendPropertyChangeMessage() | |||
| void ValueTree::deliverPropertyChangeMessage (const var::identifier& property) | |||
| { | |||
| ValueTree v (this); | |||
| ValueTree v (object); | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| ValueTree::Listener* const l = listeners[i]; | |||
| if (l != 0) | |||
| l->valueTreePropertyChanged (v); | |||
| l->valueTreePropertyChanged (v, property); | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::sendChildChangeMessage() | |||
| void ValueTree::SharedObject::sendPropertyChangeMessage (const var::identifier& property) | |||
| { | |||
| for (int i = valueTreesWithListeners.size(); --i >= 0;) | |||
| { | |||
| ValueTree* const v = valueTreesWithListeners[i]; | |||
| if (v != 0) | |||
| v->deliverPropertyChangeMessage (property); | |||
| } | |||
| } | |||
| void ValueTree::deliverChildChangeMessage() | |||
| { | |||
| ValueTree v (this); | |||
| ValueTree v (object); | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| @@ -198,25 +208,48 @@ void ValueTree::SharedObject::sendChildChangeMessage() | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::sendParentChangeMessage() | |||
| void ValueTree::SharedObject::sendChildChangeMessage() | |||
| { | |||
| for (int j = children.size(); --j >= 0;) | |||
| for (int i = valueTreesWithListeners.size(); --i >= 0;) | |||
| { | |||
| SharedObject* const t = children[j]; | |||
| if (t != 0) | |||
| t->sendParentChangeMessage(); | |||
| ValueTree* const v = valueTreesWithListeners[i]; | |||
| if (v != 0) | |||
| v->deliverChildChangeMessage(); | |||
| } | |||
| } | |||
| void ValueTree::deliverParentChangeMessage() | |||
| { | |||
| ValueTree v (object); | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| ValueTree::Listener* const l = listeners[i]; | |||
| if (l != 0) | |||
| l->valueTreeParentChanged(); | |||
| l->valueTreeParentChanged (v); | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::sendParentChangeMessage() | |||
| { | |||
| int i; | |||
| for (i = children.size(); --i >= 0;) | |||
| { | |||
| SharedObject* const t = children[i]; | |||
| if (t != 0) | |||
| t->sendParentChangeMessage(); | |||
| } | |||
| for (i = valueTreesWithListeners.size(); --i >= 0;) | |||
| { | |||
| ValueTree* const v = valueTreesWithListeners[i]; | |||
| if (v != 0) | |||
| v->deliverParentChangeMessage(); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| const var ValueTree::SharedObject::getProperty (const var::identifier& name) const throw() | |||
| const var ValueTree::SharedObject::getProperty (const var::identifier& name) const | |||
| { | |||
| for (int i = properties.size(); --i >= 0;) | |||
| { | |||
| @@ -228,7 +261,7 @@ const var ValueTree::SharedObject::getProperty (const var::identifier& name) con | |||
| return var(); | |||
| } | |||
| void ValueTree::SharedObject::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) | |||
| { | |||
| for (int i = properties.size(); --i >= 0;) | |||
| { | |||
| @@ -241,7 +274,7 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va | |||
| if (undoManager == 0) | |||
| { | |||
| p->value = newValue; | |||
| sendPropertyChangeMessage(); | |||
| sendPropertyChangeMessage (name); | |||
| } | |||
| else | |||
| { | |||
| @@ -256,7 +289,7 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va | |||
| if (undoManager == 0) | |||
| { | |||
| properties.add (new Property (name, newValue)); | |||
| sendPropertyChangeMessage(); | |||
| sendPropertyChangeMessage (name); | |||
| } | |||
| else | |||
| { | |||
| @@ -264,7 +297,7 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va | |||
| } | |||
| } | |||
| bool ValueTree::SharedObject::hasProperty (const var::identifier& name) const throw() | |||
| bool ValueTree::SharedObject::hasProperty (const var::identifier& name) const | |||
| { | |||
| for (int i = properties.size(); --i >= 0;) | |||
| if (properties.getUnchecked(i)->name == name) | |||
| @@ -273,7 +306,7 @@ bool ValueTree::SharedObject::hasProperty (const var::identifier& name) const th | |||
| return false; | |||
| } | |||
| void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoManager* const undoManager) | |||
| { | |||
| for (int i = properties.size(); --i >= 0;) | |||
| { | |||
| @@ -284,7 +317,7 @@ void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoM | |||
| if (undoManager == 0) | |||
| { | |||
| properties.remove (i); | |||
| sendPropertyChangeMessage(); | |||
| sendPropertyChangeMessage (name); | |||
| } | |||
| else | |||
| { | |||
| @@ -296,12 +329,16 @@ void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoM | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManager) | |||
| { | |||
| if (undoManager == 0) | |||
| { | |||
| properties.clear(); | |||
| sendPropertyChangeMessage(); | |||
| while (properties.size() > 0) | |||
| { | |||
| const var::identifier name (properties.getLast()->name); | |||
| properties.removeLast(); | |||
| sendPropertyChangeMessage (name); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| @@ -310,7 +347,7 @@ void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManage | |||
| } | |||
| } | |||
| ValueTree ValueTree::SharedObject::getChildWithName (const String& typeToMatch) const throw() | |||
| ValueTree ValueTree::SharedObject::getChildWithName (const String& typeToMatch) const | |||
| { | |||
| for (int i = 0; i < children.size(); ++i) | |||
| if (children.getUnchecked(i)->type == typeToMatch) | |||
| @@ -319,7 +356,7 @@ ValueTree ValueTree::SharedObject::getChildWithName (const String& typeToMatch) | |||
| return (SharedObject*) 0; | |||
| } | |||
| ValueTree ValueTree::SharedObject::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw() | |||
| ValueTree ValueTree::SharedObject::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const | |||
| { | |||
| for (int i = 0; i < children.size(); ++i) | |||
| if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue) | |||
| @@ -328,7 +365,7 @@ ValueTree ValueTree::SharedObject::getChildWithProperty (const var::identifier& | |||
| return (SharedObject*) 0; | |||
| } | |||
| bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possibleParent) const throw() | |||
| bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possibleParent) const | |||
| { | |||
| const SharedObject* p = parent; | |||
| @@ -343,7 +380,7 @@ bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possiblePare | |||
| return false; | |||
| } | |||
| void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager) | |||
| { | |||
| if (child != 0 && child->parent != this) | |||
| { | |||
| @@ -381,7 +418,7 @@ void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoMana | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* const undoManager) | |||
| { | |||
| const SharedObjectPtr child (children [childIndex]); | |||
| @@ -401,7 +438,7 @@ void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* co | |||
| } | |||
| } | |||
| void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager) throw() | |||
| void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager) | |||
| { | |||
| while (children.size() > 0) | |||
| removeChild (children.size() - 1, 0); | |||
| @@ -409,73 +446,85 @@ void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager) | |||
| //============================================================================== | |||
| ValueTree::ValueTree (const String& type_) throw() | |||
| ValueTree::ValueTree (const String& type_) | |||
| : object (new ValueTree::SharedObject (type_)) | |||
| { | |||
| jassert (type_.isNotEmpty()); // All objects should be given a sensible type name! | |||
| } | |||
| ValueTree::ValueTree (SharedObject* const object_) throw() | |||
| ValueTree::ValueTree (SharedObject* const object_) | |||
| : object (object_) | |||
| { | |||
| } | |||
| ValueTree::ValueTree (const ValueTree& other) throw() | |||
| ValueTree::ValueTree (const ValueTree& other) | |||
| : object (other.object) | |||
| { | |||
| } | |||
| const ValueTree& ValueTree::operator= (const ValueTree& other) throw() | |||
| const ValueTree& ValueTree::operator= (const ValueTree& other) | |||
| { | |||
| if (listeners.size() > 0) | |||
| { | |||
| if (object != 0) | |||
| object->valueTreesWithListeners.removeValue (this); | |||
| if (other.object != 0) | |||
| other.object->valueTreesWithListeners.add (this); | |||
| } | |||
| object = other.object; | |||
| return *this; | |||
| } | |||
| ValueTree::~ValueTree() throw() | |||
| ValueTree::~ValueTree() | |||
| { | |||
| if (listeners.size() > 0 && object != 0) | |||
| object->valueTreesWithListeners.removeValue (this); | |||
| } | |||
| bool ValueTree::operator== (const ValueTree& other) const throw() | |||
| bool ValueTree::operator== (const ValueTree& other) const | |||
| { | |||
| return object == other.object; | |||
| } | |||
| bool ValueTree::operator!= (const ValueTree& other) const throw() | |||
| bool ValueTree::operator!= (const ValueTree& other) const | |||
| { | |||
| return object != other.object; | |||
| } | |||
| ValueTree ValueTree::createCopy() const throw() | |||
| ValueTree ValueTree::createCopy() const | |||
| { | |||
| return ValueTree (object != 0 ? new SharedObject (*object) : 0); | |||
| } | |||
| bool ValueTree::hasType (const String& typeName) const throw() | |||
| bool ValueTree::hasType (const String& typeName) const | |||
| { | |||
| return object != 0 && object->type == typeName; | |||
| } | |||
| const String ValueTree::getType() const throw() | |||
| const String ValueTree::getType() const | |||
| { | |||
| return object != 0 ? object->type : String::empty; | |||
| } | |||
| ValueTree ValueTree::getParent() const throw() | |||
| ValueTree ValueTree::getParent() const | |||
| { | |||
| return object != 0 ? ValueTree (object->parent) : ValueTree ((SharedObject*) 0); | |||
| } | |||
| const var ValueTree::operator[] (const var::identifier& name) const throw() | |||
| const var ValueTree::operator[] (const var::identifier& name) const | |||
| { | |||
| return object == 0 ? var() : object->getProperty (name); | |||
| } | |||
| const var ValueTree::getProperty (const var::identifier& name) const throw() | |||
| const var ValueTree::getProperty (const var::identifier& name) const | |||
| { | |||
| return object == 0 ? var() : object->getProperty (name); | |||
| } | |||
| void ValueTree::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw() | |||
| void ValueTree::setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) | |||
| { | |||
| jassert (name.name.isNotEmpty()); | |||
| @@ -483,101 +532,158 @@ void ValueTree::setProperty (const var::identifier& name, const var& newValue, U | |||
| object->setProperty (name, newValue, undoManager); | |||
| } | |||
| bool ValueTree::hasProperty (const var::identifier& name) const throw() | |||
| bool ValueTree::hasProperty (const var::identifier& name) const | |||
| { | |||
| return object != 0 && object->hasProperty (name); | |||
| } | |||
| void ValueTree::removeProperty (const var::identifier& name, UndoManager* const undoManager) throw() | |||
| void ValueTree::removeProperty (const var::identifier& name, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeProperty (name, undoManager); | |||
| } | |||
| void ValueTree::removeAllProperties (UndoManager* const undoManager) throw() | |||
| void ValueTree::removeAllProperties (UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeAllProperties (undoManager); | |||
| } | |||
| int ValueTree::getNumProperties() const throw() | |||
| int ValueTree::getNumProperties() const | |||
| { | |||
| return object == 0 ? 0 : object->properties.size(); | |||
| } | |||
| const var::identifier ValueTree::getPropertyName (int index) const throw() | |||
| const var::identifier ValueTree::getPropertyName (int index) const | |||
| { | |||
| const SharedObject::Property* const p = (object == 0) ? 0 : object->properties [index]; | |||
| return p != 0 ? p->name : var::identifier (String::empty); | |||
| } | |||
| //============================================================================== | |||
| int ValueTree::getNumChildren() const throw() | |||
| class ValueTreePropertyValueSource : public Value::ValueSource, | |||
| public ValueTree::Listener | |||
| { | |||
| public: | |||
| ValueTreePropertyValueSource (const ValueTree& tree_, | |||
| const var::identifier& property_, | |||
| UndoManager* const undoManager_) | |||
| : tree (tree_), | |||
| property (property_), | |||
| undoManager (undoManager_) | |||
| { | |||
| tree.addListener (this); | |||
| } | |||
| ~ValueTreePropertyValueSource() | |||
| { | |||
| tree.removeListener (this); | |||
| } | |||
| const var getValue() const | |||
| { | |||
| return tree [property]; | |||
| } | |||
| void setValue (const var& newValue) | |||
| { | |||
| tree.setProperty (property, newValue, undoManager); | |||
| } | |||
| void valueTreePropertyChanged (ValueTree& tree, const var::identifier& changedProperty) | |||
| { | |||
| if (property == changedProperty) | |||
| sendChangeMessage (false); | |||
| } | |||
| void valueTreeChildrenChanged (ValueTree& tree) {} | |||
| void valueTreeParentChanged (ValueTree& tree) {} | |||
| private: | |||
| ValueTree tree; | |||
| const var::identifier property; | |||
| UndoManager* const undoManager; | |||
| const ValueTreePropertyValueSource& operator= (const ValueTreePropertyValueSource&); | |||
| }; | |||
| Value ValueTree::getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const | |||
| { | |||
| return Value (new ValueTreePropertyValueSource (*this, name, undoManager)); | |||
| } | |||
| //============================================================================== | |||
| int ValueTree::getNumChildren() const | |||
| { | |||
| return object == 0 ? 0 : object->children.size(); | |||
| } | |||
| ValueTree ValueTree::getChild (int index) const throw() | |||
| ValueTree ValueTree::getChild (int index) const | |||
| { | |||
| return object != 0 ? (SharedObject*) object->children [index] : ValueTree ((SharedObject*) 0); | |||
| } | |||
| ValueTree ValueTree::getChildWithName (const String& type) const throw() | |||
| ValueTree ValueTree::getChildWithName (const String& type) const | |||
| { | |||
| return object != 0 ? object->getChildWithName (type) : ValueTree ((SharedObject*) 0); | |||
| } | |||
| ValueTree ValueTree::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw() | |||
| ValueTree ValueTree::getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const | |||
| { | |||
| return object != 0 ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree ((SharedObject*) 0); | |||
| } | |||
| bool ValueTree::isAChildOf (const ValueTree& possibleParent) const throw() | |||
| bool ValueTree::isAChildOf (const ValueTree& possibleParent) const | |||
| { | |||
| return object != 0 && object->isAChildOf (possibleParent.object); | |||
| } | |||
| void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager) throw() | |||
| void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->addChild (child.object, index, undoManager); | |||
| } | |||
| void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager) throw() | |||
| void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeChild (childIndex, undoManager); | |||
| } | |||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) throw() | |||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeChild (object->children.indexOf (child.object), undoManager); | |||
| } | |||
| void ValueTree::removeAllChildren (UndoManager* const undoManager) throw() | |||
| void ValueTree::removeAllChildren (UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeAllChildren (undoManager); | |||
| } | |||
| //============================================================================== | |||
| void ValueTree::addListener (Listener* listener) throw() | |||
| void ValueTree::addListener (Listener* listener) | |||
| { | |||
| jassert (object != 0); // can't add listeners to a null object! | |||
| if (listener != 0) | |||
| { | |||
| if (listeners.size() == 0 && object != 0) | |||
| object->valueTreesWithListeners.add (this); | |||
| if (object != 0) | |||
| object->listeners.add (listener); | |||
| listeners.add (listener); | |||
| } | |||
| } | |||
| void ValueTree::removeListener (Listener* listener) throw() | |||
| void ValueTree::removeListener (Listener* listener) | |||
| { | |||
| if (object != 0) | |||
| object->listeners.removeValue (listener); | |||
| listeners.removeValue (listener); | |||
| if (listeners.size() == 0 && object != 0) | |||
| object->valueTreesWithListeners.removeValue (this); | |||
| } | |||
| //============================================================================== | |||
| XmlElement* ValueTree::SharedObject::createXml() const throw() | |||
| XmlElement* ValueTree::SharedObject::createXml() const | |||
| { | |||
| XmlElement* xml = new XmlElement (type); | |||
| @@ -597,12 +703,12 @@ XmlElement* ValueTree::SharedObject::createXml() const throw() | |||
| return xml; | |||
| } | |||
| XmlElement* ValueTree::createXml() const throw() | |||
| XmlElement* ValueTree::createXml() const | |||
| { | |||
| return object != 0 ? object->createXml() : 0; | |||
| } | |||
| ValueTree ValueTree::fromXml (const XmlElement& xml) throw() | |||
| ValueTree ValueTree::fromXml (const XmlElement& xml) | |||
| { | |||
| ValueTree v (xml.getTagName()); | |||
| @@ -620,7 +726,7 @@ ValueTree ValueTree::fromXml (const XmlElement& xml) throw() | |||
| } | |||
| //============================================================================== | |||
| void ValueTree::writeToStream (OutputStream& output) throw() | |||
| void ValueTree::writeToStream (OutputStream& output) | |||
| { | |||
| output.writeString (getType()); | |||
| @@ -642,7 +748,7 @@ void ValueTree::writeToStream (OutputStream& output) throw() | |||
| getChild (i).writeToStream (output); | |||
| } | |||
| ValueTree ValueTree::readFromStream (InputStream& input) throw() | |||
| ValueTree ValueTree::readFromStream (InputStream& input) | |||
| { | |||
| String type (input.readString()); | |||
| @@ -27,11 +27,11 @@ | |||
| #define __JUCE_VALUETREE_JUCEHEADER__ | |||
| #include "juce_Variant.h" | |||
| #include "juce_Value.h" | |||
| #include "../utilities/juce_UndoManager.h" | |||
| #include "../text/juce_XmlElement.h" | |||
| #include "juce_ReferenceCountedArray.h" | |||
| //============================================================================== | |||
| /** | |||
| A powerful tree structure that can be used to hold free-form data, and which can | |||
| @@ -75,50 +75,50 @@ public: | |||
| Like an XmlElement, each ValueTree node has a type, which you can access with | |||
| getType() and hasType(). | |||
| */ | |||
| ValueTree (const String& type) throw(); | |||
| ValueTree (const String& type); | |||
| /** Creates a reference to another ValueTree. */ | |||
| ValueTree (const ValueTree& other) throw(); | |||
| ValueTree (const ValueTree& other); | |||
| /** Makes this object reference another node. */ | |||
| const ValueTree& operator= (const ValueTree& other) throw(); | |||
| const ValueTree& operator= (const ValueTree& other); | |||
| /** Destructor. */ | |||
| ~ValueTree() throw(); | |||
| ~ValueTree(); | |||
| /** Returns true if both this and the other tree node refer to the same underlying structure. | |||
| Note that this isn't a value comparison - two independently-created trees which | |||
| contain identical data are not considered equal. | |||
| */ | |||
| bool operator== (const ValueTree& other) const throw(); | |||
| bool operator== (const ValueTree& other) const; | |||
| /** Returns true if this and the other node refer to different underlying structures. | |||
| Note that this isn't a value comparison - two independently-created trees which | |||
| contain identical data are not considered equal. | |||
| */ | |||
| bool operator!= (const ValueTree& other) const throw(); | |||
| bool operator!= (const ValueTree& other) const; | |||
| //============================================================================== | |||
| /** Returns true if this node refers to some valid data. | |||
| It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range | |||
| call to getChild(). | |||
| */ | |||
| bool isValid() const throw() { return object != 0; } | |||
| bool isValid() const { return object != 0; } | |||
| /** Returns a deep copy of this tree and all its sub-nodes. */ | |||
| ValueTree createCopy() const throw(); | |||
| ValueTree createCopy() const; | |||
| //============================================================================== | |||
| /** Returns the type of this node. | |||
| The type is specified when the ValueTree is created. | |||
| @see hasType | |||
| */ | |||
| const String getType() const throw(); | |||
| const String getType() const; | |||
| /** Returns true if the node has this type. | |||
| The comparison is case-sensitive. | |||
| */ | |||
| bool hasType (const String& typeName) const throw(); | |||
| bool hasType (const String& typeName) const; | |||
| //============================================================================== | |||
| /** Returns the value of a named property. | |||
| @@ -126,64 +126,72 @@ public: | |||
| You can also use operator[] to get a property. | |||
| @see var, setProperty, hasProperty | |||
| */ | |||
| const var getProperty (const var::identifier& name) const throw(); | |||
| const var getProperty (const var::identifier& name) const; | |||
| /** Returns the value of a named property. | |||
| If no such property has been set, this will return a void variant. This is the same as | |||
| calling getProperty(). | |||
| @see getProperty | |||
| */ | |||
| const var operator[] (const var::identifier& name) const throw(); | |||
| const var operator[] (const var::identifier& name) const; | |||
| /** Changes a named property of the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| @see var, getProperty, removeProperty | |||
| */ | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); | |||
| /** Returns true if the node contains a named property. */ | |||
| bool hasProperty (const var::identifier& name) const throw(); | |||
| bool hasProperty (const var::identifier& name) const; | |||
| /** Removes a property from the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager); | |||
| /** Removes all properties from the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeAllProperties (UndoManager* const undoManager) throw(); | |||
| void removeAllProperties (UndoManager* const undoManager); | |||
| /** Returns the total number of properties that the node contains. | |||
| @see getProperty. | |||
| */ | |||
| int getNumProperties() const throw(); | |||
| int getNumProperties() const; | |||
| /** Returns the identifier of the property with a given index. | |||
| @see getNumProperties | |||
| */ | |||
| const var::identifier getPropertyName (int index) const throw(); | |||
| const var::identifier getPropertyName (int index) const; | |||
| /** Returns a Value object that can be used to control and respond to one of the tree's properties. | |||
| The Value object will maintain a reference to this tree, and will use the undo manager when | |||
| it needs to change the value. Attaching a Value::Listener to the value object will provide | |||
| callbacks whenever the property changes. | |||
| */ | |||
| Value getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const; | |||
| //============================================================================== | |||
| /** Returns the number of child nodes belonging to this one. | |||
| @see getChild | |||
| */ | |||
| int getNumChildren() const throw(); | |||
| int getNumChildren() const; | |||
| /** Returns one of this node's child nodes. | |||
| If the index is out of range, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChild (int index) const throw(); | |||
| ValueTree getChild (int index) const; | |||
| /** Looks for a child node with the speficied type name. | |||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChildWithName (const String& type) const throw(); | |||
| ValueTree getChildWithName (const String& type) const; | |||
| /** Looks for the first child node that has the speficied property value. | |||
| @@ -193,7 +201,7 @@ public: | |||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; | |||
| /** Adds a child to this node. | |||
| @@ -206,36 +214,36 @@ public: | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void addChild (ValueTree child, int index, UndoManager* const undoManager) throw(); | |||
| void addChild (ValueTree child, int index, UndoManager* const undoManager); | |||
| /** Removes the specified child from this node's child-list. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager) throw(); | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager); | |||
| /** Removes a child from this node's child-list. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeChild (const int childIndex, UndoManager* const undoManager) throw(); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager); | |||
| /** Removes all child-nodes from this node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeAllChildren (UndoManager* const undoManager) throw(); | |||
| void removeAllChildren (UndoManager* const undoManager); | |||
| /** Returns true if this node is anywhere below the specified parent node. | |||
| This returns true if the node is a child-of-a-child, as well as a direct child. | |||
| */ | |||
| bool isAChildOf (const ValueTree& possibleParent) const throw(); | |||
| bool isAChildOf (const ValueTree& possibleParent) const; | |||
| /** Returns the parent node that contains this one. | |||
| If the node has no parent, this will return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getParent() const throw(); | |||
| ValueTree getParent() const; | |||
| //============================================================================== | |||
| /** Creates an XmlElement that holds a complete image of this node and all its children. | |||
| @@ -244,14 +252,14 @@ public: | |||
| be used to recreate a similar node by calling fromXml() | |||
| @see fromXml | |||
| */ | |||
| XmlElement* createXml() const throw(); | |||
| XmlElement* createXml() const; | |||
| /** Tries to recreate a node from its XML representation. | |||
| This isn't designed to cope with random XML data - for a sensible result, it should only | |||
| be fed XML that was created by the createXml() method. | |||
| */ | |||
| static ValueTree fromXml (const XmlElement& xml) throw(); | |||
| static ValueTree fromXml (const XmlElement& xml); | |||
| //============================================================================== | |||
| /** Stores this tree (and all its children) in a binary format. | |||
| @@ -261,11 +269,11 @@ public: | |||
| It's much faster to load/save your tree in binary form than as XML, but | |||
| obviously isn't human-readable. | |||
| */ | |||
| void writeToStream (OutputStream& output) throw(); | |||
| void writeToStream (OutputStream& output); | |||
| /** Reloads a tree from a stream that was written with writeToStream(). | |||
| */ | |||
| static ValueTree readFromStream (InputStream& input) throw(); | |||
| static ValueTree readFromStream (InputStream& input); | |||
| //============================================================================== | |||
| /** Listener class for events that happen to a ValueTree. | |||
| @@ -279,21 +287,34 @@ public: | |||
| /** Destructor. */ | |||
| virtual ~Listener() {} | |||
| /** This method is called when one or more of the properties of this node have changed. */ | |||
| virtual void valueTreePropertyChanged (ValueTree& tree) = 0; | |||
| /** This method is called when one of the properties of this node has been changed. */ | |||
| virtual void valueTreePropertyChanged (ValueTree& tree, const var::identifier& property) = 0; | |||
| /** This method is called when one or more of the children of this node have been added or removed. */ | |||
| virtual void valueTreeChildrenChanged (ValueTree& tree) = 0; | |||
| /** This method is called when this node has been added or removed from a parent node. */ | |||
| virtual void valueTreeParentChanged() = 0; | |||
| virtual void valueTreeParentChanged (ValueTree& tree) = 0; | |||
| }; | |||
| /** Adds a listener to receive callbacks when this node is changed. */ | |||
| void addListener (Listener* listener) throw(); | |||
| /** Adds a listener to receive callbacks when this node is changed. | |||
| The listener is added to this specific ValueTree object, and not to the shared | |||
| object that it refers to. When this object is deleted, all the listeners will | |||
| be lost, even if other references to the same ValueTree still exist. And if you | |||
| use the operator= to make this refer to a different ValueTree, any listeners will | |||
| begin listening to changes to the new tree instead of the old one. | |||
| When you're adding a listener, make sure that you add it to a ValueTree instance that | |||
| will last for as long as you need the listener. In general, you'd never want to add a | |||
| listener to a local stack-based ValueTree, and would usually add one to a member variable. | |||
| @see removeListener | |||
| */ | |||
| void addListener (Listener* listener); | |||
| /** Removes a listener that was previously added with addListener(). */ | |||
| void removeListener (Listener* listener) throw(); | |||
| void removeListener (Listener* listener); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -302,16 +323,16 @@ private: | |||
| friend class ValueTreeSetPropertyAction; | |||
| friend class ValueTreeChildChangeAction; | |||
| class SharedObject : public ReferenceCountedObject | |||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedObject (const String& type) throw(); | |||
| SharedObject (const SharedObject& other) throw(); | |||
| ~SharedObject() throw(); | |||
| SharedObject (const String& type); | |||
| SharedObject (const SharedObject& other); | |||
| ~SharedObject(); | |||
| struct Property | |||
| { | |||
| Property (const var::identifier& name, const var& value) throw(); | |||
| Property (const var::identifier& name, const var& value); | |||
| var::identifier name; | |||
| var value; | |||
| @@ -320,24 +341,29 @@ private: | |||
| const String type; | |||
| OwnedArray <Property> properties; | |||
| ReferenceCountedArray <SharedObject> children; | |||
| SortedSet <Listener*> listeners; | |||
| SortedSet <ValueTree*> valueTreesWithListeners; | |||
| SharedObject* parent; | |||
| void sendPropertyChangeMessage(); | |||
| void sendPropertyChangeMessage (const var::identifier& property); | |||
| void sendChildChangeMessage(); | |||
| void sendParentChangeMessage(); | |||
| const var getProperty (const var::identifier& name) const throw(); | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); | |||
| bool hasProperty (const var::identifier& name) const throw(); | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); | |||
| void removeAllProperties (UndoManager* const undoManager) throw(); | |||
| bool isAChildOf (const SharedObject* const possibleParent) const throw(); | |||
| ValueTree getChildWithName (const String& type) const throw(); | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); | |||
| void addChild (SharedObject* child, int index, UndoManager* const undoManager) throw(); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager) throw(); | |||
| void removeAllChildren (UndoManager* const undoManager) throw(); | |||
| XmlElement* createXml() const throw(); | |||
| const var getProperty (const var::identifier& name) const; | |||
| void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); | |||
| bool hasProperty (const var::identifier& name) const; | |||
| void removeProperty (const var::identifier& name, UndoManager* const undoManager); | |||
| void removeAllProperties (UndoManager* const undoManager); | |||
| bool isAChildOf (const SharedObject* const possibleParent) const; | |||
| ValueTree getChildWithName (const String& type) const; | |||
| ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; | |||
| void addChild (SharedObject* child, int index, UndoManager* const undoManager); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager); | |||
| void removeAllChildren (UndoManager* const undoManager); | |||
| XmlElement* createXml() const; | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| const SharedObject& operator= (const SharedObject&); | |||
| }; | |||
| friend class SharedObject; | |||
| @@ -345,8 +371,13 @@ private: | |||
| typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | |||
| ReferenceCountedObjectPtr <SharedObject> object; | |||
| SortedSet <Listener*> listeners; | |||
| void deliverPropertyChangeMessage (const var::identifier& property); | |||
| void deliverChildChangeMessage(); | |||
| void deliverParentChangeMessage(); | |||
| ValueTree (SharedObject* const object_) throw(); | |||
| ValueTree (SharedObject* const object_); | |||
| }; | |||
| @@ -92,9 +92,9 @@ private: | |||
| Slider::Slider (const String& name) | |||
| : Component (name), | |||
| listeners (2), | |||
| currentValue (0.0), | |||
| valueMin (0.0), | |||
| valueMax (0.0), | |||
| lastCurrentValue (0), | |||
| lastValueMin (0), | |||
| lastValueMax (0), | |||
| minimum (0), | |||
| maximum (10), | |||
| interval (0), | |||
| @@ -137,10 +137,17 @@ Slider::Slider (const String& name) | |||
| lookAndFeelChanged(); | |||
| updateText(); | |||
| currentValue.addListener (this); | |||
| valueMin.addListener (this); | |||
| valueMax.addListener (this); | |||
| } | |||
| Slider::~Slider() | |||
| { | |||
| currentValue.removeListener (this); | |||
| valueMin.removeListener (this); | |||
| valueMax.removeListener (this); | |||
| popupDisplay = 0; | |||
| deleteAllChildren(); | |||
| } | |||
| @@ -334,7 +341,7 @@ void Slider::colourChanged() | |||
| void Slider::lookAndFeelChanged() | |||
| { | |||
| const String previousTextBoxContent (valueBox != 0 ? valueBox->getText() | |||
| : getTextFromValue (currentValue)); | |||
| : getTextFromValue (currentValue.getValue())); | |||
| deleteAllChildren(); | |||
| valueBox = 0; | |||
| @@ -420,7 +427,7 @@ void Slider::setRange (const double newMin, | |||
| // keep the current values inside the new range.. | |||
| if (style != TwoValueHorizontal && style != TwoValueVertical) | |||
| { | |||
| setValue (currentValue, false, false); | |||
| setValue (getValue(), false, false); | |||
| } | |||
| else | |||
| { | |||
| @@ -442,13 +449,26 @@ void Slider::triggerChangeMessage (const bool synchronous) | |||
| valueChanged(); | |||
| } | |||
| void Slider::valueChanged (Value& value) | |||
| { | |||
| if (value.refersToSameSourceAs (currentValue)) | |||
| { | |||
| if (style != TwoValueHorizontal && style != TwoValueVertical) | |||
| setValue (currentValue.getValue(), false, false); | |||
| } | |||
| else if (value.refersToSameSourceAs (valueMin)) | |||
| setMinValue (valueMin.getValue(), false, false); | |||
| else if (value.refersToSameSourceAs (valueMax)) | |||
| setMaxValue (valueMax.getValue(), false, false); | |||
| } | |||
| double Slider::getValue() const | |||
| { | |||
| // for a two-value style slider, you should use the getMinValue() and getMaxValue() | |||
| // methods to get the two values. | |||
| jassert (style != TwoValueHorizontal && style != TwoValueVertical); | |||
| return currentValue; | |||
| return currentValue.getValue(); | |||
| } | |||
| void Slider::setValue (double newValue, | |||
| @@ -463,22 +483,26 @@ void Slider::setValue (double newValue, | |||
| if (style == ThreeValueHorizontal || style == ThreeValueVertical) | |||
| { | |||
| jassert (valueMin <= valueMax); | |||
| newValue = jlimit (valueMin, valueMax, newValue); | |||
| jassert ((double) valueMin.getValue() <= (double) valueMax.getValue()); | |||
| newValue = jlimit ((double) valueMin.getValue(), | |||
| (double) valueMax.getValue(), | |||
| newValue); | |||
| } | |||
| if (currentValue != newValue) | |||
| if (newValue != lastCurrentValue) | |||
| { | |||
| if (valueBox != 0) | |||
| valueBox->hideEditor (true); | |||
| currentValue = newValue; | |||
| lastCurrentValue = newValue; | |||
| currentValue = var (newValue); | |||
| updateText(); | |||
| repaint(); | |||
| if (popupDisplay != 0) | |||
| { | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (currentValue)); | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (newValue)); | |||
| popupDisplay->repaint(); | |||
| } | |||
| @@ -493,7 +517,7 @@ double Slider::getMinValue() const | |||
| jassert (style == TwoValueHorizontal || style == TwoValueVertical | |||
| || style == ThreeValueHorizontal || style == ThreeValueVertical); | |||
| return valueMin; | |||
| return valueMin.getValue(); | |||
| } | |||
| double Slider::getMaxValue() const | |||
| @@ -502,7 +526,7 @@ double Slider::getMaxValue() const | |||
| jassert (style == TwoValueHorizontal || style == TwoValueVertical | |||
| || style == ThreeValueHorizontal || style == ThreeValueVertical); | |||
| return valueMax; | |||
| return valueMax.getValue(); | |||
| } | |||
| void Slider::setMinValue (double newValue, const bool sendUpdateMessage, const bool sendMessageSynchronously, const bool allowNudgingOfOtherValues) | |||
| @@ -515,27 +539,28 @@ void Slider::setMinValue (double newValue, const bool sendUpdateMessage, const b | |||
| if (style == TwoValueHorizontal || style == TwoValueVertical) | |||
| { | |||
| if (allowNudgingOfOtherValues && newValue > valueMax) | |||
| if (allowNudgingOfOtherValues && newValue > (double) valueMax.getValue()) | |||
| setMaxValue (newValue, sendUpdateMessage, sendMessageSynchronously); | |||
| newValue = jmin (valueMax, newValue); | |||
| newValue = jmin ((double) valueMax.getValue(), newValue); | |||
| } | |||
| else | |||
| { | |||
| if (allowNudgingOfOtherValues && newValue > currentValue) | |||
| if (allowNudgingOfOtherValues && newValue > (double) currentValue.getValue()) | |||
| setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | |||
| newValue = jmin (currentValue, newValue); | |||
| newValue = jmin ((double) currentValue.getValue(), newValue); | |||
| } | |||
| if (valueMin != newValue) | |||
| if (lastValueMin != newValue) | |||
| { | |||
| lastValueMin = newValue; | |||
| valueMin = newValue; | |||
| repaint(); | |||
| if (popupDisplay != 0) | |||
| { | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMin)); | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (newValue)); | |||
| popupDisplay->repaint(); | |||
| } | |||
| @@ -554,27 +579,28 @@ void Slider::setMaxValue (double newValue, const bool sendUpdateMessage, const b | |||
| if (style == TwoValueHorizontal || style == TwoValueVertical) | |||
| { | |||
| if (allowNudgingOfOtherValues && newValue < valueMin) | |||
| if (allowNudgingOfOtherValues && newValue < (double) valueMin.getValue()) | |||
| setMinValue (newValue, sendUpdateMessage, sendMessageSynchronously); | |||
| newValue = jmax (valueMin, newValue); | |||
| newValue = jmax ((double) valueMin.getValue(), newValue); | |||
| } | |||
| else | |||
| { | |||
| if (allowNudgingOfOtherValues && newValue < currentValue) | |||
| if (allowNudgingOfOtherValues && newValue < (double) currentValue.getValue()) | |||
| setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | |||
| newValue = jmax (currentValue, newValue); | |||
| newValue = jmax ((double) currentValue.getValue(), newValue); | |||
| } | |||
| if (valueMax != newValue) | |||
| if (lastValueMax != newValue) | |||
| { | |||
| lastValueMax = newValue; | |||
| valueMax = newValue; | |||
| repaint(); | |||
| if (popupDisplay != 0) | |||
| { | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMax)); | |||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMax.getValue())); | |||
| popupDisplay->repaint(); | |||
| } | |||
| @@ -599,7 +625,7 @@ double Slider::getDoubleClickReturnValue (bool& isEnabled_) const | |||
| void Slider::updateText() | |||
| { | |||
| if (valueBox != 0) | |||
| valueBox->setText (getTextFromValue (currentValue), false); | |||
| valueBox->setText (getTextFromValue (currentValue.getValue()), false); | |||
| } | |||
| void Slider::setTextValueSuffix (const String& suffix) | |||
| @@ -687,7 +713,7 @@ void Slider::labelTextChanged (Label* label) | |||
| { | |||
| const double newValue = snapValue (getValueFromText (label->getText()), false); | |||
| if (getValue() != newValue) | |||
| if (newValue != (double) currentValue.getValue()) | |||
| { | |||
| sendDragStart(); | |||
| setValue (newValue, true, true); | |||
| @@ -798,7 +824,7 @@ void Slider::paint (Graphics& g) | |||
| { | |||
| if (style == Rotary || style == RotaryHorizontalDrag || style == RotaryVerticalDrag) | |||
| { | |||
| const float sliderPos = (float) valueToProportionOfLength (currentValue); | |||
| const float sliderPos = (float) valueToProportionOfLength (currentValue.getValue()); | |||
| jassert (sliderPos >= 0 && sliderPos <= 1.0f); | |||
| getLookAndFeel().drawRotarySlider (g, | |||
| @@ -817,9 +843,9 @@ void Slider::paint (Graphics& g) | |||
| sliderRect.getY(), | |||
| sliderRect.getWidth(), | |||
| sliderRect.getHeight(), | |||
| getLinearSliderPos (currentValue), | |||
| getLinearSliderPos (valueMin), | |||
| getLinearSliderPos (valueMax), | |||
| getLinearSliderPos (currentValue.getValue()), | |||
| getLinearSliderPos (valueMin.getValue()), | |||
| getLinearSliderPos (valueMax.getValue()), | |||
| style, | |||
| *this); | |||
| } | |||
| @@ -1027,9 +1053,9 @@ void Slider::mouseDown (const MouseEvent& e) | |||
| { | |||
| const float mousePos = (float) (isVertical() ? e.y : e.x); | |||
| const float normalPosDistance = fabsf (getLinearSliderPos (currentValue) - mousePos); | |||
| const float minPosDistance = fabsf (getLinearSliderPos (valueMin) - 0.1f - mousePos); | |||
| const float maxPosDistance = fabsf (getLinearSliderPos (valueMax) + 0.1f - mousePos); | |||
| const float normalPosDistance = fabsf (getLinearSliderPos (currentValue.getValue()) - mousePos); | |||
| const float minPosDistance = fabsf (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos); | |||
| const float maxPosDistance = fabsf (getLinearSliderPos (valueMax.getValue()) + 0.1f - mousePos); | |||
| if (style == TwoValueHorizontal || style == TwoValueVertical) | |||
| { | |||
| @@ -1047,17 +1073,14 @@ void Slider::mouseDown (const MouseEvent& e) | |||
| } | |||
| } | |||
| minMaxDiff = valueMax - valueMin; | |||
| minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | |||
| lastAngle = rotaryStart + (rotaryEnd - rotaryStart) | |||
| * valueToProportionOfLength (currentValue); | |||
| * valueToProportionOfLength (currentValue.getValue()); | |||
| if (sliderBeingDragged == 2) | |||
| valueWhenLastDragged = valueMax; | |||
| else if (sliderBeingDragged == 1) | |||
| valueWhenLastDragged = valueMin; | |||
| else | |||
| valueWhenLastDragged = currentValue; | |||
| valueWhenLastDragged = ((sliderBeingDragged == 2) ? valueMax | |||
| : ((sliderBeingDragged == 1) ? valueMin | |||
| : currentValue)).getValue(); | |||
| valueOnMouseDown = valueWhenLastDragged; | |||
| @@ -1094,7 +1117,7 @@ void Slider::mouseUp (const MouseEvent&) | |||
| { | |||
| restoreMouseIfHidden(); | |||
| if (sendChangeOnlyOnRelease && valueOnMouseDown != currentValue) | |||
| if (sendChangeOnlyOnRelease && valueOnMouseDown != (double) currentValue.getValue()) | |||
| triggerChangeMessage (false); | |||
| sendDragEnd(); | |||
| @@ -1124,7 +1147,7 @@ void Slider::restoreMouseIfHidden() | |||
| const double pos = (sliderBeingDragged == 2) ? getMaxValue() | |||
| : ((sliderBeingDragged == 1) ? getMinValue() | |||
| : currentValue); | |||
| : (double) currentValue.getValue()); | |||
| if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag) | |||
| { | |||
| @@ -1336,7 +1359,7 @@ void Slider::mouseDrag (const MouseEvent& e) | |||
| if (e.mods.isShiftDown()) | |||
| setMaxValue (getMinValue() + minMaxDiff, false, false, true); | |||
| else | |||
| minMaxDiff = valueMax - valueMin; | |||
| minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | |||
| } | |||
| else | |||
| { | |||
| @@ -1348,7 +1371,7 @@ void Slider::mouseDrag (const MouseEvent& e) | |||
| if (e.mods.isShiftDown()) | |||
| setMinValue (getMaxValue() - minMaxDiff, false, false, true); | |||
| else | |||
| minMaxDiff = valueMax - valueMin; | |||
| minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | |||
| } | |||
| mouseXWhenLastDragged = e.x; | |||
| @@ -1381,18 +1404,19 @@ void Slider::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float w | |||
| if (valueBox != 0) | |||
| valueBox->hideEditor (false); | |||
| const double value = (double) currentValue.getValue(); | |||
| const double proportionDelta = (wheelIncrementX != 0 ? -wheelIncrementX : wheelIncrementY) * 0.15f; | |||
| const double currentPos = valueToProportionOfLength (currentValue); | |||
| const double currentPos = valueToProportionOfLength (value); | |||
| const double newValue = proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)); | |||
| double delta = (newValue != currentValue) | |||
| ? jmax (fabs (newValue - currentValue), interval) : 0; | |||
| double delta = (newValue != value) | |||
| ? jmax (fabs (newValue - value), interval) : 0; | |||
| if (currentValue > newValue) | |||
| if (value > newValue) | |||
| delta = -delta; | |||
| sendDragStart(); | |||
| setValue (snapValue (currentValue + delta, false), true, true); | |||
| setValue (snapValue (value + delta, false), true, true); | |||
| sendDragEnd(); | |||
| } | |||
| } | |||
| @@ -31,6 +31,7 @@ | |||
| #include "../buttons/juce_Button.h" | |||
| #include "../../../events/juce_AsyncUpdater.h" | |||
| #include "../../../containers/juce_SortedSet.h" | |||
| #include "../../../containers/juce_Value.h" | |||
| //============================================================================== | |||
| @@ -58,7 +59,8 @@ class JUCE_API Slider : public Component, | |||
| public SettableTooltipClient, | |||
| private AsyncUpdater, | |||
| private ButtonListener, | |||
| private LabelListener | |||
| private LabelListener, | |||
| private Value::Listener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| @@ -351,6 +353,14 @@ public: | |||
| /** Returns the slider's current value. */ | |||
| double getValue() const; | |||
| /** Returns the Value object that represents the slider's current position. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMaxValue, getMinValueObject | |||
| */ | |||
| Value& getValueObject() { return currentValue; } | |||
| //============================================================================== | |||
| /** Sets the limits that the slider's value can take. | |||
| @@ -389,6 +399,14 @@ public: | |||
| */ | |||
| double getMinValue() const; | |||
| /** For a slider with two or three thumbs, this returns the lower of its values. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMinValue, getMaxValueObject | |||
| */ | |||
| Value& getMinValueObject() { return valueMin; } | |||
| /** For a slider with two or three thumbs, this sets the lower of its values. | |||
| This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | |||
| @@ -423,6 +441,14 @@ public: | |||
| */ | |||
| double getMaxValue() const; | |||
| /** For a slider with two or three thumbs, this returns the higher of its values. | |||
| You can use this Value object to connect the slider's position to external values or setters, | |||
| either by taking a copy of the Value, or by using Value::referTo() to make it point to | |||
| your own Value object. | |||
| @see Value, getMaxValue, getMinValueObject | |||
| */ | |||
| Value& getMaxValueObject() { return valueMax; } | |||
| /** For a slider with two or three thumbs, this sets the lower of its values. | |||
| This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | |||
| @@ -720,10 +746,13 @@ protected: | |||
| void handleAsyncUpdate(); | |||
| /** @internal */ | |||
| void colourChanged(); | |||
| /** @internal */ | |||
| void valueChanged (Value& value); | |||
| private: | |||
| SortedSet <void*> listeners; | |||
| double currentValue, valueMin, valueMax; | |||
| Value currentValue, valueMin, valueMax; | |||
| double lastCurrentValue, lastValueMin, lastValueMax; | |||
| double minimum, maximum, interval, doubleClickReturnValue; | |||
| double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | |||
| double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | |||
| @@ -48,41 +48,28 @@ using namespace zlibNamespace; | |||
| // included publicly. | |||
| class GZIPCompressorHelper | |||
| { | |||
| private: | |||
| HeapBlock <z_stream> stream; | |||
| uint8* data; | |||
| int dataSize, compLevel, strategy; | |||
| bool setParams; | |||
| public: | |||
| bool finished, shouldFinish; | |||
| GZIPCompressorHelper (const int compressionLevel, const bool nowrap) | |||
| : data (0), | |||
| dataSize (0), | |||
| compLevel (compressionLevel), | |||
| strategy (0), | |||
| setParams (true), | |||
| streamIsValid (false), | |||
| finished (false), | |||
| shouldFinish (false) | |||
| { | |||
| stream.calloc (1); | |||
| if (deflateInit2 (stream, | |||
| compLevel, | |||
| Z_DEFLATED, | |||
| nowrap ? -MAX_WBITS : MAX_WBITS, | |||
| 8, | |||
| strategy) != Z_OK) | |||
| { | |||
| stream.free(); | |||
| } | |||
| zerostruct (stream); | |||
| streamIsValid = (deflateInit2 (&stream, compLevel, Z_DEFLATED, | |||
| nowrap ? -MAX_WBITS : MAX_WBITS, | |||
| 8, strategy) == Z_OK); | |||
| } | |||
| ~GZIPCompressorHelper() | |||
| { | |||
| if (stream != 0) | |||
| deflateEnd (stream); | |||
| if (streamIsValid) | |||
| deflateEnd (&stream); | |||
| } | |||
| bool needsInput() const throw() | |||
| @@ -98,15 +85,15 @@ public: | |||
| int doNextBlock (uint8* const dest, const int destSize) throw() | |||
| { | |||
| if (stream != 0) | |||
| if (streamIsValid) | |||
| { | |||
| stream->next_in = data; | |||
| stream->next_out = dest; | |||
| stream->avail_in = dataSize; | |||
| stream->avail_out = destSize; | |||
| stream.next_in = data; | |||
| stream.next_out = dest; | |||
| stream.avail_in = dataSize; | |||
| stream.avail_out = destSize; | |||
| const int result = setParams ? deflateParams (stream, compLevel, strategy) | |||
| : deflate (stream, shouldFinish ? Z_FINISH : Z_NO_FLUSH); | |||
| const int result = setParams ? deflateParams (&stream, compLevel, strategy) | |||
| : deflate (&stream, shouldFinish ? Z_FINISH : Z_NO_FLUSH); | |||
| setParams = false; | |||
| @@ -114,12 +101,12 @@ public: | |||
| { | |||
| case Z_STREAM_END: | |||
| finished = true; | |||
| // Deliberate fall-through.. | |||
| case Z_OK: | |||
| data += dataSize - stream->avail_in; | |||
| dataSize = stream->avail_in; | |||
| data += dataSize - stream.avail_in; | |||
| dataSize = stream.avail_in; | |||
| return destSize - stream->avail_out; | |||
| return destSize - stream.avail_out; | |||
| default: | |||
| break; | |||
| @@ -128,6 +115,15 @@ public: | |||
| return 0; | |||
| } | |||
| private: | |||
| z_stream stream; | |||
| uint8* data; | |||
| int dataSize, compLevel, strategy; | |||
| bool setParams, streamIsValid; | |||
| public: | |||
| bool finished, shouldFinish; | |||
| }; | |||
| @@ -80,36 +80,24 @@ using namespace zlibNamespace; | |||
| // included publicly. | |||
| class GZIPDecompressHelper | |||
| { | |||
| private: | |||
| HeapBlock <z_stream> stream; | |||
| uint8* data; | |||
| int dataSize; | |||
| public: | |||
| bool finished, needsDictionary, error; | |||
| GZIPDecompressHelper (const bool noWrap) throw() | |||
| : data (0), | |||
| dataSize (0), | |||
| finished (false), | |||
| finished (true), | |||
| needsDictionary (false), | |||
| error (false) | |||
| error (true), | |||
| streamIsValid (false) | |||
| { | |||
| stream.calloc (1); | |||
| if (inflateInit2 (stream, (noWrap) ? -MAX_WBITS | |||
| : MAX_WBITS) != Z_OK) | |||
| { | |||
| stream.free(); | |||
| error = true; | |||
| finished = true; | |||
| } | |||
| zerostruct (stream); | |||
| streamIsValid = (inflateInit2 (&stream, noWrap ? -MAX_WBITS : MAX_WBITS) == Z_OK); | |||
| finished = error = ! streamIsValid; | |||
| } | |||
| ~GZIPDecompressHelper() throw() | |||
| { | |||
| if (stream != 0) | |||
| inflateEnd (stream); | |||
| if (streamIsValid) | |||
| inflateEnd (&stream); | |||
| } | |||
| bool needsInput() const throw() { return dataSize <= 0; } | |||
| @@ -122,28 +110,27 @@ public: | |||
| int doNextBlock (uint8* const dest, const int destSize) throw() | |||
| { | |||
| if (stream != 0 && data != 0 && ! finished) | |||
| if (streamIsValid && data != 0 && ! finished) | |||
| { | |||
| stream->next_in = data; | |||
| stream->next_out = dest; | |||
| stream->avail_in = dataSize; | |||
| stream->avail_out = destSize; | |||
| stream.next_in = data; | |||
| stream.next_out = dest; | |||
| stream.avail_in = dataSize; | |||
| stream.avail_out = destSize; | |||
| switch (inflate (stream, Z_PARTIAL_FLUSH)) | |||
| switch (inflate (&stream, Z_PARTIAL_FLUSH)) | |||
| { | |||
| case Z_STREAM_END: | |||
| finished = true; | |||
| // deliberate fall-through | |||
| case Z_OK: | |||
| data += dataSize - stream->avail_in; | |||
| dataSize = stream->avail_in; | |||
| return destSize - stream->avail_out; | |||
| data += dataSize - stream.avail_in; | |||
| dataSize = stream.avail_in; | |||
| return destSize - stream.avail_out; | |||
| case Z_NEED_DICT: | |||
| needsDictionary = true; | |||
| data += dataSize - stream->avail_in; | |||
| dataSize = stream->avail_in; | |||
| data += dataSize - stream.avail_in; | |||
| dataSize = stream.avail_in; | |||
| break; | |||
| case Z_DATA_ERROR: | |||
| @@ -157,6 +144,14 @@ public: | |||
| return 0; | |||
| } | |||
| private: | |||
| z_stream stream; | |||
| uint8* data; | |||
| int dataSize; | |||
| public: | |||
| bool finished, needsDictionary, error, streamIsValid; | |||
| }; | |||
| //============================================================================== | |||
| @@ -255,25 +250,18 @@ int64 GZIPDecompressorInputStream::getPosition() | |||
| bool GZIPDecompressorInputStream::setPosition (int64 newPos) | |||
| { | |||
| if (newPos != currentPos) | |||
| if (newPos < currentPos) | |||
| { | |||
| if (newPos > currentPos) | |||
| { | |||
| skipNextBytes (newPos - currentPos); | |||
| } | |||
| else | |||
| { | |||
| // reset the stream and start again.. | |||
| isEof = false; | |||
| activeBufferSize = 0; | |||
| currentPos = 0; | |||
| helper = new GZIPDecompressHelper (noWrap); | |||
| sourceStream->setPosition (originalSourcePos); | |||
| skipNextBytes (newPos); | |||
| } | |||
| // to go backwards, reset the stream and start again.. | |||
| isEof = false; | |||
| activeBufferSize = 0; | |||
| currentPos = 0; | |||
| helper = new GZIPDecompressHelper (noWrap); | |||
| sourceStream->setPosition (originalSourcePos); | |||
| } | |||
| skipNextBytes (newPos - currentPos); | |||
| return true; | |||
| } | |||
| @@ -270,12 +270,10 @@ void InputStream::skipNextBytes (int64 numBytesToSkip) | |||
| if (numBytesToSkip > 0) | |||
| { | |||
| const int skipBufferSize = (int) jmin (numBytesToSkip, (int64) 16384); | |||
| MemoryBlock temp (skipBufferSize); | |||
| HeapBlock <char> temp (skipBufferSize); | |||
| while ((numBytesToSkip > 0) && ! isExhausted()) | |||
| { | |||
| numBytesToSkip -= read (temp.getData(), (int) jmin (numBytesToSkip, (int64) skipBufferSize)); | |||
| } | |||
| while (numBytesToSkip > 0 && ! isExhausted()) | |||
| numBytesToSkip -= read (temp, (int) jmin (numBytesToSkip, (int64) skipBufferSize)); | |||
| } | |||
| } | |||
| @@ -120,6 +120,7 @@ | |||
| #if ! JUCE_ONLY_BUILD_CORE_LIBRARY | |||
| #include "containers/juce_ValueTree.cpp" | |||
| #include "containers/juce_Value.cpp" | |||
| #include "application/juce_Application.cpp" | |||
| #include "application/juce_ApplicationCommandInfo.cpp" | |||
| #include "application/juce_ApplicationCommandManager.cpp" | |||
| @@ -65,6 +65,9 @@ | |||
| #ifndef __JUCE_SPARSESET_JUCEHEADER__ | |||
| #include "containers/juce_SparseSet.h" | |||
| #endif | |||
| #ifndef __JUCE_VALUE_JUCEHEADER__ | |||
| #include "containers/juce_Value.h" | |||
| #endif | |||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | |||
| #include "containers/juce_ValueTree.h" | |||
| #endif | |||
| @@ -211,7 +211,10 @@ END_JUCE_NAMESPACE | |||
| fromConnection: (QTCaptureConnection*) connection | |||
| { | |||
| if (firstRecordedTime == 0) | |||
| firstRecordedTime = new Time (Time::getCurrentTime() - RelativeTime::milliseconds (50)); | |||
| { | |||
| const Time now (Time::getCurrentTime()); | |||
| firstRecordedTime = new Time (now - RelativeTime (0.1)); | |||
| } | |||
| } | |||
| @end | |||
| @@ -942,12 +942,20 @@ void NSViewComponentPeer::setFullScreen (bool shouldBeFullScreen) | |||
| if (fullScreen != shouldBeFullScreen) | |||
| { | |||
| if (shouldBeFullScreen) | |||
| r = Desktop::getInstance().getMainMonitorArea(); | |||
| if (shouldBeFullScreen && (getStyleFlags() & windowHasTitleBar) != 0) | |||
| { | |||
| fullScreen = true; | |||
| [window performZoom: nil]; | |||
| } | |||
| else | |||
| { | |||
| if (shouldBeFullScreen) | |||
| r = Desktop::getInstance().getMainMonitorArea(); | |||
| // (can't call the component's setBounds method because that'll reset our fullscreen flag) | |||
| if (r != getComponent()->getBounds() && ! r.isEmpty()) | |||
| setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight(), shouldBeFullScreen); | |||
| // (can't call the component's setBounds method because that'll reset our fullscreen flag) | |||
| if (r != getComponent()->getBounds() && ! r.isEmpty()) | |||
| setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight(), shouldBeFullScreen); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -479,12 +479,12 @@ bool ActiveXControlComponent::createControl (const void* controlIID) | |||
| control = info.release(); | |||
| setControlBounds (Rectangle (x, y, getWidth(), getHeight())); | |||
| info->controlHWND = getHWND (this); | |||
| ((ActiveXControlData*) control)->controlHWND = getHWND (this); | |||
| if (info->controlHWND != 0) | |||
| if (((ActiveXControlData*) control)->controlHWND != 0) | |||
| { | |||
| originalWndProc = (void*) (pointer_sized_int) GetWindowLongPtr ((HWND) info->controlHWND, GWLP_WNDPROC); | |||
| SetWindowLongPtr ((HWND) info->controlHWND, GWLP_WNDPROC, (LONG_PTR) activeXHookWndProc); | |||
| originalWndProc = (void*) (pointer_sized_int) GetWindowLongPtr ((HWND) ((ActiveXControlData*) control)->controlHWND, GWLP_WNDPROC); | |||
| SetWindowLongPtr ((HWND) ((ActiveXControlData*) control)->controlHWND, GWLP_WNDPROC, (LONG_PTR) activeXHookWndProc); | |||
| } | |||
| return true; | |||
| @@ -189,7 +189,9 @@ public: | |||
| { | |||
| if (recordNextFrameTime) | |||
| { | |||
| firstRecordedTime = Time::getCurrentTime(); | |||
| const double defaultCameraLatency = 0.1; | |||
| firstRecordedTime = Time::getCurrentTime() - RelativeTime (defaultCameraLatency); | |||
| recordNextFrameTime = false; | |||
| ComSmartPtr <IPin> pin; | |||
| @@ -42,7 +42,7 @@ | |||
| forEachXmlChildElement (*myParentXml, child) | |||
| { | |||
| if (child->hasTagName ("FOO")) | |||
| if (child->hasTagName (T("FOO"))) | |||
| doSomethingWithXmlElement (child); | |||
| } | |||
| @@ -100,12 +100,12 @@ | |||
| Here's an example of parsing some elements: @code | |||
| // check we're looking at the right kind of document.. | |||
| if (myElement->hasTagName ("ANIMALS")) | |||
| if (myElement->hasTagName (T("ANIMALS"))) | |||
| { | |||
| // now we'll iterate its sub-elements looking for 'giraffe' elements.. | |||
| forEachXmlChildElement (*myElement, e) | |||
| { | |||
| if (e->hasTagName ("GIRAFFE")) | |||
| if (e->hasTagName (T("GIRAFFE"))) | |||
| { | |||
| // found a giraffe, so use some of its attributes.. | |||