| @@ -615,6 +615,8 @@ | |||||
| 848170B110809E00008FEC33 /* juce_XmlElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E9D6104036D6006A1807 /* juce_XmlElement.cpp */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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 */; }; | 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>"; }; | 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>"; }; | 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>"; }; | 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>"; }; | 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>"; }; | 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; }; | 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 */, | 84AF3FE710EF9FF30035D74F /* juce_ScopedPointer.h */, | ||||
| 84F1E8DC10403671006A1807 /* juce_SortedSet.h */, | 84F1E8DC10403671006A1807 /* juce_SortedSet.h */, | ||||
| 84F1E8DD10403671006A1807 /* juce_SparseSet.h */, | 84F1E8DD10403671006A1807 /* juce_SparseSet.h */, | ||||
| 84BA603E10F2017A001D9D70 /* juce_Value.cpp */, | |||||
| 84BA603F10F2017A001D9D70 /* juce_Value.h */, | |||||
| 843D4A3910D3C54500624BA6 /* juce_ValueTree.cpp */, | 843D4A3910D3C54500624BA6 /* juce_ValueTree.cpp */, | ||||
| 843D4A3A10D3C54500624BA6 /* juce_ValueTree.h */, | 843D4A3A10D3C54500624BA6 /* juce_ValueTree.h */, | ||||
| 84F1E8DE10403671006A1807 /* juce_Variant.cpp */, | 84F1E8DE10403671006A1807 /* juce_Variant.cpp */, | ||||
| @@ -3216,6 +3224,7 @@ | |||||
| 84B2053E10D535EC008B4A79 /* juce_ValueTree.h in Headers */, | 84B2053E10D535EC008B4A79 /* juce_ValueTree.h in Headers */, | ||||
| 84AB6F6E10EF948B00117E64 /* juce_HeapBlock.h in Headers */, | 84AB6F6E10EF948B00117E64 /* juce_HeapBlock.h in Headers */, | ||||
| 84AF419B10F0008E0035D74F /* juce_ScopedPointer.h in Headers */, | 84AF419B10F0008E0035D74F /* juce_ScopedPointer.h in Headers */, | ||||
| 84842F9610F6559400490977 /* juce_Value.h in Headers */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -3542,6 +3551,7 @@ | |||||
| 843D4A3C10D3C54500624BA6 /* juce_ValueTree.h in Headers */, | 843D4A3C10D3C54500624BA6 /* juce_ValueTree.h in Headers */, | ||||
| 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */, | 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */, | ||||
| 84AF3FE810EF9FF30035D74F /* juce_ScopedPointer.h in Headers */, | 84AF3FE810EF9FF30035D74F /* juce_ScopedPointer.h in Headers */, | ||||
| 84BA604110F2017A001D9D70 /* juce_Value.h in Headers */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -3889,6 +3899,7 @@ | |||||
| 844BB95C10C5579A00DF5536 /* juce_FillType.cpp in Sources */, | 844BB95C10C5579A00DF5536 /* juce_FillType.cpp in Sources */, | ||||
| 844BB95E10C557A600DF5536 /* juce_mac_CoreGraphicsContext.mm in Sources */, | 844BB95E10C557A600DF5536 /* juce_mac_CoreGraphicsContext.mm in Sources */, | ||||
| 84B2053F10D535EC008B4A79 /* juce_ValueTree.cpp in Sources */, | 84B2053F10D535EC008B4A79 /* juce_ValueTree.cpp in Sources */, | ||||
| 84842F9510F6559300490977 /* juce_Value.cpp in Sources */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -4180,6 +4191,7 @@ | |||||
| 84AB91FF10A078190048FC39 /* juce_CPlusPlusCodeTokeniser.cpp in Sources */, | 84AB91FF10A078190048FC39 /* juce_CPlusPlusCodeTokeniser.cpp in Sources */, | ||||
| 84F29A9F10C2EFA5005014DF /* juce_FillType.cpp in Sources */, | 84F29A9F10C2EFA5005014DF /* juce_FillType.cpp in Sources */, | ||||
| 843D4A3B10D3C54500624BA6 /* juce_ValueTree.cpp in Sources */, | 843D4A3B10D3C54500624BA6 /* juce_ValueTree.cpp in Sources */, | ||||
| 84BA604010F2017A001D9D70 /* juce_Value.cpp in Sources */, | |||||
| ); | ); | ||||
| runOnlyForDeploymentPostprocessing = 0; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -1117,6 +1117,10 @@ | |||||
| RelativePath="..\..\..\src\containers\juce_ReferenceCountedObject.h" | RelativePath="..\..\..\src\containers\juce_ReferenceCountedObject.h" | ||||
| > | > | ||||
| </File> | </File> | ||||
| <File | |||||
| RelativePath="..\..\..\src\containers\juce_ScopedPointer.h" | |||||
| > | |||||
| </File> | |||||
| <File | <File | ||||
| RelativePath="..\..\..\src\containers\juce_SortedSet.h" | RelativePath="..\..\..\src\containers\juce_SortedSet.h" | ||||
| > | > | ||||
| @@ -1125,6 +1129,14 @@ | |||||
| RelativePath="..\..\..\src\containers\juce_SparseSet.h" | RelativePath="..\..\..\src\containers\juce_SparseSet.h" | ||||
| > | > | ||||
| </File> | </File> | ||||
| <File | |||||
| RelativePath="..\..\..\src\containers\juce_Value.cpp" | |||||
| > | |||||
| </File> | |||||
| <File | |||||
| RelativePath="..\..\..\src\containers\juce_Value.h" | |||||
| > | |||||
| </File> | |||||
| <File | <File | ||||
| RelativePath="..\..\..\src\containers\juce_ValueTree.cpp" | RelativePath="..\..\..\src\containers\juce_ValueTree.cpp" | ||||
| > | > | ||||
| @@ -385,8 +385,6 @@ public: | |||||
| shouldDeleteEditor = false; | shouldDeleteEditor = false; | ||||
| speakerIn = kSpeakerArrEmpty; | speakerIn = kSpeakerArrEmpty; | ||||
| speakerOut = kSpeakerArrEmpty; | speakerOut = kSpeakerArrEmpty; | ||||
| speakerInChans = 0; | |||||
| speakerOutChans = 0; | |||||
| numInChans = JucePlugin_MaxNumInputChannels; | numInChans = JucePlugin_MaxNumInputChannels; | ||||
| numOutChans = JucePlugin_MaxNumOutputChannels; | numOutChans = JucePlugin_MaxNumOutputChannels; | ||||
| @@ -1019,26 +1017,49 @@ public: | |||||
| return filter != 0 && filter->isParameterAutomatable ((int) index); | 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, | bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, | ||||
| VstSpeakerArrangement* pluginOutput) | 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) | 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; | speakerIn = (VstSpeakerArrangementType) pluginInput->type; | ||||
| speakerOut = (VstSpeakerArrangementType) pluginOutput->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->getSampleRate(), | ||||
| filter->getBlockSize()); | filter->getBlockSize()); | ||||
| return true; | return true; | ||||
| @@ -1392,7 +1413,6 @@ private: | |||||
| bool firstProcessCallback; | bool firstProcessCallback; | ||||
| int diffW, diffH; | int diffW, diffH; | ||||
| VstSpeakerArrangementType speakerIn, speakerOut; | VstSpeakerArrangementType speakerIn, speakerOut; | ||||
| int speakerInChans, speakerOutChans; | |||||
| int numInChans, numOutChans; | int numInChans, numOutChans; | ||||
| HeapBlock <float*> channels; | HeapBlock <float*> channels; | ||||
| VoidArray tempChannels; // see note in processReplacing() | VoidArray tempChannels; // see note in processReplacing() | ||||
| @@ -381,11 +381,32 @@ static Component* createSlidersPage() | |||||
| for (i = 7; i <= 10; ++i) | for (i = 7; i <= 10; ++i) | ||||
| { | { | ||||
| sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); | 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); | 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* 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); | label->setBounds (20, 245, 350, 150); | ||||
| page->addAndMakeVisible (label); | page->addAndMakeVisible (label); | ||||
| @@ -8132,7 +8132,7 @@ private: | |||||
| forEachXmlChildElement (*myParentXml, child) | forEachXmlChildElement (*myParentXml, child) | ||||
| { | { | ||||
| if (child->hasTagName ("FOO")) | |||||
| if (child->hasTagName (T("FOO"))) | |||||
| doSomethingWithXmlElement (child); | doSomethingWithXmlElement (child); | ||||
| } | } | ||||
| @@ -8188,12 +8188,12 @@ private: | |||||
| Here's an example of parsing some elements: @code | Here's an example of parsing some elements: @code | ||||
| // check we're looking at the right kind of document.. | // 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.. | // now we'll iterate its sub-elements looking for 'giraffe' elements.. | ||||
| forEachXmlChildElement (*myElement, e) | forEachXmlChildElement (*myElement, e) | ||||
| { | { | ||||
| if (e->hasTagName ("GIRAFFE")) | |||||
| if (e->hasTagName (T("GIRAFFE"))) | |||||
| { | { | ||||
| // found a giraffe, so use some of its attributes.. | // found a giraffe, so use some of its attributes.. | ||||
| @@ -11105,11 +11105,11 @@ private: | |||||
| /********* End of inlined file: juce_SparseSet.h *********/ | /********* End of inlined file: juce_SparseSet.h *********/ | ||||
| #endif | #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 *********/ | /********* Start of inlined file: juce_Variant.h *********/ | ||||
| #ifndef __JUCE_VARIANT_JUCEHEADER__ | #ifndef __JUCE_VARIANT_JUCEHEADER__ | ||||
| @@ -11338,51 +11338,9 @@ private: | |||||
| #endif // __JUCE_VARIANT_JUCEHEADER__ | #endif // __JUCE_VARIANT_JUCEHEADER__ | ||||
| /********* End of inlined file: juce_Variant.h *********/ | /********* 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 *********/ | /********* Start of inlined file: juce_MessageListener.h *********/ | ||||
| #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ | #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ | ||||
| @@ -11507,6 +11465,313 @@ public: | |||||
| #endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ | #endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ | ||||
| /********* End of inlined file: juce_MessageListener.h *********/ | /********* 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 *********/ | /********* Start of inlined file: juce_ScopedLock.h *********/ | ||||
| #ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ | #ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ | ||||
| #define __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 | Like an XmlElement, each ValueTree node has a type, which you can access with | ||||
| getType() and hasType(). | getType() and hasType(). | ||||
| */ | */ | ||||
| ValueTree (const String& type) throw(); | |||||
| ValueTree (const String& type); | |||||
| /** Creates a reference to another ValueTree. */ | /** Creates a reference to another ValueTree. */ | ||||
| ValueTree (const ValueTree& other) throw(); | |||||
| ValueTree (const ValueTree& other); | |||||
| /** Makes this object reference another node. */ | /** Makes this object reference another node. */ | ||||
| const ValueTree& operator= (const ValueTree& other) throw(); | |||||
| const ValueTree& operator= (const ValueTree& other); | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~ValueTree() throw(); | |||||
| ~ValueTree(); | |||||
| /** Returns true if both this and the other tree node refer to the same underlying structure. | /** 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 | Note that this isn't a value comparison - two independently-created trees which | ||||
| contain identical data are not considered equal. | 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. | /** 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 | Note that this isn't a value comparison - two independently-created trees which | ||||
| contain identical data are not considered equal. | 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. | /** 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 | It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range | ||||
| call to getChild(). | 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. */ | /** 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. | /** Returns the type of this node. | ||||
| The type is specified when the ValueTree is created. | The type is specified when the ValueTree is created. | ||||
| @see hasType | @see hasType | ||||
| */ | */ | ||||
| const String getType() const throw(); | |||||
| const String getType() const; | |||||
| /** Returns true if the node has this type. | /** Returns true if the node has this type. | ||||
| The comparison is case-sensitive. | 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. | /** Returns the value of a named property. | ||||
| If no such property has been set, this will return a void variant. | If no such property has been set, this will return a void variant. | ||||
| You can also use operator[] to get a property. | You can also use operator[] to get a property. | ||||
| @see var, setProperty, hasProperty | @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. | /** 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 | If no such property has been set, this will return a void variant. This is the same as | ||||
| calling getProperty(). | calling getProperty(). | ||||
| @see 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. | /** Changes a named property of the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | so that this change can be undone. | ||||
| @see var, getProperty, removeProperty | @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. */ | /** 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. | /** Removes a property from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes all properties from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Returns the total number of properties that the node contains. | ||||
| @see getProperty. | @see getProperty. | ||||
| */ | */ | ||||
| int getNumProperties() const throw(); | |||||
| int getNumProperties() const; | |||||
| /** Returns the identifier of the property with a given index. | /** Returns the identifier of the property with a given index. | ||||
| @see getNumProperties | @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. | /** Returns the number of child nodes belonging to this one. | ||||
| @see getChild | @see getChild | ||||
| */ | */ | ||||
| int getNumChildren() const throw(); | |||||
| int getNumChildren() const; | |||||
| /** Returns one of this node's child nodes. | /** 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 | If the index is out of range, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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 | If no such node is found, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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 | If no such node is found, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes the specified child from this node's child-list. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes a child from this node's child-list. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes all child-nodes from this node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** 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. | 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. | /** 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 | If the node has no parent, this will return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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() | be used to recreate a similar node by calling fromXml() | ||||
| @see fromXml | @see fromXml | ||||
| */ | */ | ||||
| XmlElement* createXml() const throw(); | |||||
| XmlElement* createXml() const; | |||||
| /** Tries to recreate a node from its XML representation. | /** 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 | 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. | 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. | /** 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 | It's much faster to load/save your tree in binary form than as XML, but | ||||
| obviously isn't human-readable. | 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(). | /** 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. | /** Listener class for events that happen to a ValueTree. | ||||
| @@ -12275,21 +12548,34 @@ public: | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| virtual ~Listener() {} | 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. */ | /** 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; | virtual void valueTreeChildrenChanged (ValueTree& tree) = 0; | ||||
| /** This method is called when this node has been added or removed from a parent node. */ | /** 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(). */ | /** Removes a listener that was previously added with addListener(). */ | ||||
| void removeListener (Listener* listener) throw(); | |||||
| void removeListener (Listener* listener); | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -12297,16 +12583,16 @@ private: | |||||
| friend class ValueTreeSetPropertyAction; | friend class ValueTreeSetPropertyAction; | ||||
| friend class ValueTreeChildChangeAction; | friend class ValueTreeChildChangeAction; | ||||
| class SharedObject : public ReferenceCountedObject | |||||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||||
| { | { | ||||
| public: | public: | ||||
| SharedObject (const String& type) throw(); | |||||
| SharedObject (const SharedObject& other) throw(); | |||||
| ~SharedObject() throw(); | |||||
| SharedObject (const String& type); | |||||
| SharedObject (const SharedObject& other); | |||||
| ~SharedObject(); | |||||
| struct Property | struct Property | ||||
| { | { | ||||
| Property (const var::identifier& name, const var& value) throw(); | |||||
| Property (const var::identifier& name, const var& value); | |||||
| var::identifier name; | var::identifier name; | ||||
| var value; | var value; | ||||
| @@ -12315,24 +12601,29 @@ private: | |||||
| const String type; | const String type; | ||||
| OwnedArray <Property> properties; | OwnedArray <Property> properties; | ||||
| ReferenceCountedArray <SharedObject> children; | ReferenceCountedArray <SharedObject> children; | ||||
| SortedSet <Listener*> listeners; | |||||
| SortedSet <ValueTree*> valueTreesWithListeners; | |||||
| SharedObject* parent; | SharedObject* parent; | ||||
| void sendPropertyChangeMessage(); | |||||
| void sendPropertyChangeMessage (const var::identifier& property); | |||||
| void sendChildChangeMessage(); | void sendChildChangeMessage(); | ||||
| void sendParentChangeMessage(); | 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; | friend class SharedObject; | ||||
| @@ -12340,8 +12631,13 @@ private: | |||||
| typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | ||||
| ReferenceCountedObjectPtr <SharedObject> object; | 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__ | #endif // __JUCE_VALUETREE_JUCEHEADER__ | ||||
| @@ -25633,92 +25929,6 @@ public: | |||||
| #ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ | #ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ | ||||
| #define __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 *********/ | /********* Start of inlined file: juce_Desktop.h *********/ | ||||
| #ifndef __JUCE_DESKTOP_JUCEHEADER__ | #ifndef __JUCE_DESKTOP_JUCEHEADER__ | ||||
| #define __JUCE_DESKTOP_JUCEHEADER__ | #define __JUCE_DESKTOP_JUCEHEADER__ | ||||
| @@ -42583,7 +42793,8 @@ class JUCE_API Slider : public Component, | |||||
| public SettableTooltipClient, | public SettableTooltipClient, | ||||
| private AsyncUpdater, | private AsyncUpdater, | ||||
| private ButtonListener, | private ButtonListener, | ||||
| private LabelListener | |||||
| private LabelListener, | |||||
| private Value::Listener | |||||
| { | { | ||||
| public: | public: | ||||
| @@ -42868,6 +43079,14 @@ public: | |||||
| /** Returns the slider's current value. */ | /** Returns the slider's current value. */ | ||||
| double getValue() const; | 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. | /** Sets the limits that the slider's value can take. | ||||
| @param newMinimum the lowest value allowed | @param newMinimum the lowest value allowed | ||||
| @@ -42904,6 +43123,14 @@ public: | |||||
| */ | */ | ||||
| double getMinValue() const; | 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. | /** 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 | This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | ||||
| @@ -42938,6 +43165,14 @@ public: | |||||
| */ | */ | ||||
| double getMaxValue() const; | 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. | /** 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 | This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | ||||
| @@ -43223,10 +43458,13 @@ protected: | |||||
| void handleAsyncUpdate(); | void handleAsyncUpdate(); | ||||
| /** @internal */ | /** @internal */ | ||||
| void colourChanged(); | void colourChanged(); | ||||
| /** @internal */ | |||||
| void valueChanged (Value& value); | |||||
| private: | private: | ||||
| SortedSet <void*> listeners; | SortedSet <void*> listeners; | ||||
| double currentValue, valueMin, valueMax; | |||||
| Value currentValue, valueMin, valueMax; | |||||
| double lastCurrentValue, lastValueMin, lastValueMax; | |||||
| double minimum, maximum, interval, doubleClickReturnValue; | double minimum, maximum, interval, doubleClickReturnValue; | ||||
| double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | ||||
| double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | ||||
| @@ -254,24 +254,24 @@ MidiMessage::MidiMessage (const uint8* src, | |||||
| const MidiMessage& MidiMessage::operator= (const MidiMessage& other) throw() | 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; | return *this; | ||||
| @@ -293,12 +293,16 @@ int MidiMessage::getChannel() const throw() | |||||
| bool MidiMessage::isForChannel (const int channel) 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) | return ((data[0] & 0xf) == channel - 1) | ||||
| && ((data[0] & 0xf0) != 0xf0); | && ((data[0] & 0xf0) != 0xf0); | ||||
| } | } | ||||
| void MidiMessage::setChannel (const int channel) throw() | 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) | if ((data[0] & 0xf0) != (uint8) 0xf0) | ||||
| data[0] = (uint8) ((data[0] & (uint8)0xf0) | data[0] = (uint8) ((data[0] & (uint8)0xf0) | ||||
| | (uint8)(channel - 1)); | | (uint8)(channel - 1)); | ||||
| @@ -372,7 +376,7 @@ const MidiMessage MidiMessage::aftertouchChange (const int channel, | |||||
| const int noteNum, | const int noteNum, | ||||
| const int aftertouchValue) throw() | 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) noteNum) <= 127); | ||||
| jassert (((unsigned int) aftertouchValue) <= 127); | jassert (((unsigned int) aftertouchValue) <= 127); | ||||
| @@ -396,7 +400,7 @@ int MidiMessage::getChannelPressureValue() const throw() | |||||
| const MidiMessage MidiMessage::channelPressureChange (const int channel, | const MidiMessage MidiMessage::channelPressureChange (const int channel, | ||||
| const int pressure) throw() | 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); | jassert (((unsigned int) pressure) <= 127); | ||||
| return MidiMessage (0xd0 | jlimit (0, 15, channel - 1), | 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 MidiMessage MidiMessage::programChange (const int channel, | ||||
| const int programNumber) throw() | 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), | return MidiMessage (0xc0 | jlimit (0, 15, channel - 1), | ||||
| programNumber & 0x7f); | programNumber & 0x7f); | ||||
| @@ -435,7 +439,7 @@ int MidiMessage::getPitchWheelValue() const throw() | |||||
| const MidiMessage MidiMessage::pitchWheel (const int channel, | const MidiMessage MidiMessage::pitchWheel (const int channel, | ||||
| const int position) throw() | 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); | jassert (((unsigned int) position) <= 0x3fff); | ||||
| return MidiMessage (0xe0 | jlimit (0, 15, channel - 1), | 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: | public: | ||||
| ValueTreeSetPropertyAction (const ValueTree::SharedObjectPtr& target_, const var::identifier& name_, | 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_), | : target (target_), name (name_), newValue (newValue_), | ||||
| isAddingNewProperty (isAddingNewProperty_), | isAddingNewProperty (isAddingNewProperty_), | ||||
| isDeletingProperty (isDeletingProperty_) | isDeletingProperty (isDeletingProperty_) | ||||
| @@ -89,7 +89,7 @@ class ValueTreeChildChangeAction : public UndoableAction | |||||
| { | { | ||||
| public: | public: | ||||
| ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_, | ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_, | ||||
| const ValueTree::SharedObjectPtr& newChild_) throw() | |||||
| const ValueTree::SharedObjectPtr& newChild_) | |||||
| : target (target_), | : target (target_), | ||||
| child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]), | child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]), | ||||
| childIndex (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) | : type (type_), parent (0) | ||||
| { | { | ||||
| } | } | ||||
| ValueTree::SharedObject::SharedObject (const SharedObject& other) throw() | |||||
| ValueTree::SharedObject::SharedObject (const SharedObject& other) | |||||
| : type (other.type), parent (0) | : type (other.type), parent (0) | ||||
| { | { | ||||
| int i; | int i; | ||||
| @@ -155,7 +155,7 @@ ValueTree::SharedObject::SharedObject (const SharedObject& other) throw() | |||||
| children.add (new SharedObject (*other.children.getUnchecked(i))); | 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! | 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_) | : 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;) | for (int i = listeners.size(); --i >= 0;) | ||||
| { | { | ||||
| ValueTree::Listener* const l = listeners[i]; | ValueTree::Listener* const l = listeners[i]; | ||||
| if (l != 0) | 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;) | 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;) | for (int i = listeners.size(); --i >= 0;) | ||||
| { | { | ||||
| ValueTree::Listener* const l = listeners[i]; | ValueTree::Listener* const l = listeners[i]; | ||||
| if (l != 0) | 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;) | for (int i = properties.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -228,7 +261,7 @@ const var ValueTree::SharedObject::getProperty (const var::identifier& name) con | |||||
| return var(); | 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;) | for (int i = properties.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -241,7 +274,7 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va | |||||
| if (undoManager == 0) | if (undoManager == 0) | ||||
| { | { | ||||
| p->value = newValue; | p->value = newValue; | ||||
| sendPropertyChangeMessage(); | |||||
| sendPropertyChangeMessage (name); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -256,7 +289,7 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va | |||||
| if (undoManager == 0) | if (undoManager == 0) | ||||
| { | { | ||||
| properties.add (new Property (name, newValue)); | properties.add (new Property (name, newValue)); | ||||
| sendPropertyChangeMessage(); | |||||
| sendPropertyChangeMessage (name); | |||||
| } | } | ||||
| else | 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;) | for (int i = properties.size(); --i >= 0;) | ||||
| if (properties.getUnchecked(i)->name == name) | if (properties.getUnchecked(i)->name == name) | ||||
| @@ -273,7 +306,7 @@ bool ValueTree::SharedObject::hasProperty (const var::identifier& name) const th | |||||
| return false; | 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;) | for (int i = properties.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -284,7 +317,7 @@ void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoM | |||||
| if (undoManager == 0) | if (undoManager == 0) | ||||
| { | { | ||||
| properties.remove (i); | properties.remove (i); | ||||
| sendPropertyChangeMessage(); | |||||
| sendPropertyChangeMessage (name); | |||||
| } | } | ||||
| else | 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) | if (undoManager == 0) | ||||
| { | { | ||||
| properties.clear(); | |||||
| sendPropertyChangeMessage(); | |||||
| while (properties.size() > 0) | |||||
| { | |||||
| const var::identifier name (properties.getLast()->name); | |||||
| properties.removeLast(); | |||||
| sendPropertyChangeMessage (name); | |||||
| } | |||||
| } | } | ||||
| else | 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) | for (int i = 0; i < children.size(); ++i) | ||||
| if (children.getUnchecked(i)->type == typeToMatch) | if (children.getUnchecked(i)->type == typeToMatch) | ||||
| @@ -319,7 +356,7 @@ ValueTree ValueTree::SharedObject::getChildWithName (const String& typeToMatch) | |||||
| return (SharedObject*) 0; | 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) | for (int i = 0; i < children.size(); ++i) | ||||
| if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue) | if (children.getUnchecked(i)->getProperty (propertyName) == propertyValue) | ||||
| @@ -328,7 +365,7 @@ ValueTree ValueTree::SharedObject::getChildWithProperty (const var::identifier& | |||||
| return (SharedObject*) 0; | 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; | const SharedObject* p = parent; | ||||
| @@ -343,7 +380,7 @@ bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possiblePare | |||||
| return false; | 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) | 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]); | 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) | while (children.size() > 0) | ||||
| removeChild (children.size() - 1, 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_)) | : object (new ValueTree::SharedObject (type_)) | ||||
| { | { | ||||
| jassert (type_.isNotEmpty()); // All objects should be given a sensible type name! | 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_) | : object (object_) | ||||
| { | { | ||||
| } | } | ||||
| ValueTree::ValueTree (const ValueTree& other) throw() | |||||
| ValueTree::ValueTree (const ValueTree& other) | |||||
| : object (other.object) | : 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; | object = other.object; | ||||
| return *this; | 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; | return object == other.object; | ||||
| } | } | ||||
| bool ValueTree::operator!= (const ValueTree& other) const throw() | |||||
| bool ValueTree::operator!= (const ValueTree& other) const | |||||
| { | { | ||||
| return object != other.object; | return object != other.object; | ||||
| } | } | ||||
| ValueTree ValueTree::createCopy() const throw() | |||||
| ValueTree ValueTree::createCopy() const | |||||
| { | { | ||||
| return ValueTree (object != 0 ? new SharedObject (*object) : 0); | 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; | return object != 0 && object->type == typeName; | ||||
| } | } | ||||
| const String ValueTree::getType() const throw() | |||||
| const String ValueTree::getType() const | |||||
| { | { | ||||
| return object != 0 ? object->type : String::empty; | 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); | 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); | 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); | 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()); | jassert (name.name.isNotEmpty()); | ||||
| @@ -483,101 +532,158 @@ void ValueTree::setProperty (const var::identifier& name, const var& newValue, U | |||||
| object->setProperty (name, newValue, undoManager); | 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); | 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) | if (object != 0) | ||||
| object->removeProperty (name, undoManager); | object->removeProperty (name, undoManager); | ||||
| } | } | ||||
| void ValueTree::removeAllProperties (UndoManager* const undoManager) throw() | |||||
| void ValueTree::removeAllProperties (UndoManager* const undoManager) | |||||
| { | { | ||||
| if (object != 0) | if (object != 0) | ||||
| object->removeAllProperties (undoManager); | object->removeAllProperties (undoManager); | ||||
| } | } | ||||
| int ValueTree::getNumProperties() const throw() | |||||
| int ValueTree::getNumProperties() const | |||||
| { | { | ||||
| return object == 0 ? 0 : object->properties.size(); | 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]; | const SharedObject::Property* const p = (object == 0) ? 0 : object->properties [index]; | ||||
| return p != 0 ? p->name : var::identifier (String::empty); | 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(); | 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); | 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); | 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); | 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); | 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) | if (object != 0) | ||||
| object->addChild (child.object, index, undoManager); | 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) | if (object != 0) | ||||
| object->removeChild (childIndex, undoManager); | object->removeChild (childIndex, undoManager); | ||||
| } | } | ||||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) throw() | |||||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) | |||||
| { | { | ||||
| if (object != 0) | if (object != 0) | ||||
| object->removeChild (object->children.indexOf (child.object), undoManager); | object->removeChild (object->children.indexOf (child.object), undoManager); | ||||
| } | } | ||||
| void ValueTree::removeAllChildren (UndoManager* const undoManager) throw() | |||||
| void ValueTree::removeAllChildren (UndoManager* const undoManager) | |||||
| { | { | ||||
| if (object != 0) | if (object != 0) | ||||
| object->removeAllChildren (undoManager); | 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); | XmlElement* xml = new XmlElement (type); | ||||
| @@ -597,12 +703,12 @@ XmlElement* ValueTree::SharedObject::createXml() const throw() | |||||
| return xml; | return xml; | ||||
| } | } | ||||
| XmlElement* ValueTree::createXml() const throw() | |||||
| XmlElement* ValueTree::createXml() const | |||||
| { | { | ||||
| return object != 0 ? object->createXml() : 0; | return object != 0 ? object->createXml() : 0; | ||||
| } | } | ||||
| ValueTree ValueTree::fromXml (const XmlElement& xml) throw() | |||||
| ValueTree ValueTree::fromXml (const XmlElement& xml) | |||||
| { | { | ||||
| ValueTree v (xml.getTagName()); | 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()); | output.writeString (getType()); | ||||
| @@ -642,7 +748,7 @@ void ValueTree::writeToStream (OutputStream& output) throw() | |||||
| getChild (i).writeToStream (output); | getChild (i).writeToStream (output); | ||||
| } | } | ||||
| ValueTree ValueTree::readFromStream (InputStream& input) throw() | |||||
| ValueTree ValueTree::readFromStream (InputStream& input) | |||||
| { | { | ||||
| String type (input.readString()); | String type (input.readString()); | ||||
| @@ -27,11 +27,11 @@ | |||||
| #define __JUCE_VALUETREE_JUCEHEADER__ | #define __JUCE_VALUETREE_JUCEHEADER__ | ||||
| #include "juce_Variant.h" | #include "juce_Variant.h" | ||||
| #include "juce_Value.h" | |||||
| #include "../utilities/juce_UndoManager.h" | #include "../utilities/juce_UndoManager.h" | ||||
| #include "../text/juce_XmlElement.h" | #include "../text/juce_XmlElement.h" | ||||
| #include "juce_ReferenceCountedArray.h" | #include "juce_ReferenceCountedArray.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| A powerful tree structure that can be used to hold free-form data, and which can | 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 | Like an XmlElement, each ValueTree node has a type, which you can access with | ||||
| getType() and hasType(). | getType() and hasType(). | ||||
| */ | */ | ||||
| ValueTree (const String& type) throw(); | |||||
| ValueTree (const String& type); | |||||
| /** Creates a reference to another ValueTree. */ | /** Creates a reference to another ValueTree. */ | ||||
| ValueTree (const ValueTree& other) throw(); | |||||
| ValueTree (const ValueTree& other); | |||||
| /** Makes this object reference another node. */ | /** Makes this object reference another node. */ | ||||
| const ValueTree& operator= (const ValueTree& other) throw(); | |||||
| const ValueTree& operator= (const ValueTree& other); | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~ValueTree() throw(); | |||||
| ~ValueTree(); | |||||
| /** Returns true if both this and the other tree node refer to the same underlying structure. | /** 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 | Note that this isn't a value comparison - two independently-created trees which | ||||
| contain identical data are not considered equal. | 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. | /** 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 | Note that this isn't a value comparison - two independently-created trees which | ||||
| contain identical data are not considered equal. | 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. | /** 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 | It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range | ||||
| call to getChild(). | 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. */ | /** 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. | /** Returns the type of this node. | ||||
| The type is specified when the ValueTree is created. | The type is specified when the ValueTree is created. | ||||
| @see hasType | @see hasType | ||||
| */ | */ | ||||
| const String getType() const throw(); | |||||
| const String getType() const; | |||||
| /** Returns true if the node has this type. | /** Returns true if the node has this type. | ||||
| The comparison is case-sensitive. | 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. | /** Returns the value of a named property. | ||||
| @@ -126,64 +126,72 @@ public: | |||||
| You can also use operator[] to get a property. | You can also use operator[] to get a property. | ||||
| @see var, setProperty, hasProperty | @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. | /** 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 | If no such property has been set, this will return a void variant. This is the same as | ||||
| calling getProperty(). | calling getProperty(). | ||||
| @see 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. | /** Changes a named property of the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | so that this change can be undone. | ||||
| @see var, getProperty, removeProperty | @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. */ | /** 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. | /** Removes a property from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes all properties from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Returns the total number of properties that the node contains. | ||||
| @see getProperty. | @see getProperty. | ||||
| */ | */ | ||||
| int getNumProperties() const throw(); | |||||
| int getNumProperties() const; | |||||
| /** Returns the identifier of the property with a given index. | /** Returns the identifier of the property with a given index. | ||||
| @see getNumProperties | @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. | /** Returns the number of child nodes belonging to this one. | ||||
| @see getChild | @see getChild | ||||
| */ | */ | ||||
| int getNumChildren() const throw(); | |||||
| int getNumChildren() const; | |||||
| /** Returns one of this node's child nodes. | /** 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 | If the index is out of range, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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 | If no such node is found, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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 | If no such node is found, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes the specified child from this node's child-list. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes a child from this node's child-list. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** Removes all child-nodes from this node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | 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. | /** 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. | 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. | /** 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 | If the node has no parent, this will return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | 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. | /** 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() | be used to recreate a similar node by calling fromXml() | ||||
| @see fromXml | @see fromXml | ||||
| */ | */ | ||||
| XmlElement* createXml() const throw(); | |||||
| XmlElement* createXml() const; | |||||
| /** Tries to recreate a node from its XML representation. | /** 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 | 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. | 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. | /** 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 | It's much faster to load/save your tree in binary form than as XML, but | ||||
| obviously isn't human-readable. | 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(). | /** 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. | /** Listener class for events that happen to a ValueTree. | ||||
| @@ -279,21 +287,34 @@ public: | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| virtual ~Listener() {} | 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. */ | /** 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; | virtual void valueTreeChildrenChanged (ValueTree& tree) = 0; | ||||
| /** This method is called when this node has been added or removed from a parent node. */ | /** 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(). */ | /** Removes a listener that was previously added with addListener(). */ | ||||
| void removeListener (Listener* listener) throw(); | |||||
| void removeListener (Listener* listener); | |||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -302,16 +323,16 @@ private: | |||||
| friend class ValueTreeSetPropertyAction; | friend class ValueTreeSetPropertyAction; | ||||
| friend class ValueTreeChildChangeAction; | friend class ValueTreeChildChangeAction; | ||||
| class SharedObject : public ReferenceCountedObject | |||||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||||
| { | { | ||||
| public: | public: | ||||
| SharedObject (const String& type) throw(); | |||||
| SharedObject (const SharedObject& other) throw(); | |||||
| ~SharedObject() throw(); | |||||
| SharedObject (const String& type); | |||||
| SharedObject (const SharedObject& other); | |||||
| ~SharedObject(); | |||||
| struct Property | struct Property | ||||
| { | { | ||||
| Property (const var::identifier& name, const var& value) throw(); | |||||
| Property (const var::identifier& name, const var& value); | |||||
| var::identifier name; | var::identifier name; | ||||
| var value; | var value; | ||||
| @@ -320,24 +341,29 @@ private: | |||||
| const String type; | const String type; | ||||
| OwnedArray <Property> properties; | OwnedArray <Property> properties; | ||||
| ReferenceCountedArray <SharedObject> children; | ReferenceCountedArray <SharedObject> children; | ||||
| SortedSet <Listener*> listeners; | |||||
| SortedSet <ValueTree*> valueTreesWithListeners; | |||||
| SharedObject* parent; | SharedObject* parent; | ||||
| void sendPropertyChangeMessage(); | |||||
| void sendPropertyChangeMessage (const var::identifier& property); | |||||
| void sendChildChangeMessage(); | void sendChildChangeMessage(); | ||||
| void sendParentChangeMessage(); | 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; | friend class SharedObject; | ||||
| @@ -345,8 +371,13 @@ private: | |||||
| typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr; | ||||
| ReferenceCountedObjectPtr <SharedObject> object; | 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) | Slider::Slider (const String& name) | ||||
| : Component (name), | : Component (name), | ||||
| listeners (2), | listeners (2), | ||||
| currentValue (0.0), | |||||
| valueMin (0.0), | |||||
| valueMax (0.0), | |||||
| lastCurrentValue (0), | |||||
| lastValueMin (0), | |||||
| lastValueMax (0), | |||||
| minimum (0), | minimum (0), | ||||
| maximum (10), | maximum (10), | ||||
| interval (0), | interval (0), | ||||
| @@ -137,10 +137,17 @@ Slider::Slider (const String& name) | |||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| updateText(); | updateText(); | ||||
| currentValue.addListener (this); | |||||
| valueMin.addListener (this); | |||||
| valueMax.addListener (this); | |||||
| } | } | ||||
| Slider::~Slider() | Slider::~Slider() | ||||
| { | { | ||||
| currentValue.removeListener (this); | |||||
| valueMin.removeListener (this); | |||||
| valueMax.removeListener (this); | |||||
| popupDisplay = 0; | popupDisplay = 0; | ||||
| deleteAllChildren(); | deleteAllChildren(); | ||||
| } | } | ||||
| @@ -334,7 +341,7 @@ void Slider::colourChanged() | |||||
| void Slider::lookAndFeelChanged() | void Slider::lookAndFeelChanged() | ||||
| { | { | ||||
| const String previousTextBoxContent (valueBox != 0 ? valueBox->getText() | const String previousTextBoxContent (valueBox != 0 ? valueBox->getText() | ||||
| : getTextFromValue (currentValue)); | |||||
| : getTextFromValue (currentValue.getValue())); | |||||
| deleteAllChildren(); | deleteAllChildren(); | ||||
| valueBox = 0; | valueBox = 0; | ||||
| @@ -420,7 +427,7 @@ void Slider::setRange (const double newMin, | |||||
| // keep the current values inside the new range.. | // keep the current values inside the new range.. | ||||
| if (style != TwoValueHorizontal && style != TwoValueVertical) | if (style != TwoValueHorizontal && style != TwoValueVertical) | ||||
| { | { | ||||
| setValue (currentValue, false, false); | |||||
| setValue (getValue(), false, false); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -442,13 +449,26 @@ void Slider::triggerChangeMessage (const bool synchronous) | |||||
| valueChanged(); | 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 | double Slider::getValue() const | ||||
| { | { | ||||
| // for a two-value style slider, you should use the getMinValue() and getMaxValue() | // for a two-value style slider, you should use the getMinValue() and getMaxValue() | ||||
| // methods to get the two values. | // methods to get the two values. | ||||
| jassert (style != TwoValueHorizontal && style != TwoValueVertical); | jassert (style != TwoValueHorizontal && style != TwoValueVertical); | ||||
| return currentValue; | |||||
| return currentValue.getValue(); | |||||
| } | } | ||||
| void Slider::setValue (double newValue, | void Slider::setValue (double newValue, | ||||
| @@ -463,22 +483,26 @@ void Slider::setValue (double newValue, | |||||
| if (style == ThreeValueHorizontal || style == ThreeValueVertical) | 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) | if (valueBox != 0) | ||||
| valueBox->hideEditor (true); | valueBox->hideEditor (true); | ||||
| currentValue = newValue; | |||||
| lastCurrentValue = newValue; | |||||
| currentValue = var (newValue); | |||||
| updateText(); | updateText(); | ||||
| repaint(); | repaint(); | ||||
| if (popupDisplay != 0) | if (popupDisplay != 0) | ||||
| { | { | ||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (currentValue)); | |||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (newValue)); | |||||
| popupDisplay->repaint(); | popupDisplay->repaint(); | ||||
| } | } | ||||
| @@ -493,7 +517,7 @@ double Slider::getMinValue() const | |||||
| jassert (style == TwoValueHorizontal || style == TwoValueVertical | jassert (style == TwoValueHorizontal || style == TwoValueVertical | ||||
| || style == ThreeValueHorizontal || style == ThreeValueVertical); | || style == ThreeValueHorizontal || style == ThreeValueVertical); | ||||
| return valueMin; | |||||
| return valueMin.getValue(); | |||||
| } | } | ||||
| double Slider::getMaxValue() const | double Slider::getMaxValue() const | ||||
| @@ -502,7 +526,7 @@ double Slider::getMaxValue() const | |||||
| jassert (style == TwoValueHorizontal || style == TwoValueVertical | jassert (style == TwoValueHorizontal || style == TwoValueVertical | ||||
| || style == ThreeValueHorizontal || style == ThreeValueVertical); | || style == ThreeValueHorizontal || style == ThreeValueVertical); | ||||
| return valueMax; | |||||
| return valueMax.getValue(); | |||||
| } | } | ||||
| void Slider::setMinValue (double newValue, const bool sendUpdateMessage, const bool sendMessageSynchronously, const bool allowNudgingOfOtherValues) | 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 (style == TwoValueHorizontal || style == TwoValueVertical) | ||||
| { | { | ||||
| if (allowNudgingOfOtherValues && newValue > valueMax) | |||||
| if (allowNudgingOfOtherValues && newValue > (double) valueMax.getValue()) | |||||
| setMaxValue (newValue, sendUpdateMessage, sendMessageSynchronously); | setMaxValue (newValue, sendUpdateMessage, sendMessageSynchronously); | ||||
| newValue = jmin (valueMax, newValue); | |||||
| newValue = jmin ((double) valueMax.getValue(), newValue); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (allowNudgingOfOtherValues && newValue > currentValue) | |||||
| if (allowNudgingOfOtherValues && newValue > (double) currentValue.getValue()) | |||||
| setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | ||||
| newValue = jmin (currentValue, newValue); | |||||
| newValue = jmin ((double) currentValue.getValue(), newValue); | |||||
| } | } | ||||
| if (valueMin != newValue) | |||||
| if (lastValueMin != newValue) | |||||
| { | { | ||||
| lastValueMin = newValue; | |||||
| valueMin = newValue; | valueMin = newValue; | ||||
| repaint(); | repaint(); | ||||
| if (popupDisplay != 0) | if (popupDisplay != 0) | ||||
| { | { | ||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMin)); | |||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (newValue)); | |||||
| popupDisplay->repaint(); | popupDisplay->repaint(); | ||||
| } | } | ||||
| @@ -554,27 +579,28 @@ void Slider::setMaxValue (double newValue, const bool sendUpdateMessage, const b | |||||
| if (style == TwoValueHorizontal || style == TwoValueVertical) | if (style == TwoValueHorizontal || style == TwoValueVertical) | ||||
| { | { | ||||
| if (allowNudgingOfOtherValues && newValue < valueMin) | |||||
| if (allowNudgingOfOtherValues && newValue < (double) valueMin.getValue()) | |||||
| setMinValue (newValue, sendUpdateMessage, sendMessageSynchronously); | setMinValue (newValue, sendUpdateMessage, sendMessageSynchronously); | ||||
| newValue = jmax (valueMin, newValue); | |||||
| newValue = jmax ((double) valueMin.getValue(), newValue); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (allowNudgingOfOtherValues && newValue < currentValue) | |||||
| if (allowNudgingOfOtherValues && newValue < (double) currentValue.getValue()) | |||||
| setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | setValue (newValue, sendUpdateMessage, sendMessageSynchronously); | ||||
| newValue = jmax (currentValue, newValue); | |||||
| newValue = jmax ((double) currentValue.getValue(), newValue); | |||||
| } | } | ||||
| if (valueMax != newValue) | |||||
| if (lastValueMax != newValue) | |||||
| { | { | ||||
| lastValueMax = newValue; | |||||
| valueMax = newValue; | valueMax = newValue; | ||||
| repaint(); | repaint(); | ||||
| if (popupDisplay != 0) | if (popupDisplay != 0) | ||||
| { | { | ||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMax)); | |||||
| ((SliderPopupDisplayComponent*) popupDisplay)->updatePosition (getTextFromValue (valueMax.getValue())); | |||||
| popupDisplay->repaint(); | popupDisplay->repaint(); | ||||
| } | } | ||||
| @@ -599,7 +625,7 @@ double Slider::getDoubleClickReturnValue (bool& isEnabled_) const | |||||
| void Slider::updateText() | void Slider::updateText() | ||||
| { | { | ||||
| if (valueBox != 0) | if (valueBox != 0) | ||||
| valueBox->setText (getTextFromValue (currentValue), false); | |||||
| valueBox->setText (getTextFromValue (currentValue.getValue()), false); | |||||
| } | } | ||||
| void Slider::setTextValueSuffix (const String& suffix) | void Slider::setTextValueSuffix (const String& suffix) | ||||
| @@ -687,7 +713,7 @@ void Slider::labelTextChanged (Label* label) | |||||
| { | { | ||||
| const double newValue = snapValue (getValueFromText (label->getText()), false); | const double newValue = snapValue (getValueFromText (label->getText()), false); | ||||
| if (getValue() != newValue) | |||||
| if (newValue != (double) currentValue.getValue()) | |||||
| { | { | ||||
| sendDragStart(); | sendDragStart(); | ||||
| setValue (newValue, true, true); | setValue (newValue, true, true); | ||||
| @@ -798,7 +824,7 @@ void Slider::paint (Graphics& g) | |||||
| { | { | ||||
| if (style == Rotary || style == RotaryHorizontalDrag || style == RotaryVerticalDrag) | 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); | jassert (sliderPos >= 0 && sliderPos <= 1.0f); | ||||
| getLookAndFeel().drawRotarySlider (g, | getLookAndFeel().drawRotarySlider (g, | ||||
| @@ -817,9 +843,9 @@ void Slider::paint (Graphics& g) | |||||
| sliderRect.getY(), | sliderRect.getY(), | ||||
| sliderRect.getWidth(), | sliderRect.getWidth(), | ||||
| sliderRect.getHeight(), | sliderRect.getHeight(), | ||||
| getLinearSliderPos (currentValue), | |||||
| getLinearSliderPos (valueMin), | |||||
| getLinearSliderPos (valueMax), | |||||
| getLinearSliderPos (currentValue.getValue()), | |||||
| getLinearSliderPos (valueMin.getValue()), | |||||
| getLinearSliderPos (valueMax.getValue()), | |||||
| style, | style, | ||||
| *this); | *this); | ||||
| } | } | ||||
| @@ -1027,9 +1053,9 @@ void Slider::mouseDown (const MouseEvent& e) | |||||
| { | { | ||||
| const float mousePos = (float) (isVertical() ? e.y : e.x); | 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) | 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) | 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; | valueOnMouseDown = valueWhenLastDragged; | ||||
| @@ -1094,7 +1117,7 @@ void Slider::mouseUp (const MouseEvent&) | |||||
| { | { | ||||
| restoreMouseIfHidden(); | restoreMouseIfHidden(); | ||||
| if (sendChangeOnlyOnRelease && valueOnMouseDown != currentValue) | |||||
| if (sendChangeOnlyOnRelease && valueOnMouseDown != (double) currentValue.getValue()) | |||||
| triggerChangeMessage (false); | triggerChangeMessage (false); | ||||
| sendDragEnd(); | sendDragEnd(); | ||||
| @@ -1124,7 +1147,7 @@ void Slider::restoreMouseIfHidden() | |||||
| const double pos = (sliderBeingDragged == 2) ? getMaxValue() | const double pos = (sliderBeingDragged == 2) ? getMaxValue() | ||||
| : ((sliderBeingDragged == 1) ? getMinValue() | : ((sliderBeingDragged == 1) ? getMinValue() | ||||
| : currentValue); | |||||
| : (double) currentValue.getValue()); | |||||
| if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag) | if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag) | ||||
| { | { | ||||
| @@ -1336,7 +1359,7 @@ void Slider::mouseDrag (const MouseEvent& e) | |||||
| if (e.mods.isShiftDown()) | if (e.mods.isShiftDown()) | ||||
| setMaxValue (getMinValue() + minMaxDiff, false, false, true); | setMaxValue (getMinValue() + minMaxDiff, false, false, true); | ||||
| else | else | ||||
| minMaxDiff = valueMax - valueMin; | |||||
| minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -1348,7 +1371,7 @@ void Slider::mouseDrag (const MouseEvent& e) | |||||
| if (e.mods.isShiftDown()) | if (e.mods.isShiftDown()) | ||||
| setMinValue (getMaxValue() - minMaxDiff, false, false, true); | setMinValue (getMaxValue() - minMaxDiff, false, false, true); | ||||
| else | else | ||||
| minMaxDiff = valueMax - valueMin; | |||||
| minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); | |||||
| } | } | ||||
| mouseXWhenLastDragged = e.x; | mouseXWhenLastDragged = e.x; | ||||
| @@ -1381,18 +1404,19 @@ void Slider::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float w | |||||
| if (valueBox != 0) | if (valueBox != 0) | ||||
| valueBox->hideEditor (false); | valueBox->hideEditor (false); | ||||
| const double value = (double) currentValue.getValue(); | |||||
| const double proportionDelta = (wheelIncrementX != 0 ? -wheelIncrementX : wheelIncrementY) * 0.15f; | 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)); | 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; | delta = -delta; | ||||
| sendDragStart(); | sendDragStart(); | ||||
| setValue (snapValue (currentValue + delta, false), true, true); | |||||
| setValue (snapValue (value + delta, false), true, true); | |||||
| sendDragEnd(); | sendDragEnd(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -31,6 +31,7 @@ | |||||
| #include "../buttons/juce_Button.h" | #include "../buttons/juce_Button.h" | ||||
| #include "../../../events/juce_AsyncUpdater.h" | #include "../../../events/juce_AsyncUpdater.h" | ||||
| #include "../../../containers/juce_SortedSet.h" | #include "../../../containers/juce_SortedSet.h" | ||||
| #include "../../../containers/juce_Value.h" | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -58,7 +59,8 @@ class JUCE_API Slider : public Component, | |||||
| public SettableTooltipClient, | public SettableTooltipClient, | ||||
| private AsyncUpdater, | private AsyncUpdater, | ||||
| private ButtonListener, | private ButtonListener, | ||||
| private LabelListener | |||||
| private LabelListener, | |||||
| private Value::Listener | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -351,6 +353,14 @@ public: | |||||
| /** Returns the slider's current value. */ | /** Returns the slider's current value. */ | ||||
| double getValue() const; | 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. | /** Sets the limits that the slider's value can take. | ||||
| @@ -389,6 +399,14 @@ public: | |||||
| */ | */ | ||||
| double getMinValue() const; | 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. | /** 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 | This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | ||||
| @@ -423,6 +441,14 @@ public: | |||||
| */ | */ | ||||
| double getMaxValue() const; | 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. | /** 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 | This will trigger a callback to SliderListener::sliderValueChanged() for any listeners | ||||
| @@ -720,10 +746,13 @@ protected: | |||||
| void handleAsyncUpdate(); | void handleAsyncUpdate(); | ||||
| /** @internal */ | /** @internal */ | ||||
| void colourChanged(); | void colourChanged(); | ||||
| /** @internal */ | |||||
| void valueChanged (Value& value); | |||||
| private: | private: | ||||
| SortedSet <void*> listeners; | SortedSet <void*> listeners; | ||||
| double currentValue, valueMin, valueMax; | |||||
| Value currentValue, valueMin, valueMax; | |||||
| double lastCurrentValue, lastValueMin, lastValueMax; | |||||
| double minimum, maximum, interval, doubleClickReturnValue; | double minimum, maximum, interval, doubleClickReturnValue; | ||||
| double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; | ||||
| double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | ||||
| @@ -48,41 +48,28 @@ using namespace zlibNamespace; | |||||
| // included publicly. | // included publicly. | ||||
| class GZIPCompressorHelper | class GZIPCompressorHelper | ||||
| { | { | ||||
| private: | |||||
| HeapBlock <z_stream> stream; | |||||
| uint8* data; | |||||
| int dataSize, compLevel, strategy; | |||||
| bool setParams; | |||||
| public: | public: | ||||
| bool finished, shouldFinish; | |||||
| GZIPCompressorHelper (const int compressionLevel, const bool nowrap) | GZIPCompressorHelper (const int compressionLevel, const bool nowrap) | ||||
| : data (0), | : data (0), | ||||
| dataSize (0), | dataSize (0), | ||||
| compLevel (compressionLevel), | compLevel (compressionLevel), | ||||
| strategy (0), | strategy (0), | ||||
| setParams (true), | setParams (true), | ||||
| streamIsValid (false), | |||||
| finished (false), | finished (false), | ||||
| shouldFinish (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() | ~GZIPCompressorHelper() | ||||
| { | { | ||||
| if (stream != 0) | |||||
| deflateEnd (stream); | |||||
| if (streamIsValid) | |||||
| deflateEnd (&stream); | |||||
| } | } | ||||
| bool needsInput() const throw() | bool needsInput() const throw() | ||||
| @@ -98,15 +85,15 @@ public: | |||||
| int doNextBlock (uint8* const dest, const int destSize) throw() | 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; | setParams = false; | ||||
| @@ -114,12 +101,12 @@ public: | |||||
| { | { | ||||
| case Z_STREAM_END: | case Z_STREAM_END: | ||||
| finished = true; | finished = true; | ||||
| // Deliberate fall-through.. | |||||
| case Z_OK: | 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: | default: | ||||
| break; | break; | ||||
| @@ -128,6 +115,15 @@ public: | |||||
| return 0; | 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. | // included publicly. | ||||
| class GZIPDecompressHelper | class GZIPDecompressHelper | ||||
| { | { | ||||
| private: | |||||
| HeapBlock <z_stream> stream; | |||||
| uint8* data; | |||||
| int dataSize; | |||||
| public: | public: | ||||
| bool finished, needsDictionary, error; | |||||
| GZIPDecompressHelper (const bool noWrap) throw() | GZIPDecompressHelper (const bool noWrap) throw() | ||||
| : data (0), | : data (0), | ||||
| dataSize (0), | dataSize (0), | ||||
| finished (false), | |||||
| finished (true), | |||||
| needsDictionary (false), | 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() | ~GZIPDecompressHelper() throw() | ||||
| { | { | ||||
| if (stream != 0) | |||||
| inflateEnd (stream); | |||||
| if (streamIsValid) | |||||
| inflateEnd (&stream); | |||||
| } | } | ||||
| bool needsInput() const throw() { return dataSize <= 0; } | bool needsInput() const throw() { return dataSize <= 0; } | ||||
| @@ -122,28 +110,27 @@ public: | |||||
| int doNextBlock (uint8* const dest, const int destSize) throw() | 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: | case Z_STREAM_END: | ||||
| finished = true; | finished = true; | ||||
| // deliberate fall-through | // deliberate fall-through | ||||
| case Z_OK: | 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: | case Z_NEED_DICT: | ||||
| needsDictionary = true; | needsDictionary = true; | ||||
| data += dataSize - stream->avail_in; | |||||
| dataSize = stream->avail_in; | |||||
| data += dataSize - stream.avail_in; | |||||
| dataSize = stream.avail_in; | |||||
| break; | break; | ||||
| case Z_DATA_ERROR: | case Z_DATA_ERROR: | ||||
| @@ -157,6 +144,14 @@ public: | |||||
| return 0; | 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) | 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; | return true; | ||||
| } | } | ||||
| @@ -270,12 +270,10 @@ void InputStream::skipNextBytes (int64 numBytesToSkip) | |||||
| if (numBytesToSkip > 0) | if (numBytesToSkip > 0) | ||||
| { | { | ||||
| const int skipBufferSize = (int) jmin (numBytesToSkip, (int64) 16384); | 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 | #if ! JUCE_ONLY_BUILD_CORE_LIBRARY | ||||
| #include "containers/juce_ValueTree.cpp" | #include "containers/juce_ValueTree.cpp" | ||||
| #include "containers/juce_Value.cpp" | |||||
| #include "application/juce_Application.cpp" | #include "application/juce_Application.cpp" | ||||
| #include "application/juce_ApplicationCommandInfo.cpp" | #include "application/juce_ApplicationCommandInfo.cpp" | ||||
| #include "application/juce_ApplicationCommandManager.cpp" | #include "application/juce_ApplicationCommandManager.cpp" | ||||
| @@ -65,6 +65,9 @@ | |||||
| #ifndef __JUCE_SPARSESET_JUCEHEADER__ | #ifndef __JUCE_SPARSESET_JUCEHEADER__ | ||||
| #include "containers/juce_SparseSet.h" | #include "containers/juce_SparseSet.h" | ||||
| #endif | #endif | ||||
| #ifndef __JUCE_VALUE_JUCEHEADER__ | |||||
| #include "containers/juce_Value.h" | |||||
| #endif | |||||
| #ifndef __JUCE_VALUETREE_JUCEHEADER__ | #ifndef __JUCE_VALUETREE_JUCEHEADER__ | ||||
| #include "containers/juce_ValueTree.h" | #include "containers/juce_ValueTree.h" | ||||
| #endif | #endif | ||||
| @@ -211,7 +211,10 @@ END_JUCE_NAMESPACE | |||||
| fromConnection: (QTCaptureConnection*) connection | fromConnection: (QTCaptureConnection*) connection | ||||
| { | { | ||||
| if (firstRecordedTime == 0) | if (firstRecordedTime == 0) | ||||
| firstRecordedTime = new Time (Time::getCurrentTime() - RelativeTime::milliseconds (50)); | |||||
| { | |||||
| const Time now (Time::getCurrentTime()); | |||||
| firstRecordedTime = new Time (now - RelativeTime (0.1)); | |||||
| } | |||||
| } | } | ||||
| @end | @end | ||||
| @@ -942,12 +942,20 @@ void NSViewComponentPeer::setFullScreen (bool shouldBeFullScreen) | |||||
| if (fullScreen != 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(); | control = info.release(); | ||||
| setControlBounds (Rectangle (x, y, getWidth(), getHeight())); | 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; | return true; | ||||
| @@ -189,7 +189,9 @@ public: | |||||
| { | { | ||||
| if (recordNextFrameTime) | if (recordNextFrameTime) | ||||
| { | { | ||||
| firstRecordedTime = Time::getCurrentTime(); | |||||
| const double defaultCameraLatency = 0.1; | |||||
| firstRecordedTime = Time::getCurrentTime() - RelativeTime (defaultCameraLatency); | |||||
| recordNextFrameTime = false; | recordNextFrameTime = false; | ||||
| ComSmartPtr <IPin> pin; | ComSmartPtr <IPin> pin; | ||||
| @@ -42,7 +42,7 @@ | |||||
| forEachXmlChildElement (*myParentXml, child) | forEachXmlChildElement (*myParentXml, child) | ||||
| { | { | ||||
| if (child->hasTagName ("FOO")) | |||||
| if (child->hasTagName (T("FOO"))) | |||||
| doSomethingWithXmlElement (child); | doSomethingWithXmlElement (child); | ||||
| } | } | ||||
| @@ -100,12 +100,12 @@ | |||||
| Here's an example of parsing some elements: @code | Here's an example of parsing some elements: @code | ||||
| // check we're looking at the right kind of document.. | // 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.. | // now we'll iterate its sub-elements looking for 'giraffe' elements.. | ||||
| forEachXmlChildElement (*myElement, e) | forEachXmlChildElement (*myElement, e) | ||||
| { | { | ||||
| if (e->hasTagName ("GIRAFFE")) | |||||
| if (e->hasTagName (T("GIRAFFE"))) | |||||
| { | { | ||||
| // found a giraffe, so use some of its attributes.. | // found a giraffe, so use some of its attributes.. | ||||